diff --git a/.coveragerc36 b/.coveragerc36 deleted file mode 100644 index b396c6a362..0000000000 --- a/.coveragerc36 +++ /dev/null @@ -1,23 +0,0 @@ -# This is the coverage.py config for Python 3.6 -# The config for newer Python versions is in pyproject.toml. - -[run] -branch = true -# Match pyproject.toml so the 3.6 container's data file combines with the rest. -relative_files = true -disable_warnings = couldnt-parse -omit = - /tmp/* - */tests/* - */.venv/* - - -[paths] -source = - sentry_sdk/ - */sentry_sdk/ - - -[report] -exclude_lines = - if TYPE_CHECKING: diff --git a/.github/workflows/test-integrations-agents.yml b/.github/workflows/test-integrations-agents.yml index 6a447af889..7d7e290e15 100644 --- a/.github/workflows/test-integrations-agents.yml +++ b/.github/workflows/test-integrations-agents.yml @@ -17,22 +17,22 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.10","3.11","3.12","3.13","3.14","3.14t"] + python-version: ["3.10","3.13","3.14","3.14t"] os: [ubuntu-22.04] env: - # 3.6/3.7 run in the python:X.Y container; tell uv to use that system Python. - TOX_UV_PYTHON_PREFERENCE: ${{ (matrix.python-version == '3.6' || matrix.python-version == '3.7') && 'only-system' || 'managed' }} - container: ${{ (matrix.python-version == '3.6' || matrix.python-version == '3.7') && format('python:{0}', matrix.python-version) || null }} + # 3.7 runs in the python:X.Y container; tell uv to use that system Python. + TOX_UV_PYTHON_PREFERENCE: ${{ (matrix.python-version == '3.7') && 'only-system' || 'managed' }} + container: ${{ (matrix.python-version == '3.7') && format('python:{0}', matrix.python-version) || null }} steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Install uv uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1 with: enable-cache: false - - name: Mark workspace safe for git (3.6/3.7 container) + - name: Mark workspace safe for git (3.7 container) # needed to make git rev-parse work in the containers # subprocesses (e.g. sentry_sdk.utils.get_git_revision) can run git. - if: ${{ matrix.python-version == '3.6' || matrix.python-version == '3.7' }} + if: ${{ matrix.python-version == '3.7' }} run: git config --global --add safe.directory "$GITHUB_WORKSPACE" - name: Setup Test Env run: | diff --git a/.github/workflows/test-integrations-ai-workflow.yml b/.github/workflows/test-integrations-ai-workflow.yml index 9378fbd8d9..bfa2452fd8 100644 --- a/.github/workflows/test-integrations-ai-workflow.yml +++ b/.github/workflows/test-integrations-ai-workflow.yml @@ -20,19 +20,19 @@ jobs: python-version: ["3.9","3.10","3.11","3.12","3.13","3.14"] os: [ubuntu-22.04] env: - # 3.6/3.7 run in the python:X.Y container; tell uv to use that system Python. - TOX_UV_PYTHON_PREFERENCE: ${{ (matrix.python-version == '3.6' || matrix.python-version == '3.7') && 'only-system' || 'managed' }} - container: ${{ (matrix.python-version == '3.6' || matrix.python-version == '3.7') && format('python:{0}', matrix.python-version) || null }} + # 3.7 runs in the python:X.Y container; tell uv to use that system Python. + TOX_UV_PYTHON_PREFERENCE: ${{ (matrix.python-version == '3.7') && 'only-system' || 'managed' }} + container: ${{ (matrix.python-version == '3.7') && format('python:{0}', matrix.python-version) || null }} steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Install uv uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1 with: enable-cache: false - - name: Mark workspace safe for git (3.6/3.7 container) + - name: Mark workspace safe for git (3.7 container) # needed to make git rev-parse work in the containers # subprocesses (e.g. sentry_sdk.utils.get_git_revision) can run git. - if: ${{ matrix.python-version == '3.6' || matrix.python-version == '3.7' }} + if: ${{ matrix.python-version == '3.7' }} run: git config --global --add safe.directory "$GITHUB_WORKSPACE" - name: Setup Test Env run: | diff --git a/.github/workflows/test-integrations-ai.yml b/.github/workflows/test-integrations-ai.yml index 98fc7ced2b..a4cdecaa7a 100644 --- a/.github/workflows/test-integrations-ai.yml +++ b/.github/workflows/test-integrations-ai.yml @@ -20,19 +20,19 @@ jobs: python-version: ["3.8","3.9","3.10","3.11","3.12","3.13","3.14","3.14t","3.15","3.15t"] os: [ubuntu-22.04] env: - # 3.6/3.7 run in the python:X.Y container; tell uv to use that system Python. - TOX_UV_PYTHON_PREFERENCE: ${{ (matrix.python-version == '3.6' || matrix.python-version == '3.7') && 'only-system' || 'managed' }} - container: ${{ (matrix.python-version == '3.6' || matrix.python-version == '3.7') && format('python:{0}', matrix.python-version) || null }} + # 3.7 runs in the python:X.Y container; tell uv to use that system Python. + TOX_UV_PYTHON_PREFERENCE: ${{ (matrix.python-version == '3.7') && 'only-system' || 'managed' }} + container: ${{ (matrix.python-version == '3.7') && format('python:{0}', matrix.python-version) || null }} steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Install uv uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1 with: enable-cache: false - - name: Mark workspace safe for git (3.6/3.7 container) + - name: Mark workspace safe for git (3.7 container) # needed to make git rev-parse work in the containers # subprocesses (e.g. sentry_sdk.utils.get_git_revision) can run git. - if: ${{ matrix.python-version == '3.6' || matrix.python-version == '3.7' }} + if: ${{ matrix.python-version == '3.7' }} run: git config --global --add safe.directory "$GITHUB_WORKSPACE" - name: Setup Test Env run: | diff --git a/.github/workflows/test-integrations-cloud.yml b/.github/workflows/test-integrations-cloud.yml index 7cd947a0b4..337844fc61 100644 --- a/.github/workflows/test-integrations-cloud.yml +++ b/.github/workflows/test-integrations-cloud.yml @@ -17,26 +17,26 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.6","3.7","3.8","3.9","3.10","3.11","3.12","3.13","3.14","3.14t"] + python-version: ["3.7","3.8","3.9","3.10","3.11","3.12","3.13","3.14","3.14t"] os: [ubuntu-22.04] services: docker: image: docker:dind # Required for Docker network management options: --privileged # Required for Docker-in-Docker operations env: - # 3.6/3.7 run in the python:X.Y container; tell uv to use that system Python. - TOX_UV_PYTHON_PREFERENCE: ${{ (matrix.python-version == '3.6' || matrix.python-version == '3.7') && 'only-system' || 'managed' }} - container: ${{ (matrix.python-version == '3.6' || matrix.python-version == '3.7') && format('python:{0}', matrix.python-version) || null }} + # 3.7 runs in the python:X.Y container; tell uv to use that system Python. + TOX_UV_PYTHON_PREFERENCE: ${{ (matrix.python-version == '3.7') && 'only-system' || 'managed' }} + container: ${{ (matrix.python-version == '3.7') && format('python:{0}', matrix.python-version) || null }} steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Install uv uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1 with: enable-cache: false - - name: Mark workspace safe for git (3.6/3.7 container) + - name: Mark workspace safe for git (3.7 container) # needed to make git rev-parse work in the containers # subprocesses (e.g. sentry_sdk.utils.get_git_revision) can run git. - if: ${{ matrix.python-version == '3.6' || matrix.python-version == '3.7' }} + if: ${{ matrix.python-version == '3.7' }} run: git config --global --add safe.directory "$GITHUB_WORKSPACE" - name: Setup Test Env run: | diff --git a/.github/workflows/test-integrations-common.yml b/.github/workflows/test-integrations-common.yml index b4aa179437..f42ac9f6f1 100644 --- a/.github/workflows/test-integrations-common.yml +++ b/.github/workflows/test-integrations-common.yml @@ -17,22 +17,22 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.6","3.7","3.8","3.9","3.10","3.11","3.12","3.13","3.14","3.14t","3.15","3.15t"] + python-version: ["3.7","3.8","3.9","3.10","3.11","3.12","3.13","3.14","3.14t","3.15","3.15t"] os: [ubuntu-22.04] env: - # 3.6/3.7 run in the python:X.Y container; tell uv to use that system Python. - TOX_UV_PYTHON_PREFERENCE: ${{ (matrix.python-version == '3.6' || matrix.python-version == '3.7') && 'only-system' || 'managed' }} - container: ${{ (matrix.python-version == '3.6' || matrix.python-version == '3.7') && format('python:{0}', matrix.python-version) || null }} + # 3.7 runs in the python:X.Y container; tell uv to use that system Python. + TOX_UV_PYTHON_PREFERENCE: ${{ (matrix.python-version == '3.7') && 'only-system' || 'managed' }} + container: ${{ (matrix.python-version == '3.7') && format('python:{0}', matrix.python-version) || null }} steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Install uv uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1 with: enable-cache: false - - name: Mark workspace safe for git (3.6/3.7 container) + - name: Mark workspace safe for git (3.7 container) # needed to make git rev-parse work in the containers # subprocesses (e.g. sentry_sdk.utils.get_git_revision) can run git. - if: ${{ matrix.python-version == '3.6' || matrix.python-version == '3.7' }} + if: ${{ matrix.python-version == '3.7' }} run: git config --global --add safe.directory "$GITHUB_WORKSPACE" - name: Setup Test Env run: | diff --git a/.github/workflows/test-integrations-dbs.yml b/.github/workflows/test-integrations-dbs.yml index ffa832a931..7bc419094b 100644 --- a/.github/workflows/test-integrations-dbs.yml +++ b/.github/workflows/test-integrations-dbs.yml @@ -17,7 +17,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.6","3.7","3.8","3.9","3.10","3.11","3.12","3.13","3.14","3.14t","3.15","3.15t"] + python-version: ["3.7","3.8","3.9","3.10","3.11","3.12","3.13","3.14","3.14t","3.15","3.15t"] os: [ubuntu-22.04] services: postgres: @@ -45,14 +45,14 @@ jobs: ports: - 3306:3306 env: - # 3.6/3.7 run in the python:X.Y container; tell uv to use that system Python. - TOX_UV_PYTHON_PREFERENCE: ${{ (matrix.python-version == '3.6' || matrix.python-version == '3.7') && 'only-system' || 'managed' }} - SENTRY_PYTHON_TEST_POSTGRES_HOST: ${{ (matrix.python-version == '3.6' || matrix.python-version == '3.7') && 'postgres' || 'localhost' }} + # 3.7 runs in the python:X.Y container; tell uv to use that system Python. + TOX_UV_PYTHON_PREFERENCE: ${{ (matrix.python-version == '3.7') && 'only-system' || 'managed' }} + SENTRY_PYTHON_TEST_POSTGRES_HOST: ${{ (matrix.python-version == '3.7') && 'postgres' || 'localhost' }} SENTRY_PYTHON_TEST_POSTGRES_USER: postgres SENTRY_PYTHON_TEST_POSTGRES_PASSWORD: sentry SENTRY_PYTHON_TEST_MYSQL_USER: root SENTRY_PYTHON_TEST_MYSQL_PASSWORD: sentry - container: ${{ (matrix.python-version == '3.6' || matrix.python-version == '3.7') && format('python:{0}', matrix.python-version) || null }} + container: ${{ (matrix.python-version == '3.7') && format('python:{0}', matrix.python-version) || null }} steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Install uv @@ -61,10 +61,10 @@ jobs: enable-cache: false - name: "Setup ClickHouse Server" uses: getsentry/action-clickhouse-in-ci@5dc8a6a50d689bd6051db0241f34849e5a36490b # v1.7 - - name: Mark workspace safe for git (3.6/3.7 container) + - name: Mark workspace safe for git (3.7 container) # needed to make git rev-parse work in the containers # subprocesses (e.g. sentry_sdk.utils.get_git_revision) can run git. - if: ${{ matrix.python-version == '3.6' || matrix.python-version == '3.7' }} + if: ${{ matrix.python-version == '3.7' }} run: git config --global --add safe.directory "$GITHUB_WORKSPACE" - name: Setup Test Env run: | @@ -89,10 +89,6 @@ jobs: run: | set -x # print commands that are executed ./scripts/runtox.sh "py${{ matrix.python-version }}-redis" - - name: Test redis_py_cluster_legacy - run: | - set -x # print commands that are executed - ./scripts/runtox.sh "py${{ matrix.python-version }}-redis_py_cluster_legacy" - name: Test sqlalchemy run: | set -x # print commands that are executed diff --git a/.github/workflows/test-integrations-flags.yml b/.github/workflows/test-integrations-flags.yml index b2acbedab3..fe67ffb0a9 100644 --- a/.github/workflows/test-integrations-flags.yml +++ b/.github/workflows/test-integrations-flags.yml @@ -20,19 +20,19 @@ jobs: python-version: ["3.7","3.8","3.10","3.12","3.13","3.14","3.14t","3.15","3.15t"] os: [ubuntu-22.04] env: - # 3.6/3.7 run in the python:X.Y container; tell uv to use that system Python. - TOX_UV_PYTHON_PREFERENCE: ${{ (matrix.python-version == '3.6' || matrix.python-version == '3.7') && 'only-system' || 'managed' }} - container: ${{ (matrix.python-version == '3.6' || matrix.python-version == '3.7') && format('python:{0}', matrix.python-version) || null }} + # 3.7 runs in the python:X.Y container; tell uv to use that system Python. + TOX_UV_PYTHON_PREFERENCE: ${{ (matrix.python-version == '3.7') && 'only-system' || 'managed' }} + container: ${{ (matrix.python-version == '3.7') && format('python:{0}', matrix.python-version) || null }} steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Install uv uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1 with: enable-cache: false - - name: Mark workspace safe for git (3.6/3.7 container) + - name: Mark workspace safe for git (3.7 container) # needed to make git rev-parse work in the containers # subprocesses (e.g. sentry_sdk.utils.get_git_revision) can run git. - if: ${{ matrix.python-version == '3.6' || matrix.python-version == '3.7' }} + if: ${{ matrix.python-version == '3.7' }} run: git config --global --add safe.directory "$GITHUB_WORKSPACE" - name: Setup Test Env run: | diff --git a/.github/workflows/test-integrations-gevent.yml b/.github/workflows/test-integrations-gevent.yml index f314f1cca4..09c4163f71 100644 --- a/.github/workflows/test-integrations-gevent.yml +++ b/.github/workflows/test-integrations-gevent.yml @@ -17,22 +17,22 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.6","3.8","3.10","3.11","3.12"] + python-version: ["3.7","3.8","3.10","3.11","3.12"] os: [ubuntu-22.04] env: - # 3.6/3.7 run in the python:X.Y container; tell uv to use that system Python. - TOX_UV_PYTHON_PREFERENCE: ${{ (matrix.python-version == '3.6' || matrix.python-version == '3.7') && 'only-system' || 'managed' }} - container: ${{ (matrix.python-version == '3.6' || matrix.python-version == '3.7') && format('python:{0}', matrix.python-version) || null }} + # 3.7 runs in the python:X.Y container; tell uv to use that system Python. + TOX_UV_PYTHON_PREFERENCE: ${{ (matrix.python-version == '3.7') && 'only-system' || 'managed' }} + container: ${{ (matrix.python-version == '3.7') && format('python:{0}', matrix.python-version) || null }} steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Install uv uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1 with: enable-cache: false - - name: Mark workspace safe for git (3.6/3.7 container) + - name: Mark workspace safe for git (3.7 container) # needed to make git rev-parse work in the containers # subprocesses (e.g. sentry_sdk.utils.get_git_revision) can run git. - if: ${{ matrix.python-version == '3.6' || matrix.python-version == '3.7' }} + if: ${{ matrix.python-version == '3.7' }} run: git config --global --add safe.directory "$GITHUB_WORKSPACE" - name: Setup Test Env run: | diff --git a/.github/workflows/test-integrations-graphql.yml b/.github/workflows/test-integrations-graphql.yml index 276ae83682..ed395f4eff 100644 --- a/.github/workflows/test-integrations-graphql.yml +++ b/.github/workflows/test-integrations-graphql.yml @@ -17,22 +17,22 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.6","3.8","3.9","3.10","3.11","3.12","3.13","3.14","3.14t","3.15","3.15t"] + python-version: ["3.7","3.8","3.9","3.10","3.11","3.12","3.13","3.14","3.14t","3.15","3.15t"] os: [ubuntu-22.04] env: - # 3.6/3.7 run in the python:X.Y container; tell uv to use that system Python. - TOX_UV_PYTHON_PREFERENCE: ${{ (matrix.python-version == '3.6' || matrix.python-version == '3.7') && 'only-system' || 'managed' }} - container: ${{ (matrix.python-version == '3.6' || matrix.python-version == '3.7') && format('python:{0}', matrix.python-version) || null }} + # 3.7 runs in the python:X.Y container; tell uv to use that system Python. + TOX_UV_PYTHON_PREFERENCE: ${{ (matrix.python-version == '3.7') && 'only-system' || 'managed' }} + container: ${{ (matrix.python-version == '3.7') && format('python:{0}', matrix.python-version) || null }} steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Install uv uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1 with: enable-cache: false - - name: Mark workspace safe for git (3.6/3.7 container) + - name: Mark workspace safe for git (3.7 container) # needed to make git rev-parse work in the containers # subprocesses (e.g. sentry_sdk.utils.get_git_revision) can run git. - if: ${{ matrix.python-version == '3.6' || matrix.python-version == '3.7' }} + if: ${{ matrix.python-version == '3.7' }} run: git config --global --add safe.directory "$GITHUB_WORKSPACE" - name: Setup Test Env run: | diff --git a/.github/workflows/test-integrations-mcp.yml b/.github/workflows/test-integrations-mcp.yml index 6a0bd2cbc7..ecef354b2a 100644 --- a/.github/workflows/test-integrations-mcp.yml +++ b/.github/workflows/test-integrations-mcp.yml @@ -17,22 +17,22 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.10","3.12","3.13","3.14","3.14t","3.15","3.15t"] + python-version: ["3.10","3.12","3.13","3.14","3.14t"] os: [ubuntu-22.04] env: - # 3.6/3.7 run in the python:X.Y container; tell uv to use that system Python. - TOX_UV_PYTHON_PREFERENCE: ${{ (matrix.python-version == '3.6' || matrix.python-version == '3.7') && 'only-system' || 'managed' }} - container: ${{ (matrix.python-version == '3.6' || matrix.python-version == '3.7') && format('python:{0}', matrix.python-version) || null }} + # 3.7 runs in the python:X.Y container; tell uv to use that system Python. + TOX_UV_PYTHON_PREFERENCE: ${{ (matrix.python-version == '3.7') && 'only-system' || 'managed' }} + container: ${{ (matrix.python-version == '3.7') && format('python:{0}', matrix.python-version) || null }} steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Install uv uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1 with: enable-cache: false - - name: Mark workspace safe for git (3.6/3.7 container) + - name: Mark workspace safe for git (3.7 container) # needed to make git rev-parse work in the containers # subprocesses (e.g. sentry_sdk.utils.get_git_revision) can run git. - if: ${{ matrix.python-version == '3.6' || matrix.python-version == '3.7' }} + if: ${{ matrix.python-version == '3.7' }} run: git config --global --add safe.directory "$GITHUB_WORKSPACE" - name: Setup Test Env run: | diff --git a/.github/workflows/test-integrations-misc.yml b/.github/workflows/test-integrations-misc.yml index 9b2cda8e85..db0a992b57 100644 --- a/.github/workflows/test-integrations-misc.yml +++ b/.github/workflows/test-integrations-misc.yml @@ -17,22 +17,22 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.6","3.7","3.8","3.9","3.10","3.11","3.12","3.13","3.14","3.14t","3.15","3.15t"] + python-version: ["3.7","3.8","3.9","3.10","3.11","3.12","3.13","3.14","3.14t","3.15","3.15t"] os: [ubuntu-22.04] env: - # 3.6/3.7 run in the python:X.Y container; tell uv to use that system Python. - TOX_UV_PYTHON_PREFERENCE: ${{ (matrix.python-version == '3.6' || matrix.python-version == '3.7') && 'only-system' || 'managed' }} - container: ${{ (matrix.python-version == '3.6' || matrix.python-version == '3.7') && format('python:{0}', matrix.python-version) || null }} + # 3.7 runs in the python:X.Y container; tell uv to use that system Python. + TOX_UV_PYTHON_PREFERENCE: ${{ (matrix.python-version == '3.7') && 'only-system' || 'managed' }} + container: ${{ (matrix.python-version == '3.7') && format('python:{0}', matrix.python-version) || null }} steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Install uv uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1 with: enable-cache: false - - name: Mark workspace safe for git (3.6/3.7 container) + - name: Mark workspace safe for git (3.7 container) # needed to make git rev-parse work in the containers # subprocesses (e.g. sentry_sdk.utils.get_git_revision) can run git. - if: ${{ matrix.python-version == '3.6' || matrix.python-version == '3.7' }} + if: ${{ matrix.python-version == '3.7' }} run: git config --global --add safe.directory "$GITHUB_WORKSPACE" - name: Setup Test Env run: | @@ -41,34 +41,22 @@ jobs: run: | set -x # print commands that are executed ./scripts/runtox.sh "py${{ matrix.python-version }}-loguru" - - name: Test opentelemetry - run: | - set -x # print commands that are executed - ./scripts/runtox.sh "py${{ matrix.python-version }}-opentelemetry" - name: Test otlp run: | set -x # print commands that are executed ./scripts/runtox.sh "py${{ matrix.python-version }}-otlp" - - name: Test potel - run: | - set -x # print commands that are executed - ./scripts/runtox.sh "py${{ matrix.python-version }}-potel" - name: Test pure_eval run: | set -x # print commands that are executed ./scripts/runtox.sh "py${{ matrix.python-version }}-pure_eval" - - name: Test trytond + - name: Test trytond_wsgi run: | set -x # print commands that are executed - ./scripts/runtox.sh "py${{ matrix.python-version }}-trytond" + ./scripts/runtox.sh "py${{ matrix.python-version }}-trytond_wsgi" - name: Test typer run: | set -x # print commands that are executed ./scripts/runtox.sh "py${{ matrix.python-version }}-typer" - - name: Test integration_deactivation - run: | - set -x # print commands that are executed - ./scripts/runtox.sh "py${{ matrix.python-version }}-integration_deactivation" - name: Test shadowed_module run: | set -x # print commands that are executed diff --git a/.github/workflows/test-integrations-network.yml b/.github/workflows/test-integrations-network.yml index 155b16b20b..17401dac65 100644 --- a/.github/workflows/test-integrations-network.yml +++ b/.github/workflows/test-integrations-network.yml @@ -17,22 +17,22 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.6","3.7","3.8","3.9","3.10","3.11","3.12","3.13","3.14","3.14t","3.15","3.15t"] + python-version: ["3.7","3.8","3.9","3.10","3.11","3.12","3.13","3.14","3.14t","3.15","3.15t"] os: [ubuntu-22.04] env: - # 3.6/3.7 run in the python:X.Y container; tell uv to use that system Python. - TOX_UV_PYTHON_PREFERENCE: ${{ (matrix.python-version == '3.6' || matrix.python-version == '3.7') && 'only-system' || 'managed' }} - container: ${{ (matrix.python-version == '3.6' || matrix.python-version == '3.7') && format('python:{0}', matrix.python-version) || null }} + # 3.7 runs in the python:X.Y container; tell uv to use that system Python. + TOX_UV_PYTHON_PREFERENCE: ${{ (matrix.python-version == '3.7') && 'only-system' || 'managed' }} + container: ${{ (matrix.python-version == '3.7') && format('python:{0}', matrix.python-version) || null }} steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Install uv uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1 with: enable-cache: false - - name: Mark workspace safe for git (3.6/3.7 container) + - name: Mark workspace safe for git (3.7 container) # needed to make git rev-parse work in the containers # subprocesses (e.g. sentry_sdk.utils.get_git_revision) can run git. - if: ${{ matrix.python-version == '3.6' || matrix.python-version == '3.7' }} + if: ${{ matrix.python-version == '3.7' }} run: git config --global --add safe.directory "$GITHUB_WORKSPACE" - name: Setup Test Env run: | diff --git a/.github/workflows/test-integrations-tasks.yml b/.github/workflows/test-integrations-tasks.yml index cff09610e6..d37a70430f 100644 --- a/.github/workflows/test-integrations-tasks.yml +++ b/.github/workflows/test-integrations-tasks.yml @@ -17,7 +17,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.6","3.7","3.8","3.9","3.10","3.11","3.12","3.13","3.14","3.14t","3.15","3.15t"] + python-version: ["3.7","3.8","3.9","3.10","3.11","3.12","3.13","3.14","3.14t","3.15","3.15t"] os: [ubuntu-22.04] services: redis: @@ -30,10 +30,10 @@ jobs: ports: - 6379:6379 env: - # 3.6/3.7 run in the python:X.Y container; tell uv to use that system Python. - TOX_UV_PYTHON_PREFERENCE: ${{ (matrix.python-version == '3.6' || matrix.python-version == '3.7') && 'only-system' || 'managed' }} - SENTRY_PYTHON_TEST_REDIS_HOST: ${{ (matrix.python-version == '3.6' || matrix.python-version == '3.7') && 'redis' || 'localhost' }} - container: ${{ (matrix.python-version == '3.6' || matrix.python-version == '3.7') && format('python:{0}', matrix.python-version) || null }} + # 3.7 runs in the python:X.Y container; tell uv to use that system Python. + TOX_UV_PYTHON_PREFERENCE: ${{ (matrix.python-version == '3.7') && 'only-system' || 'managed' }} + SENTRY_PYTHON_TEST_REDIS_HOST: ${{ (matrix.python-version == '3.7') && 'redis' || 'localhost' }} + container: ${{ (matrix.python-version == '3.7') && format('python:{0}', matrix.python-version) || null }} steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Install uv @@ -45,10 +45,10 @@ jobs: with: distribution: 'temurin' java-version: '21' - - name: Mark workspace safe for git (3.6/3.7 container) + - name: Mark workspace safe for git (3.7 container) # needed to make git rev-parse work in the containers # subprocesses (e.g. sentry_sdk.utils.get_git_revision) can run git. - if: ${{ matrix.python-version == '3.6' || matrix.python-version == '3.7' }} + if: ${{ matrix.python-version == '3.7' }} run: git config --global --add safe.directory "$GITHUB_WORKSPACE" - name: Setup Test Env run: | diff --git a/.github/workflows/test-integrations-web-1.yml b/.github/workflows/test-integrations-web-1.yml index d97b06fefa..0c62c26d76 100644 --- a/.github/workflows/test-integrations-web-1.yml +++ b/.github/workflows/test-integrations-web-1.yml @@ -17,7 +17,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.6","3.7","3.8","3.9","3.10","3.11","3.12","3.13","3.14","3.14t","3.15","3.15t"] + python-version: ["3.7","3.8","3.9","3.10","3.11","3.12","3.13","3.14","3.14t","3.15","3.15t"] os: [ubuntu-22.04] services: postgres: @@ -34,22 +34,22 @@ jobs: ports: - 5432:5432 env: - # 3.6/3.7 run in the python:X.Y container; tell uv to use that system Python. - TOX_UV_PYTHON_PREFERENCE: ${{ (matrix.python-version == '3.6' || matrix.python-version == '3.7') && 'only-system' || 'managed' }} - SENTRY_PYTHON_TEST_POSTGRES_HOST: ${{ (matrix.python-version == '3.6' || matrix.python-version == '3.7') && 'postgres' || 'localhost' }} + # 3.7 runs in the python:X.Y container; tell uv to use that system Python. + TOX_UV_PYTHON_PREFERENCE: ${{ (matrix.python-version == '3.7') && 'only-system' || 'managed' }} + SENTRY_PYTHON_TEST_POSTGRES_HOST: ${{ (matrix.python-version == '3.7') && 'postgres' || 'localhost' }} SENTRY_PYTHON_TEST_POSTGRES_USER: postgres SENTRY_PYTHON_TEST_POSTGRES_PASSWORD: sentry - container: ${{ (matrix.python-version == '3.6' || matrix.python-version == '3.7') && format('python:{0}', matrix.python-version) || null }} + container: ${{ (matrix.python-version == '3.7') && format('python:{0}', matrix.python-version) || null }} steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Install uv uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1 with: enable-cache: false - - name: Mark workspace safe for git (3.6/3.7 container) + - name: Mark workspace safe for git (3.7 container) # needed to make git rev-parse work in the containers # subprocesses (e.g. sentry_sdk.utils.get_git_revision) can run git. - if: ${{ matrix.python-version == '3.6' || matrix.python-version == '3.7' }} + if: ${{ matrix.python-version == '3.7' }} run: git config --global --add safe.directory "$GITHUB_WORKSPACE" - name: Setup Test Env run: | diff --git a/.github/workflows/test-integrations-web-2.yml b/.github/workflows/test-integrations-web-2.yml index 6ebacf98d8..2e1c4bf084 100644 --- a/.github/workflows/test-integrations-web-2.yml +++ b/.github/workflows/test-integrations-web-2.yml @@ -17,22 +17,22 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.6","3.7","3.8","3.9","3.10","3.11","3.12","3.13","3.14","3.14t","3.15","3.15t"] + python-version: ["3.7","3.8","3.9","3.10","3.11","3.12","3.13","3.14","3.14t","3.15","3.15t"] os: [ubuntu-22.04] env: - # 3.6/3.7 run in the python:X.Y container; tell uv to use that system Python. - TOX_UV_PYTHON_PREFERENCE: ${{ (matrix.python-version == '3.6' || matrix.python-version == '3.7') && 'only-system' || 'managed' }} - container: ${{ (matrix.python-version == '3.6' || matrix.python-version == '3.7') && format('python:{0}', matrix.python-version) || null }} + # 3.7 runs in the python:X.Y container; tell uv to use that system Python. + TOX_UV_PYTHON_PREFERENCE: ${{ (matrix.python-version == '3.7') && 'only-system' || 'managed' }} + container: ${{ (matrix.python-version == '3.7') && format('python:{0}', matrix.python-version) || null }} steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Install uv uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1 with: enable-cache: false - - name: Mark workspace safe for git (3.6/3.7 container) + - name: Mark workspace safe for git (3.7 container) # needed to make git rev-parse work in the containers # subprocesses (e.g. sentry_sdk.utils.get_git_revision) can run git. - if: ${{ matrix.python-version == '3.6' || matrix.python-version == '3.7' }} + if: ${{ matrix.python-version == '3.7' }} run: git config --global --add safe.directory "$GITHUB_WORKSPACE" - name: Setup Test Env run: | diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 5bd58610b5..c23a1b8701 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -110,7 +110,7 @@ jobs: - name: Combine coverage and generate XML run: | uv sync - # relative_files + [tool.coverage.paths] let the 3.6/3.7 container and + # relative_files + [tool.coverage.paths] let the 3.7 container and # the runner data files merge into one source tree. uv run coverage combine .coverage-sentry-* uv run coverage xml diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b31d918e88..11a1a66ceb 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -100,7 +100,7 @@ uv run ruff format tests sentry_sdk We use `mypy` for typing our codebase. Use the following command to typecheck the source: ``` -uv run --group typing mypy sentry_sdk +uv run --group typing mypy sentry_sdk ``` ##### Install Coding Style Pre-commit Hooks @@ -167,7 +167,7 @@ TESTPATH=tests/integrations/logging/test_logging.py uv run tox -e py3.12-common To select specific tests, you can forward arguments to `pytest` like so ```bash -uv run tox -e py3.12-celery-v5.5.3 -- -k test_transaction_events +uv run tox -e py3.12-celery-v5.5.3 -- -k test_simple_with_performance ``` In general, you use diff --git a/MIGRATION_GUIDE.md b/MIGRATION_GUIDE.md index 53396a37ba..4f403f4e55 100644 --- a/MIGRATION_GUIDE.md +++ b/MIGRATION_GUIDE.md @@ -1,3 +1,171 @@ +# Sentry SDK 3.0 Migration Guide + + +Looking to upgrade from Sentry SDK 2.x to 3.x? Here's a comprehensive list of what's changed. Looking for a more digestable summary? See the [guide in the docs](https://docs.sentry.io/platforms/python/migration/2.x-to-3.x) with the most common migration patterns. + +## New Features + + +## Changed + +- The Strawberry integration won't auto-enable anymore if we detect `strawberry-graphql` is installed. Set it up manually, setting the `async_execution` integration option to either `True` or `False` depending on if your app is async or sync. + + ```python + from sentry_sdk.integrations.strawberry import StrawberryIntegration + + sentry_sdk.init( + integrations=[ + StrawberryIntegration(async_execution=True), # or False + ], + ... + ) + ``` + +- The FastAPI and Starlette integrations no longer eagerly consume the request body. As a result, the body is only reported in events if your handler parsed it with `Request.json()` or `Request.form()` before the event is captured. +- The UnraisableHookIntegration is now enabled by default. +- We now don't suppress chained exceptions in the ASGI and asyncio integrations by default. The related `suppress_asgi_chained_exceptions` experimental option was removed. +- In the AWS Lambda and GCP integrations, the message of the warning the SDK optionally emits if a function is about to time out has changed. +- We changed the way we emit warnings. Deprecations will from now on be always emitted using `warnings.warn()`, while all other warnings will be emitted using `logger.warning()`. +- `sentry_sdk.init()` can no longer be used as a context manager. +- The `@trace` decorator doesn't accept a `template` parameter anymore. +- The option `attach_stacktrace` is now `True` by default, meaning the SDK will attach stack traces to messages. +- The Django integration now creates spans for cache operations by default. Pass `DjangoIntegration(cache_spans=False)` to `sentry_sdk.init()` to turn them off. +- The Django integration no longer force-enables cache spans when Spotlight is active and `settings.DEBUG` is `True`. The `cache_spans` option is now always respected as given. + +### Logging + +- The standard library logging integration is not auto-enabled by default anymore. To continue using it, add it to the `integrations` list in your `sentry_sdk.init()`: + + ```python + import sentry_sdk + from sentry_sdk.integrations.logging import LoggingIntegration + + sentry_sdk.init( + integrations=[ + LoggingIntegration(), + ] + ) + ``` + +- The `level` integration option is now called `breadcrumb_level`. +- The `sentry_logs_level` integration option is now called `level`. +- The `capture_sentry_logs` option was removed. Use `level=None` to disable log capture. +- The `ignore_logger` helper was renamed to `ignore_logger_for_events`. +- The `ignore_logger_for_sentry_logs` helper was renamed to `ignore_logger`. +- `SentryHandler` was removed. Use `EventHandler` instead. +- When you enable the integration by adding `LoggingIntegration` to your `sentry_sdk.init()`, it'll start capturing Sentry logs and breadcrumbs. Creating events from logs can be enabled by providing additional integration options. + + | Old name | New name | Old default | New default | Description | + | --- | --- | --- | --- | --- | + | `level` | `breadcrumb_level` | `INFO` | `INFO` | Captures logs of that level and higher as breadcrumbs. | + | `event_level` | `event_level` | `ERROR` | `None` | Captures logs of that level and higher as events. | + | `sentry_logs_level` | `level` | `INFO` | `INFO` | Captures logs of that level and higher as Sentry logs. | + | `capture_sentry_logs` | removed | `False` | n/a | Allows to opt out of instrumenting logs as Sentry logs. Use `level` (previously `sentry_logs_level`) to adjust what should be captured instead. | + | `ignore_logger` | `ignore_logger_for_events` | n/a | n/a | Loggers that match this name will not create breadcrumbs and events. | + | `unignore_logger` | `unignore_logger_for_events` | n/a | n/a | Loggers that match this name will create breadcrumbs and events again. | + | `ignore_logger_for_sentry_logs` | `ignore_logger` | n/a | n/a | Loggers that match this name will not create Sentry logs. | + | `unignore_logger_for_sentry_logs` | `unignore_logger` | n/a | n/a | Loggers that match this name will create Sentry logs again. | + + +### Loguru + +- The Loguru logging integration is not auto-enabled by default anymore if you have Loguru installed. To continue using it, add it to the `integrations` list in your `sentry_sdk.init()`: + + ```python + import sentry_sdk + from sentry_sdk.integrations.loguru import LoguruIntegration + + sentry_sdk.init( + integrations=[ + LoguruIntegration(), + ] + ) + ``` + +- The `level` integration option is now called `breadcrumb_level`. +- The `sentry_logs_level` integration option is now called `level`. +- The `capture_sentry_logs` option was removed. Use `level=None` to disable log capture. +- When you enable the integration by adding `LoguruIntegration` to your `sentry_sdk.init()`, it'll start capturing Sentry logs and breadcrumbs. Creating events from logs can be enabled by providing additional integration options. + + | Old name | New name | Old default | New default | Description | + | --- | --- | --- | --- | --- | + | `level` | `breadcrumb_level` | `INFO` | `INFO` | Captures logs of that level and higher as breadcrumbs. | + | `event_level` | `event_level` | `ERROR` | `None` | Captures logs of that level and higher as events. | + | `sentry_logs_level` | `level` | `INFO` | `INFO` | Captures logs of that level and higher as Sentry logs. | + | `capture_sentry_logs` | removed | `False` | n/a | Allows to opt out of instrumenting logs as Sentry logs. Use `level` (previously `sentry_logs_level`) to adjust what should be captured instead. | + + +## Removed + +- The SDK no longer supports Python 3.6. The oldest supported version is now 3.7. +- Dropped support for Django versions below 2.0. +- Dropped support for gevent versions below 20.9. +- Dropped support for greenlet versions below 0.4.17. +- Dropped support for Falcon versions below 3.0. +- Dropped support for Flask below 2.0. +- Dropped support for Chalice below 1.22. +- Dropped support for aiohttp below 3.7. +- Dropped support for Starlette below 0.20. +- Dropped support for FastAPI below 0.85. +- Dropped support for trytond below 5.4. +- Dropped support for Pyramid below 2.0. +- Dropped support for rq below 1.0. +- Dropped support for Quart below 0.19. +- Dropped support for Sanic below 22.0. +- Dropped support for Celery below 5.0. +- Dropped support for SQLAlchemy below 1.4. +- Dropped support for Huey below 2.0. +- Dropped support for Litestar below 2.0. +- Dropped support for PySpark below 3.0. +- Dropped support for redis-py below 4.2. +- Dropped support for Pydantic AI below 1.76. +- Dropped support for OpenAI Agents below 0.10.3. +- Dropped support for MCP below 2.0. +- Removed the RedisIntegration `max_data_size` option. +- Removed the possibility to supply a specific client to the LaunchDarklyIntegration. +- The `enable_tracing` option was removed. Use `traces_sample_rate=1.0` instead. +- The `enable_logs` option was removed. Using Sentry's logging API now works without requiring setting `enable_logs=True`. +- The `enable_metrics` option was removed. +- The deprecated `@ai_track` decorator was removed. +- The deprecated `push_scope` and `configure_scope` APIs have been removed. Use `with new_scope():` to push a new scope and `scope = get_current_scope()` to retrieve the current scope instead. +- Transaction profiling and related code was removed. +- The `start_profile_session` and `stop_profile_session` were removed in favor of `start_profiler` and `stop_profiler`, respectively. +- The experimental `continuous_profiling_mode` option was removed. Use the top-level `profiler_mode`, instead. +- Removed the deprecated Hub class and all uses of hub throughout the SDK in arguments, options, etc. Use a scope instead. +- The `SentrySpanProcessor`, `SentryPropagator`, `instrumenter`, and associated OpenTelemetry compatibility code was removed along with the `opentelemetry` extra and the `SentryPropagator` entrypoint. Use the `OTLPIntegration` instead. +- Removed the `auto_session_tracing` decorator. Use `track_session` instead. +- The deprecated `set_measurement` API was removed. +- The experimental option `otel_powered_performance` has been removed together with the associated `OpenTelemetryIntegration` and `opentelemetry-experimental` extra. +- A number of extras (installable via `sentry-sdk[extra-name]`) has been removed. Use the base package (`sentry-sdk`) instead; there is no difference in functionality. The following extras have been removed: `aiohttp`, `anthropic`, `arq`, `asyncpg`, `beam`, `bottle`, `celery`, `celery-redbeat`, `chalice`, `clickhouse-driver`, `django`, `falcon`, `fastapi`, `google-genai`, `httpx`, `huey`, `huggingface_hub`, `langchain`, `langgraph`, `launchdarkly`, `litellm`, `litestar`, `loguru`, `mcp`, `openai`, `openfeature`, `pydantic_ai`, `pymongo`, `pyspark`, `rq`, `sanic`, `sqlalchemy`, `starlette`, `starlite`, `statsig`, `tornado`, `unleash`. +- The `failed_request_status_codes` integration option now only supports a set of integers as input. Lists of integers or containers of integers are no longer supported. +- The deprecated `propagate_traces` option has been removed. Use `trace_propagation_targets` instead, which gives you more power over trace propagation. Note that only the top-level `init` option was removed; the `propagate_traces` option of the Celery integration remains available. +- Removed Spotlight integration for Django. See [Spotlight 2.0](https://github.com/getsentry/spotlight/issues/891) for more context. +- The deprecated parameter `propagate_hub` in `ThreadingIntegration()` was removed. +- The experimental `max_spans` option was removed. +- The experimental `before_send_log` option was removed. Use the top-level `before_send_log` instead. +- The experimental `before_send_metric` option was removed. Use the top-level `before_send_metric` instead. +- The experimental `ignore_spans` option was removed. Use the top-level `ignore_spans` instead. +- The experimental `before_send_span` option was removed. Use the top-level `before_send_span` instead. +- `configure_debug_hub` was removed. +- The `max_spans` option of the `LangchainIntegration` was removed. +- `Baggage.from_options` was removed. +- `Transport.capture_event` was removed. Use `Transport.capture_envelope` instead. +- Function transports were removed. +- The `Scope.trace_propagation_meta` function no longer accepts a `span` as argument. +- Direct assignment to `Scope.level` was removed. Use `Scope.set_level` instead. +- Direct assignment to `Scope.user` was removed. Use `Scope.set_user` instead. +- `Scope.iter_headers` was removed. +- The SDK won't set any tags on its own anymore. +- The `update_current_span` API was removed. +- `SanicIntegration` no longer accepts `unsampled_statuses`. +- The `trace_ignore_status_codes` option was removed. +- `add_attachment` no longer accepts an `add_to_transactions` argument. +- The `stream_gen_ai_spans` option was removed. All spans are streamed now. + + +## Deprecated + + # Sentry SDK 2.0 Migration Guide Looking to upgrade from Sentry SDK 1.x to 2.x? Here's a comprehensive list of what's changed. Looking for a more digestable summary? See the [guide in the docs](https://docs.sentry.io/platforms/python/migration/1.x-to-2.x) with the most common migration patterns. diff --git a/docs/api.rst b/docs/api.rst index 802abee75d..a790054f4f 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -39,10 +39,9 @@ Performance Monitoring .. autofunction:: sentry_sdk.api.trace .. autofunction:: sentry_sdk.api.continue_trace +.. autofunction:: sentry_sdk.api.new_trace .. autofunction:: sentry_sdk.api.get_current_span .. autofunction:: sentry_sdk.api.start_span -.. autofunction:: sentry_sdk.api.start_transaction -.. autofunction:: sentry_sdk.api.update_current_span Distributed Tracing @@ -62,7 +61,4 @@ Client Management Managing Scope (advanced) ========================= -.. autofunction:: sentry_sdk.api.configure_scope -.. autofunction:: sentry_sdk.api.push_scope - .. autofunction:: sentry_sdk.api.new_scope diff --git a/docs/apidocs.rst b/docs/apidocs.rst index a3c8a6e150..dd16a59233 100644 --- a/docs/apidocs.rst +++ b/docs/apidocs.rst @@ -2,9 +2,6 @@ API Docs ======== -.. autoclass:: sentry_sdk.Hub - :members: - .. autoclass:: sentry_sdk.Scope :members: @@ -26,13 +23,10 @@ API Docs .. autoclass:: sentry_sdk.HttpTransport :members: -.. autoclass:: sentry_sdk.tracing.Transaction - :members: - -.. autoclass:: sentry_sdk.tracing.Span +.. autoclass:: sentry_sdk.traces.StreamedSpan :members: -.. autoclass:: sentry_sdk.profiler.transaction_profiler.Profile +.. autoclass:: sentry_sdk.traces.NoOpStreamedSpan :members: .. autoclass:: sentry_sdk.session.Session diff --git a/scripts/find_raise_from_none.py b/scripts/find_raise_from_none.py index 63b2b84333..089a14a1df 100644 --- a/scripts/find_raise_from_none.py +++ b/scripts/find_raise_from_none.py @@ -42,17 +42,11 @@ def main(): for module_path in walk_package_modules(): scan_file(module_path) - # TODO: Investigate why we suppress exception chains here. - ignored_raises = { - pathlib.Path("sentry_sdk/integrations/asgi.py"): 2, - pathlib.Path("sentry_sdk/integrations/asyncio.py"): 1, - } - raise_from_none_count = { file: len(occurences) for file, occurences in RaiseFromNoneVisitor.line_numbers.items() } - if raise_from_none_count != ignored_raises: + if raise_from_none_count: exc = Exception("Detected unexpected raise ... from None.") exc.add_note( "Raise ... from None suppresses chained exceptions, removing valuable context." diff --git a/scripts/init_serverless_sdk.py b/scripts/init_serverless_sdk.py index d27036af48..33a85be4b0 100644 --- a/scripts/init_serverless_sdk.py +++ b/scripts/init_serverless_sdk.py @@ -49,8 +49,8 @@ def extract_and_load_lambda_function_module(self, module_path): module_name = module_path.split(os.path.sep)[-1] module_file_path = module_path + ".py" - # Supported python versions are 3.6, 3.7, 3.8 - if py_version >= (3, 6): + # Supported python versions are 3.7, 3.8 + if py_version >= (3, 7): import importlib.util spec = importlib.util.spec_from_file_location( diff --git a/scripts/populate_tox/config.py b/scripts/populate_tox/config.py index 43c0ce7a7b..3fc19d1e18 100644 --- a/scripts/populate_tox/config.py +++ b/scripts/populate_tox/config.py @@ -11,14 +11,12 @@ "*": ["pytest-aiohttp"], ">=3.8": ["pytest-asyncio"], }, - "python": ">=3.7", }, "aiomysql": { "package": "aiomysql", "deps": { "*": ["pytest-asyncio", "cryptography"], }, - "python": ">=3.7", }, "anthropic": { "package": "anthropic", @@ -45,7 +43,7 @@ "*": ["async-timeout", "pytest-asyncio", "fakeredis"], "<=0.23": ["pydantic<2"], # https://github.com/cunla/fakeredis-py/issues/490 - "py3.6,py3.7,py3.8": ["fakeredis<2.36.0"], + "py3.7,py3.8": ["fakeredis<2.36.0"], }, "num_versions": 2, }, @@ -54,11 +52,9 @@ "deps": { "*": ["pytest-asyncio"], }, - "python": ">=3.7", }, "beam": { "package": "apache-beam", - "python": ">=3.7", "num_versions": 2, "deps": { "*": ["dill"], @@ -81,7 +77,6 @@ "package": "celery", "deps": { "*": ["newrelic<10.17.0", "redis", "pytest-forked"], - "py3.6": ["newrelic<8"], "py3.7": ["importlib-metadata<5.0"], }, }, @@ -150,24 +145,22 @@ # FastAPI versions we use older httpx which still supports the # deprecated argument. "<0.110.1": ["httpx<0.28.0"], - "<0.80": ["anyio<4"], - "py3.6": ["aiocontextvars"], + # Old Starlette (< 0.21, used by FastAPI < 0.95) uses + # anyio.start_blocking_portal (removed in anyio 4) and its + # TestClient _MockOriginalResponse lacks close() (called by + # urllib3 >= 2). + "<0.95.0": ["anyio<4", "urllib3<2"], }, }, "flask": { "package": "flask", "deps": { "*": ["flask-login", "werkzeug", "blinker"], - # https://github.com/pallets/flask/issues/4455 - "<2.0": [ - "werkzeug<2.1.0", - "markupsafe<2.0.0", - "itsdangerous>=0.24,<2.0", - "jinja2<3.1.1", - ], - "py3.6,py3.7": [ - "setuptools<82" - ], # Handled by importlib.metadata on Python 3.8+ + "<2.3": ["werkzeug<2.3"], + "py3.7": ["setuptools<82"], # Handled by importlib.metadata on Python 3.8+ + }, + "python": { + "<2.3": "<3.11", }, }, "gql": { @@ -188,7 +181,6 @@ "package": "graphene", "deps": { "*": ["blinker", "fastapi[test]", "flask", "httpx"], - "py3.6": ["aiocontextvars", "setuptools<82"], "py3.7": ["setuptools<82"], # Handled by importlib.metadata on Python 3.8+ }, }, @@ -203,7 +195,6 @@ "pytest-forked", ], }, - "python": ">=3.7", }, "httpx0": { "package": "httpx", @@ -322,10 +313,8 @@ "package": "fastmcp", "deps": { "*": ["pytest-asyncio", "httpx"], - "<0.3.0": [ - "mcp<2" - ], # Pin added to package in https://github.com/PrefectHQ/fastmcp/commit/5f58621f8b7c7ba257c9837333b09b391f868456#diff-50c86b7ed8ac2cf95bd48334961bf0530cdc77b5a56f852c5c61b89d735fd711 }, + "include": ">=4", }, "openai-base": { "package": "openai", @@ -391,9 +380,6 @@ "deps": { "*": ["mockupdb"], }, - "python": { - "<3.6": "<3.7", - }, }, "pyramid": { "package": "pyramid", @@ -415,7 +401,7 @@ "hypercorn<0.15.0", ], "py3.8": ["taskgroup==0.0.0a4"], - "py3.6,py3.7": ["importlib_metadata"], + "py3.7": ["importlib_metadata"], }, "num_versions": 2, }, @@ -434,18 +420,11 @@ "redis": { "package": "redis", "deps": { - "*": ["fakeredis!=1.7.4", "pytest<8.0.0"], + "*": ["fakeredis!=1.7.4", "pytest<8.0.0", "pytest-asyncio"], ">=4.0,<5.0": ["fakeredis<2.31.0"], - "py3.6,py3.7,py3.8": ["fakeredis<2.26.0"], - "py3.7,py3.8,py3.9,py3.10,py3.11,py3.12,py3.13,py3.14,py3.14t": [ - "pytest-asyncio" - ], + "py3.7,py3.8": ["fakeredis<2.26.0"], }, }, - "redis_py_cluster_legacy": { - "package": "redis-py-cluster", - "num_versions": 2, - }, "requests": { "package": "requests", "num_versions": 2, @@ -463,7 +442,7 @@ ">=1.1.14": ["fakeredis<2.36.0"], "<0.9": ["fakeredis<1.0", "redis<3.2.2"], ">=0.9,<0.14": ["fakeredis>=1.0,<1.7.4"], - "py3.6,py3.7": ["fakeredis!=2.26.0"], + "py3.7": ["fakeredis!=2.26.0"], }, "python": { "<0.13": "<3.7", @@ -472,9 +451,8 @@ "sanic": { "package": "sanic", "deps": { - "*": ["websockets<11.0", "aiohttp"], - ">=22": ["sanic-testing"], - "py3.6": ["aiocontextvars==0.2.1"], + "*": ["websockets<11.0", "aiohttp", "sanic-testing"], + "<22.9": ["sanic-testing<22.9", "httpx<0.24"], # tracerite imports pkg_resources before https://github.com/sanic-org/tracerite/commit/2f68543fab726d12d5c5d71fab584eb42140f410 "py3.8": ["tracerite<1.1.2", "setuptools<82"], }, @@ -486,9 +464,6 @@ }, "sqlalchemy": { "package": "sqlalchemy", - "python": { - "<1.4": "<3.10", - }, }, "starlette": { "package": "starlette", @@ -503,8 +478,6 @@ ], # See the comment on FastAPI's httpx bound for more info "<0.37.2": ["httpx<0.28.0"], - "<0.15": ["jinja2<3.1"], - "py3.6": ["aiocontextvars"], }, }, "starlite": { @@ -546,15 +519,14 @@ "<=6.4.1": [ "pytest<8.2" ], # https://github.com/tornadoweb/tornado/pull/3382 - "py3.6": ["aiocontextvars"], }, "num_versions": 2, }, - "trytond": { + "trytond_wsgi": { "package": "trytond", "deps": { "*": ["werkzeug"], - "<=5.0": ["werkzeug<1.0"], + "<5.5": ["werkzeug<2.0"], }, }, "typer": { diff --git a/scripts/populate_tox/package_dependencies.jsonl b/scripts/populate_tox/package_dependencies.jsonl index 3cd5041325..ac70af30ac 100644 --- a/scripts/populate_tox/package_dependencies.jsonl +++ b/scripts/populate_tox/package_dependencies.jsonl @@ -1,26 +1,51 @@ {"python_version": "3.10", "dependencies": [{"metadata": {"name": "openai-agents", "version": "0.22.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f8/56/f5d32edb2e890a5dea9824cb76d179cef47c6a5ea8269d3559d092936106/openai_agents-0.22.3-py3-none-any.whl"}}, {"metadata": {"name": "griffelib", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/63/e876e789525063c840ccfa8857febdabd6523bcef9ce7eb979b9305ea895/griffelib-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "mcp", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/ff/8e7eade68b8a28f7da0ed1085544341b51f9c935dbf6b95c76b7edfea6a0/mcp-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mcp-types", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8f/d7/6ffba5d8cd5dd9b8a19478875c50e04945314ba5074e84d749283f27f62d/mcp_types-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "3.16.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/17/72/2b1fe3e303db76ab2ba0c2de2b57822869bcb588db82334d4ff3aea8acf2/openai-3.16.2-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/2c/af9ca503b38683a82b6732352a861515f28e2d46fe445aea57e07fc86e06/jiter-0.17.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/34/a1/c8e6b66f499f510752c07a092dfe27621f9c255635e59d38704b5681c35a/pydantic_core-2.46.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/cd/4f564b8f132de25db594efc706897069f016790cea63a5669c9df2675f64/charset_normalizer-3.5.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f3/18/a17e2f0cde02dc10154c808deed7e1d8528afff93612f70d3f0a5b19b011/websockets-16.1.1-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/6f/a04e900f465ff3221ccc395522503e2d10e79fa21f2723c8e177aae1e0d1/opentelemetry_api-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/97/672cb32ce0dfea44b740cb7b4f97038463b9cf7c0ead1aacf595572851d6/pyjwt-2.14.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8c/eb/5d7124083e8d8cda8f5b348f544b71ad6f707ad63193758ef4d8e569da02/cryptography-50.0.1-cp39-abi3-manylinux_2_34_x86_64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/75/77/60bebf6f818bec84210ac5b6979ce4eeadce6fbbaabc9c7ab23e506d1ce5/cffi-2.1.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "0.30.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/61/b5/707f6cf0066a6412aacc11d17920ea2e19e5b2f04081c64526eb35b5c6e7/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/6a/2ba3ed4a69babf3afdddf7d8314a48d87562c0a442206bbc2a1b50d5efc0/sse_starlette-3.4.11-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.53.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/76/18/0eea75741ee812e9f598b687619ce2454f6c3a1c5cd21ea990ec6bd26f45/uvicorn-0.53.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "00309e9160aac64c6c329f5b3a40b95e"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "pyramid", "version": "2.0.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/db/41/a2114b8dd2187ae007e022a2baabdc7937cc78211cefc0c01fc5452193af/pyramid-2.0.2-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "2.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/f3/22afbdb20cc4654b10c98043414a14057cd27fdba9d4ae61cea596000ba2/Werkzeug-2.0.3-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "81.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/e3/c164c88b2e5ce7b24d667b9bd83589cf4f3520d97cad01534cd3c4f55fdb/setuptools-81.0.0-py3-none-any.whl"}}, {"metadata": {"name": "hupper", "version": "1.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/86/7d/3888833e4f5ea56af4a9935066ec09a83228e533d7b8877f65889d706ee4/hupper-1.12.1-py3-none-any.whl"}}, {"metadata": {"name": "translationstring", "version": "1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3b/98/36187601a15e3d37e9bfcf0e0e1055532b39d044353b06861c3a519737a9/translationstring-1.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "venusian", "version": "3.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5a/4b/34d926eba40db81b204066a60b4efdc5d8867a8efcbfe44d69b634b1c907/venusian-3.1.1-py3-none-any.whl"}}, {"metadata": {"name": "WebOb", "version": "1.8.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/71/370a65bc7726a1cbf478445c898c7affe907aa42e2e9e5bb38319db74115/webob-1.8.11-py2.py3-none-any.whl"}}, {"metadata": {"name": "zope.deprecation", "version": "6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/ed/da7f8b1c73caf989a0ff7096cc73c59e6c36f35a8f967c51104098602e2d/zope_deprecation-6.0-py3-none-any.whl"}}, {"metadata": {"name": "zope.interface", "version": "8.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/17/0f/8f1a29966bcf863e3a2121edcafb81c55715de7886bcc9544749cc79e7da/zope_interface-8.5-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "plaster", "version": "1.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e7/8b/3f98db1448e3b4d2d142716874a7e02f6101685fdaa0f55a8668e9ffa048/plaster-1.1.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "plaster-pastedeploy", "version": "1.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/30/2d4cf89035c22a89bf0e34dbc50fdc07c42c9bdc90fd972d495257ad2b6e/plaster_pastedeploy-1.0.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "PasteDeploy", "version": "3.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/85/30/cdddd9a88969683a59222a6d61cd6dce923977f2e9f9ffba38e1324149cd/PasteDeploy-3.1.0-py3-none-any.whl"}}], "install_targets_hash": "051f4fcff8eeaa999798b3c8bbc76a3b"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "pyramid", "version": "2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1f/d4/03a8f9b60b8f2a9198c962d08fd9b657c1c0797cbbde3793babbad200845/pyramid-2.1-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "2.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/f3/22afbdb20cc4654b10c98043414a14057cd27fdba9d4ae61cea596000ba2/Werkzeug-2.0.3-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "81.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/e3/c164c88b2e5ce7b24d667b9bd83589cf4f3520d97cad01534cd3c4f55fdb/setuptools-81.0.0-py3-none-any.whl"}}, {"metadata": {"name": "hupper", "version": "1.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/86/7d/3888833e4f5ea56af4a9935066ec09a83228e533d7b8877f65889d706ee4/hupper-1.12.1-py3-none-any.whl"}}, {"metadata": {"name": "translationstring", "version": "1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3b/98/36187601a15e3d37e9bfcf0e0e1055532b39d044353b06861c3a519737a9/translationstring-1.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "venusian", "version": "3.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5a/4b/34d926eba40db81b204066a60b4efdc5d8867a8efcbfe44d69b634b1c907/venusian-3.1.1-py3-none-any.whl"}}, {"metadata": {"name": "WebOb", "version": "1.8.10"}, "download_info": {"url": "https://files.pythonhosted.org/packages/83/21/fce134877fb6fc6ad3c464e4a07ede0ee9219f705d26a981ae58ea36ca13/webob-1.8.10-py2.py3-none-any.whl"}}, {"metadata": {"name": "zope.deprecation", "version": "6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/ed/da7f8b1c73caf989a0ff7096cc73c59e6c36f35a8f967c51104098602e2d/zope_deprecation-6.0-py3-none-any.whl"}}, {"metadata": {"name": "zope.interface", "version": "8.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/17/0f/8f1a29966bcf863e3a2121edcafb81c55715de7886bcc9544749cc79e7da/zope_interface-8.5-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "plaster", "version": "1.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e7/8b/3f98db1448e3b4d2d142716874a7e02f6101685fdaa0f55a8668e9ffa048/plaster-1.1.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "plaster-pastedeploy", "version": "1.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/30/2d4cf89035c22a89bf0e34dbc50fdc07c42c9bdc90fd972d495257ad2b6e/plaster_pastedeploy-1.0.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "PasteDeploy", "version": "3.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/85/30/cdddd9a88969683a59222a6d61cd6dce923977f2e9f9ffba38e1324149cd/PasteDeploy-3.1.0-py3-none-any.whl"}}], "install_targets_hash": "060f93eb8052b63b08924e439967bba6"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "boto3", "version": "1.43.99"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/6f/37/d59247c882bc078b73cfa6f6bb247ac51bedc7637f6a8800def385dcfbba/boto3-1.43.99-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.99"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/9a/2a62da42bc8bd55d99e5b9599c112260dfe9872bedf335bdc5a10dbb653a/botocore-1.43.99-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "s3transfer", "version": "0.19.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/bc/e7/5c595c75e9f41a44f30e526eda465ea0b4eec93470e074e4a111b253f13a/s3transfer-0.19.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}], "install_targets_hash": "0757b3ed0bd295834a1bf3155319b4f9"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "cohere", "version": "6.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/b4/00c2f9f8387a2e77faf8410210466c46d55dd30a0388de41c54441b148fb/cohere-6.1.0-py3-none-any.whl"}}, {"metadata": {"name": "fastavro", "version": "1.12.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3c/91/16c3508447e7cf9f413a6a01792a990ed94d17505fc80a7fb76027078aed/fastavro-1.12.2-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/26/08/0f303cb0b529e456bb116f2d50565a482694fbb94340bf56d44677e7ed03/charset_normalizer-3.4.7-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "tokenizers", "version": "0.23.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e2/6a/068ed9f6e444c9d7e9d55ce134181325700f3d7f30410721bdc8f848d727/tokenizers-0.23.1-cp310-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "huggingface_hub", "version": "1.22.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/9c/a1a377265abd8b823a2c661c665028ccb6b9fba1ca9d08e52ff679c20ecd/huggingface_hub-1.22.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/35/94/4b2ecfbad8f8b04701a23aefb62f540b9137d058b7e1dbef16a32676f0e9/hf_xet-1.5.1-cp37-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "types-requests", "version": "2.33.0.20260518"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1c/bc/b139710a3b6018f7fb2b9508b35c8af564e61bf2bf4fa619d088f3e16f85/types_requests-2.33.0.20260518-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "filelock", "version": "3.29.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4a/e3/f1fae3647d170919c2cf2a898e77e7d1a4e5c7cae0aed7bb4bd3f5ebff6f/filelock-3.29.5-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e5/22/4222d7ddf3da30f363edaa98e329c2bce6c65497c9cb2810931c8b2c0fbc/fsspec-2026.6.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.12.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.41.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/a8/61c96a77fe28993d9a6fb0f4127e05430a267b235a124545d79fea46dd65/pydantic_core-2.41.5-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tqdm", "version": "4.68.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d8/8e/bb97bb0c71802080bfc8952937d174e49cfc50de5c951dd47b2496f0dcdb/tqdm-4.68.3-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "0ad658fae5aa5a77bc7d2271d7f24fcf"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "openai-agents", "version": "0.10.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e2/07/ad27018fb42d6f1e70f471a5ca3f6398a2159575b623edf86e1ddde66ce4/openai_agents-0.10.5-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "2.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ae/f4/561ed79fd94876160018a5e75254cfcb9b0e62d4dded9dcb20072e86d623/openai-2.44.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "griffe", "version": "1.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/83/3b1d03d36f224edded98e9affd0467630fc09d766c0e56fb1498cbb04a9b/griffe-1.15.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/e9/5993079500530586655c6f2823e2926b3f5ceddd49918c5a86757eadba3a/jiter-0.17.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "mcp", "version": "1.30.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f5/f4/e58bc33317c92a0203664daaf00bf6f41166cc0149e5d6870a03f7cd004a/mcp-1.30.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/d0/c787604c71c2bdcda1a5656942fc822cd0f9cd879b9484bb84fc42172703/pydantic_core-2.46.5-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/03/921a3d3c75785aca9ebfbfcabfbc3a1be12e2ab5265deb026d55a5a3f83e/tqdm-4.70.1-py3-none-any.whl"}}, {"metadata": {"name": "types-requests", "version": "2.33.0.20260906"}, "download_info": {"url": "https://files.pythonhosted.org/packages/60/4c/51ec821d22a45b4162fa3f3e9e94ea4c0f8c49e82363b10955baa5438391/types_requests-2.33.0.20260906-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/aa/554e2614f38fc34c58ff1d0911ae8535ad2516440d5482d76fe59f1088b0/charset_normalizer-3.5.1-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "colorama", "version": "0.4.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/97/672cb32ce0dfea44b740cb7b4f97038463b9cf7c0ead1aacf595572851d6/pyjwt-2.14.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/6a/2ba3ed4a69babf3afdddf7d8314a48d87562c0a442206bbc2a1b50d5efc0/sse_starlette-3.4.11-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.52.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/79/4a20b54ab0491485ccd8c077db2d39187c7f12b3e15485d38a7be37c81b4/uvicorn-0.52.4-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/84/a9/ee16a903f13755e914d1eecc482fe64d1f10761c3960e5d8fa6837377aff/cryptography-50.0.1-cp39-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "0.30.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/6a/4ba3d0fb7297ebae71171822554abe48d7cab29c28b8f9f2c04b79988c05/rpds_py-0.30.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/1a/4b2f7c92293ba05cbd4a9a1b28faaf0326272d9488e6354657571c48a7aa/cffi-2.1.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "0ce5e787d33b4cfe2c733e90e400524e"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "openai", "version": "2.54.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/a8/bb76c7356de8ad57f59d5ff993d434df0607f07f08bcc9c9a5c275e399c0/openai-2.54.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/18/e2/d39ae33d3dc30a0c229ff0cb683df961ebb5e7b8691feb2d08b3ee6ac327/tiktoken-0.14.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c6/3d/4d7f5667ea0e0548534ba880b84bb3d12924fd133aa83ad6c6c80fca3d76/jiter-0.16.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/c6/65f646c7ff09bd257f660434adb45c4dfcbbcebcc030562fecf6f5bf887d/pydantic_core-2.46.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.7.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/16/01/cefe4f051302ca298d3f3e79ed6dbd933ac84485b9515acdd6a52d70cef7/regex-2026.7.19-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/aa/554e2614f38fc34c58ff1d0911ae8535ad2516440d5482d76fe59f1088b0/charset_normalizer-3.5.1-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}], "install_targets_hash": "0e0a649708de8e981a20111ea63dbf51"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "openfeature-sdk", "version": "0.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/44/8a4f5225e930ff0d999fd43f5d743a4babeb6c7e76dddc00f0e118878ef3/openfeature_sdk-0.10.0-py3-none-any.whl"}}], "install_targets_hash": "113a6c8b15a3b8283663d37f7b69e71e"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "requests", "version": "2.30.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/80/034ffeca15c0f4e01b7b9c6ad0fb704b44e190cde4e757edbd60be404c41/requests-2.30.0-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/81/8e983840c6e5b93b33c2ba81aa3d52c2e42f0e9a690ce7607a2e61da4a5c/charset_normalizer-3.4.9-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}], "install_targets_hash": "12f06a29703c12e613113f5e51de4e73"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "fastapi", "version": "0.104.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f3/4f/0ce34195b63240b6693086496c9bab4ef23999112184399a3e88854c7674/fastapi-0.104.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/c6/65f646c7ff09bd257f660434adb45c4dfcbbcebcc030562fecf6f5bf887d/pydantic_core-2.46.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "starlette", "version": "0.27.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/f8/e2cca22387965584a409795913b774235752be4176d276714e15e1a58884/starlette-0.27.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/81/8e983840c6e5b93b33c2ba81aa3d52c2e42f0e9a690ce7607a2e61da4a5c/charset_normalizer-3.4.9-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}], "install_targets_hash": "169e3a84c7fb134352fce11f7e68103c"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "redis", "version": "7.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4a/2e/2677f3f93dae0497e7e33b6637302e7f3744efc553f34231183e32584885/redis-7.4.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "7.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ff/f6e8b8f39e08547faece4bd80f89d5a8de68a38b2d179cc1c4490ffa3286/pytest-7.4.4-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/4d/e6e40f93031adbf654d34e542bd396e9f3bc1c6209b40c920d58c9e1317a/fakeredis-2.36.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.23.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ee/82/62e2d63639ecb0fbe8a7ee59ef0bc69a4669ec50f6d3459f74ad4e4189a2/pytest_asyncio-0.23.8-py3-none-any.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}], "install_targets_hash": "186c82b63ae560049b87efb5870e7d53"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "redis", "version": "7.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4a/2e/2677f3f93dae0497e7e33b6637302e7f3744efc553f34231183e32584885/redis-7.4.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "7.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ff/f6e8b8f39e08547faece4bd80f89d5a8de68a38b2d179cc1c4490ffa3286/pytest-7.4.4-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/4d/e6e40f93031adbf654d34e542bd396e9f3bc1c6209b40c920d58c9e1317a/fakeredis-2.36.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.23.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ee/82/62e2d63639ecb0fbe8a7ee59ef0bc69a4669ec50f6d3459f74ad4e4189a2/pytest_asyncio-0.23.8-py3-none-any.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}], "install_targets_hash": "186c82b63ae560049b87efb5870e7d53"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "redis", "version": "7.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4a/2e/2677f3f93dae0497e7e33b6637302e7f3744efc553f34231183e32584885/redis-7.4.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "7.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ff/f6e8b8f39e08547faece4bd80f89d5a8de68a38b2d179cc1c4490ffa3286/pytest-7.4.4-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/4d/e6e40f93031adbf654d34e542bd396e9f3bc1c6209b40c920d58c9e1317a/fakeredis-2.36.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.23.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ee/82/62e2d63639ecb0fbe8a7ee59ef0bc69a4669ec50f6d3459f74ad4e4189a2/pytest_asyncio-0.23.8-py3-none-any.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}], "install_targets_hash": "186c82b63ae560049b87efb5870e7d53"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "redis", "version": "7.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4a/2e/2677f3f93dae0497e7e33b6637302e7f3744efc553f34231183e32584885/redis-7.4.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "7.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ff/f6e8b8f39e08547faece4bd80f89d5a8de68a38b2d179cc1c4490ffa3286/pytest-7.4.4-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/4d/e6e40f93031adbf654d34e542bd396e9f3bc1c6209b40c920d58c9e1317a/fakeredis-2.36.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.23.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ee/82/62e2d63639ecb0fbe8a7ee59ef0bc69a4669ec50f6d3459f74ad4e4189a2/pytest_asyncio-0.23.8-py3-none-any.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}], "install_targets_hash": "186c82b63ae560049b87efb5870e7d53"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "redis", "version": "7.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4a/2e/2677f3f93dae0497e7e33b6637302e7f3744efc553f34231183e32584885/redis-7.4.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "7.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ff/f6e8b8f39e08547faece4bd80f89d5a8de68a38b2d179cc1c4490ffa3286/pytest-7.4.4-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/4d/e6e40f93031adbf654d34e542bd396e9f3bc1c6209b40c920d58c9e1317a/fakeredis-2.36.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.23.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ee/82/62e2d63639ecb0fbe8a7ee59ef0bc69a4669ec50f6d3459f74ad4e4189a2/pytest_asyncio-0.23.8-py3-none-any.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}], "install_targets_hash": "186c82b63ae560049b87efb5870e7d53"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "redis", "version": "7.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4a/2e/2677f3f93dae0497e7e33b6637302e7f3744efc553f34231183e32584885/redis-7.4.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "7.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ff/f6e8b8f39e08547faece4bd80f89d5a8de68a38b2d179cc1c4490ffa3286/pytest-7.4.4-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/4d/e6e40f93031adbf654d34e542bd396e9f3bc1c6209b40c920d58c9e1317a/fakeredis-2.36.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.23.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ee/82/62e2d63639ecb0fbe8a7ee59ef0bc69a4669ec50f6d3459f74ad4e4189a2/pytest_asyncio-0.23.8-py3-none-any.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}], "install_targets_hash": "186c82b63ae560049b87efb5870e7d53"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "fastapi", "version": "0.85.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/d4/4256804791b1e822f46bf79015270e9e9f14e9b634cb8231a88f6dc100c3/fastapi-0.85.2-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "0.20.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/37/8ac52116984d6a0d8502ec2c7e4a4a78f862b76410cdb1a4bcb384c91cb3/starlette-0.20.4-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "1.26.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/33/cf/8435d5a7159e2a9c83a95896ed596f68cf798005fe107cc655b5c5c14704/urllib3-1.26.20-py2.py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "1.10.26"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/e6/10df5f08c105bcbb4adbee7d1108ff4b347702b110fed058f6a03f1c6b73/pydantic-1.10.26-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/81/8e983840c6e5b93b33c2ba81aa3d52c2e42f0e9a690ce7607a2e61da4a5c/charset_normalizer-3.4.9-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}], "install_targets_hash": "19e353ce40ba92d24a84d4e21339caaa"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "pyspark", "version": "3.5.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/ce/81e53e729790556e3983e95de1a7d5df91a34adfcd34b5a5ab0e0c6e9b33/pyspark-3.5.9.tar.gz"}}, {"metadata": {"name": "py4j", "version": "0.10.9.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/db/ea0203e495be491c85af87b66e37acfd3bf756fd985f87e46fc5e3bf022c/py4j-0.10.9.9-py2.py3-none-any.whl"}}], "install_targets_hash": "1a79880f834ae1c486d6aca78b08c546"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "pyspark", "version": "3.5.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/ce/81e53e729790556e3983e95de1a7d5df91a34adfcd34b5a5ab0e0c6e9b33/pyspark-3.5.9.tar.gz"}}, {"metadata": {"name": "py4j", "version": "0.10.9.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/db/ea0203e495be491c85af87b66e37acfd3bf756fd985f87e46fc5e3bf022c/py4j-0.10.9.9-py2.py3-none-any.whl"}}], "install_targets_hash": "1a79880f834ae1c486d6aca78b08c546"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "boto3", "version": "1.24.96"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e2/53/e9c9f18f97f1565d9194c0ebbfb8bd9bd4bbb93a54569d2e7af256980511/boto3-1.24.96-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.27.96"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/73/aa345e22ce21e86fa99e8dc25ab7ae4fd73eedc4c365282c82fa6ba3f66f/botocore-1.27.96-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "s3transfer", "version": "0.6.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d9/17/a3b666f5ef9543cfd3c661d39d1e193abb9649d0cfbbfee3cf3b51d5af02/s3transfer-0.6.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "1.26.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/33/cf/8435d5a7159e2a9c83a95896ed596f68cf798005fe107cc655b5c5c14704/urllib3-1.26.20-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}], "install_targets_hash": "1c0ddec7e53a8ba50dcb4c9c41d77fc6"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "boto3", "version": "1.24.96"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e2/53/e9c9f18f97f1565d9194c0ebbfb8bd9bd4bbb93a54569d2e7af256980511/boto3-1.24.96-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.27.96"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/73/aa345e22ce21e86fa99e8dc25ab7ae4fd73eedc4c365282c82fa6ba3f66f/botocore-1.27.96-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "s3transfer", "version": "0.6.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d9/17/a3b666f5ef9543cfd3c661d39d1e193abb9649d0cfbbfee3cf3b51d5af02/s3transfer-0.6.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "1.26.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/33/cf/8435d5a7159e2a9c83a95896ed596f68cf798005fe107cc655b5c5c14704/urllib3-1.26.20-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}], "install_targets_hash": "1c0ddec7e53a8ba50dcb4c9c41d77fc6"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "boto3", "version": "1.24.96"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e2/53/e9c9f18f97f1565d9194c0ebbfb8bd9bd4bbb93a54569d2e7af256980511/boto3-1.24.96-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.27.96"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/73/aa345e22ce21e86fa99e8dc25ab7ae4fd73eedc4c365282c82fa6ba3f66f/botocore-1.27.96-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "s3transfer", "version": "0.6.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d9/17/a3b666f5ef9543cfd3c661d39d1e193abb9649d0cfbbfee3cf3b51d5af02/s3transfer-0.6.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "1.26.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/33/cf/8435d5a7159e2a9c83a95896ed596f68cf798005fe107cc655b5c5c14704/urllib3-1.26.20-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}], "install_targets_hash": "1c0ddec7e53a8ba50dcb4c9c41d77fc6"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "boto3", "version": "1.24.96"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e2/53/e9c9f18f97f1565d9194c0ebbfb8bd9bd4bbb93a54569d2e7af256980511/boto3-1.24.96-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.27.96"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/73/aa345e22ce21e86fa99e8dc25ab7ae4fd73eedc4c365282c82fa6ba3f66f/botocore-1.27.96-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "s3transfer", "version": "0.6.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d9/17/a3b666f5ef9543cfd3c661d39d1e193abb9649d0cfbbfee3cf3b51d5af02/s3transfer-0.6.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "1.26.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/33/cf/8435d5a7159e2a9c83a95896ed596f68cf798005fe107cc655b5c5c14704/urllib3-1.26.20-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}], "install_targets_hash": "1c0ddec7e53a8ba50dcb4c9c41d77fc6"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "boto3", "version": "1.24.96"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e2/53/e9c9f18f97f1565d9194c0ebbfb8bd9bd4bbb93a54569d2e7af256980511/boto3-1.24.96-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.27.96"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/73/aa345e22ce21e86fa99e8dc25ab7ae4fd73eedc4c365282c82fa6ba3f66f/botocore-1.27.96-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "s3transfer", "version": "0.6.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d9/17/a3b666f5ef9543cfd3c661d39d1e193abb9649d0cfbbfee3cf3b51d5af02/s3transfer-0.6.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "1.26.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/33/cf/8435d5a7159e2a9c83a95896ed596f68cf798005fe107cc655b5c5c14704/urllib3-1.26.20-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}], "install_targets_hash": "1c0ddec7e53a8ba50dcb4c9c41d77fc6"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "boto3", "version": "1.24.96"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e2/53/e9c9f18f97f1565d9194c0ebbfb8bd9bd4bbb93a54569d2e7af256980511/boto3-1.24.96-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.27.96"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/73/aa345e22ce21e86fa99e8dc25ab7ae4fd73eedc4c365282c82fa6ba3f66f/botocore-1.27.96-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "s3transfer", "version": "0.6.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d9/17/a3b666f5ef9543cfd3c661d39d1e193abb9649d0cfbbfee3cf3b51d5af02/s3transfer-0.6.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "1.26.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/33/cf/8435d5a7159e2a9c83a95896ed596f68cf798005fe107cc655b5c5c14704/urllib3-1.26.20-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}], "install_targets_hash": "1c0ddec7e53a8ba50dcb4c9c41d77fc6"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "boto3", "version": "1.24.96"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e2/53/e9c9f18f97f1565d9194c0ebbfb8bd9bd4bbb93a54569d2e7af256980511/boto3-1.24.96-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.27.96"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/73/aa345e22ce21e86fa99e8dc25ab7ae4fd73eedc4c365282c82fa6ba3f66f/botocore-1.27.96-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "s3transfer", "version": "0.6.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d9/17/a3b666f5ef9543cfd3c661d39d1e193abb9649d0cfbbfee3cf3b51d5af02/s3transfer-0.6.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "1.26.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/33/cf/8435d5a7159e2a9c83a95896ed596f68cf798005fe107cc655b5c5c14704/urllib3-1.26.20-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}], "install_targets_hash": "1c0ddec7e53a8ba50dcb4c9c41d77fc6"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "langchain", "version": "1.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/85/86/cc13651cfda820d96ca8c612538166334935e8cf4331a31f5dd369d27760/langchain-1.4.2-py3-none-any.whl"}}, {"metadata": {"name": "langchain-core", "version": "1.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e6/18/cf18cfec118b02e003f35300b54d6a1173dc6e4905cffdf5ea49e390a7f9/langchain_core-1.6.3-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "jsonpatch", "version": "1.33"}, "download_info": {"url": "https://files.pythonhosted.org/packages/73/07/02e16ed01e04a374e644b575638ec7987ae846d25ad97bcc9945a3ee4b0e/jsonpatch-1.33-py2.py3-none-any.whl"}}, {"metadata": {"name": "langgraph", "version": "1.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0a/7f/c5c30e4be99ff821029c7ac872a480676bb179c9f3df85ea3f38d13f86d4/langgraph-1.2.11-py3-none-any.whl"}}, {"metadata": {"name": "langgraph-checkpoint", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/71/3b475f09bd57d3a5649792c66353312b4432afd843f301739dfcebd157f0/langgraph_checkpoint-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "langgraph-prebuilt", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/43/3fe1a700b8490ed02679cdbbc8c915eb23a092faf496c9c1118abcd10be3/langgraph_prebuilt-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "langgraph-sdk", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/43/d5/2ad7f3a835c6fcebf58b6669552536ecd52d2dfe4cf49c6c36648fd83572/langgraph_sdk-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "langsmith", "version": "0.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/51/892ff5a2efc8e222ca114dd0e19b56978f78a5ee62d3b33783588dd8e6d4/langsmith-0.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/34/a1/c8e6b66f499f510752c07a092dfe27621f9c255635e59d38704b5681c35a/pydantic_core-2.46.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7a/1e/7acc4f0e74c4b3d9531e24739e0ab832a5edf40e64fbae1a9c01941cabd7/pyyaml-6.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "uuid_utils", "version": "0.17.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/76/6b/516183ba5f7d35521edf8cfaea9b1192da8b262587faa8106d1f73ab0eb1/uuid_utils-0.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f3/18/a17e2f0cde02dc10154c808deed7e1d8528afff93612f70d3f0a5b19b011/websockets-16.1.1-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "3.16.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/17/72/2b1fe3e303db76ab2ba0c2de2b57822869bcb588db82334d4ff3aea8acf2/openai-3.16.2-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/2c/af9ca503b38683a82b6732352a861515f28e2d46fe445aea57e07fc86e06/jiter-0.17.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "langchain-openai", "version": "1.6.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b2/47/b87a3c372e52678eb4408360eadbe04cdd5371e21fe2560b6efd66989624/langchain_openai-1.6.2-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/af/c8/051e7b72a816ff50eb34a1c7c5b185cd2429ffdf59a497baea35b2b6b2dd/tiktoken-0.14.0-cp310-cp310-manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "langchain-community", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8f/39/5d97e42a3e95dc2a6d71b2f902a3fae71786131e11d01bddb604accb0ebe/langchain_community-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "langchain-classic", "version": "1.0.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/9a/b8f5cb7490fdbf233088031fc69c9c747439d4097f67f196c1eb4869916d/langchain_classic-1.0.8-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/ff/cb36724e8c8d17f90ada567a9ff3efe1d6e9b549fba697a242aece180f21/aiohttp-3.14.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "async-timeout", "version": "4.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/fa/e01228c2938de91d47b307831c62ab9e4001e747789d0b05baf779a6488c/async_timeout-4.0.3-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "langchain-text-splitters", "version": "1.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d3/26/1ef06f56198d631296d646a6223de35bcc6cf9795ceb2442816bc963b84c/langchain_text_splitters-1.1.2-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ea/e4/4ea1ab36ab8ed969c945f1abdc350e5865043b7466789d917735213d2369/multidict-6.9.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/cd/4f564b8f132de25db594efc706897069f016790cea63a5669c9df2675f64/charset_normalizer-3.5.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "SQLAlchemy", "version": "2.0.54"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/93/9d26b109f5472017bf6e7a1b9dac12ac5f6165ba37a297834d0690c42cf3/sqlalchemy-2.0.54-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "urllib3", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.25.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/28/b9/7818ac6dec7fbcd16be2d19495807c01e2c38834e57d41c63356a75e786b/yarl-1.25.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "google-genai", "version": "2.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/84/5b/87913fe392ba7b6402577259289ed3740c577956554a674b191a2971d33e/google_genai-2.24.0-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.58.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/59/13/477d90d09591b3938b45c4e11f4d8a51291682112cb5efcac961e815d562/google_auth-2.58.0-py3-none-any.whl"}}, {"metadata": {"name": "langchain-google-genai", "version": "4.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/10/83bb535e78c2cf767a6193c2f3b00b2894c1581a36ef85911ebaa3b9a891/langchain_google_genai-4.4.0-py3-none-any.whl"}}, {"metadata": {"name": "filetype", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/18/79/1b8fa1bb3568781e84c9200f951c735f3f157429f44be0495da55894d620/filetype-1.2.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8c/eb/5d7124083e8d8cda8f5b348f544b71ad6f707ad63193758ef4d8e569da02/cryptography-50.0.1-cp39-abi3-manylinux_2_34_x86_64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/75/77/60bebf6f818bec84210ac5b6979ce4eeadce6fbbaabc9c7ab23e506d1ce5/cffi-2.1.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/ed/c7895fd2fde7f3ee70d248175f9b6cdf792fb741ab92dc59cd9ef3bd241b/frozenlist-1.8.0-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl"}}, {"metadata": {"name": "greenlet", "version": "3.5.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/5c/092682ae7ca1aadd44aa36b0bc35c48c9ed55f9ffebb5794980b1e2ae74b/greenlet-3.5.6-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonpointer", "version": "3.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/6a/a83720e953b1682d2d109d3c2dbb0bc9bf28cc1cbc205be4ef4be5da709d/jsonpointer-3.1.1-py3-none-any.whl"}}, {"metadata": {"name": "langchain-protocol", "version": "0.0.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/80/c9/f6cbf357d48ccbd18bb394433b1fd7ad9be004eed9377ad08bb85777e5e6/langchain_protocol-0.0.19-py3-none-any.whl"}}, {"metadata": {"name": "numpy", "version": "2.2.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b4/63/3de6a34ad7ad6646ac7d2f55ebc6ad439dbbf9c4370017c50cf403fb19b5/numpy-2.2.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "orjson", "version": "3.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/75/20/930824c07685c22af23f26818ed3853b0270488a412b6ab757904b7f787b/orjson-3.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "ormsgpack", "version": "1.12.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/72/30/a436be9ce27d693d4e19fa94900028067133779f09fc45776db3f689c822/ormsgpack-1.12.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f0/51/5adee15e12a7e314cece4543fbf295b0fe1b504dc78b32dff4c8eb1e29b0/propcache-0.5.4-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/3b/6163796d69c3977d1e4287bea4a6979161cbbdd170ebb430511e8e1999ce/pyasn1-0.6.4-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "xxhash", "version": "4.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5f/3b/e5d20b4f602d15fc5fc066f601052a7d6f5a401a50d67fac92098a5829a5/xxhash-4.0.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "zstandard", "version": "0.25.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/e5/6d36f92a197c3c17729a2125e29c169f460538a7d939a27eaaa6dcfcba8e/zstandard-0.25.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.9.10"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/b2/be9fafe5e05888296fdd35d82ba9cbb67b0d352e9911fad3c458beb3a34a/regex-2026.9.10-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}], "install_targets_hash": "1f1d7e5fcc21f036dd1fe5ff2434a014"} -{"python_version": "3.10", "dependencies": [{"metadata": {"name": "fastmcp", "version": "1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/bf/0a77688242f30f81e3633d3765289966d9c7e408f9dcb4928a85852b9fde/fastmcp-1.0-py3-none-any.whl"}}, {"metadata": {"name": "mcp", "version": "1.29.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/c8/248b201f6d753d69fd5d6506011abbb35a946d9142b2ae311a948fd0be3d/mcp-1.29.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/c6/65f646c7ff09bd257f660434adb45c4dfcbbcebcc030562fecf6f5bf887d/pydantic_core-2.46.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/77/c1/6e422f34e569cf8e18df68d1939c81c099d2b61e4f7d9621c8a77560799c/pydantic_settings-2.14.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/2a/5bb823f5bedcf80718cea7fbc95ec5515cca3769633c4b01a32be7f30e7c/cryptography-49.0.0-cp39-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/aa/24580a278de21fd7322635556334d9b535f1cbc00b0a3919447cdf464c65/cffi-2.1.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "0.30.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/6a/4ba3d0fb7297ebae71171822554abe48d7cab29c28b8f9f2c04b79988c05/rpds_py-0.30.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/36/e10c1d1b7ca881d2625db2ec28508578499187bb1c389952c398474e1834/sse_starlette-3.4.6-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typer", "version": "0.27.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/40/03/26a383c9e58c213199d1aad1c3d353cfc22d4444ec6d2c0bf8ad02523843/typer-0.27.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "shellingham", "version": "1.5.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.52.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/39/e6/b5c0630ace9757232aec07112be8146b812787db52141ff9d50674aa7634/uvicorn-0.52.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "20723503fc47693dca3f6601f6cab1ee"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "fastapi", "version": "0.141.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/03/10388a42375ee7e4ac9b94eb2c5c569c8b5795e377e701c9ac3ad63de890/fastapi-0.141.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/81/8e983840c6e5b93b33c2ba81aa3d52c2e42f0e9a690ce7607a2e61da4a5c/charset_normalizer-3.4.9-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/c6/65f646c7ff09bd257f660434adb45c4dfcbbcebcc030562fecf6f5bf887d/pydantic_core-2.46.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}], "install_targets_hash": "20b998148dda6aa7b3fb3474012892c8"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "fastapi", "version": "0.141.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/03/10388a42375ee7e4ac9b94eb2c5c569c8b5795e377e701c9ac3ad63de890/fastapi-0.141.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/81/8e983840c6e5b93b33c2ba81aa3d52c2e42f0e9a690ce7607a2e61da4a5c/charset_normalizer-3.4.9-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/c6/65f646c7ff09bd257f660434adb45c4dfcbbcebcc030562fecf6f5bf887d/pydantic_core-2.46.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}], "install_targets_hash": "20b998148dda6aa7b3fb3474012892c8"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "fastapi", "version": "0.141.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/03/10388a42375ee7e4ac9b94eb2c5c569c8b5795e377e701c9ac3ad63de890/fastapi-0.141.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/81/8e983840c6e5b93b33c2ba81aa3d52c2e42f0e9a690ce7607a2e61da4a5c/charset_normalizer-3.4.9-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/c6/65f646c7ff09bd257f660434adb45c4dfcbbcebcc030562fecf6f5bf887d/pydantic_core-2.46.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}], "install_targets_hash": "20b998148dda6aa7b3fb3474012892c8"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "fastapi", "version": "0.141.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/03/10388a42375ee7e4ac9b94eb2c5c569c8b5795e377e701c9ac3ad63de890/fastapi-0.141.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/81/8e983840c6e5b93b33c2ba81aa3d52c2e42f0e9a690ce7607a2e61da4a5c/charset_normalizer-3.4.9-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/c6/65f646c7ff09bd257f660434adb45c4dfcbbcebcc030562fecf6f5bf887d/pydantic_core-2.46.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}], "install_targets_hash": "20b998148dda6aa7b3fb3474012892c8"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "fastapi", "version": "0.141.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/03/10388a42375ee7e4ac9b94eb2c5c569c8b5795e377e701c9ac3ad63de890/fastapi-0.141.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/81/8e983840c6e5b93b33c2ba81aa3d52c2e42f0e9a690ce7607a2e61da4a5c/charset_normalizer-3.4.9-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/c6/65f646c7ff09bd257f660434adb45c4dfcbbcebcc030562fecf6f5bf887d/pydantic_core-2.46.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}], "install_targets_hash": "20b998148dda6aa7b3fb3474012892c8"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "fastapi", "version": "0.141.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/03/10388a42375ee7e4ac9b94eb2c5c569c8b5795e377e701c9ac3ad63de890/fastapi-0.141.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/81/8e983840c6e5b93b33c2ba81aa3d52c2e42f0e9a690ce7607a2e61da4a5c/charset_normalizer-3.4.9-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/c6/65f646c7ff09bd257f660434adb45c4dfcbbcebcc030562fecf6f5bf887d/pydantic_core-2.46.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}], "install_targets_hash": "20b998148dda6aa7b3fb3474012892c8"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "fastapi", "version": "0.141.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/03/10388a42375ee7e4ac9b94eb2c5c569c8b5795e377e701c9ac3ad63de890/fastapi-0.141.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/5f/b98b8da398637b551e427e7be922bdec19177dc54d6811dcdaa503f23aac/charset_normalizer-3.4.9-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/af/cd/ce6e848bbf2c32314c9b237839119c5a564a59725b53157c856e90937b7a/markupsafe-3.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"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"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}], "install_targets_hash": "20b998148dda6aa7b3fb3474012892c8"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "fastapi", "version": "0.141.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/03/10388a42375ee7e4ac9b94eb2c5c569c8b5795e377e701c9ac3ad63de890/fastapi-0.141.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/5f/b98b8da398637b551e427e7be922bdec19177dc54d6811dcdaa503f23aac/charset_normalizer-3.4.9-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/af/cd/ce6e848bbf2c32314c9b237839119c5a564a59725b53157c856e90937b7a/markupsafe-3.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"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"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}], "install_targets_hash": "20b998148dda6aa7b3fb3474012892c8"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "httpx2", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/29/45/82bc57c3d9c3314f663b67cc057f1c017a6450685dde513f4f8db5cf431f/httpx2-2.4.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2-pytest", "version": "1.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/46/ef/e9b6fb576f1f518f68e9f9cce9776870452ae2b8cfbba53b4127701b9a55/httpx2_pytest-1.0.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/72/4fdf2306143a92a471fad9f3655aa542d43aa9188a7c9534e82c9aecf837/httpcore2-2.4.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}], "install_targets_hash": "20f77812852d7e4a68656d7028ccce45"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "httpx2", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/29/45/82bc57c3d9c3314f663b67cc057f1c017a6450685dde513f4f8db5cf431f/httpx2-2.4.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2-pytest", "version": "1.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/46/ef/e9b6fb576f1f518f68e9f9cce9776870452ae2b8cfbba53b4127701b9a55/httpx2_pytest-1.0.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/72/4fdf2306143a92a471fad9f3655aa542d43aa9188a7c9534e82c9aecf837/httpcore2-2.4.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}], "install_targets_hash": "20f77812852d7e4a68656d7028ccce45"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "celery", "version": "5.2.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1d/99/21fe9d1829cab4fc77d18f89d0c4cbcfe754e95f8b8f4af64fe4997c442f/celery-5.2.7-py3-none-any.whl"}}, {"metadata": {"name": "newrelic", "version": "10.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d4/71/07c41fd5e8c94e95216b000d00c3cf735f769cb406c0f33c6ff83b7b7418/newrelic-10.16.0.tar.gz"}}, {"metadata": {"name": "billiard", "version": "3.6.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2b/89/0c43de91d4e52eaa7bd748771d417f6ac9e51e66b2f61928c2151bf65878/billiard-3.6.4.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "kombu", "version": "5.6.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/0f/834427d8c03ff1d7e867d3db3d176470c64871753252b21b4f4897d1fa45/kombu-5.6.2-py3-none-any.whl"}}, {"metadata": {"name": "vine", "version": "5.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/ff/7c0c86c43b3cbb927e0ccc0255cb4057ceba4799cd44ae95174ce8e8b5b2/vine-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "amqp", "version": "5.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/26/99/fc813cd978842c26c82534010ea849eee9ab3a13ea2b74e95cb9c99e747b/amqp-5.3.1-py3-none-any.whl"}}, {"metadata": {"name": "redis", "version": "8.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/66/9d/c5731f6e3608663d4d3656fd8d3aecee8b509c3082818f5a13eae925baea/redis-8.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/af/9c0bda43e486a3c9bf1e0f876d0f241bc3f229d7d65d09331a0868db9629/pytest_forked-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "click-didyoumean", "version": "0.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/5b/974430b5ffdb7a4f1941d13d83c64a0395114503cc357c6b9ae4ce5047ed/click_didyoumean-0.3.1-py3-none-any.whl"}}, {"metadata": {"name": "click-plugins", "version": "1.1.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/9a/2abecb28ae875e39c8cad711eb1186d8d14eab564705325e77e4e6ab9ae5/click_plugins-1.1.1.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "click-repl", "version": "0.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/52/40/9d857001228658f0d59e97ebd4c346fe73e138c6de1bce61dc568a57c7f8/click_repl-0.3.0-py3-none-any.whl"}}, {"metadata": {"name": "prompt_toolkit", "version": "3.0.53"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/6f/84908cad2d6aa5144abcf7b42709fe4fdb459bc640ec7ac5786e7693dabc/prompt_toolkit-3.0.53-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "pytz", "version": "2026.3.post1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0f/7b/39c34ca613b0b198cb866466651b26b045e2009864c5183c979a3b83f383/pytz-2026.3.post1-py2.py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "tzdata", "version": "2026.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e5/6d/b53b99a9f2766d095985947a5782f1702cabb129a34f7a802d7197af832f/tzdata-2026.3-py2.py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl"}}, {"metadata": {"name": "py", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl"}}], "install_targets_hash": "21a451706547ac63c2f4503acadf8746"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "mistralai", "version": "2.3.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/83/e0/9f246d18f8fe6e815f7cae88c437c986b342d3ff568607c8e0d53f4710d0/mistralai-2.3.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "eval_type_backport", "version": "0.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/a7/bb99bf5e6f78736ddb53480f2c3ff3702ffe2196a7c5e1661c03081d398e/eval_type_backport-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonpath-python", "version": "1.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/8a/1270a6803bd821cbfcdda387eaa13cb41a7b1f7b9bd145979b3bfb9d6cb7/jsonpath_python-1.1.6-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-semantic-conventions", "version": "0.60b1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7a/5e/5958555e09635d09b75de3c4f8b9cae7335ca545d77392ffe7331534c402/opentelemetry_semantic_conventions-0.60b1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.39.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/df/d3f1ddf4bb4cb50ed9b1139cc7b1c54c34a1e7ce8fd1b9a37c0d1551a6bd/opentelemetry_api-1.39.1-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/d0/c787604c71c2bdcda1a5656942fc822cd0f9cd879b9484bb84fc42172703/pydantic_core-2.46.5-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fa/5e/f8e9a1d23b9c20a551a8a02ea3637b4642e22c2626e3a13a9a29cdea99eb/importlib_metadata-8.7.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "zipp", "version": "4.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl"}}], "install_targets_hash": "220b48fa30e6d4e6ee437946e03f7dfd"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "langgraph", "version": "1.2.12"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/52/27/5a02054c535ed6fcfb2ab1e5c33c51c810cf1e773194ad28c928f0473509/langgraph-1.2.12-py3-none-any.whl"}}, {"metadata": {"name": "langchain-core", "version": "1.6.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c4/f2/41435d9a5448c52a0388f75741edb979fde7415eaa820d6a42878cad7e38/langchain_core-1.6.4-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "jsonpatch", "version": "1.33"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/73/07/02e16ed01e04a374e644b575638ec7987ae846d25ad97bcc9945a3ee4b0e/jsonpatch-1.33-py2.py3-none-any.whl"}}, {"metadata": {"name": "langgraph-checkpoint", "version": "4.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/05/71/3b475f09bd57d3a5649792c66353312b4432afd843f301739dfcebd157f0/langgraph_checkpoint-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "langgraph-prebuilt", "version": "1.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e9/43/3fe1a700b8490ed02679cdbbc8c915eb23a092faf496c9c1118abcd10be3/langgraph_prebuilt-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "langgraph-sdk", "version": "0.4.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/a9/71a6499f3481bc00bf4f42a17cb81caf19a02fce762db356626d7214e2c2/langgraph_sdk-0.4.5-py3-none-any.whl"}}, {"metadata": {"name": "langsmith", "version": "0.14.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/4d/be/d55279f7bfc43763fd479aa526d6f952fa93aaf4d86a40919f78726691cc/langsmith-0.14.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/bd/d0/c787604c71c2bdcda1a5656942fc822cd0f9cd879b9484bb84fc42172703/pydantic_core-2.46.5-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "uuid_utils", "version": "0.17.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/db/af/bfe6e67693597361a65daaa37029c489b24e3302c2f7a676e8e5b0eb20ac/uuid_utils-0.17.1-cp310-cp310-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/90/72/2f14b2e167170b8bf1c8bb7f9b0d78000f470d41a2085a91f33e3917b6c9/websockets-16.1.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "jsonpointer", "version": "3.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/9e/6a/a83720e953b1682d2d109d3c2dbb0bc9bf28cc1cbc205be4ef4be5da709d/jsonpointer-3.1.1-py3-none-any.whl"}}, {"metadata": {"name": "langchain-protocol", "version": "0.0.19"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/80/c9/f6cbf357d48ccbd18bb394433b1fd7ad9be004eed9377ad08bb85777e5e6/langchain_protocol-0.0.19-py3-none-any.whl"}}, {"metadata": {"name": "orjson", "version": "3.12.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cf/35/819eeb4fa8ee676d38fdbb8213a76fd496f7dbbfdfafa89d34e02b22dfac/orjson-3.12.0-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl"}}, {"metadata": {"name": "ormsgpack", "version": "1.12.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/93/fa/a91f70829ebccf6387c4946e0a1a109f6ba0d6a28d65f628bedfad94b890/ormsgpack-1.12.2-cp310-cp310-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/aa/554e2614f38fc34c58ff1d0911ae8535ad2516440d5482d76fe59f1088b0/charset_normalizer-3.5.1-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "urllib3", "version": "2.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "xxhash", "version": "4.0.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/91/2a/7d79952633fccbf9c2a59cc1dfe9d073f9edfceb052ba9bff5075e31408d/xxhash-4.0.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "zstandard", "version": "0.25.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/96/34/ef34ef77f1ee38fc8e4f9775217a613b452916e633c4f1d98f31db52c4a5/zstandard-0.25.0-cp310-cp310-macosx_11_0_arm64.whl"}}], "install_targets_hash": "26d1a3b577a5cb444398332d2ce874d0"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "cohere", "version": "5.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/8d/67ea6917f6ec6a094858c7b2514cd3be3e1fed45b8b9769e2571d781704b/cohere-5.4.0-py3-none-any.whl"}}, {"metadata": {"name": "boto3", "version": "1.43.40"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/3b/2abcc7f47e955a8cb45a6378ec69cd8ed2dcb3d14ceb67717dea020a794a/boto3-1.43.40-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.40"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/8c/5f7e73fd66b28f0705bc55d7060d41ef72328b656b86ca53e75765b3ba2c/botocore-1.43.40-py3-none-any.whl"}}, {"metadata": {"name": "fastavro", "version": "1.12.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3c/91/16c3508447e7cf9f413a6a01792a990ed94d17505fc80a7fb76027078aed/fastavro-1.12.2-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/26/08/0f303cb0b529e456bb116f2d50565a482694fbb94340bf56d44677e7ed03/charset_normalizer-3.4.7-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "s3transfer", "version": "0.19.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/46/5f/4c174edad94f82de888ac00a5ddd8d07b35609b6c94f0bdf4d74af57703e/s3transfer-0.19.0-py3-none-any.whl"}}, {"metadata": {"name": "tokenizers", "version": "0.19.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4c/12/9cb68762ff5fee1efd51aefe2f62cb225f26f060a68a3779e1060bbc7a59/tokenizers-0.19.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "huggingface_hub", "version": "0.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/af/48ac8483240de756d2438c380746e7130d1c6f75802ef22f3c6d49982787/huggingface_hub-0.36.2-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/35/94/4b2ecfbad8f8b04701a23aefb62f540b9137d058b7e1dbef16a32676f0e9/hf_xet-1.5.1-cp37-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "types-requests", "version": "2.33.0.20260518"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1c/bc/b139710a3b6018f7fb2b9508b35c8af564e61bf2bf4fa619d088f3e16f85/types_requests-2.33.0.20260518-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e5/22/4222d7ddf3da30f363edaa98e329c2bce6c65497c9cb2810931c8b2c0fbc/fsspec-2026.6.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/c6/65f646c7ff09bd257f660434adb45c4dfcbbcebcc030562fecf6f5bf887d/pydantic_core-2.46.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.68.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d8/8e/bb97bb0c71802080bfc8952937d174e49cfc50de5c951dd47b2496f0dcdb/tqdm-4.68.3-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "filelock", "version": "3.29.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4a/e3/f1fae3647d170919c2cf2a898e77e7d1a4e5c7cae0aed7bb4bd3f5ebff6f/filelock-3.29.5-py3-none-any.whl"}}], "install_targets_hash": "2d88f925409259ac1c50c7222be95be6"} -{"python_version": "3.10", "dependencies": [{"metadata": {"name": "quart", "version": "0.16.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/41/2405163b533eb53a7563e899d13ad5b62bfa11a7ea6b066b9f3d0a04f797/Quart-0.16.3-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "2.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/f8/9da63c1617ae2a1dec2fbf6412f3a0cfe9d4ce029eccbda6e1e4258ca45f/Werkzeug-2.2.3-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/41/caa5da2dbe6d26029dfe11d31dfa8132b4d6d30b6d6b61a24824075a5f06/blinker-1.5-py2.py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/9a/e5d9ec41927401e41aea8af6d16e78b5e612bca4699d417f646a9610a076/Jinja2-3.0.3-py3-none-any.whl"}}, {"metadata": {"name": "hypercorn", "version": "0.14.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f8/aa/0632f628205f09ec7daa5875e4142db519bfa7a161d48a6417b0f9ab5e08/hypercorn-0.14.4-py3-none-any.whl"}}, {"metadata": {"name": "quart-auth", "version": "0.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6f/ed/3226df1bb2cafcf33142622c856a4931018973ccd799e47094e1d4356222/quart_auth-0.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/af/9c0bda43e486a3c9bf1e0f876d0f241bc3f229d7d65d09331a0868db9629/pytest_forked-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h2", "version": "4.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/b2/119f6e6dcbd96f9069ce9a2665e0146588dc9f88f29549711853645e736a/h2-4.3.0-py3-none-any.whl"}}, {"metadata": {"name": "hpack", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/b4/4a9fcfb2aef6ba44d9073ecd301443aa00b3dac95de5619f2a7de7ec8a91/hpack-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "hyperframe", "version": "6.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/48/30/47d0bf6072f7252e6521f3447ccfa40b421b6824517f82854703d0f5a98b/hyperframe-6.1.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "wsproto", "version": "1.3.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a4/f5/10b68b7b1544245097b2a1b8238f66f2fc6dcaeb24ba5d917f52bd2eed4f/wsproto-1.3.2-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "priority", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5e/5f/82c8074f7e84978129347c2c6ec8b6c59f3584ff1a20bc3c940a3e061790/priority-2.0.0-py3-none-any.whl"}}, {"metadata": {"name": "py", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "toml", "version": "0.10.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/44/6f/7120676b6d73228c96e17f1f794d8ab046fc910d781c8d151120c3f1569e/toml-0.10.2-py2.py3-none-any.whl"}}], "install_targets_hash": "3000515a7f6417494c5933d27bad674f"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "starlette", "version": "0.52.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/0d/13d1d239a25cbfb19e740db83143e95c772a1fe10202dda4b76792b114dd/starlette-0.52.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/26/08/0f303cb0b529e456bb116f2d50565a482694fbb94340bf56d44677e7ed03/charset_normalizer-3.4.7-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}], "install_targets_hash": "30eeef4352d79f7d31c630da4104816d"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "starlite", "version": "1.51.16"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f3/02/664dda98e4f715ef0cba583f53dabddb3f42667d464d38156e1837ed4ce2/starlite-1.51.16-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "1.10.26"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/e6/10df5f08c105bcbb4adbee7d1108ff4b347702b110fed058f6a03f1c6b73/pydantic-1.10.26-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/26/08/0f303cb0b529e456bb116f2d50565a482694fbb94340bf56d44677e7ed03/charset_normalizer-3.4.7-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/2a/5bb823f5bedcf80718cea7fbc95ec5515cca3769633c4b01a32be7f30e7c/cryptography-49.0.0-cp39-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/84/ad6a0b408daa859246f57c03efd28e5dd1b33c21737c2db84cae8c237aa5/cffi-2.0.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "Mako", "version": "1.3.12"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/b1/a0ec7a5a9db730a08daef1fdfb8090435b82465abbf758a596f0ea88727e/mako-1.3.12-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "msgspec", "version": "0.21.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/1a/6899188b5982ec1324e0c629b7801eed2db987f6634fab58abd9fc82d317/msgspec-0.21.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/31/5c/08c7f7fe311f32e83f7621cd3f99d805f45519cd06fafb247628b861da7d/multidict-6.7.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-openapi-schema", "version": "1.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bb/a1/9b906584055e2a9ee48368e2ad7148625e06594fb0f81f8656c6e71eb672/pydantic_openapi_schema-1.5.1-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "email-validator", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "dnspython", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "fast-query-parsers", "version": "1.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/21/c8c160f61a740efc4577079eb5747a6b2cb8d1168a84a0bfda6044113768/fast_query_parsers-1.0.3-cp38-abi3-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-factories", "version": "1.17.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/40/49/81bbfccaf7174e7a94be1fa95d9ed46da6663372b2a7cd597c1c6fdfcabe/pydantic_factories-1.17.3-py3-none-any.whl"}}, {"metadata": {"name": "Faker", "version": "40.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/a6/6111b9f13c1564b0e2f5dbeeb611fd00dc731e6add2336f62b798598c73d/faker-40.28.1-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}], "install_targets_hash": "33d6741d45d5018c097d63500582c5d9"} -{"python_version": "3.10", "dependencies": [{"metadata": {"name": "redis", "version": "4.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/2e/409703d645363352a20c944f5d119bdae3eb3034051a53724a7c5fee12b8/redis-4.6.0-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.30.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f7/26/16ab46747e1aeed6c021da72bae500b6c42c0a5bb9d25d1af97c6f74d61f/fakeredis-2.30.3-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "7.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ff/f6e8b8f39e08547faece4bd80f89d5a8de68a38b2d179cc1c4490ffa3286/pytest-7.4.4-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.23.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ee/82/62e2d63639ecb0fbe8a7ee59ef0bc69a4669ec50f6d3459f74ad4e4189a2/pytest_asyncio-0.23.8-py3-none-any.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}], "install_targets_hash": "36c1a312b04d12e5bc3f2de14c48e482"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "starlite", "version": "1.48.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/46/84/fdfb336bf788e52a5fead1e9e302ac5a0b8a5a0094bdd2c491d6162cd147/starlite-1.48.1-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "1.10.26"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/e6/10df5f08c105bcbb4adbee7d1108ff4b347702b110fed058f6a03f1c6b73/pydantic-1.10.26-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/26/08/0f303cb0b529e456bb116f2d50565a482694fbb94340bf56d44677e7ed03/charset_normalizer-3.4.7-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/2a/5bb823f5bedcf80718cea7fbc95ec5515cca3769633c4b01a32be7f30e7c/cryptography-49.0.0-cp39-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/84/ad6a0b408daa859246f57c03efd28e5dd1b33c21737c2db84cae8c237aa5/cffi-2.0.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "Mako", "version": "1.3.12"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/b1/a0ec7a5a9db730a08daef1fdfb8090435b82465abbf758a596f0ea88727e/mako-1.3.12-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "msgspec", "version": "0.21.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/1a/6899188b5982ec1324e0c629b7801eed2db987f6634fab58abd9fc82d317/msgspec-0.21.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/31/5c/08c7f7fe311f32e83f7621cd3f99d805f45519cd06fafb247628b861da7d/multidict-6.7.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-openapi-schema", "version": "1.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bb/a1/9b906584055e2a9ee48368e2ad7148625e06594fb0f81f8656c6e71eb672/pydantic_openapi_schema-1.5.1-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "email-validator", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "dnspython", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "fast-query-parsers", "version": "1.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/21/c8c160f61a740efc4577079eb5747a6b2cb8d1168a84a0bfda6044113768/fast_query_parsers-1.0.3-cp38-abi3-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-factories", "version": "1.17.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/40/49/81bbfccaf7174e7a94be1fa95d9ed46da6663372b2a7cd597c1c6fdfcabe/pydantic_factories-1.17.3-py3-none-any.whl"}}, {"metadata": {"name": "Faker", "version": "40.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/a6/6111b9f13c1564b0e2f5dbeeb611fd00dc731e6add2336f62b798598c73d/faker-40.28.1-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "3907d2f6a755b140082148b91c7e757f"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "pyspark", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c3/33/c987434f5d50aa802779a004ca0fd45ee4350caab50554ad7283d5a22b50/pyspark-4.2.0.tar.gz"}}, {"metadata": {"name": "py4j", "version": "0.10.9.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/db/ea0203e495be491c85af87b66e37acfd3bf756fd985f87e46fc5e3bf022c/py4j-0.10.9.9-py2.py3-none-any.whl"}}], "install_targets_hash": "390b2ae4157b0a35d160339447ce08cb"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "rq", "version": "2.12.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a4/c2/995863e88669133a058c2a6a912b62d18a64fa7baaf78eb66aaa4350b48d/rq-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.35.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/6f/27/b8b057a23f7777177e92d3a602fd866751b6b45014964548997e92e048fd/fakeredis-2.35.1-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "redis", "version": "8.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/66/9d/c5731f6e3608663d4d3656fd8d3aecee8b509c3082818f5a13eae925baea/redis-8.1.0-py3-none-any.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "croniter", "version": "6.2.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cd/ba/d678e5bd329646ca51d3c92addbc77804e86d21f4b6b6a027218e6abb010/croniter-6.2.4-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}], "install_targets_hash": "39c8ef325254f7a619a821794c33e958"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "rq", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a4/c2/995863e88669133a058c2a6a912b62d18a64fa7baaf78eb66aaa4350b48d/rq-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.35.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6f/27/b8b057a23f7777177e92d3a602fd866751b6b45014964548997e92e048fd/fakeredis-2.35.1-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "redis", "version": "8.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/66/9d/c5731f6e3608663d4d3656fd8d3aecee8b509c3082818f5a13eae925baea/redis-8.1.0-py3-none-any.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "croniter", "version": "6.2.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cd/ba/d678e5bd329646ca51d3c92addbc77804e86d21f4b6b6a027218e6abb010/croniter-6.2.4-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}], "install_targets_hash": "39c8ef325254f7a619a821794c33e958"} -{"python_version": "3.10", "dependencies": [{"metadata": {"name": "openai", "version": "3.16.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/17/72/2b1fe3e303db76ab2ba0c2de2b57822869bcb588db82334d4ff3aea8acf2/openai-3.16.2-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/2c/af9ca503b38683a82b6732352a861515f28e2d46fe445aea57e07fc86e06/jiter-0.17.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/34/a1/c8e6b66f499f510752c07a092dfe27621f9c255635e59d38704b5681c35a/pydantic_core-2.46.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "41aa894704882aa63f37bce872a4e2a2"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "redis", "version": "4.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/2e/409703d645363352a20c944f5d119bdae3eb3034051a53724a7c5fee12b8/redis-4.6.0-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.30.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f7/26/16ab46747e1aeed6c021da72bae500b6c42c0a5bb9d25d1af97c6f74d61f/fakeredis-2.30.3-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "7.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ff/f6e8b8f39e08547faece4bd80f89d5a8de68a38b2d179cc1c4490ffa3286/pytest-7.4.4-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.23.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ee/82/62e2d63639ecb0fbe8a7ee59ef0bc69a4669ec50f6d3459f74ad4e4189a2/pytest_asyncio-0.23.8-py3-none-any.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}], "install_targets_hash": "3a7e93f79584af54dfef58a62cafb907"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "chalice", "version": "1.33.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/ed/c721931d966d135387ab2d5404a026ca0ae205325fbac4b8f9ac91a45186/chalice-1.33.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "81.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/e3/c164c88b2e5ce7b24d667b9bd83589cf4f3520d97cad01534cd3c4f55fdb/setuptools-81.0.0-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.40"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/8c/5f7e73fd66b28f0705bc55d7060d41ef72328b656b86ca53e75765b3ba2c/botocore-1.43.40-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "inquirer", "version": "3.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f0/fd/7c404169a3e04a908df0644893a331f253a7f221961f2b6c0cf44430ae5a/inquirer-3.4.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pip", "version": "26.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/95/6b5cb3461ea5673ba0995989746db58eb18b91b54dbf331e72f569540946/pip-26.1.2-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-chalice", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/0f/3344996a9ca6d1b301f55805bd2aa0daf9055f13317720b4567226e4cb38/pytest-chalice-0.0.5.tar.gz"}}, {"metadata": {"name": "blessed", "version": "1.46.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/8f/c10d44ba50d5d298699c3c5698ce4e89b397ec72e2139381b9964f87356c/blessed-1.46.0-py3-none-any.whl"}}, {"metadata": {"name": "jinxed", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/1d/0a6be99b69bb448448403a45a241aff0dca751832ae54f027ed940d2eb52/jinxed-2.1.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "editor", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/b8/6648cadf38b61045262bf2a534e526f04eb833275ad1fc77a2026e9f7e3a/editor-1.8.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "readchar", "version": "4.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/ca/36133653e00939922dd1416f4c56177361289172a30563fcb9552c9ccde4/readchar-4.2.2-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl"}}, {"metadata": {"name": "runs", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/b6/049c75d399ccf6e25abea0652b85bf7e7e101e0300aa9c1d284ad7061c0b/runs-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "wheel", "version": "0.47.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/87/1b/9e33c09813d65e248f7f773119148a612516a4bea93e9c6f545f78455b7c/wheel-0.47.0-py3-none-any.whl"}}, {"metadata": {"name": "xmod", "version": "1.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/e9/c362d47ed2b1928d65d61888c1419fae8ef69417fba2067d2fd3da1d400b/xmod-1.10.0-py3-none-any.whl"}}], "install_targets_hash": "41e4a9a78e14781d2190b51041252959"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "chalice", "version": "1.33.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/ed/c721931d966d135387ab2d5404a026ca0ae205325fbac4b8f9ac91a45186/chalice-1.33.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "81.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/e3/c164c88b2e5ce7b24d667b9bd83589cf4f3520d97cad01534cd3c4f55fdb/setuptools-81.0.0-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.40"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/8c/5f7e73fd66b28f0705bc55d7060d41ef72328b656b86ca53e75765b3ba2c/botocore-1.43.40-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "inquirer", "version": "3.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f0/fd/7c404169a3e04a908df0644893a331f253a7f221961f2b6c0cf44430ae5a/inquirer-3.4.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pip", "version": "26.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/95/6b5cb3461ea5673ba0995989746db58eb18b91b54dbf331e72f569540946/pip-26.1.2-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-chalice", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/0f/3344996a9ca6d1b301f55805bd2aa0daf9055f13317720b4567226e4cb38/pytest-chalice-0.0.5.tar.gz"}}, {"metadata": {"name": "blessed", "version": "1.46.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/8f/c10d44ba50d5d298699c3c5698ce4e89b397ec72e2139381b9964f87356c/blessed-1.46.0-py3-none-any.whl"}}, {"metadata": {"name": "jinxed", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/1d/0a6be99b69bb448448403a45a241aff0dca751832ae54f027ed940d2eb52/jinxed-2.1.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "editor", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/b8/6648cadf38b61045262bf2a534e526f04eb833275ad1fc77a2026e9f7e3a/editor-1.8.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "readchar", "version": "4.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/ca/36133653e00939922dd1416f4c56177361289172a30563fcb9552c9ccde4/readchar-4.2.2-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl"}}, {"metadata": {"name": "runs", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/b6/049c75d399ccf6e25abea0652b85bf7e7e101e0300aa9c1d284ad7061c0b/runs-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "wheel", "version": "0.47.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/87/1b/9e33c09813d65e248f7f773119148a612516a4bea93e9c6f545f78455b7c/wheel-0.47.0-py3-none-any.whl"}}, {"metadata": {"name": "xmod", "version": "1.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/e9/c362d47ed2b1928d65d61888c1419fae8ef69417fba2067d2fd3da1d400b/xmod-1.10.0-py3-none-any.whl"}}], "install_targets_hash": "41e4a9a78e14781d2190b51041252959"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "redis", "version": "8.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/66/9d/c5731f6e3608663d4d3656fd8d3aecee8b509c3082818f5a13eae925baea/redis-8.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "7.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ff/f6e8b8f39e08547faece4bd80f89d5a8de68a38b2d179cc1c4490ffa3286/pytest-7.4.4-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/76/e2/964e6ef372770dd7c32f9738b50ff4924f1d3cccd665b568680e4bcb0167/fakeredis-2.37.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.23.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ee/82/62e2d63639ecb0fbe8a7ee59ef0bc69a4669ec50f6d3459f74ad4e4189a2/pytest_asyncio-0.23.8-py3-none-any.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}], "install_targets_hash": "42549a00e196f5a73560e967c6bf368f"} @@ -29,154 +54,266 @@ {"python_version": "3.10", "dependencies": [{"metadata": {"name": "Django", "version": "3.2.25"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/8e/cc23c762c5dcd1d367d73cf006a326e0df2bd0e785cba18b658b39904c1e/Django-3.2.25-py3-none-any.whl"}}, {"metadata": {"name": "djangorestframework", "version": "3.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c0/7e/8c45ea7f85dd5d52ceddbacc6f56ecaca21ecbfc0e8c34c95618a14d5082/djangorestframework-3.15.1-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "2.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/f3/22afbdb20cc4654b10c98043414a14057cd27fdba9d4ae61cea596000ba2/Werkzeug-2.0.3-py3-none-any.whl"}}, {"metadata": {"name": "asgiref", "version": "3.11.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5c/0a/a72d10ed65068e115044937873362e6e32fab1b7dce0046aeb224682c989/asgiref-3.11.1-py3-none-any.whl"}}, {"metadata": {"name": "psycopg2-binary", "version": "2.9.12"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d3/f2/98eeac7d60c43df9338287834edf9b3e69be68a2db78a57b1b81d705e735/psycopg2_binary-2.9.12-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-django", "version": "4.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/83/a5/41d091f697c09609e7ef1d5d61925494e0454ebf51de7de05f0f0a728f1d/pytest_django-4.12.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/af/9c0bda43e486a3c9bf1e0f876d0f241bc3f229d7d65d09331a0868db9629/pytest_forked-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "channels", "version": "4.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f5/52/a233dc63996547f171c2013f2d0505dcfa7d0557e7cde8748a2bd70b5a31/channels-4.0.0-py3-none-any.whl"}}, {"metadata": {"name": "executing", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "daphne", "version": "4.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/ab/85534d9cbca09f3c10f58fc2093659062280ed5703707c0b41dbca8ec297/daphne-4.2.2-py3-none-any.whl"}}, {"metadata": {"name": "autobahn", "version": "24.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/13/ee/a6475f39ef6c6f41c33da6b193e0ffd2c6048f52e1698be6253c59301b72/autobahn-24.4.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/2a/5bb823f5bedcf80718cea7fbc95ec5515cca3769633c4b01a32be7f30e7c/cryptography-49.0.0-cp39-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/84/ad6a0b408daa859246f57c03efd28e5dd1b33c21737c2db84cae8c237aa5/cffi-2.0.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "hyperlink", "version": "21.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/aa/8caf6a0a3e62863cbb9dab27135660acba46903b703e224f14f447e57934/hyperlink-21.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "sqlparse", "version": "0.5.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/4b/359f28a903c13438ef59ebeee215fb25da53066db67b305c125f1c6d2a25/sqlparse-0.5.5-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "Twisted", "version": "26.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/57/bcf4e2370dd218c9aa68a9140a65d86729c73f1d529f7e94786c2766fc72/twisted-26.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "Automat", "version": "25.4.16"}, "download_info": {"url": "https://files.pythonhosted.org/packages/02/ff/1175b0b7371e46244032d43a56862d0af455823b5280a50c63d99cc50f18/automat-25.4.16-py3-none-any.whl"}}, {"metadata": {"name": "constantly", "version": "23.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b8/40/c199d095151addf69efdb4b9ca3a4f20f70e20508d6222bffb9b76f58573/constantly-23.10.4-py3-none-any.whl"}}, {"metadata": {"name": "Incremental", "version": "24.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1d/55/0f4df2a44053867ea9cbea73fc588b03c55605cd695cee0a3d86f0029cb2/incremental-24.11.0-py3-none-any.whl"}}, {"metadata": {"name": "pyOpenSSL", "version": "26.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/18/1dd71c9b43192ab83f1d531ad6002dc81108ac36c475f79fb7a295abe2f4/pyopenssl-26.3.0-py3-none-any.whl"}}, {"metadata": {"name": "service-identity", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/eb/2433e1af4ff903499144de4846569fb3300b816179ae99a03c2f011b666a/service_identity-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "txaio", "version": "25.9.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/2c/e276b80f73fc0411cefa1c1eeae6bc17955197a9c3e2b41b41f957322549/txaio-25.9.2-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "zope.interface", "version": "8.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/17/0f/8f1a29966bcf863e3a2121edcafb81c55715de7886bcc9544749cc79e7da/zope_interface-8.5-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "py", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "pytz", "version": "2026.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/dd/96da98f892250475bdf2328112d7468abdd4acc7b902b6af23f4ed958ea0/pytz-2026.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "83.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/40/e1e72872c6354b306daef1703549e8e83b4d43cfea356311bf722a043752/setuptools-83.0.0-py3-none-any.whl"}}], "install_targets_hash": "44564eb565ac68ae270112ab5e229c6c"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "anthropic", "version": "1.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c0/dc/74995efda028421917f4caabd24db1373ee0742573a2363fff1a21191441/anthropic-1.7.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/2c/af9ca503b38683a82b6732352a861515f28e2d46fe445aea57e07fc86e06/jiter-0.17.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/34/a1/c8e6b66f499f510752c07a092dfe27621f9c255635e59d38704b5681c35a/pydantic_core-2.46.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}], "install_targets_hash": "4727845e3afb2745d5e910cf0c6cbc97"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "trytond", "version": "6.8.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/13/b994f377d1896f70ca6edbfb0c068f8f9739fe706485b2d0759d96c798d1/trytond-6.8.17-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "lxml", "version": "6.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/da/dbe4dfc01ac226fb0504fad035f4d69f3202f3502e20e68537631daddd96/lxml-6.1.1-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "passlib", "version": "1.7.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3b/a4/ab6b7589382ca3df236e03faa71deac88cae040af60c071a78d254a62172/passlib-1.7.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "python-sql", "version": "1.8.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/77/ac/3603bbdde340f7354c975431c94b70ef3e99966c5b170fa121f8e64d269e/python_sql-1.8.1-py3-none-any.whl"}}, {"metadata": {"name": "relatorio", "version": "0.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4d/4c/ab43c3a35a402f17a153a66c27c3dce184e4ff511a8a414d208dfaa4c5bf/relatorio-0.12.1-py3-none-any.whl"}}, {"metadata": {"name": "Genshi", "version": "0.7.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/27/503016bc329720ba2856eb4831d6ba36089cd6f15bc4fe85db69fea5b563/genshi-0.7.11-py3-none-any.whl"}}, {"metadata": {"name": "defusedxml", "version": "0.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "polib", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6b/99/45bb1f9926efe370c6dbe324741c749658e44cb060124f28dad201202274/polib-1.2.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "python-magic", "version": "0.4.27"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6c/73/9f872cb81fc5c3bb48f7227872c28975f998f3e7c2b1c16e95e6432bbb90/python_magic-0.4.27-py2.py3-none-any.whl"}}], "install_targets_hash": "4a8a27395c61752c0a56a6636507732c"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "trytond", "version": "6.8.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/13/b994f377d1896f70ca6edbfb0c068f8f9739fe706485b2d0759d96c798d1/trytond-6.8.17-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "lxml", "version": "6.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/da/dbe4dfc01ac226fb0504fad035f4d69f3202f3502e20e68537631daddd96/lxml-6.1.1-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "passlib", "version": "1.7.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3b/a4/ab6b7589382ca3df236e03faa71deac88cae040af60c071a78d254a62172/passlib-1.7.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "python-sql", "version": "1.8.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/77/ac/3603bbdde340f7354c975431c94b70ef3e99966c5b170fa121f8e64d269e/python_sql-1.8.1-py3-none-any.whl"}}, {"metadata": {"name": "relatorio", "version": "0.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4d/4c/ab43c3a35a402f17a153a66c27c3dce184e4ff511a8a414d208dfaa4c5bf/relatorio-0.12.1-py3-none-any.whl"}}, {"metadata": {"name": "Genshi", "version": "0.7.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/27/503016bc329720ba2856eb4831d6ba36089cd6f15bc4fe85db69fea5b563/genshi-0.7.11-py3-none-any.whl"}}, {"metadata": {"name": "defusedxml", "version": "0.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "polib", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6b/99/45bb1f9926efe370c6dbe324741c749658e44cb060124f28dad201202274/polib-1.2.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "python-magic", "version": "0.4.27"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6c/73/9f872cb81fc5c3bb48f7227872c28975f998f3e7c2b1c16e95e6432bbb90/python_magic-0.4.27-py2.py3-none-any.whl"}}], "install_targets_hash": "4a8a27395c61752c0a56a6636507732c"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "trytond", "version": "6.8.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/13/b994f377d1896f70ca6edbfb0c068f8f9739fe706485b2d0759d96c798d1/trytond-6.8.17-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "lxml", "version": "6.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/da/dbe4dfc01ac226fb0504fad035f4d69f3202f3502e20e68537631daddd96/lxml-6.1.1-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "passlib", "version": "1.7.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3b/a4/ab6b7589382ca3df236e03faa71deac88cae040af60c071a78d254a62172/passlib-1.7.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "python-sql", "version": "1.8.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/77/ac/3603bbdde340f7354c975431c94b70ef3e99966c5b170fa121f8e64d269e/python_sql-1.8.1-py3-none-any.whl"}}, {"metadata": {"name": "relatorio", "version": "0.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4d/4c/ab43c3a35a402f17a153a66c27c3dce184e4ff511a8a414d208dfaa4c5bf/relatorio-0.12.1-py3-none-any.whl"}}, {"metadata": {"name": "Genshi", "version": "0.7.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/27/503016bc329720ba2856eb4831d6ba36089cd6f15bc4fe85db69fea5b563/genshi-0.7.11-py3-none-any.whl"}}, {"metadata": {"name": "defusedxml", "version": "0.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "polib", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6b/99/45bb1f9926efe370c6dbe324741c749658e44cb060124f28dad201202274/polib-1.2.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "python-magic", "version": "0.4.27"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6c/73/9f872cb81fc5c3bb48f7227872c28975f998f3e7c2b1c16e95e6432bbb90/python_magic-0.4.27-py2.py3-none-any.whl"}}], "install_targets_hash": "4a8a27395c61752c0a56a6636507732c"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "trytond", "version": "6.8.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/13/b994f377d1896f70ca6edbfb0c068f8f9739fe706485b2d0759d96c798d1/trytond-6.8.17-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "lxml", "version": "6.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/da/dbe4dfc01ac226fb0504fad035f4d69f3202f3502e20e68537631daddd96/lxml-6.1.1-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "passlib", "version": "1.7.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3b/a4/ab6b7589382ca3df236e03faa71deac88cae040af60c071a78d254a62172/passlib-1.7.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "python-sql", "version": "1.8.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/77/ac/3603bbdde340f7354c975431c94b70ef3e99966c5b170fa121f8e64d269e/python_sql-1.8.1-py3-none-any.whl"}}, {"metadata": {"name": "relatorio", "version": "0.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4d/4c/ab43c3a35a402f17a153a66c27c3dce184e4ff511a8a414d208dfaa4c5bf/relatorio-0.12.1-py3-none-any.whl"}}, {"metadata": {"name": "Genshi", "version": "0.7.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/27/503016bc329720ba2856eb4831d6ba36089cd6f15bc4fe85db69fea5b563/genshi-0.7.11-py3-none-any.whl"}}, {"metadata": {"name": "defusedxml", "version": "0.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "polib", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6b/99/45bb1f9926efe370c6dbe324741c749658e44cb060124f28dad201202274/polib-1.2.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "python-magic", "version": "0.4.27"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6c/73/9f872cb81fc5c3bb48f7227872c28975f998f3e7c2b1c16e95e6432bbb90/python_magic-0.4.27-py2.py3-none-any.whl"}}], "install_targets_hash": "4a8a27395c61752c0a56a6636507732c"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "trytond", "version": "6.8.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/13/b994f377d1896f70ca6edbfb0c068f8f9739fe706485b2d0759d96c798d1/trytond-6.8.17-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "lxml", "version": "6.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/da/dbe4dfc01ac226fb0504fad035f4d69f3202f3502e20e68537631daddd96/lxml-6.1.1-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "passlib", "version": "1.7.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3b/a4/ab6b7589382ca3df236e03faa71deac88cae040af60c071a78d254a62172/passlib-1.7.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "python-sql", "version": "1.8.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/77/ac/3603bbdde340f7354c975431c94b70ef3e99966c5b170fa121f8e64d269e/python_sql-1.8.1-py3-none-any.whl"}}, {"metadata": {"name": "relatorio", "version": "0.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4d/4c/ab43c3a35a402f17a153a66c27c3dce184e4ff511a8a414d208dfaa4c5bf/relatorio-0.12.1-py3-none-any.whl"}}, {"metadata": {"name": "Genshi", "version": "0.7.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/27/503016bc329720ba2856eb4831d6ba36089cd6f15bc4fe85db69fea5b563/genshi-0.7.11-py3-none-any.whl"}}, {"metadata": {"name": "defusedxml", "version": "0.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "polib", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6b/99/45bb1f9926efe370c6dbe324741c749658e44cb060124f28dad201202274/polib-1.2.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "python-magic", "version": "0.4.27"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6c/73/9f872cb81fc5c3bb48f7227872c28975f998f3e7c2b1c16e95e6432bbb90/python_magic-0.4.27-py2.py3-none-any.whl"}}], "install_targets_hash": "4a8a27395c61752c0a56a6636507732c"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "trytond", "version": "6.8.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/13/b994f377d1896f70ca6edbfb0c068f8f9739fe706485b2d0759d96c798d1/trytond-6.8.17-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "lxml", "version": "6.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/da/dbe4dfc01ac226fb0504fad035f4d69f3202f3502e20e68537631daddd96/lxml-6.1.1-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "passlib", "version": "1.7.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3b/a4/ab6b7589382ca3df236e03faa71deac88cae040af60c071a78d254a62172/passlib-1.7.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "python-sql", "version": "1.8.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/77/ac/3603bbdde340f7354c975431c94b70ef3e99966c5b170fa121f8e64d269e/python_sql-1.8.1-py3-none-any.whl"}}, {"metadata": {"name": "relatorio", "version": "0.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4d/4c/ab43c3a35a402f17a153a66c27c3dce184e4ff511a8a414d208dfaa4c5bf/relatorio-0.12.1-py3-none-any.whl"}}, {"metadata": {"name": "Genshi", "version": "0.7.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/27/503016bc329720ba2856eb4831d6ba36089cd6f15bc4fe85db69fea5b563/genshi-0.7.11-py3-none-any.whl"}}, {"metadata": {"name": "defusedxml", "version": "0.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "polib", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6b/99/45bb1f9926efe370c6dbe324741c749658e44cb060124f28dad201202274/polib-1.2.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "python-magic", "version": "0.4.27"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6c/73/9f872cb81fc5c3bb48f7227872c28975f998f3e7c2b1c16e95e6432bbb90/python_magic-0.4.27-py2.py3-none-any.whl"}}], "install_targets_hash": "4a8a27395c61752c0a56a6636507732c"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "trytond", "version": "6.8.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/13/b994f377d1896f70ca6edbfb0c068f8f9739fe706485b2d0759d96c798d1/trytond-6.8.17-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "lxml", "version": "6.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/da/dbe4dfc01ac226fb0504fad035f4d69f3202f3502e20e68537631daddd96/lxml-6.1.1-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "passlib", "version": "1.7.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3b/a4/ab6b7589382ca3df236e03faa71deac88cae040af60c071a78d254a62172/passlib-1.7.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "python-sql", "version": "1.8.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/77/ac/3603bbdde340f7354c975431c94b70ef3e99966c5b170fa121f8e64d269e/python_sql-1.8.1-py3-none-any.whl"}}, {"metadata": {"name": "relatorio", "version": "0.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4d/4c/ab43c3a35a402f17a153a66c27c3dce184e4ff511a8a414d208dfaa4c5bf/relatorio-0.12.1-py3-none-any.whl"}}, {"metadata": {"name": "Genshi", "version": "0.7.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/27/503016bc329720ba2856eb4831d6ba36089cd6f15bc4fe85db69fea5b563/genshi-0.7.11-py3-none-any.whl"}}, {"metadata": {"name": "defusedxml", "version": "0.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "polib", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6b/99/45bb1f9926efe370c6dbe324741c749658e44cb060124f28dad201202274/polib-1.2.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "python-magic", "version": "0.4.27"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6c/73/9f872cb81fc5c3bb48f7227872c28975f998f3e7c2b1c16e95e6432bbb90/python_magic-0.4.27-py2.py3-none-any.whl"}}], "install_targets_hash": "4a8a27395c61752c0a56a6636507732c"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "trytond", "version": "6.8.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/13/b994f377d1896f70ca6edbfb0c068f8f9739fe706485b2d0759d96c798d1/trytond-6.8.17-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "lxml", "version": "6.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/da/dbe4dfc01ac226fb0504fad035f4d69f3202f3502e20e68537631daddd96/lxml-6.1.1-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "passlib", "version": "1.7.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3b/a4/ab6b7589382ca3df236e03faa71deac88cae040af60c071a78d254a62172/passlib-1.7.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "python-sql", "version": "1.8.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/77/ac/3603bbdde340f7354c975431c94b70ef3e99966c5b170fa121f8e64d269e/python_sql-1.8.1-py3-none-any.whl"}}, {"metadata": {"name": "relatorio", "version": "0.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4d/4c/ab43c3a35a402f17a153a66c27c3dce184e4ff511a8a414d208dfaa4c5bf/relatorio-0.12.1-py3-none-any.whl"}}, {"metadata": {"name": "Genshi", "version": "0.7.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/27/503016bc329720ba2856eb4831d6ba36089cd6f15bc4fe85db69fea5b563/genshi-0.7.11-py3-none-any.whl"}}, {"metadata": {"name": "defusedxml", "version": "0.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "polib", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6b/99/45bb1f9926efe370c6dbe324741c749658e44cb060124f28dad201202274/polib-1.2.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "python-magic", "version": "0.4.27"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6c/73/9f872cb81fc5c3bb48f7227872c28975f998f3e7c2b1c16e95e6432bbb90/python_magic-0.4.27-py2.py3-none-any.whl"}}], "install_targets_hash": "4a8a27395c61752c0a56a6636507732c"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "ariadne", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/48/e0bd1918ef56b1a570dfc1882a036286bf4b3f13e5a659a8d9e16d888c69/ariadne-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "fastapi", "version": "0.139.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/7c/8e3c6ad324ea5cb36604fc3f968554887891c316d9dfde57761611d907ad/fastapi-0.139.0-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/15/b92b4e1d88d02c6eff9733c9eea21846ab435cc4d813d84ccc5d335955df/graphql_core-3.2.11-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/c6/65f646c7ff09bd257f660434adb45c4dfcbbcebcc030562fecf6f5bf887d/pydantic_core-2.46.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "4be724db1412c7b7718411b02cd97084"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "ariadne", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/48/e0bd1918ef56b1a570dfc1882a036286bf4b3f13e5a659a8d9e16d888c69/ariadne-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "fastapi", "version": "0.139.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/7c/8e3c6ad324ea5cb36604fc3f968554887891c316d9dfde57761611d907ad/fastapi-0.139.0-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/15/b92b4e1d88d02c6eff9733c9eea21846ab435cc4d813d84ccc5d335955df/graphql_core-3.2.11-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/c6/65f646c7ff09bd257f660434adb45c4dfcbbcebcc030562fecf6f5bf887d/pydantic_core-2.46.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "4be724db1412c7b7718411b02cd97084"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "ariadne", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/48/e0bd1918ef56b1a570dfc1882a036286bf4b3f13e5a659a8d9e16d888c69/ariadne-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "fastapi", "version": "0.139.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/7c/8e3c6ad324ea5cb36604fc3f968554887891c316d9dfde57761611d907ad/fastapi-0.139.0-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/15/b92b4e1d88d02c6eff9733c9eea21846ab435cc4d813d84ccc5d335955df/graphql_core-3.2.11-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/c6/65f646c7ff09bd257f660434adb45c4dfcbbcebcc030562fecf6f5bf887d/pydantic_core-2.46.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "4be724db1412c7b7718411b02cd97084"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "ariadne", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/48/e0bd1918ef56b1a570dfc1882a036286bf4b3f13e5a659a8d9e16d888c69/ariadne-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "fastapi", "version": "0.139.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/7c/8e3c6ad324ea5cb36604fc3f968554887891c316d9dfde57761611d907ad/fastapi-0.139.0-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/15/b92b4e1d88d02c6eff9733c9eea21846ab435cc4d813d84ccc5d335955df/graphql_core-3.2.11-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/c6/65f646c7ff09bd257f660434adb45c4dfcbbcebcc030562fecf6f5bf887d/pydantic_core-2.46.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "4be724db1412c7b7718411b02cd97084"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "ariadne", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/48/e0bd1918ef56b1a570dfc1882a036286bf4b3f13e5a659a8d9e16d888c69/ariadne-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "fastapi", "version": "0.139.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/7c/8e3c6ad324ea5cb36604fc3f968554887891c316d9dfde57761611d907ad/fastapi-0.139.0-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/15/b92b4e1d88d02c6eff9733c9eea21846ab435cc4d813d84ccc5d335955df/graphql_core-3.2.11-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/c6/65f646c7ff09bd257f660434adb45c4dfcbbcebcc030562fecf6f5bf887d/pydantic_core-2.46.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "4be724db1412c7b7718411b02cd97084"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "ariadne", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/48/e0bd1918ef56b1a570dfc1882a036286bf4b3f13e5a659a8d9e16d888c69/ariadne-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "fastapi", "version": "0.139.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/7c/8e3c6ad324ea5cb36604fc3f968554887891c316d9dfde57761611d907ad/fastapi-0.139.0-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/15/b92b4e1d88d02c6eff9733c9eea21846ab435cc4d813d84ccc5d335955df/graphql_core-3.2.11-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/c6/65f646c7ff09bd257f660434adb45c4dfcbbcebcc030562fecf6f5bf887d/pydantic_core-2.46.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "4be724db1412c7b7718411b02cd97084"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "ariadne", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/48/e0bd1918ef56b1a570dfc1882a036286bf4b3f13e5a659a8d9e16d888c69/ariadne-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "fastapi", "version": "0.139.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/7c/8e3c6ad324ea5cb36604fc3f968554887891c316d9dfde57761611d907ad/fastapi-0.139.0-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/15/b92b4e1d88d02c6eff9733c9eea21846ab435cc4d813d84ccc5d335955df/graphql_core-3.2.11-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/c6/65f646c7ff09bd257f660434adb45c4dfcbbcebcc030562fecf6f5bf887d/pydantic_core-2.46.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "4be724db1412c7b7718411b02cd97084"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "ariadne", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/48/e0bd1918ef56b1a570dfc1882a036286bf4b3f13e5a659a8d9e16d888c69/ariadne-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "fastapi", "version": "0.139.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/7c/8e3c6ad324ea5cb36604fc3f968554887891c316d9dfde57761611d907ad/fastapi-0.139.0-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/15/b92b4e1d88d02c6eff9733c9eea21846ab435cc4d813d84ccc5d335955df/graphql_core-3.2.11-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/c6/65f646c7ff09bd257f660434adb45c4dfcbbcebcc030562fecf6f5bf887d/pydantic_core-2.46.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "4be724db1412c7b7718411b02cd97084"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "ariadne", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/48/e0bd1918ef56b1a570dfc1882a036286bf4b3f13e5a659a8d9e16d888c69/ariadne-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "fastapi", "version": "0.139.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/7c/8e3c6ad324ea5cb36604fc3f968554887891c316d9dfde57761611d907ad/fastapi-0.139.0-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/15/b92b4e1d88d02c6eff9733c9eea21846ab435cc4d813d84ccc5d335955df/graphql_core-3.2.11-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/c6/65f646c7ff09bd257f660434adb45c4dfcbbcebcc030562fecf6f5bf887d/pydantic_core-2.46.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "4be724db1412c7b7718411b02cd97084"} -{"python_version": "3.10", "dependencies": [{"metadata": {"name": "langgraph", "version": "1.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0a/7f/c5c30e4be99ff821029c7ac872a480676bb179c9f3df85ea3f38d13f86d4/langgraph-1.2.11-py3-none-any.whl"}}, {"metadata": {"name": "langchain-core", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/84/4c/508a90b9d2e3bd7738fd93cb2ac2178ce734662c75e69b3b81c445f1b360/langchain_core-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "jsonpatch", "version": "1.33"}, "download_info": {"url": "https://files.pythonhosted.org/packages/73/07/02e16ed01e04a374e644b575638ec7987ae846d25ad97bcc9945a3ee4b0e/jsonpatch-1.33-py2.py3-none-any.whl"}}, {"metadata": {"name": "langgraph-checkpoint", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/71/3b475f09bd57d3a5649792c66353312b4432afd843f301739dfcebd157f0/langgraph_checkpoint-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "langgraph-prebuilt", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/43/3fe1a700b8490ed02679cdbbc8c915eb23a092faf496c9c1118abcd10be3/langgraph_prebuilt-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "langgraph-sdk", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5a/a0/f3bc44b46ef730588f66fdf9e9ddc54189db78482a9e914ae6a554a2b2e0/langgraph_sdk-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "langsmith", "version": "0.11.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/85/0ad6df25588122760b2b40ec182eafc55532c9e66015c83e16675bd34a29/langsmith-0.11.1-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/c6/65f646c7ff09bd257f660434adb45c4dfcbbcebcc030562fecf6f5bf887d/pydantic_core-2.46.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "uuid_utils", "version": "0.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/60/659104207938f2ac62508b9aa595fc0515ac7452dd515c8e1d47d0b91169/uuid_utils-0.17.0-cp310-cp310-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/90/72/2f14b2e167170b8bf1c8bb7f9b0d78000f470d41a2085a91f33e3917b6c9/websockets-16.1.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "jsonpointer", "version": "3.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/6a/a83720e953b1682d2d109d3c2dbb0bc9bf28cc1cbc205be4ef4be5da709d/jsonpointer-3.1.1-py3-none-any.whl"}}, {"metadata": {"name": "langchain-protocol", "version": "0.0.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/2e/d82db9eec13ad0f72e7aaad5c4bc730ab111934fdc83c85523206eb9b0a0/langchain_protocol-0.0.18-py3-none-any.whl"}}, {"metadata": {"name": "orjson", "version": "3.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/35/819eeb4fa8ee676d38fdbb8213a76fd496f7dbbfdfafa89d34e02b22dfac/orjson-3.12.0-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl"}}, {"metadata": {"name": "ormsgpack", "version": "1.12.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/fa/a91f70829ebccf6387c4946e0a1a109f6ba0d6a28d65f628bedfad94b890/ormsgpack-1.12.2-cp310-cp310-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/aa/554e2614f38fc34c58ff1d0911ae8535ad2516440d5482d76fe59f1088b0/charset_normalizer-3.5.1-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "xxhash", "version": "4.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/91/2a/7d79952633fccbf9c2a59cc1dfe9d073f9edfceb052ba9bff5075e31408d/xxhash-4.0.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "zstandard", "version": "0.25.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/34/ef34ef77f1ee38fc8e4f9775217a613b452916e633c4f1d98f31db52c4a5/zstandard-0.25.0-cp310-cp310-macosx_11_0_arm64.whl"}}], "install_targets_hash": "4ded69ebfc3885a149b764fa94a36954"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "fastmcp", "version": "4.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/c0/1f985175c9eee7725ebef1be5a7c210787ad0c7649f56dab5c5af5185816/fastmcp-4.0.5-py3-none-any.whl"}}, {"metadata": {"name": "fastmcp-slim", "version": "4.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ed/76/8dc551ef1f222bd146537ae100baf7441628aa1050494b567249ece997c2/fastmcp_slim-4.0.5-py3-none-any.whl"}}, {"metadata": {"name": "mcp", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/ff/8e7eade68b8a28f7da0ed1085544341b51f9c935dbf6b95c76b7edfea6a0/mcp-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mcp-types", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8f/d7/6ffba5d8cd5dd9b8a19478875c50e04945314ba5074e84d749283f27f62d/mcp_types-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "py-key-value-aio", "version": "0.4.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/46/12871550fb0613d149144bb9d41f22680d5f46717bc45a76eb5798c20c3f/py_key_value_aio-0.4.6-py3-none-any.whl"}}, {"metadata": {"name": "aiofile", "version": "3.8.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/76/ea/b6aae3275bb0991c43fff401e7b8db198047b6f692e8954520ec7aed3652/aiofile-3.8.8-py3-none-any.whl"}}, {"metadata": {"name": "caio", "version": "0.9.25"}, "download_info": {"url": "https://files.pythonhosted.org/packages/88/95/dd55757bb671eb4c376e006c04e83beb413486821f517792ea603ef216e9/caio-0.9.25-cp310-cp310-manylinux_2_34_x86_64.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7a/1e/7acc4f0e74c4b3d9531e24739e0ab832a5edf40e64fbae1a9c01941cabd7/pyyaml-6.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "Authlib", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b8/c6/6f124bcfbbfb20fba22c939b4e43a06dccfc0e1ca20e5634ca573cb1e271/authlib-1.8.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "beartype", "version": "0.22.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/cc/18245721fa7747065ab478316c7fea7c74777d07f37ae60db2e84f8172e8/beartype-0.22.9-py3-none-any.whl"}}, {"metadata": {"name": "cachetools", "version": "7.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cc/bb/1c6e7a89b11da19f137e4ef5a5c5fe47a5bb686449ba343944ccf8fb34b2/cachetools-7.2.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8c/eb/5d7124083e8d8cda8f5b348f544b71ad6f707ad63193758ef4d8e569da02/cryptography-50.0.1-cp39-abi3-manylinux_2_34_x86_64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/75/77/60bebf6f818bec84210ac5b6979ce4eeadce6fbbaabc9c7ab23e506d1ce5/cffi-2.1.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "cyclopts", "version": "4.25.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/cc/e879da3d54cf727f90e6d90118e132672c3913338b566740486f8797190d/cyclopts-4.25.3-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "rich-rst", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/68/1fc93dd759605b5d00fc98b50200739e41ed32bd22d6ba35ca6c3932371b/rich_rst-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "griffelib", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/63/e876e789525063c840ccfa8857febdabd6523bcef9ce7eb979b9305ea895/griffelib-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "joserfc", "version": "1.7.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/c5/82addfd375e5ee6520644e0553e4aadde92d668c4fc99cc716d337fe7bb3/joserfc-1.7.5-py3-none-any.whl"}}, {"metadata": {"name": "jsonref", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/ec/e1db9922bceb168197a558a2b8c03a7963f1afe93517ddd3cf99f202f996/jsonref-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-path", "version": "0.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/2c/9e69d73c4297508be9e3b64a970ea3971b3eb8db64ffc5802d40bd25981f/jsonschema_path-0.5.0-py3-none-any.whl"}}, {"metadata": {"name": "pathable", "version": "0.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a2/e8/6d75ffd9784bce2e93d1ae4415649427e39a53bb172d4672b2b59c6f0a7b/pathable-0.6.0-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "keyring", "version": "25.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/db/e655086b7f3a705df045bf0933bdd9c2f79bb3c97bfef1384598bb79a217/keyring-25.7.0-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "9.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/55/ecca97ae19075f1fac62def77731e7f535e6c1fb8f92ff08160c5e6dade8/importlib_metadata-9.0.1-py3-none-any.whl"}}, {"metadata": {"name": "jeepney", "version": "0.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b2/a3/e137168c9c44d18eff0376253da9f1e9234d0239e0ee230d2fee6cea8e55/jeepney-0.9.0-py3-none-any.whl"}}, {"metadata": {"name": "openapi-pydantic", "version": "0.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/cf/03675d8bd8ecbf4445504d8071adab19f5f993676795708e36402ab38263/openapi_pydantic-0.5.1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/6f/a04e900f465ff3221ccc395522503e2d10e79fa21f2723c8e177aae1e0d1/opentelemetry_api-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "platformdirs", "version": "4.11.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/39/be/3ae887e84c38c4dd1c549cd5825adc93f48069a94fe1cb8ac52a9da16f15/platformdirs-4.11.11-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/34/a1/c8e6b66f499f510752c07a092dfe27621f9c255635e59d38704b5681c35a/pydantic_core-2.46.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "email-validator", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "dnspython", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/97/672cb32ce0dfea44b740cb7b4f97038463b9cf7c0ead1aacf595572851d6/pyjwt-2.14.0-py3-none-any.whl"}}, {"metadata": {"name": "pyperclip", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/80/fc9d01d5ed37ba4c42ca2b55b4339ae6e200b456be3a1aaddf4a9fa99b8c/pyperclip-1.11.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "0.30.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/61/b5/707f6cf0066a6412aacc11d17920ea2e19e5b2f04081c64526eb35b5c6e7/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "SecretStorage", "version": "3.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/46/f5af3402b579fd5e11573ce652019a67074317e18c1935cc0b4ba9b35552/secretstorage-3.5.0-py3-none-any.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/6a/2ba3ed4a69babf3afdddf7d8314a48d87562c0a442206bbc2a1b50d5efc0/sse_starlette-3.4.11-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uncalled-for", "version": "0.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a2/40/97cec87c077eb3291fc7905e6633e08b7ca593c57d30238444bcb6bb3d53/uncalled_for-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.53.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/76/18/0eea75741ee812e9f598b687619ce2454f6c3a1c5cd21ea990ec6bd26f45/uvicorn-0.53.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "watchfiles", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/02/c8/79eee650c62d2c186598489814468e389b5def0ebe755399ff645b35b1b2/watchfiles-1.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f3/18/a17e2f0cde02dc10154c808deed7e1d8528afff93612f70d3f0a5b19b011/websockets-16.1.1-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl"}}, {"metadata": {"name": "zipp", "version": "4.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.classes", "version": "3.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/66/b15ce62552d84bbfcec9a4873ab79d993a1dd4edb922cbfccae192bd5b5f/jaraco.classes-3.4.0-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.context", "version": "6.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f2/58/bc8954bda5fcda97bd7c19be11b85f91973d67a706ed4a3aec33e7de22db/jaraco_context-6.1.2-py3-none-any.whl"}}, {"metadata": {"name": "backports.tarfile", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/fa/123043af240e49752f1c4bd24da5053b6bd00cad78c2be53c0d1e8b975bc/backports.tarfile-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.functools", "version": "4.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/02/36/ecc85bc96c273dc8a11273ed4782272975e6338d4a3e9228621175edf0e3/jaraco_functools-4.6.0-py3-none-any.whl"}}, {"metadata": {"name": "more-itertools", "version": "11.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/3d/1087453384dbde46a8c7f9356eead2c58be8a7bf156bca40243377c85715/more_itertools-11.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "4ea2151a96fd3708d6bee248d6499707"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "Django", "version": "5.2.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/f8/ce120525ca78f12b07daf65786679c5d0b54a75285a8958d3ae55e39da35/django-5.2.17-py3-none-any.whl"}}, {"metadata": {"name": "psycopg2-binary", "version": "2.9.12"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d3/f2/98eeac7d60c43df9338287834edf9b3e69be68a2db78a57b1b81d705e735/psycopg2_binary-2.9.12-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "djangorestframework", "version": "3.17.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5a/e1/2c516bdc83652b1a60c6119366ac2c0607b479ed05cd6093f916ca8928f8/djangorestframework-3.17.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-django", "version": "4.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/83/a5/41d091f697c09609e7ef1d5d61925494e0454ebf51de7de05f0f0a728f1d/pytest_django-4.12.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/af/9c0bda43e486a3c9bf1e0f876d0f241bc3f229d7d65d09331a0868db9629/pytest_forked-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "channels", "version": "4.3.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/16/34/c32915288b7ef482377b6adc401192f98c6a99b3a145423d3b8aed807898/channels-4.3.2-py3-none-any.whl"}}, {"metadata": {"name": "asgiref", "version": "3.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c0/1b/54f4ad77cd8a584fa70746c47df988e002cf1ee1eba43364d46f87803647/asgiref-3.12.1-py3-none-any.whl"}}, {"metadata": {"name": "executing", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "daphne", "version": "4.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/0c/59e966c167880904f2e6a235c63169760dce58ba8062a7a153a6183539cc/daphne-4.2.3-py3-none-any.whl"}}, {"metadata": {"name": "autobahn", "version": "24.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/13/ee/a6475f39ef6c6f41c33da6b193e0ffd2c6048f52e1698be6253c59301b72/autobahn-24.4.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/37/73d005be173aff344af30e9fd2a576575cb2391a7101d9cd3842e1fa8cce/cryptography-50.0.0-cp39-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/1a/4b2f7c92293ba05cbd4a9a1b28faaf0326272d9488e6354657571c48a7aa/cffi-2.1.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "hyperlink", "version": "21.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/aa/8caf6a0a3e62863cbb9dab27135660acba46903b703e224f14f447e57934/hyperlink-21.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "sqlparse", "version": "0.5.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/4b/359f28a903c13438ef59ebeee215fb25da53066db67b305c125f1c6d2a25/sqlparse-0.5.5-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "Twisted", "version": "26.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/57/bcf4e2370dd218c9aa68a9140a65d86729c73f1d529f7e94786c2766fc72/twisted-26.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "Automat", "version": "25.4.16"}, "download_info": {"url": "https://files.pythonhosted.org/packages/02/ff/1175b0b7371e46244032d43a56862d0af455823b5280a50c63d99cc50f18/automat-25.4.16-py3-none-any.whl"}}, {"metadata": {"name": "constantly", "version": "23.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b8/40/c199d095151addf69efdb4b9ca3a4f20f70e20508d6222bffb9b76f58573/constantly-23.10.4-py3-none-any.whl"}}, {"metadata": {"name": "Incremental", "version": "24.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1d/55/0f4df2a44053867ea9cbea73fc588b03c55605cd695cee0a3d86f0029cb2/incremental-24.11.0-py3-none-any.whl"}}, {"metadata": {"name": "pyOpenSSL", "version": "26.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ad/2cf6d3fa2fae5c79e1ed9960c0d42badd0f94d81dd12b50604cdc839e648/pyopenssl-26.4.0-py3-none-any.whl"}}, {"metadata": {"name": "service-identity", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/eb/2433e1af4ff903499144de4846569fb3300b816179ae99a03c2f011b666a/service_identity-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "txaio", "version": "25.9.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/2c/e276b80f73fc0411cefa1c1eeae6bc17955197a9c3e2b41b41f957322549/txaio-25.9.2-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "zope.interface", "version": "8.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/17/0f/8f1a29966bcf863e3a2121edcafb81c55715de7886bcc9544749cc79e7da/zope_interface-8.5-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "py", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "83.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/40/e1e72872c6354b306daef1703549e8e83b4d43cfea356311bf722a043752/setuptools-83.0.0-py3-none-any.whl"}}], "install_targets_hash": "4ed72e643e6a9d9ab4940427b6f18363"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "Django", "version": "5.2.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/f8/ce120525ca78f12b07daf65786679c5d0b54a75285a8958d3ae55e39da35/django-5.2.17-py3-none-any.whl"}}, {"metadata": {"name": "psycopg2-binary", "version": "2.9.12"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d3/f2/98eeac7d60c43df9338287834edf9b3e69be68a2db78a57b1b81d705e735/psycopg2_binary-2.9.12-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "djangorestframework", "version": "3.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/d7/7461738e819b853275b35fd35712a85806c09a327e1fd5f8ff766bdd317e/djangorestframework-3.18.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-django", "version": "4.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/27/88/52db7a840fdbd74934f8df11b7450c9919ac00f61c02e88827f3d58180f7/pytest_django-4.13.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.7.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/18/f1/46d32fe4b9aae09fe397e768ff376d9b6bdbb4f11faaa727f163c3457b43/pytest_forked-1.7.5-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "channels", "version": "4.3.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/16/34/c32915288b7ef482377b6adc401192f98c6a99b3a145423d3b8aed807898/channels-4.3.2-py3-none-any.whl"}}, {"metadata": {"name": "asgiref", "version": "3.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c0/1b/54f4ad77cd8a584fa70746c47df988e002cf1ee1eba43364d46f87803647/asgiref-3.12.1-py3-none-any.whl"}}, {"metadata": {"name": "executing", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "daphne", "version": "4.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/0c/59e966c167880904f2e6a235c63169760dce58ba8062a7a153a6183539cc/daphne-4.2.3-py3-none-any.whl"}}, {"metadata": {"name": "autobahn", "version": "24.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/13/ee/a6475f39ef6c6f41c33da6b193e0ffd2c6048f52e1698be6253c59301b72/autobahn-24.4.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/37/73d005be173aff344af30e9fd2a576575cb2391a7101d9cd3842e1fa8cce/cryptography-50.0.0-cp39-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/1a/4b2f7c92293ba05cbd4a9a1b28faaf0326272d9488e6354657571c48a7aa/cffi-2.1.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "hyperlink", "version": "21.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/aa/8caf6a0a3e62863cbb9dab27135660acba46903b703e224f14f447e57934/hyperlink-21.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "sqlparse", "version": "0.5.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/4b/359f28a903c13438ef59ebeee215fb25da53066db67b305c125f1c6d2a25/sqlparse-0.5.5-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "Twisted", "version": "26.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/57/bcf4e2370dd218c9aa68a9140a65d86729c73f1d529f7e94786c2766fc72/twisted-26.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "Automat", "version": "25.4.16"}, "download_info": {"url": "https://files.pythonhosted.org/packages/02/ff/1175b0b7371e46244032d43a56862d0af455823b5280a50c63d99cc50f18/automat-25.4.16-py3-none-any.whl"}}, {"metadata": {"name": "constantly", "version": "23.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b8/40/c199d095151addf69efdb4b9ca3a4f20f70e20508d6222bffb9b76f58573/constantly-23.10.4-py3-none-any.whl"}}, {"metadata": {"name": "Incremental", "version": "24.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1d/55/0f4df2a44053867ea9cbea73fc588b03c55605cd695cee0a3d86f0029cb2/incremental-24.11.0-py3-none-any.whl"}}, {"metadata": {"name": "pyOpenSSL", "version": "26.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ad/2cf6d3fa2fae5c79e1ed9960c0d42badd0f94d81dd12b50604cdc839e648/pyopenssl-26.4.0-py3-none-any.whl"}}, {"metadata": {"name": "service-identity", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/eb/2433e1af4ff903499144de4846569fb3300b816179ae99a03c2f011b666a/service_identity-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "txaio", "version": "25.9.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/2c/e276b80f73fc0411cefa1c1eeae6bc17955197a9c3e2b41b41f957322549/txaio-25.9.2-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "zope.interface", "version": "8.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/17/0f/8f1a29966bcf863e3a2121edcafb81c55715de7886bcc9544749cc79e7da/zope_interface-8.5-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "84.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/9c/c510029fc6ef33a6275cd2c5d3cecd6613dfd6aa401d57c54f1c18852ccf/setuptools-84.0.0-py3-none-any.whl"}}], "install_targets_hash": "4ed72e643e6a9d9ab4940427b6f18363"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "Django", "version": "5.2.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/f8/ce120525ca78f12b07daf65786679c5d0b54a75285a8958d3ae55e39da35/django-5.2.17-py3-none-any.whl"}}, {"metadata": {"name": "psycopg2-binary", "version": "2.9.12"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d3/f2/98eeac7d60c43df9338287834edf9b3e69be68a2db78a57b1b81d705e735/psycopg2_binary-2.9.12-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "djangorestframework", "version": "3.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/d7/7461738e819b853275b35fd35712a85806c09a327e1fd5f8ff766bdd317e/djangorestframework-3.18.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-django", "version": "4.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/27/88/52db7a840fdbd74934f8df11b7450c9919ac00f61c02e88827f3d58180f7/pytest_django-4.13.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.7.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/18/f1/46d32fe4b9aae09fe397e768ff376d9b6bdbb4f11faaa727f163c3457b43/pytest_forked-1.7.5-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "channels", "version": "4.3.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/16/34/c32915288b7ef482377b6adc401192f98c6a99b3a145423d3b8aed807898/channels-4.3.2-py3-none-any.whl"}}, {"metadata": {"name": "asgiref", "version": "3.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c0/1b/54f4ad77cd8a584fa70746c47df988e002cf1ee1eba43364d46f87803647/asgiref-3.12.1-py3-none-any.whl"}}, {"metadata": {"name": "executing", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "daphne", "version": "4.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/0c/59e966c167880904f2e6a235c63169760dce58ba8062a7a153a6183539cc/daphne-4.2.3-py3-none-any.whl"}}, {"metadata": {"name": "autobahn", "version": "24.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/13/ee/a6475f39ef6c6f41c33da6b193e0ffd2c6048f52e1698be6253c59301b72/autobahn-24.4.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/37/73d005be173aff344af30e9fd2a576575cb2391a7101d9cd3842e1fa8cce/cryptography-50.0.0-cp39-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/1a/4b2f7c92293ba05cbd4a9a1b28faaf0326272d9488e6354657571c48a7aa/cffi-2.1.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "hyperlink", "version": "21.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/aa/8caf6a0a3e62863cbb9dab27135660acba46903b703e224f14f447e57934/hyperlink-21.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "sqlparse", "version": "0.5.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/4b/359f28a903c13438ef59ebeee215fb25da53066db67b305c125f1c6d2a25/sqlparse-0.5.5-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "Twisted", "version": "26.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/57/bcf4e2370dd218c9aa68a9140a65d86729c73f1d529f7e94786c2766fc72/twisted-26.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "Automat", "version": "25.4.16"}, "download_info": {"url": "https://files.pythonhosted.org/packages/02/ff/1175b0b7371e46244032d43a56862d0af455823b5280a50c63d99cc50f18/automat-25.4.16-py3-none-any.whl"}}, {"metadata": {"name": "constantly", "version": "23.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b8/40/c199d095151addf69efdb4b9ca3a4f20f70e20508d6222bffb9b76f58573/constantly-23.10.4-py3-none-any.whl"}}, {"metadata": {"name": "Incremental", "version": "24.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1d/55/0f4df2a44053867ea9cbea73fc588b03c55605cd695cee0a3d86f0029cb2/incremental-24.11.0-py3-none-any.whl"}}, {"metadata": {"name": "pyOpenSSL", "version": "26.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ad/2cf6d3fa2fae5c79e1ed9960c0d42badd0f94d81dd12b50604cdc839e648/pyopenssl-26.4.0-py3-none-any.whl"}}, {"metadata": {"name": "service-identity", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/eb/2433e1af4ff903499144de4846569fb3300b816179ae99a03c2f011b666a/service_identity-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "txaio", "version": "25.9.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/2c/e276b80f73fc0411cefa1c1eeae6bc17955197a9c3e2b41b41f957322549/txaio-25.9.2-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "zope.interface", "version": "8.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/17/0f/8f1a29966bcf863e3a2121edcafb81c55715de7886bcc9544749cc79e7da/zope_interface-8.5-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "84.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/9c/c510029fc6ef33a6275cd2c5d3cecd6613dfd6aa401d57c54f1c18852ccf/setuptools-84.0.0-py3-none-any.whl"}}], "install_targets_hash": "4ed72e643e6a9d9ab4940427b6f18363"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "Django", "version": "5.2.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/f8/ce120525ca78f12b07daf65786679c5d0b54a75285a8958d3ae55e39da35/django-5.2.17-py3-none-any.whl"}}, {"metadata": {"name": "psycopg2-binary", "version": "2.9.12"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d3/f2/98eeac7d60c43df9338287834edf9b3e69be68a2db78a57b1b81d705e735/psycopg2_binary-2.9.12-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "djangorestframework", "version": "3.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/d7/7461738e819b853275b35fd35712a85806c09a327e1fd5f8ff766bdd317e/djangorestframework-3.18.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-django", "version": "4.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/27/88/52db7a840fdbd74934f8df11b7450c9919ac00f61c02e88827f3d58180f7/pytest_django-4.13.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.7.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/18/f1/46d32fe4b9aae09fe397e768ff376d9b6bdbb4f11faaa727f163c3457b43/pytest_forked-1.7.5-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "channels", "version": "4.3.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/16/34/c32915288b7ef482377b6adc401192f98c6a99b3a145423d3b8aed807898/channels-4.3.2-py3-none-any.whl"}}, {"metadata": {"name": "asgiref", "version": "3.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c0/1b/54f4ad77cd8a584fa70746c47df988e002cf1ee1eba43364d46f87803647/asgiref-3.12.1-py3-none-any.whl"}}, {"metadata": {"name": "executing", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "daphne", "version": "4.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/0c/59e966c167880904f2e6a235c63169760dce58ba8062a7a153a6183539cc/daphne-4.2.3-py3-none-any.whl"}}, {"metadata": {"name": "autobahn", "version": "24.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/13/ee/a6475f39ef6c6f41c33da6b193e0ffd2c6048f52e1698be6253c59301b72/autobahn-24.4.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/37/73d005be173aff344af30e9fd2a576575cb2391a7101d9cd3842e1fa8cce/cryptography-50.0.0-cp39-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/1a/4b2f7c92293ba05cbd4a9a1b28faaf0326272d9488e6354657571c48a7aa/cffi-2.1.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "hyperlink", "version": "21.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/aa/8caf6a0a3e62863cbb9dab27135660acba46903b703e224f14f447e57934/hyperlink-21.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "sqlparse", "version": "0.5.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/4b/359f28a903c13438ef59ebeee215fb25da53066db67b305c125f1c6d2a25/sqlparse-0.5.5-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "Twisted", "version": "26.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/57/bcf4e2370dd218c9aa68a9140a65d86729c73f1d529f7e94786c2766fc72/twisted-26.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "Automat", "version": "25.4.16"}, "download_info": {"url": "https://files.pythonhosted.org/packages/02/ff/1175b0b7371e46244032d43a56862d0af455823b5280a50c63d99cc50f18/automat-25.4.16-py3-none-any.whl"}}, {"metadata": {"name": "constantly", "version": "23.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b8/40/c199d095151addf69efdb4b9ca3a4f20f70e20508d6222bffb9b76f58573/constantly-23.10.4-py3-none-any.whl"}}, {"metadata": {"name": "Incremental", "version": "24.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1d/55/0f4df2a44053867ea9cbea73fc588b03c55605cd695cee0a3d86f0029cb2/incremental-24.11.0-py3-none-any.whl"}}, {"metadata": {"name": "pyOpenSSL", "version": "26.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ad/2cf6d3fa2fae5c79e1ed9960c0d42badd0f94d81dd12b50604cdc839e648/pyopenssl-26.4.0-py3-none-any.whl"}}, {"metadata": {"name": "service-identity", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/eb/2433e1af4ff903499144de4846569fb3300b816179ae99a03c2f011b666a/service_identity-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "txaio", "version": "25.9.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/2c/e276b80f73fc0411cefa1c1eeae6bc17955197a9c3e2b41b41f957322549/txaio-25.9.2-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "zope.interface", "version": "8.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/17/0f/8f1a29966bcf863e3a2121edcafb81c55715de7886bcc9544749cc79e7da/zope_interface-8.5-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "84.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/9c/c510029fc6ef33a6275cd2c5d3cecd6613dfd6aa401d57c54f1c18852ccf/setuptools-84.0.0-py3-none-any.whl"}}], "install_targets_hash": "4ed72e643e6a9d9ab4940427b6f18363"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "Django", "version": "5.2.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/f8/ce120525ca78f12b07daf65786679c5d0b54a75285a8958d3ae55e39da35/django-5.2.17-py3-none-any.whl"}}, {"metadata": {"name": "psycopg2-binary", "version": "2.9.12"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d3/f2/98eeac7d60c43df9338287834edf9b3e69be68a2db78a57b1b81d705e735/psycopg2_binary-2.9.12-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "djangorestframework", "version": "3.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/d7/7461738e819b853275b35fd35712a85806c09a327e1fd5f8ff766bdd317e/djangorestframework-3.18.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-django", "version": "4.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/27/88/52db7a840fdbd74934f8df11b7450c9919ac00f61c02e88827f3d58180f7/pytest_django-4.13.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.7.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/18/f1/46d32fe4b9aae09fe397e768ff376d9b6bdbb4f11faaa727f163c3457b43/pytest_forked-1.7.5-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "channels", "version": "4.3.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/16/34/c32915288b7ef482377b6adc401192f98c6a99b3a145423d3b8aed807898/channels-4.3.2-py3-none-any.whl"}}, {"metadata": {"name": "asgiref", "version": "3.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c0/1b/54f4ad77cd8a584fa70746c47df988e002cf1ee1eba43364d46f87803647/asgiref-3.12.1-py3-none-any.whl"}}, {"metadata": {"name": "executing", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "daphne", "version": "4.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/0c/59e966c167880904f2e6a235c63169760dce58ba8062a7a153a6183539cc/daphne-4.2.3-py3-none-any.whl"}}, {"metadata": {"name": "autobahn", "version": "24.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/13/ee/a6475f39ef6c6f41c33da6b193e0ffd2c6048f52e1698be6253c59301b72/autobahn-24.4.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/37/73d005be173aff344af30e9fd2a576575cb2391a7101d9cd3842e1fa8cce/cryptography-50.0.0-cp39-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/1a/4b2f7c92293ba05cbd4a9a1b28faaf0326272d9488e6354657571c48a7aa/cffi-2.1.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "hyperlink", "version": "21.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/aa/8caf6a0a3e62863cbb9dab27135660acba46903b703e224f14f447e57934/hyperlink-21.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "sqlparse", "version": "0.5.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/4b/359f28a903c13438ef59ebeee215fb25da53066db67b305c125f1c6d2a25/sqlparse-0.5.5-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "Twisted", "version": "26.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/57/bcf4e2370dd218c9aa68a9140a65d86729c73f1d529f7e94786c2766fc72/twisted-26.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "Automat", "version": "25.4.16"}, "download_info": {"url": "https://files.pythonhosted.org/packages/02/ff/1175b0b7371e46244032d43a56862d0af455823b5280a50c63d99cc50f18/automat-25.4.16-py3-none-any.whl"}}, {"metadata": {"name": "constantly", "version": "23.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b8/40/c199d095151addf69efdb4b9ca3a4f20f70e20508d6222bffb9b76f58573/constantly-23.10.4-py3-none-any.whl"}}, {"metadata": {"name": "Incremental", "version": "24.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1d/55/0f4df2a44053867ea9cbea73fc588b03c55605cd695cee0a3d86f0029cb2/incremental-24.11.0-py3-none-any.whl"}}, {"metadata": {"name": "pyOpenSSL", "version": "26.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ad/2cf6d3fa2fae5c79e1ed9960c0d42badd0f94d81dd12b50604cdc839e648/pyopenssl-26.4.0-py3-none-any.whl"}}, {"metadata": {"name": "service-identity", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/eb/2433e1af4ff903499144de4846569fb3300b816179ae99a03c2f011b666a/service_identity-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "txaio", "version": "25.9.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/2c/e276b80f73fc0411cefa1c1eeae6bc17955197a9c3e2b41b41f957322549/txaio-25.9.2-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "zope.interface", "version": "8.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/17/0f/8f1a29966bcf863e3a2121edcafb81c55715de7886bcc9544749cc79e7da/zope_interface-8.5-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "84.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/9c/c510029fc6ef33a6275cd2c5d3cecd6613dfd6aa401d57c54f1c18852ccf/setuptools-84.0.0-py3-none-any.whl"}}], "install_targets_hash": "4ed72e643e6a9d9ab4940427b6f18363"} -{"python_version": "3.10", "dependencies": [{"metadata": {"name": "fastmcp", "version": "0.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f5/07/bc69e65b45d638822190bce0defb497a50d240291b8467cb79078d0064b7/fastmcp-0.1.0-py3-none-any.whl"}}, {"metadata": {"name": "mcp", "version": "1.29.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/c8/248b201f6d753d69fd5d6506011abbb35a946d9142b2ae311a948fd0be3d/mcp-1.29.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/c6/65f646c7ff09bd257f660434adb45c4dfcbbcebcc030562fecf6f5bf887d/pydantic_core-2.46.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/77/c1/6e422f34e569cf8e18df68d1939c81c099d2b61e4f7d9621c8a77560799c/pydantic_settings-2.14.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/2a/5bb823f5bedcf80718cea7fbc95ec5515cca3769633c4b01a32be7f30e7c/cryptography-49.0.0-cp39-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/aa/24580a278de21fd7322635556334d9b535f1cbc00b0a3919447cdf464c65/cffi-2.1.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "0.30.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/6a/4ba3d0fb7297ebae71171822554abe48d7cab29c28b8f9f2c04b79988c05/rpds_py-0.30.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/36/e10c1d1b7ca881d2625db2ec28508578499187bb1c389952c398474e1834/sse_starlette-3.4.6-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typer", "version": "0.27.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/40/03/26a383c9e58c213199d1aad1c3d353cfc22d4444ec6d2c0bf8ad02523843/typer-0.27.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "shellingham", "version": "1.5.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.52.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/39/e6/b5c0630ace9757232aec07112be8146b812787db52141ff9d50674aa7634/uvicorn-0.52.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "4ef5d5161db3a01ccf52260b7895e529"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "mistralai", "version": "2.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e3/d5/6b9c08ab9b5b890970e8949bf00a9f8f82653826de5cc5ad506fe1c1fb73/mistralai-2.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "eval_type_backport", "version": "0.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/a7/bb99bf5e6f78736ddb53480f2c3ff3702ffe2196a7c5e1661c03081d398e/eval_type_backport-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonpath-python", "version": "1.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/8a/1270a6803bd821cbfcdda387eaa13cb41a7b1f7b9bd145979b3bfb9d6cb7/jsonpath_python-1.1.6-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-semantic-conventions", "version": "0.60b1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7a/5e/5958555e09635d09b75de3c4f8b9cae7335ca545d77392ffe7331534c402/opentelemetry_semantic_conventions-0.60b1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.39.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/df/d3f1ddf4bb4cb50ed9b1139cc7b1c54c34a1e7ce8fd1b9a37c0d1551a6bd/opentelemetry_api-1.39.1-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/d0/c787604c71c2bdcda1a5656942fc822cd0f9cd879b9484bb84fc42172703/pydantic_core-2.46.5-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fa/5e/f8e9a1d23b9c20a551a8a02ea3637b4642e22c2626e3a13a9a29cdea99eb/importlib_metadata-8.7.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "zipp", "version": "4.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl"}}], "install_targets_hash": "4f94c708225730a84d6fdb55c929ba1b"} -{"python_version": "3.10", "dependencies": [{"metadata": {"name": "openai-agents", "version": "0.0.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/69/899b33c97d5ee6ce454d5cdf89ddddcec9100bece4ed508229b06b1a07ca/openai_agents-0.0.19-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "2.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ae/f4/561ed79fd94876160018a5e75254cfcb9b0e62d4dded9dcb20072e86d623/openai-2.44.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "griffe", "version": "1.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/83/3b1d03d36f224edded98e9affd0467630fc09d766c0e56fb1498cbb04a9b/griffe-1.15.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c6/3d/4d7f5667ea0e0548534ba880b84bb3d12924fd133aa83ad6c6c80fca3d76/jiter-0.16.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "mcp", "version": "1.29.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/c8/248b201f6d753d69fd5d6506011abbb35a946d9142b2ae311a948fd0be3d/mcp-1.29.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/c6/65f646c7ff09bd257f660434adb45c4dfcbbcebcc030562fecf6f5bf887d/pydantic_core-2.46.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "types-requests", "version": "2.33.0.20260712"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/e7/010c87f559e216d83f9dc51e939633fd0d0ead3377340181ab0e223cd3b5/types_requests-2.33.0.20260712-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/aa/554e2614f38fc34c58ff1d0911ae8535ad2516440d5482d76fe59f1088b0/charset_normalizer-3.5.1-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "colorama", "version": "0.4.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/3a/764912c58293d95b6dcdf4cc255f9d10de310580ced547b082eb9d72018c/sse_starlette-3.4.8-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.52.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/79/4a20b54ab0491485ccd8c077db2d39187c7f12b3e15485d38a7be37c81b4/uvicorn-0.52.4-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/37/73d005be173aff344af30e9fd2a576575cb2391a7101d9cd3842e1fa8cce/cryptography-50.0.0-cp39-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "0.30.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/6a/4ba3d0fb7297ebae71171822554abe48d7cab29c28b8f9f2c04b79988c05/rpds_py-0.30.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/1a/4b2f7c92293ba05cbd4a9a1b28faaf0326272d9488e6354657571c48a7aa/cffi-2.1.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "516bab83ca4281a985cea82f50b07b4c"} -{"python_version": "3.10", "dependencies": [{"metadata": {"name": "openai-agents", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a2/92/9cbbdd604f858056d4e4f105a1b99779128bae61b6a3681db0f035ef73b4/openai_agents-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "2.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ae/f4/561ed79fd94876160018a5e75254cfcb9b0e62d4dded9dcb20072e86d623/openai-2.44.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "griffe", "version": "1.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/83/3b1d03d36f224edded98e9affd0467630fc09d766c0e56fb1498cbb04a9b/griffe-1.15.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c6/3d/4d7f5667ea0e0548534ba880b84bb3d12924fd133aa83ad6c6c80fca3d76/jiter-0.16.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "mcp", "version": "1.29.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/c8/248b201f6d753d69fd5d6506011abbb35a946d9142b2ae311a948fd0be3d/mcp-1.29.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/c6/65f646c7ff09bd257f660434adb45c4dfcbbcebcc030562fecf6f5bf887d/pydantic_core-2.46.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "types-requests", "version": "2.33.0.20260712"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/e7/010c87f559e216d83f9dc51e939633fd0d0ead3377340181ab0e223cd3b5/types_requests-2.33.0.20260712-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/aa/554e2614f38fc34c58ff1d0911ae8535ad2516440d5482d76fe59f1088b0/charset_normalizer-3.5.1-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "colorama", "version": "0.4.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/3a/764912c58293d95b6dcdf4cc255f9d10de310580ced547b082eb9d72018c/sse_starlette-3.4.8-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.52.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/79/4a20b54ab0491485ccd8c077db2d39187c7f12b3e15485d38a7be37c81b4/uvicorn-0.52.4-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/37/73d005be173aff344af30e9fd2a576575cb2391a7101d9cd3842e1fa8cce/cryptography-50.0.0-cp39-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "0.30.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/6a/4ba3d0fb7297ebae71171822554abe48d7cab29c28b8f9f2c04b79988c05/rpds_py-0.30.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/1a/4b2f7c92293ba05cbd4a9a1b28faaf0326272d9488e6354657571c48a7aa/cffi-2.1.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "54acb8a9a6cd450523a6e79a8e22ef0c"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "celery", "version": "5.7.0a1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/de/bf/72703e2ac184cc9c4c641ba5abaec725cbdcf48755c7582f006005d38848/celery-5.7.0a1-py3-none-any.whl"}}, {"metadata": {"name": "billiard", "version": "4.3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/60/60/ade6d336983b82fbc330d0d0371f945249b448152852952f643787a3288d/billiard-4.3.0-py3-none-any.whl"}}, {"metadata": {"name": "click-repl", "version": "0.4.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e0/ae/63d94d251d2e1a7bf3794ea47cb1c99fe6de055b732ea79d7bcdabef8ff5/click_repl-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "newrelic", "version": "10.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/d4/71/07c41fd5e8c94e95216b000d00c3cf735f769cb406c0f33c6ff83b7b7418/newrelic-10.16.0.tar.gz"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "vine", "version": "5.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/03/ff/7c0c86c43b3cbb927e0ccc0255cb4057ceba4799cd44ae95174ce8e8b5b2/vine-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "redis", "version": "8.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/66/9d/c5731f6e3608663d4d3656fd8d3aecee8b509c3082818f5a13eae925baea/redis-8.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.7.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/18/f1/46d32fe4b9aae09fe397e768ff376d9b6bdbb4f11faaa727f163c3457b43/pytest_forked-1.7.5-py3-none-any.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "click-didyoumean", "version": "0.3.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/1b/5b/974430b5ffdb7a4f1941d13d83c64a0395114503cc357c6b9ae4ce5047ed/click_didyoumean-0.3.1-py3-none-any.whl"}}, {"metadata": {"name": "click-plugins", "version": "1.1.1.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/3d/9a/2abecb28ae875e39c8cad711eb1186d8d14eab564705325e77e4e6ab9ae5/click_plugins-1.1.1.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "kombu", "version": "5.7.0a1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b6/d9/1b98be4b45c3cb6737663ea5e7847fcc8f6c21de204a0411ae12874fbfc0/kombu-5.7.0a1-py3-none-any.whl"}}, {"metadata": {"name": "amqp", "version": "5.4.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/07/99/6b965aa99a32630c1c61ce57c9dcf81cec6fec354274a87f14525302b7f7/amqp-5.4.0-py3-none-any.whl"}}, {"metadata": {"name": "prompt_toolkit", "version": "3.0.53"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/54/6f/84908cad2d6aa5144abcf7b42709fe4fdb459bc640ec7ac5786e7693dabc/prompt_toolkit-3.0.53-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "tzdata", "version": "2026.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/f9/bc/8737e8d54cf51106118039b83f485a4783112fab49ea9d044b234978a46e/tzdata-2026.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/39/cc/9c0adc5861020de426ec71716b6c1bef8d90694b7d6d0a16202cdb1647f5/wcwidth-0.8.4-py3-none-any.whl"}}, {"metadata": {"name": "tzlocal", "version": "5.4.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/9e/a4/017a7a6cbe387d961a688ec31364ae60a5c4e22c96ae9921b79a947c855d/tzlocal-5.4.4-py3-none-any.whl"}}], "install_targets_hash": "571b466b11beb803cdcf782ce81876e3"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "pydantic-ai", "version": "2.47.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/12/1a/a46dad48b18c004eb686596d360d2310fc9c928b5b9b31341c03c6c813f1/pydantic_ai-2.47.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-ai-slim", "version": "2.47.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/eb/94/5d8a27dbe4a9e27378698c31c5848310d7a7727e22e1334f683dfbe5397d/pydantic_ai_slim-2.47.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-evals", "version": "2.47.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a9/81/34504d9426f420cc3ea05eb5d3f387a17f14d5ea678b6ced18d6f4be9da4/pydantic_evals-2.47.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-graph", "version": "2.47.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/3c/b0/4630a964201fb04dba730cbe54b7941309d97d59c01537465b075c26cae7/pydantic_graph-2.47.0-py3-none-any.whl"}}, {"metadata": {"name": "fastmcp-slim", "version": "4.0.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ed/76/8dc551ef1f222bd146537ae100baf7441628aa1050494b567249ece997c2/fastmcp_slim-4.0.5-py3-none-any.whl"}}, {"metadata": {"name": "mcp", "version": "2.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/1b/ff/8e7eade68b8a28f7da0ed1085544341b51f9c935dbf6b95c76b7edfea6a0/mcp-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mcp-types", "version": "2.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/8f/d7/6ffba5d8cd5dd9b8a19478875c50e04945314ba5074e84d749283f27f62d/mcp_types-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "py-key-value-aio", "version": "0.4.6"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/9a/46/12871550fb0613d149144bb9d41f22680d5f46717bc45a76eb5798c20c3f/py_key_value_aio-0.4.6-py3-none-any.whl"}}, {"metadata": {"name": "aiofile", "version": "3.8.8"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/76/ea/b6aae3275bb0991c43fff401e7b8db198047b6f692e8954520ec7aed3652/aiofile-3.8.8-py3-none-any.whl"}}, {"metadata": {"name": "caio", "version": "0.9.25"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/6a/80/ea4ead0c5d52a9828692e7df20f0eafe8d26e671ce4883a0a146bb91049e/caio-0.9.25-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "anthropic", "version": "1.7.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c0/dc/74995efda028421917f4caabd24db1373ee0742573a2363fff1a21191441/anthropic-1.7.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.17.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ca/e9/5993079500530586655c6f2823e2926b3f5ceddd49918c5a86757eadba3a/jiter-0.17.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/bd/d0/c787604c71c2bdcda1a5656942fc822cd0f9cd879b9484bb84fc42172703/pydantic_core-2.46.5-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "argcomplete", "version": "3.7.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/46/bd/551ee6af426af84ca33e02622be722925c196608e9127d731ef17c47f06e/argcomplete-3.7.2-py3-none-any.whl"}}, {"metadata": {"name": "Authlib", "version": "1.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b8/c6/6f124bcfbbfb20fba22c939b4e43a06dccfc0e1ca20e5634ca573cb1e271/authlib-1.8.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "beartype", "version": "0.22.9"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/cc/18245721fa7747065ab478316c7fea7c74777d07f37ae60db2e84f8172e8/beartype-0.22.9-py3-none-any.whl"}}, {"metadata": {"name": "cachetools", "version": "7.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cc/bb/1c6e7a89b11da19f137e4ef5a5c5fe47a5bb686449ba343944ccf8fb34b2/cachetools-7.2.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/84/a9/ee16a903f13755e914d1eecc482fe64d1f10761c3960e5d8fa6837377aff/cryptography-50.0.1-cp39-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/94/1a/4b2f7c92293ba05cbd4a9a1b28faaf0326272d9488e6354657571c48a7aa/cffi-2.1.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "genai-prices", "version": "0.1.7"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/d5/4a/9e04f3dca5ffe74133779ab5e9925ffb6411afbeac55d26fa0e148722599/genai_prices-0.1.7-py3-none-any.whl"}}, {"metadata": {"name": "google-genai", "version": "2.24.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/84/5b/87913fe392ba7b6402577259289ed3740c577956554a674b191a2971d33e/google_genai-2.24.0-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.58.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/59/13/477d90d09591b3938b45c4e11f4d8a51291682112cb5efcac961e815d562/google_auth-2.58.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/aa/554e2614f38fc34c58ff1d0911ae8535ad2516440d5482d76fe59f1088b0/charset_normalizer-3.5.1-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/90/72/2f14b2e167170b8bf1c8bb7f9b0d78000f470d41a2085a91f33e3917b6c9/websockets-16.1.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "griffelib", "version": "2.3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/41/63/e876e789525063c840ccfa8857febdabd6523bcef9ce7eb979b9305ea895/griffelib-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "joserfc", "version": "1.7.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/67/c5/82addfd375e5ee6520644e0553e4aadde92d668c4fc99cc716d337fe7bb3/joserfc-1.7.5-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "keyring", "version": "25.7.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/81/db/e655086b7f3a705df045bf0933bdd9c2f79bb3c97bfef1384598bb79a217/keyring-25.7.0-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "9.0.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b3/55/ecca97ae19075f1fac62def77731e7f535e6c1fb8f92ff08160c5e6dade8/importlib_metadata-9.0.1-py3-none-any.whl"}}, {"metadata": {"name": "logfire", "version": "5.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cd/02/b32c3d5c298e4a9010694d261fb82c2c672747c0bf2b47bffda484aef349/logfire-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-exporter-otlp-proto-http", "version": "1.44.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cd/d0/fdeb1a98d8d3a6205f5f297c51b4a9bfe65126ab60339669bbe3dd54c2e2/opentelemetry_exporter_otlp_proto_http-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-exporter-otlp-proto-common", "version": "1.44.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/5e/71/65fd9d54c10b860f87c045ccee1264cab7011268895d3528818a29c1172a/opentelemetry_exporter_otlp_proto_common-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-proto", "version": "1.44.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/d1/7c/8be563d68e93bbefa5c8affb82ddcff91b3ad858ce49957ba7b16fd3e0ab/opentelemetry_proto-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "googleapis-common-protos", "version": "1.75.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/1a/7a/7d79170c6ce6f12e109df2b3879d6b934010cf4f99aea8de8b7e5408c174/googleapis_common_protos-1.75.3-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.44.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ca/6f/a04e900f465ff3221ccc395522503e2d10e79fa21f2723c8e177aae1e0d1/opentelemetry_api-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-sdk", "version": "1.44.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e7/23/ff077e61886ee020a17ce9c8b6fa11c601c8d8345b09ea24f605445df62a/opentelemetry_sdk-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-semantic-conventions", "version": "0.65b0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a6/0e/49df70d9b81fb5cbae4bbf2a49d865b09bcbcbc4eb53f5851b1027738d78/opentelemetry_semantic_conventions-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "protobuf", "version": "7.36.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/32/72/98342feb672507c8f3a69e34b4fa8961f608edba5c1a48a6f47156d92cb5/protobuf-7.36.2-cp310-abi3-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "executing", "version": "2.2.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "logfire-api", "version": "5.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2d/51/123dab197fb08c0892e3bea1c2266bff159aa2ee82ad43bef93505859705/logfire_api-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "3.17.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/57/bc/5b80a0ca4069a6b5ba6c7d48ae7a4f8176b2c0bde0bebccdb867472ec6f6/openai-3.17.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-instrumentation", "version": "0.65b0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/40/7b/85eab1215f72adf0e68d3dc4a679b9bff993fa679ff34cd8dd378e2659fd/opentelemetry_instrumentation-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "wrapt", "version": "2.4.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e2/cb/08025a4402bd6f34ac7c07e4d5c75e4f32e595cd7424d697c6fce1663bc3/wrapt-2.4.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "opentelemetry-instrumentation-httpx", "version": "0.65b0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/9d/0f/c6144096b4914bbf44b43ba21c962e8f333ff045770b50a3e79ed8bd455f/opentelemetry_instrumentation_httpx-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-util-http", "version": "0.65b0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/23/3f/ab8d29df207ce5f470a07fa96ebb48af4e95b7fab7e7635311b9a32f2fab/opentelemetry_util_http-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "platformdirs", "version": "4.11.12"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ec/2b/69de6317fbf48865bb12aa56c9cfcfff46b3add0cd45250725d96146dce0/platformdirs-4.11.12-py3-none-any.whl"}}, {"metadata": {"name": "prompt_toolkit", "version": "3.0.53"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/54/6f/84908cad2d6aa5144abcf7b42709fe4fdb459bc640ec7ac5786e7693dabc/prompt_toolkit-3.0.53-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/9a/3b/6163796d69c3977d1e4287bea4a6979161cbbdd170ebb430511e8e1999ce/pyasn1-0.6.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "email-validator", "version": "2.3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "dnspython", "version": "2.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.14.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/9c/97/672cb32ce0dfea44b740cb7b4f97038463b9cf7c0ead1aacf595572851d6/pyjwt-2.14.0-py3-none-any.whl"}}, {"metadata": {"name": "pyperclip", "version": "1.11.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/df/80/fc9d01d5ed37ba4c42ca2b55b4339ae6e200b456be3a1aaddf4a9fa99b8c/pyperclip-1.11.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "0.30.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/19/6a/4ba3d0fb7297ebae71171822554abe48d7cab29c28b8f9f2c04b79988c05/rpds_py-0.30.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.11"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/98/6a/2ba3ed4a69babf3afdddf7d8314a48d87562c0a442206bbc2a1b50d5efc0/sse_starlette-3.4.11-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/18/e2/d39ae33d3dc30a0c229ff0cb683df961ebb5e7b8691feb2d08b3ee6ac327/tiktoken-0.14.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.53.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/76/18/0eea75741ee812e9f598b687619ce2454f6c3a1c5cd21ea990ec6bd26f45/uvicorn-0.53.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/39/cc/9c0adc5861020de426ec71716b6c1bef8d90694b7d6d0a16202cdb1647f5/wcwidth-0.8.4-py3-none-any.whl"}}, {"metadata": {"name": "zipp", "version": "4.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.classes", "version": "3.4.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7f/66/b15ce62552d84bbfcec9a4873ab79d993a1dd4edb922cbfccae192bd5b5f/jaraco.classes-3.4.0-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.context", "version": "6.1.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/f2/58/bc8954bda5fcda97bd7c19be11b85f91973d67a706ed4a3aec33e7de22db/jaraco_context-6.1.2-py3-none-any.whl"}}, {"metadata": {"name": "backports.tarfile", "version": "1.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b9/fa/123043af240e49752f1c4bd24da5053b6bd00cad78c2be53c0d1e8b975bc/backports.tarfile-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.functools", "version": "4.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/02/36/ecc85bc96c273dc8a11273ed4782272975e6338d4a3e9228621175edf0e3/jaraco_functools-4.6.0-py3-none-any.whl"}}, {"metadata": {"name": "more-itertools", "version": "11.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e8/3d/1087453384dbde46a8c7f9356eead2c58be8a7bf156bca40243377c85715/more_itertools-11.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.9.10"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/cd/2f540fc813d1f71f18e1cc6861483133a0e6afb349a4e770fbdce4811d8d/regex-2026.9.10-cp310-cp310-macosx_11_0_arm64.whl"}}], "install_targets_hash": "59d07114fce5d52fca16194a659dc9bf"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "sanic", "version": "22.3.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d9/84/e6cf5cd2aa1c0f000cd10c8601f198143ab2c9273912a57d63c3c4c269cd/sanic-22.3.2-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/7a/bd0ce7ac1cfafc76c84d6e8051bcbd0f7def8e45207230833bd6ff77a41d/websockets-10.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-testing", "version": "22.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/f2/df592d4cac9212355a7de5931258f3a25c86ec894a3e50f168956d8d1a00/sanic_testing-22.6.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.23.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ac/a2/0260c0f5d73bdf06e8d3fc1013a82b9f0633dc21750c9e3f3cb1dba7bb8c/httpx-0.23.3-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "0.16.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/7e/ef97af4623024e8159993b3114ce208de4f677098ae058ec5882a1bf7605/httpcore-0.16.3-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/04/ff642e65ad6b90db43e668d70ffb6736436c7ce41fcc549f4e9472234127/h11-0.14.0-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/31/5c/08c7f7fe311f32e83f7621cd3f99d805f45519cd06fafb247628b861da7d/multidict-6.7.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "rfc3986", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c4/e5/63ca2c4edf4e00657584608bee1001302bbf8c5f569340b78304f2f446cb/rfc3986-1.5.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "sanic-routing", "version": "22.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e4/3d/c704085138f7a70c4879a96844f922dd5540ffd524b1de7d7a49150e0e28/sanic_routing-22.3.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9e/73b582c4dbbc3c12ef4473822475effaabf1f934b56f14f5b03fe5d3a2af/aiohttp-3.14.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/59/1d/340d1a0db7bbce1f291afc044255ebf4ebbce2b25ab1b3f7d3d069080f5d/yarl-1.24.5-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/70/26ca3f06aace16f2352796b08704338d74b6d1a24ca38f2771afbb7ed915/frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httptools", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/f7/b4d41eaae2869d31356bc4bbf546f44fae83ff298af0a043ca0625b06773/httptools-0.8.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/42/0e7443c90310498561addf346e7d57fe3c6ba1914e1ba938b5464c7bbfd2/propcache-0.5.2-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "5.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8e/d2/92e83af35cd65d3b7c47fb0e24927aa2b478897af8b0dd0ee19abcd50c03/ujson-5.13.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "uvloop", "version": "0.22.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/14/ecceb239b65adaaf7fde510aa8bd534075695d1e5f8dadfa32b5723d9cfb/uvloop-0.22.1-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}], "install_targets_hash": "5d067be4256a3d8225e2000b2e369c37"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/81/8e983840c6e5b93b33c2ba81aa3d52c2e42f0e9a690ce7607a2e61da4a5c/charset_normalizer-3.4.9-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}], "install_targets_hash": "623a652072a7d5d73d07fc99e6bd44fb"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/81/8e983840c6e5b93b33c2ba81aa3d52c2e42f0e9a690ce7607a2e61da4a5c/charset_normalizer-3.4.9-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}], "install_targets_hash": "623a652072a7d5d73d07fc99e6bd44fb"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/81/8e983840c6e5b93b33c2ba81aa3d52c2e42f0e9a690ce7607a2e61da4a5c/charset_normalizer-3.4.9-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}], "install_targets_hash": "623a652072a7d5d73d07fc99e6bd44fb"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/81/8e983840c6e5b93b33c2ba81aa3d52c2e42f0e9a690ce7607a2e61da4a5c/charset_normalizer-3.4.9-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}], "install_targets_hash": "623a652072a7d5d73d07fc99e6bd44fb"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "litellm", "version": "1.89.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/1a/f087e0555d91ab5f93fb8c740447423aa785468b8edca9987724815b51ec/litellm-1.89.7-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9e/73b582c4dbbc3c12ef4473822475effaabf1f934b56f14f5b03fe5d3a2af/aiohttp-3.14.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "fastuuid", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/c5/84c1eea05977c8ba5173555b0133e3558dc628bcf868d6bf1689ff14aedc/fastuuid-0.14.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7d/f9/97f2ca8bb3ec6e4b1d64f983ebe98b9a192faddff67fac3d6303a537e670/importlib_metadata-8.9.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/31/5c/08c7f7fe311f32e83f7621cd3f99d805f45519cd06fafb247628b861da7d/multidict-6.7.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "openai", "version": "2.54.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/a8/bb76c7356de8ad57f59d5ff993d434df0607f07f08bcc9c9a5c275e399c0/openai-2.54.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c6/3d/4d7f5667ea0e0548534ba880b84bb3d12924fd133aa83ad6c6c80fca3d76/jiter-0.16.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/c6/65f646c7ff09bd257f660434adb45c4dfcbbcebcc030562fecf6f5bf887d/pydantic_core-2.46.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/18/e2/d39ae33d3dc30a0c229ff0cb683df961ebb5e7b8691feb2d08b3ee6ac327/tiktoken-0.14.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tokenizers", "version": "0.23.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e2/6a/068ed9f6e444c9d7e9d55ce134181325700f3d7f30410721bdc8f848d727/tokenizers-0.23.1-cp310-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "huggingface_hub", "version": "1.28.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/0e/eafef18f1a75e125e68395db21131db0cf868a128ecd2fce69b4df6c584b/huggingface_hub-1.28.0-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/69/55b8dcf636142ae660fec1869fcac14c4da2e8412e14d6eee1523be77e9f/hf_xet-1.6.0-cp38-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/59/1d/340d1a0db7bbce1f291afc044255ebf4ebbce2b25ab1b3f7d3d069080f5d/yarl-1.24.5-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anthropic", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/5b/db4a854aebf5d33a5ab714c46af6eb85ee44f390ed29b7b325c00b9f11ed/anthropic-1.0.0-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/95/411ba65569158e862368917aaf56597f3e5fa3b91b0502919638465a08f3/httpx2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/74/d370e55600d9bcfa0d9794b0166126d49291a3d2b20c268fc98c453a4948/httpcore2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "google-genai", "version": "2.19.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/e8/de0accd8cd004cf11252ca53fc5c3dda59bcf1856abfc7609842ceba7363/google_genai-2.19.0-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.56.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/b3/6117b2f24065cd7e2c4f140e9a193e215f089ca8ba314cf91eb9d0b7fe0a/google_auth-2.56.3-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/aa/554e2614f38fc34c58ff1d0911ae8535ad2516440d5482d76fe59f1088b0/charset_normalizer-3.5.1-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/90/72/2f14b2e167170b8bf1c8bb7f9b0d78000f470d41a2085a91f33e3917b6c9/websockets-16.1.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/37/73d005be173aff344af30e9fd2a576575cb2391a7101d9cd3842e1fa8cce/cryptography-50.0.0-cp39-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/1a/4b2f7c92293ba05cbd4a9a1b28faaf0326272d9488e6354657571c48a7aa/cffi-2.1.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "filelock", "version": "3.32.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/a4/9b63d595d748e3aff8812b65eacc1a2c4bd90b7c2012e08e72373b4835eb/filelock-3.32.4-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/70/26ca3f06aace16f2352796b08704338d74b6d1a24ca38f2771afbb7ed915/frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/3c/6a2bf344106328fd04963664a60b9bb6496fc25df8e962fcdc1367285fb9/fsspec-2026.7.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/42/0e7443c90310498561addf346e7d57fe3c6ba1914e1ba938b5464c7bbfd2/propcache-0.5.2-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/3b/6163796d69c3977d1e4287bea4a6979161cbbdd170ebb430511e8e1999ce/pyasn1-0.6.4-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "0.30.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/6a/4ba3d0fb7297ebae71171822554abe48d7cab29c28b8f9f2c04b79988c05/rpds_py-0.30.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "zipp", "version": "4.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.7.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/16/01/cefe4f051302ca298d3f3e79ed6dbd933ac84485b9515acdd6a52d70cef7/regex-2026.7.19-cp310-cp310-macosx_11_0_arm64.whl"}}], "install_targets_hash": "6ecbfdc651853ff775d0f1f4b1d21bec"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "litellm", "version": "1.89.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/1a/f087e0555d91ab5f93fb8c740447423aa785468b8edca9987724815b51ec/litellm-1.89.7-py3-none-any.whl"}}, {"metadata": {"name": "anthropic", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/5b/db4a854aebf5d33a5ab714c46af6eb85ee44f390ed29b7b325c00b9f11ed/anthropic-1.0.0-py3-none-any.whl"}}, {"metadata": {"name": "google-genai", "version": "2.19.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/e8/de0accd8cd004cf11252ca53fc5c3dda59bcf1856abfc7609842ceba7363/google_genai-2.19.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9e/73b582c4dbbc3c12ef4473822475effaabf1f934b56f14f5b03fe5d3a2af/aiohttp-3.14.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "fastuuid", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/c5/84c1eea05977c8ba5173555b0133e3558dc628bcf868d6bf1689ff14aedc/fastuuid-0.14.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "google-auth", "version": "2.56.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/b3/6117b2f24065cd7e2c4f140e9a193e215f089ca8ba314cf91eb9d0b7fe0a/google_auth-2.56.3-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/95/411ba65569158e862368917aaf56597f3e5fa3b91b0502919638465a08f3/httpx2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/74/d370e55600d9bcfa0d9794b0166126d49291a3d2b20c268fc98c453a4948/httpcore2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7d/f9/97f2ca8bb3ec6e4b1d64f983ebe98b9a192faddff67fac3d6303a537e670/importlib_metadata-8.9.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c6/3d/4d7f5667ea0e0548534ba880b84bb3d12924fd133aa83ad6c6c80fca3d76/jiter-0.16.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "2.54.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/a8/bb76c7356de8ad57f59d5ff993d434df0607f07f08bcc9c9a5c275e399c0/openai-2.54.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/c6/65f646c7ff09bd257f660434adb45c4dfcbbcebcc030562fecf6f5bf887d/pydantic_core-2.46.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/18/e2/d39ae33d3dc30a0c229ff0cb683df961ebb5e7b8691feb2d08b3ee6ac327/tiktoken-0.14.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tokenizers", "version": "0.23.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e2/6a/068ed9f6e444c9d7e9d55ce134181325700f3d7f30410721bdc8f848d727/tokenizers-0.23.1-cp310-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/90/72/2f14b2e167170b8bf1c8bb7f9b0d78000f470d41a2085a91f33e3917b6c9/websockets-16.1.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/aa/554e2614f38fc34c58ff1d0911ae8535ad2516440d5482d76fe59f1088b0/charset_normalizer-3.5.1-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/37/73d005be173aff344af30e9fd2a576575cb2391a7101d9cd3842e1fa8cce/cryptography-50.0.0-cp39-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/70/26ca3f06aace16f2352796b08704338d74b6d1a24ca38f2771afbb7ed915/frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "huggingface_hub", "version": "1.28.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/0e/eafef18f1a75e125e68395db21131db0cf868a128ecd2fce69b4df6c584b/huggingface_hub-1.28.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/31/5c/08c7f7fe311f32e83f7621cd3f99d805f45519cd06fafb247628b861da7d/multidict-6.7.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/42/0e7443c90310498561addf346e7d57fe3c6ba1914e1ba938b5464c7bbfd2/propcache-0.5.2-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "0.30.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/6a/4ba3d0fb7297ebae71171822554abe48d7cab29c28b8f9f2c04b79988c05/rpds_py-0.30.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/59/1d/340d1a0db7bbce1f291afc044255ebf4ebbce2b25ab1b3f7d3d069080f5d/yarl-1.24.5-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "zipp", "version": "4.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.7.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/16/01/cefe4f051302ca298d3f3e79ed6dbd933ac84485b9515acdd6a52d70cef7/regex-2026.7.19-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/1a/4b2f7c92293ba05cbd4a9a1b28faaf0326272d9488e6354657571c48a7aa/cffi-2.1.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "filelock", "version": "3.32.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/a4/9b63d595d748e3aff8812b65eacc1a2c4bd90b7c2012e08e72373b4835eb/filelock-3.32.4-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/3c/6a2bf344106328fd04963664a60b9bb6496fc25df8e962fcdc1367285fb9/fsspec-2026.7.0-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/69/55b8dcf636142ae660fec1869fcac14c4da2e8412e14d6eee1523be77e9f/hf_xet-1.6.0-cp38-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/3b/6163796d69c3977d1e4287bea4a6979161cbbdd170ebb430511e8e1999ce/pyasn1-0.6.4-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "6ecbfdc651853ff775d0f1f4b1d21bec"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "litellm", "version": "1.89.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/1a/f087e0555d91ab5f93fb8c740447423aa785468b8edca9987724815b51ec/litellm-1.89.7-py3-none-any.whl"}}, {"metadata": {"name": "anthropic", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/5b/db4a854aebf5d33a5ab714c46af6eb85ee44f390ed29b7b325c00b9f11ed/anthropic-1.0.0-py3-none-any.whl"}}, {"metadata": {"name": "google-genai", "version": "2.19.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/e8/de0accd8cd004cf11252ca53fc5c3dda59bcf1856abfc7609842ceba7363/google_genai-2.19.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9e/73b582c4dbbc3c12ef4473822475effaabf1f934b56f14f5b03fe5d3a2af/aiohttp-3.14.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "fastuuid", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/c5/84c1eea05977c8ba5173555b0133e3558dc628bcf868d6bf1689ff14aedc/fastuuid-0.14.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "google-auth", "version": "2.56.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/b3/6117b2f24065cd7e2c4f140e9a193e215f089ca8ba314cf91eb9d0b7fe0a/google_auth-2.56.3-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/95/411ba65569158e862368917aaf56597f3e5fa3b91b0502919638465a08f3/httpx2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/74/d370e55600d9bcfa0d9794b0166126d49291a3d2b20c268fc98c453a4948/httpcore2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7d/f9/97f2ca8bb3ec6e4b1d64f983ebe98b9a192faddff67fac3d6303a537e670/importlib_metadata-8.9.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c6/3d/4d7f5667ea0e0548534ba880b84bb3d12924fd133aa83ad6c6c80fca3d76/jiter-0.16.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "2.54.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/a8/bb76c7356de8ad57f59d5ff993d434df0607f07f08bcc9c9a5c275e399c0/openai-2.54.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/c6/65f646c7ff09bd257f660434adb45c4dfcbbcebcc030562fecf6f5bf887d/pydantic_core-2.46.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/18/e2/d39ae33d3dc30a0c229ff0cb683df961ebb5e7b8691feb2d08b3ee6ac327/tiktoken-0.14.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tokenizers", "version": "0.23.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e2/6a/068ed9f6e444c9d7e9d55ce134181325700f3d7f30410721bdc8f848d727/tokenizers-0.23.1-cp310-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/90/72/2f14b2e167170b8bf1c8bb7f9b0d78000f470d41a2085a91f33e3917b6c9/websockets-16.1.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/aa/554e2614f38fc34c58ff1d0911ae8535ad2516440d5482d76fe59f1088b0/charset_normalizer-3.5.1-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/37/73d005be173aff344af30e9fd2a576575cb2391a7101d9cd3842e1fa8cce/cryptography-50.0.0-cp39-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/70/26ca3f06aace16f2352796b08704338d74b6d1a24ca38f2771afbb7ed915/frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "huggingface_hub", "version": "1.28.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/0e/eafef18f1a75e125e68395db21131db0cf868a128ecd2fce69b4df6c584b/huggingface_hub-1.28.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/31/5c/08c7f7fe311f32e83f7621cd3f99d805f45519cd06fafb247628b861da7d/multidict-6.7.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/42/0e7443c90310498561addf346e7d57fe3c6ba1914e1ba938b5464c7bbfd2/propcache-0.5.2-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "0.30.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/6a/4ba3d0fb7297ebae71171822554abe48d7cab29c28b8f9f2c04b79988c05/rpds_py-0.30.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/59/1d/340d1a0db7bbce1f291afc044255ebf4ebbce2b25ab1b3f7d3d069080f5d/yarl-1.24.5-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "zipp", "version": "4.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.7.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/16/01/cefe4f051302ca298d3f3e79ed6dbd933ac84485b9515acdd6a52d70cef7/regex-2026.7.19-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/1a/4b2f7c92293ba05cbd4a9a1b28faaf0326272d9488e6354657571c48a7aa/cffi-2.1.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "filelock", "version": "3.32.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/a4/9b63d595d748e3aff8812b65eacc1a2c4bd90b7c2012e08e72373b4835eb/filelock-3.32.4-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/3c/6a2bf344106328fd04963664a60b9bb6496fc25df8e962fcdc1367285fb9/fsspec-2026.7.0-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/69/55b8dcf636142ae660fec1869fcac14c4da2e8412e14d6eee1523be77e9f/hf_xet-1.6.0-cp38-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/3b/6163796d69c3977d1e4287bea4a6979161cbbdd170ebb430511e8e1999ce/pyasn1-0.6.4-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "6ecbfdc651853ff775d0f1f4b1d21bec"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "litellm", "version": "1.89.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/1a/f087e0555d91ab5f93fb8c740447423aa785468b8edca9987724815b51ec/litellm-1.89.7-py3-none-any.whl"}}, {"metadata": {"name": "anthropic", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/5b/db4a854aebf5d33a5ab714c46af6eb85ee44f390ed29b7b325c00b9f11ed/anthropic-1.0.0-py3-none-any.whl"}}, {"metadata": {"name": "google-genai", "version": "2.19.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/e8/de0accd8cd004cf11252ca53fc5c3dda59bcf1856abfc7609842ceba7363/google_genai-2.19.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9e/73b582c4dbbc3c12ef4473822475effaabf1f934b56f14f5b03fe5d3a2af/aiohttp-3.14.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "fastuuid", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/c5/84c1eea05977c8ba5173555b0133e3558dc628bcf868d6bf1689ff14aedc/fastuuid-0.14.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "google-auth", "version": "2.56.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/b3/6117b2f24065cd7e2c4f140e9a193e215f089ca8ba314cf91eb9d0b7fe0a/google_auth-2.56.3-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/95/411ba65569158e862368917aaf56597f3e5fa3b91b0502919638465a08f3/httpx2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/74/d370e55600d9bcfa0d9794b0166126d49291a3d2b20c268fc98c453a4948/httpcore2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7d/f9/97f2ca8bb3ec6e4b1d64f983ebe98b9a192faddff67fac3d6303a537e670/importlib_metadata-8.9.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c6/3d/4d7f5667ea0e0548534ba880b84bb3d12924fd133aa83ad6c6c80fca3d76/jiter-0.16.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "2.54.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/a8/bb76c7356de8ad57f59d5ff993d434df0607f07f08bcc9c9a5c275e399c0/openai-2.54.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/c6/65f646c7ff09bd257f660434adb45c4dfcbbcebcc030562fecf6f5bf887d/pydantic_core-2.46.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/18/e2/d39ae33d3dc30a0c229ff0cb683df961ebb5e7b8691feb2d08b3ee6ac327/tiktoken-0.14.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tokenizers", "version": "0.23.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e2/6a/068ed9f6e444c9d7e9d55ce134181325700f3d7f30410721bdc8f848d727/tokenizers-0.23.1-cp310-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/90/72/2f14b2e167170b8bf1c8bb7f9b0d78000f470d41a2085a91f33e3917b6c9/websockets-16.1.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/aa/554e2614f38fc34c58ff1d0911ae8535ad2516440d5482d76fe59f1088b0/charset_normalizer-3.5.1-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/37/73d005be173aff344af30e9fd2a576575cb2391a7101d9cd3842e1fa8cce/cryptography-50.0.0-cp39-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/70/26ca3f06aace16f2352796b08704338d74b6d1a24ca38f2771afbb7ed915/frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "huggingface_hub", "version": "1.28.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/0e/eafef18f1a75e125e68395db21131db0cf868a128ecd2fce69b4df6c584b/huggingface_hub-1.28.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/31/5c/08c7f7fe311f32e83f7621cd3f99d805f45519cd06fafb247628b861da7d/multidict-6.7.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/42/0e7443c90310498561addf346e7d57fe3c6ba1914e1ba938b5464c7bbfd2/propcache-0.5.2-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "0.30.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/6a/4ba3d0fb7297ebae71171822554abe48d7cab29c28b8f9f2c04b79988c05/rpds_py-0.30.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/59/1d/340d1a0db7bbce1f291afc044255ebf4ebbce2b25ab1b3f7d3d069080f5d/yarl-1.24.5-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "zipp", "version": "4.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.7.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/16/01/cefe4f051302ca298d3f3e79ed6dbd933ac84485b9515acdd6a52d70cef7/regex-2026.7.19-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/1a/4b2f7c92293ba05cbd4a9a1b28faaf0326272d9488e6354657571c48a7aa/cffi-2.1.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "filelock", "version": "3.32.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/a4/9b63d595d748e3aff8812b65eacc1a2c4bd90b7c2012e08e72373b4835eb/filelock-3.32.4-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/3c/6a2bf344106328fd04963664a60b9bb6496fc25df8e962fcdc1367285fb9/fsspec-2026.7.0-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/69/55b8dcf636142ae660fec1869fcac14c4da2e8412e14d6eee1523be77e9f/hf_xet-1.6.0-cp38-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/3b/6163796d69c3977d1e4287bea4a6979161cbbdd170ebb430511e8e1999ce/pyasn1-0.6.4-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "6ecbfdc651853ff775d0f1f4b1d21bec"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "pydantic-ai", "version": "1.107.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/64/72ff998a79459c41f0e40f079a06ad45934fb2c095f604b9d44b983620b8/pydantic_ai-1.107.6-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-ai-slim", "version": "1.107.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/41/140a5e2d339e20d50e7685ffdc463977ae708f139a035fc658eced234afb/pydantic_ai_slim-1.107.6-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-evals", "version": "1.107.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/21/bc/299d19d27e237c407a77edb3f72d81a1cac0dd09964ea8cc9beac4e61f96/pydantic_evals-1.107.6-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-graph", "version": "1.107.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/2f/4f94314f952d242de53e6ae0f250d249609710ce500209f0acf46a7133a8/pydantic_graph-1.107.6-py3-none-any.whl"}}, {"metadata": {"name": "anthropic", "version": "0.125.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2f/1a/b1bd30cda3790557e8791bec5922a6ec8fabb6fa8b008c76a39cf7be6152/anthropic-0.125.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "fastmcp", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ac/14/6d950459cc831fa17fe2d1797926b6eb2d2f2af50f830e62d0c098cc1ec8/fastmcp-3.4.7-py3-none-any.whl"}}, {"metadata": {"name": "fastmcp-slim", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b4/97/e0e53642cd029a9a7635ae9c548f9f2cc995af5914e487b3df795664e4be/fastmcp_slim-3.4.7-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/9a/a24b26dc8a65f0ecc0fe5be981a19e61e7ca963b85e062c083f3a9100529/hf_xet-1.4.3-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "huggingface_hub", "version": "1.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/03/40a05316cb6616e5b7efd7773656441ab04b4b022c2199e79bb4622a92a3/huggingface_hub-1.18.0-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/2c/af9ca503b38683a82b6732352a861515f28e2d46fe445aea57e07fc86e06/jiter-0.17.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "mcp", "version": "1.30.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f5/f4/e58bc33317c92a0203664daaf00bf6f41166cc0149e5d6870a03f7cd004a/mcp-1.30.0-py3-none-any.whl"}}, {"metadata": {"name": "py-key-value-aio", "version": "0.4.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/46/12871550fb0613d149144bb9d41f22680d5f46717bc45a76eb5798c20c3f/py_key_value_aio-0.4.6-py3-none-any.whl"}}, {"metadata": {"name": "aiofile", "version": "3.8.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/76/ea/b6aae3275bb0991c43fff401e7b8db198047b6f692e8954520ec7aed3652/aiofile-3.8.8-py3-none-any.whl"}}, {"metadata": {"name": "caio", "version": "0.9.25"}, "download_info": {"url": "https://files.pythonhosted.org/packages/88/95/dd55757bb671eb4c376e006c04e83beb413486821f517792ea603ef216e9/caio-0.9.25-cp310-cp310-manylinux_2_34_x86_64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/34/a1/c8e6b66f499f510752c07a092dfe27621f9c255635e59d38704b5681c35a/pydantic_core-2.46.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7a/1e/7acc4f0e74c4b3d9531e24739e0ab832a5edf40e64fbae1a9c01941cabd7/pyyaml-6.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typer", "version": "0.25.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/f9/2b3ff4e56e5fa7debfaf9eb135d0da96f3e9a1d5b27222223c7296336e5f/typer-0.25.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "ag-ui-protocol", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/b0/850be4576e6443dc575daa54188d8136ae2b2eca3f19e098e7a088fc9ebc/ag_ui_protocol-1.0.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "argcomplete", "version": "3.7.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/46/bd/551ee6af426af84ca33e02622be722925c196608e9127d731ef17c47f06e/argcomplete-3.7.2-py3-none-any.whl"}}, {"metadata": {"name": "Authlib", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b8/c6/6f124bcfbbfb20fba22c939b4e43a06dccfc0e1ca20e5634ca573cb1e271/authlib-1.8.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "beartype", "version": "0.22.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/cc/18245721fa7747065ab478316c7fea7c74777d07f37ae60db2e84f8172e8/beartype-0.22.9-py3-none-any.whl"}}, {"metadata": {"name": "boto3", "version": "1.43.98"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/46/d29efd46ecac6637065a39418c5fb95500d70ec63e76065b5a72c936172f/boto3-1.43.98-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.98"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/ca/c7617e99c3247f545233ab2181840d142c5f72034e22864172866fb1369a/botocore-1.43.98-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "s3transfer", "version": "0.19.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/e7/5c595c75e9f41a44f30e526eda465ea0b4eec93470e074e4a111b253f13a/s3transfer-0.19.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "cachetools", "version": "7.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cc/bb/1c6e7a89b11da19f137e4ef5a5c5fe47a5bb686449ba343944ccf8fb34b2/cachetools-7.2.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "cohere", "version": "7.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4a/c3/064a44c498bf6ae8621caa14307d3ef5471157f149e33cfd64417c8e9ad3/cohere-7.1.1-py3-none-any.whl"}}, {"metadata": {"name": "fastavro", "version": "1.12.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ee/e4/26512b52f58305b9d2194169de2e82c16d5131f0a0b6359e50d34faf4021/fastavro-1.12.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/cd/4f564b8f132de25db594efc706897069f016790cea63a5669c9df2675f64/charset_normalizer-3.5.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "tokenizers", "version": "0.23.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/ca/ca6b93c7820df123b2662a9469e8facc826ccc94e98fdd0d615f6431e73a/tokenizers-0.23.2-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "types-requests", "version": "2.33.0.20260906"}, "download_info": {"url": "https://files.pythonhosted.org/packages/60/4c/51ec821d22a45b4162fa3f3e9e94ea4c0f8c49e82363b10955baa5438391/types_requests-2.33.0.20260906-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8c/eb/5d7124083e8d8cda8f5b348f544b71ad6f707ad63193758ef4d8e569da02/cryptography-50.0.1-cp39-abi3-manylinux_2_34_x86_64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/75/77/60bebf6f818bec84210ac5b6979ce4eeadce6fbbaabc9c7ab23e506d1ce5/cffi-2.1.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "cyclopts", "version": "4.25.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/cc/e879da3d54cf727f90e6d90118e132672c3913338b566740486f8797190d/cyclopts-4.25.3-py3-none-any.whl"}}, {"metadata": {"name": "rich-rst", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/68/1fc93dd759605b5d00fc98b50200739e41ed32bd22d6ba35ca6c3932371b/rich_rst-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "filelock", "version": "4.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/29/33/af0635ab07fe83b1788a1dbe370ff3e226062495a998335cb18a1cac81aa/filelock-4.0.1-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6c/c0/a98505f18594f1bce828bb159cec0fcf9860562f1a2c85913409fc8f3d9e/fsspec-2026.9.0-py3-none-any.whl"}}, {"metadata": {"name": "genai-prices", "version": "0.1.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d5/4a/9e04f3dca5ffe74133779ab5e9925ffb6411afbeac55d26fa0e148722599/genai_prices-0.1.7-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.58.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/59/13/477d90d09591b3938b45c4e11f4d8a51291682112cb5efcac961e815d562/google_auth-2.58.0-py3-none-any.whl"}}, {"metadata": {"name": "google-genai", "version": "2.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/84/5b/87913fe392ba7b6402577259289ed3740c577956554a674b191a2971d33e/google_genai-2.24.0-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f3/18/a17e2f0cde02dc10154c808deed7e1d8528afff93612f70d3f0a5b19b011/websockets-16.1.1-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl"}}, {"metadata": {"name": "griffelib", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/63/e876e789525063c840ccfa8857febdabd6523bcef9ce7eb979b9305ea895/griffelib-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "groq", "version": "1.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/f6/c3d8ea3194d7d7d8292edd4dbb4b6832d29c2eab04887dda4a742e83902c/groq-1.7.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "joserfc", "version": "1.7.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/c5/82addfd375e5ee6520644e0553e4aadde92d668c4fc99cc716d337fe7bb3/joserfc-1.7.5-py3-none-any.whl"}}, {"metadata": {"name": "jsonref", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/ec/e1db9922bceb168197a558a2b8c03a7963f1afe93517ddd3cf99f202f996/jsonref-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-path", "version": "0.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/2c/9e69d73c4297508be9e3b64a970ea3971b3eb8db64ffc5802d40bd25981f/jsonschema_path-0.5.0-py3-none-any.whl"}}, {"metadata": {"name": "pathable", "version": "0.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a2/e8/6d75ffd9784bce2e93d1ae4415649427e39a53bb172d4672b2b59c6f0a7b/pathable-0.6.0-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "keyring", "version": "25.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/db/e655086b7f3a705df045bf0933bdd9c2f79bb3c97bfef1384598bb79a217/keyring-25.7.0-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "9.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/55/ecca97ae19075f1fac62def77731e7f535e6c1fb8f92ff08160c5e6dade8/importlib_metadata-9.0.1-py3-none-any.whl"}}, {"metadata": {"name": "jeepney", "version": "0.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b2/a3/e137168c9c44d18eff0376253da9f1e9234d0239e0ee230d2fee6cea8e55/jeepney-0.9.0-py3-none-any.whl"}}, {"metadata": {"name": "logfire", "version": "5.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cd/02/b32c3d5c298e4a9010694d261fb82c2c672747c0bf2b47bffda484aef349/logfire-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-exporter-otlp-proto-http", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cd/d0/fdeb1a98d8d3a6205f5f297c51b4a9bfe65126ab60339669bbe3dd54c2e2/opentelemetry_exporter_otlp_proto_http-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-exporter-otlp-proto-common", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5e/71/65fd9d54c10b860f87c045ccee1264cab7011268895d3528818a29c1172a/opentelemetry_exporter_otlp_proto_common-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-proto", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d1/7c/8be563d68e93bbefa5c8affb82ddcff91b3ad858ce49957ba7b16fd3e0ab/opentelemetry_proto-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "googleapis-common-protos", "version": "1.75.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1a/7a/7d79170c6ce6f12e109df2b3879d6b934010cf4f99aea8de8b7e5408c174/googleapis_common_protos-1.75.3-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/6f/a04e900f465ff3221ccc395522503e2d10e79fa21f2723c8e177aae1e0d1/opentelemetry_api-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-sdk", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e7/23/ff077e61886ee020a17ce9c8b6fa11c601c8d8345b09ea24f605445df62a/opentelemetry_sdk-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-semantic-conventions", "version": "0.65b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/0e/49df70d9b81fb5cbae4bbf2a49d865b09bcbcbc4eb53f5851b1027738d78/opentelemetry_semantic_conventions-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "executing", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "logfire-api", "version": "5.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2d/51/123dab197fb08c0892e3bea1c2266bff159aa2ee82ad43bef93505859705/logfire_api-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "mistralai", "version": "2.10.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/98/f64b54166a607ece4e5c8494c843ac1f9c7c0af6f1014272cc420fe1d519/mistralai-2.10.1-py3-none-any.whl"}}, {"metadata": {"name": "eval_type_backport", "version": "0.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/a7/bb99bf5e6f78736ddb53480f2c3ff3702ffe2196a7c5e1661c03081d398e/eval_type_backport-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonpath-python", "version": "1.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/8a/1270a6803bd821cbfcdda387eaa13cb41a7b1f7b9bd145979b3bfb9d6cb7/jsonpath_python-1.1.6-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "3.16.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/17/72/2b1fe3e303db76ab2ba0c2de2b57822869bcb588db82334d4ff3aea8acf2/openai-3.16.2-py3-none-any.whl"}}, {"metadata": {"name": "openapi-pydantic", "version": "0.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/cf/03675d8bd8ecbf4445504d8071adab19f5f993676795708e36402ab38263/openapi_pydantic-0.5.1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-instrumentation", "version": "0.65b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/40/7b/85eab1215f72adf0e68d3dc4a679b9bff993fa679ff34cd8dd378e2659fd/opentelemetry_instrumentation-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "wrapt", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3c/e9/2c1a482052cfabd6906887096993099afa2db738e7597c30e4f2b9922718/wrapt-2.4.1-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl"}}, {"metadata": {"name": "opentelemetry-instrumentation-httpx", "version": "0.65b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/0f/c6144096b4914bbf44b43ba21c962e8f333ff045770b50a3e79ed8bd455f/opentelemetry_instrumentation_httpx-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-util-http", "version": "0.65b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/23/3f/ab8d29df207ce5f470a07fa96ebb48af4e95b7fab7e7635311b9a32f2fab/opentelemetry_util_http-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "platformdirs", "version": "4.11.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/39/be/3ae887e84c38c4dd1c549cd5825adc93f48069a94fe1cb8ac52a9da16f15/platformdirs-4.11.11-py3-none-any.whl"}}, {"metadata": {"name": "prompt_toolkit", "version": "3.0.53"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/6f/84908cad2d6aa5144abcf7b42709fe4fdb459bc640ec7ac5786e7693dabc/prompt_toolkit-3.0.53-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/3b/6163796d69c3977d1e4287bea4a6979161cbbdd170ebb430511e8e1999ce/pyasn1-0.6.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-handlebars", "version": "0.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/11/364bc401f1d8fdb3947079fc43ffdfbfc9132d065981a03a95d2e87440c4/pydantic_handlebars-0.2.1-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "email-validator", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "dnspython", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/97/672cb32ce0dfea44b740cb7b4f97038463b9cf7c0ead1aacf595572851d6/pyjwt-2.14.0-py3-none-any.whl"}}, {"metadata": {"name": "pyperclip", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/80/fc9d01d5ed37ba4c42ca2b55b4339ae6e200b456be3a1aaddf4a9fa99b8c/pyperclip-1.11.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "0.30.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/61/b5/707f6cf0066a6412aacc11d17920ea2e19e5b2f04081c64526eb35b5c6e7/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "SecretStorage", "version": "3.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/46/f5af3402b579fd5e11573ce652019a67074317e18c1935cc0b4ba9b35552/secretstorage-3.5.0-py3-none-any.whl"}}, {"metadata": {"name": "shellingham", "version": "1.5.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/6a/2ba3ed4a69babf3afdddf7d8314a48d87562c0a442206bbc2a1b50d5efc0/sse_starlette-3.4.11-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "temporalio", "version": "1.33.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7a/12/63e13f93b5772f5bd2128990bfeec050f7de9e80ce4d8504d99f7f794b10/temporalio-1.33.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "nexus-rpc", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/11/52/6327a5f4fda01207205038a106a99848a41c83e933cd23ea2cab3d2ebc6c/nexus_rpc-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "types-protobuf", "version": "7.35.1.20260906"}, "download_info": {"url": "https://files.pythonhosted.org/packages/44/4e/f63e826c68f77ef875506d72f225918800346545ee99847bc28f3394f18d/types_protobuf-7.35.1.20260906-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/af/c8/051e7b72a816ff50eb34a1c7c5b185cd2429ffdf59a497baea35b2b6b2dd/tiktoken-0.14.0-cp310-cp310-manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/03/921a3d3c75785aca9ebfbfcabfbc3a1be12e2ab5265deb026d55a5a3f83e/tqdm-4.70.1-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uncalled-for", "version": "0.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a2/40/97cec87c077eb3291fc7905e6633e08b7ca593c57d30238444bcb6bb3d53/uncalled_for-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.53.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/76/18/0eea75741ee812e9f598b687619ce2454f6c3a1c5cd21ea990ec6bd26f45/uvicorn-0.53.0-py3-none-any.whl"}}, {"metadata": {"name": "watchfiles", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/02/c8/79eee650c62d2c186598489814468e389b5def0ebe755399ff645b35b1b2/watchfiles-1.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/39/cc/9c0adc5861020de426ec71716b6c1bef8d90694b7d6d0a16202cdb1647f5/wcwidth-0.8.4-py3-none-any.whl"}}, {"metadata": {"name": "xai-sdk", "version": "1.19.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/b5/6f6783b97fb3a5498eb852ccaa706e1a2c0de2409480e3c99428e85234fe/xai_sdk-1.19.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/ff/cb36724e8c8d17f90ada567a9ff3efe1d6e9b549fba697a242aece180f21/aiohttp-3.14.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "grpcio", "version": "1.84.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/7c/da97476f3c2e90e9f00bfb19def7cbb5f841b7661e3cd09c6a89beaa5b98/grpcio-1.84.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "multidict", "version": "6.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ea/e4/4ea1ab36ab8ed969c945f1abdc350e5865043b7466789d917735213d2369/multidict-6.9.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "packaging", "version": "25.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl"}}, {"metadata": {"name": "protobuf", "version": "6.33.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/16/92/d1e32e3e0d894fe00b15ce28ad4944ab692713f2e7f0a99787405e43533a/protobuf-6.33.6-cp39-abi3-manylinux2014_x86_64.whl"}}, {"metadata": {"name": "yarl", "version": "1.25.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/28/b9/7818ac6dec7fbcd16be2d19495807c01e2c38834e57d41c63356a75e786b/yarl-1.25.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/ed/c7895fd2fde7f3ee70d248175f9b6cdf792fb741ab92dc59cd9ef3bd241b/frozenlist-1.8.0-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f0/51/5adee15e12a7e314cece4543fbf295b0fe1b504dc78b32dff4c8eb1e29b0/propcache-0.5.4-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "zipp", "version": "4.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.classes", "version": "3.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/66/b15ce62552d84bbfcec9a4873ab79d993a1dd4edb922cbfccae192bd5b5f/jaraco.classes-3.4.0-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.context", "version": "6.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f2/58/bc8954bda5fcda97bd7c19be11b85f91973d67a706ed4a3aec33e7de22db/jaraco_context-6.1.2-py3-none-any.whl"}}, {"metadata": {"name": "backports.tarfile", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/fa/123043af240e49752f1c4bd24da5053b6bd00cad78c2be53c0d1e8b975bc/backports.tarfile-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.functools", "version": "4.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/02/36/ecc85bc96c273dc8a11273ed4782272975e6338d4a3e9228621175edf0e3/jaraco_functools-4.6.0-py3-none-any.whl"}}, {"metadata": {"name": "more-itertools", "version": "11.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/3d/1087453384dbde46a8c7f9356eead2c58be8a7bf156bca40243377c85715/more_itertools-11.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.9.10"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/b2/be9fafe5e05888296fdd35d82ba9cbb67b0d352e9911fad3c458beb3a34a/regex-2026.9.10-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}], "install_targets_hash": "6f4f519d18d963ec7cd5445acdc50e5e"} -{"python_version": "3.10", "dependencies": [{"metadata": {"name": "boto3", "version": "1.43.98"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/46/d29efd46ecac6637065a39418c5fb95500d70ec63e76065b5a72c936172f/boto3-1.43.98-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.98"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/ca/c7617e99c3247f545233ab2181840d142c5f72034e22864172866fb1369a/botocore-1.43.98-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "s3transfer", "version": "0.19.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/e7/5c595c75e9f41a44f30e526eda465ea0b4eec93470e074e4a111b253f13a/s3transfer-0.19.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}], "install_targets_hash": "732c20a252602bec78b6c7ee26050916"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "openai", "version": "3.17.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/57/bc/5b80a0ca4069a6b5ba6c7d48ae7a4f8176b2c0bde0bebccdb867472ec6f6/openai-3.17.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.17.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ca/e9/5993079500530586655c6f2823e2926b3f5ceddd49918c5a86757eadba3a/jiter-0.17.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/bd/d0/c787604c71c2bdcda1a5656942fc822cd0f9cd879b9484bb84fc42172703/pydantic_core-2.46.5-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "6fe5caedd83b044975e2a5e20436ed3f"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "openai-agents", "version": "0.18.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/7c/08b9929a15131081898e38c5612d44ee293851d5c80f31ca1153efe82143/openai_agents-0.18.3-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "griffelib", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/63/e876e789525063c840ccfa8857febdabd6523bcef9ce7eb979b9305ea895/griffelib-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "mcp", "version": "1.30.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f5/f4/e58bc33317c92a0203664daaf00bf6f41166cc0149e5d6870a03f7cd004a/mcp-1.30.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "2.54.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/a8/bb76c7356de8ad57f59d5ff993d434df0607f07f08bcc9c9a5c275e399c0/openai-2.54.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/d0/c787604c71c2bdcda1a5656942fc822cd0f9cd879b9484bb84fc42172703/pydantic_core-2.46.5-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/90/72/2f14b2e167170b8bf1c8bb7f9b0d78000f470d41a2085a91f33e3917b6c9/websockets-16.1.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/aa/554e2614f38fc34c58ff1d0911ae8535ad2516440d5482d76fe59f1088b0/charset_normalizer-3.5.1-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/e9/5993079500530586655c6f2823e2926b3f5ceddd49918c5a86757eadba3a/jiter-0.17.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/97/672cb32ce0dfea44b740cb7b4f97038463b9cf7c0ead1aacf595572851d6/pyjwt-2.14.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/6a/2ba3ed4a69babf3afdddf7d8314a48d87562c0a442206bbc2a1b50d5efc0/sse_starlette-3.4.11-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/03/921a3d3c75785aca9ebfbfcabfbc3a1be12e2ab5265deb026d55a5a3f83e/tqdm-4.70.1-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.52.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/79/4a20b54ab0491485ccd8c077db2d39187c7f12b3e15485d38a7be37c81b4/uvicorn-0.52.4-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/84/a9/ee16a903f13755e914d1eecc482fe64d1f10761c3960e5d8fa6837377aff/cryptography-50.0.1-cp39-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "0.30.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/6a/4ba3d0fb7297ebae71171822554abe48d7cab29c28b8f9f2c04b79988c05/rpds_py-0.30.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/1a/4b2f7c92293ba05cbd4a9a1b28faaf0326272d9488e6354657571c48a7aa/cffi-2.1.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "72e451893bc86523078d768ca9965660"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "openai", "version": "2.54.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/a8/bb76c7356de8ad57f59d5ff993d434df0607f07f08bcc9c9a5c275e399c0/openai-2.54.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c6/3d/4d7f5667ea0e0548534ba880b84bb3d12924fd133aa83ad6c6c80fca3d76/jiter-0.16.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/c6/65f646c7ff09bd257f660434adb45c4dfcbbcebcc030562fecf6f5bf887d/pydantic_core-2.46.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "74376afb5a970b70b12c3903563ea5a0"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "openai", "version": "2.54.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/a8/bb76c7356de8ad57f59d5ff993d434df0607f07f08bcc9c9a5c275e399c0/openai-2.54.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c6/3d/4d7f5667ea0e0548534ba880b84bb3d12924fd133aa83ad6c6c80fca3d76/jiter-0.16.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/c6/65f646c7ff09bd257f660434adb45c4dfcbbcebcc030562fecf6f5bf887d/pydantic_core-2.46.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}], "install_targets_hash": "74376afb5a970b70b12c3903563ea5a0"} -{"python_version": "3.10", "dependencies": [{"metadata": {"name": "pydantic-ai", "version": "1.0.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/c3/0237cba693b26fd3d78acdb9c97b07c3cdd7c807c6fadbbba6abede4a7b7/pydantic_ai-1.0.18-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-ai-slim", "version": "1.0.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/18/45/0f6b98ce09d1cdf9403ef228c57d8251c6682713dc1c8870708c6a17378a/pydantic_ai_slim-1.0.18-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-evals", "version": "1.0.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4d/84/1008d2c9e66ab93d132a67f85770f2e58eb9e70d1b76ee2a88f6cefac90a/pydantic_evals-1.0.18-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-graph", "version": "1.0.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/68/8a/b6fa505b12fdd5bfcd846bb52087c30003c925e9820f91dd930a6500e5a9/pydantic_graph-1.0.18-py3-none-any.whl"}}, {"metadata": {"name": "temporalio", "version": "1.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/be/94/24bd903b5594420a4d131bfa3de965313f9a409af77b47e9a9a56d85bb9e/temporalio-1.18.0-cp39-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "nexus-rpc", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bf/2f/9e9d0dcaa4c6ffa22b7aa31069a8a264c753ff8027b36af602cce038c92f/nexus_rpc-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "protobuf", "version": "6.33.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5c/01/a3c3ed5cd186f39e7880f8303cc51385a198a81469d53d0fdecf1f64d929/protobuf-6.33.6-cp39-abi3-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "ag-ui-protocol", "version": "0.1.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4c/0a/bcad8116eb058e4b4a305e3fc37ebd7efc879deeb86b854f1c5b8b6e97dd/ag_ui_protocol-0.1.19-py3-none-any.whl"}}, {"metadata": {"name": "anthropic", "version": "0.116.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c7/dd/2a1e81cf1b163acc340afc4ec74ed1d86f5eed1a809fabdeed3e0997b346/anthropic-0.116.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c6/3d/4d7f5667ea0e0548534ba880b84bb3d12924fd133aa83ad6c6c80fca3d76/jiter-0.16.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/c6/65f646c7ff09bd257f660434adb45c4dfcbbcebcc030562fecf6f5bf887d/pydantic_core-2.46.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "argcomplete", "version": "3.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/f6/5b8ec087cd9cfa9449491ec83f76fb6b7006b4dff57d2ba8aaab330fe8e4/argcomplete-3.7.0-py3-none-any.whl"}}, {"metadata": {"name": "boto3", "version": "1.43.40"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/3b/2abcc7f47e955a8cb45a6378ec69cd8ed2dcb3d14ceb67717dea020a794a/boto3-1.43.40-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.40"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/8c/5f7e73fd66b28f0705bc55d7060d41ef72328b656b86ca53e75765b3ba2c/botocore-1.43.40-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "s3transfer", "version": "0.19.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/46/5f/4c174edad94f82de888ac00a5ddd8d07b35609b6c94f0bdf4d74af57703e/s3transfer-0.19.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "cohere", "version": "7.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e6/eb/64ca464baa34d0fa8144fc09ec7a35c8fcdeea1be878a518e901b0a6032b/cohere-7.0.5-py3-none-any.whl"}}, {"metadata": {"name": "fastavro", "version": "1.12.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3c/91/16c3508447e7cf9f413a6a01792a990ed94d17505fc80a7fb76027078aed/fastavro-1.12.2-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/26/08/0f303cb0b529e456bb116f2d50565a482694fbb94340bf56d44677e7ed03/charset_normalizer-3.4.7-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "tokenizers", "version": "0.23.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e2/6a/068ed9f6e444c9d7e9d55ce134181325700f3d7f30410721bdc8f848d727/tokenizers-0.23.1-cp310-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "huggingface_hub", "version": "1.22.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/9c/a1a377265abd8b823a2c661c665028ccb6b9fba1ca9d08e52ff679c20ecd/huggingface_hub-1.22.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/35/94/4b2ecfbad8f8b04701a23aefb62f540b9137d058b7e1dbef16a32676f0e9/hf_xet-1.5.1-cp37-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "types-requests", "version": "2.33.0.20260518"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1c/bc/b139710a3b6018f7fb2b9508b35c8af564e61bf2bf4fa619d088f3e16f85/types_requests-2.33.0.20260518-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "filelock", "version": "3.29.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4a/e3/f1fae3647d170919c2cf2a898e77e7d1a4e5c7cae0aed7bb4bd3f5ebff6f/filelock-3.29.5-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e5/22/4222d7ddf3da30f363edaa98e329c2bce6c65497c9cb2810931c8b2c0fbc/fsspec-2026.6.0-py3-none-any.whl"}}, {"metadata": {"name": "genai-prices", "version": "0.0.69"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/05/6bb176d603210b61d2bf4585c7119dcf5491bbcae195e21254668c5ee07a/genai_prices-0.0.69-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.55.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/1d/f6d3ca1ad0725f2e08a1c6915640748a52de2e66596160a4d53b010cccf0/google_auth-2.55.1-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/2a/5bb823f5bedcf80718cea7fbc95ec5515cca3769633c4b01a32be7f30e7c/cryptography-49.0.0-cp39-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/84/ad6a0b408daa859246f57c03efd28e5dd1b33c21737c2db84cae8c237aa5/cffi-2.0.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "google-genai", "version": "2.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/39/00bcfd94de255d24249401efff4f48d77bf6066b46447e519fa193c0c299/google_genai-2.10.0-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/40/904a4cb30d9b61c0e278899bf36342e9b0208eb3c470324a9ecbaac2a30f/websockets-16.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "griffe", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6b/fb/3c65d392feae6c36dc2b55a14dd8270b7b35a3171c93b71a4d2ee4abf241/griffe-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "griffecli", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/80/2f/513232ec1d5f5da182e4ce45a11427e37dd210844a9e2bca451fc9661fb3/griffecli-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "griffelib", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e4/d3/5268aeabf2ad82658c4e2ff3a060648d0f02f3926cb53247c0e4d0dab49e/griffelib-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "colorama", "version": "0.4.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl"}}, {"metadata": {"name": "groq", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ce/c3/cac2aee75198c0382a2e6070619a798de2288e01850abb6e999746bb92e3/groq-1.5.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/31/22/859d8252dad9bc9adee34b52e62cde621ece07b042ccb2ab4da1be46695f/httpx2-2.5.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c9/a1/7564199d1a8728fe737b0a72e5b3f8d92dfe085a74ddf7cdd83bce5f206d/httpcore2-2.5.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "logfire", "version": "4.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7a/08/1805d2f26955671115aae555d78cc4c72a6fe733f332d44d69756bc1737b/logfire-4.37.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-exporter-otlp-proto-http", "version": "1.42.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d3/96/82cb223a1502f0787d4bbff12907f5f8d870a50731febcd5818d93ef9555/opentelemetry_exporter_otlp_proto_http-1.42.1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-exporter-otlp-proto-common", "version": "1.42.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d6/43/2375e7612e1121a4518c17603b6e0b03ad94f565aafad53f464dc5be2bf6/opentelemetry_exporter_otlp_proto_common-1.42.1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-proto", "version": "1.42.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/9d/171c02c84a76940b7e601805b3bb536985aded9168fbcc9ba52f0a730fa2/opentelemetry_proto-1.42.1-py3-none-any.whl"}}, {"metadata": {"name": "googleapis-common-protos", "version": "1.75.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e7/c8/e2645aa8ed02fd4c7a2f59d68783b65b1f3cbdfe39a6308e156509d1fee8/googleapis_common_protos-1.75.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-sdk", "version": "1.42.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8f/6b/4287766cfbde577ae2272e8884abac325aeaac0d64f41c61d5b8cc595105/opentelemetry_sdk-1.42.1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.42.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/ca/9520cc1f3dfbbd03ac5903bbf55833e257bc64b1cf30fa8b0d6df374d821/opentelemetry_api-1.42.1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-semantic-conventions", "version": "0.63b1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/7a/7fe66f5f3682b1dd47d88cc4e11f1c6c0966b737de2d16671146e23c39a5/opentelemetry_semantic_conventions-0.63b1-py3-none-any.whl"}}, {"metadata": {"name": "executing", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "logfire-api", "version": "4.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/2f/23e5b8fa22f75f73965c72e5c29e6fb8715263457394601e254fe26fbe31/logfire_api-4.37.0-py3-none-any.whl"}}, {"metadata": {"name": "mcp", "version": "1.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e2/5e/d118fce19f87a2e7d8101c35c8ae0ec289098a4df0ff244cec23e415aca0/mcp-1.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "mistralai", "version": "1.12.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c9/f9/98d825105c450b9c67c27026caa374112b7e466c18331601d02ca278a01b/mistralai-1.12.4-py3-none-any.whl"}}, {"metadata": {"name": "invoke", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/4b/b99e37f88336009971405cbb7630610322ed6fbfa31e1d7ab3fbf3049a2d/invoke-2.2.1-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "eval_type_backport", "version": "0.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/a7/bb99bf5e6f78736ddb53480f2c3ff3702ffe2196a7c5e1661c03081d398e/eval_type_backport-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "2.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ae/f4/561ed79fd94876160018a5e75254cfcb9b0e62d4dded9dcb20072e86d623/openai-2.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-instrumentation", "version": "0.63b1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/35/a1/9314e621c143e4d82a5bf7a43c2ff7a745d31023506336857607c8c543cc/opentelemetry_instrumentation-0.63b1-py3-none-any.whl"}}, {"metadata": {"name": "wrapt", "version": "2.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/dc/66c61aca927230c9cf97a3cb005c803971a1076ff9f7d61085d035c20085/wrapt-2.2.2-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "opentelemetry-instrumentation-httpx", "version": "0.63b1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/b8/f536780996195c3b9f2354998554671e05a7a262df8c043f63fe9e5a6f0b/opentelemetry_instrumentation_httpx-0.63b1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-util-http", "version": "0.63b1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e5/f1/34e047e8f6a3c67e5220acf1af7b9f62868c25d77791bca74457bd2180a6/opentelemetry_util_http-0.63b1-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "prompt_toolkit", "version": "3.0.52"}, "download_info": {"url": "https://files.pythonhosted.org/packages/84/03/0d3ce49e2505ae70cf43bc5bb3033955d2fc9f932163e84dc0779cc47f48/prompt_toolkit-3.0.52-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/a0/7d793dce3fa811fe047d6ae2431c672364b462850c6235ae306c0efd025f/pyasn1-0.6.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/77/c1/6e422f34e569cf8e18df68d1939c81c099d2b61e4f7d9621c8a77560799c/pydantic_settings-2.14.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "pyperclip", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/80/fc9d01d5ed37ba4c42ca2b55b4339ae6e200b456be3a1aaddf4a9fa99b8c/pyperclip-1.11.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "0.30.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/6a/4ba3d0fb7297ebae71171822554abe48d7cab29c28b8f9f2c04b79988c05/rpds_py-0.30.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/75/c88d3f5dafd59c791da1ce27650d30bf5b70cbf1cbf01cd00e5f9e360915/sse_starlette-3.4.5-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.68.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d8/8e/bb97bb0c71802080bfc8952937d174e49cfc50de5c951dd47b2496f0dcdb/tqdm-4.68.3-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "types-protobuf", "version": "7.34.1.20260518"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/1f/ec5caf72c2e3b688ca3927e0979a04ddad19e1afc4bf1c199bd743e0f419/types_protobuf-7.34.1.20260518-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.50.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f2/59/02c7859295b001e77b8079fc9df9f8161b7c872cbf7ea8dab70cf51d61f1/uvicorn-0.50.1-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl"}}], "install_targets_hash": "76bc8d4da920add2d6433f5bd69d9ec8"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "sanic", "version": "23.12.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/e6/5adc2ca570f165d6027a775a655c1c09b9b8432a6c4a6fcb4c43a08eac7e/sanic-23.12.2-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/7a/bd0ce7ac1cfafc76c84d6e8051bcbd0f7def8e45207230833bd6ff77a41d/websockets-10.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/31/5c/08c7f7fe311f32e83f7621cd3f99d805f45519cd06fafb247628b861da7d/multidict-6.7.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9e/73b582c4dbbc3c12ef4473822475effaabf1f934b56f14f5b03fe5d3a2af/aiohttp-3.14.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/59/1d/340d1a0db7bbce1f291afc044255ebf4ebbce2b25ab1b3f7d3d069080f5d/yarl-1.24.5-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-testing", "version": "24.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/93/1d588f1cb9b710b9f22fa78b53d699a8062edc94204d50dd0d78c5f5b495/sanic_testing-24.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/70/26ca3f06aace16f2352796b08704338d74b6d1a24ca38f2771afbb7ed915/frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "html5tagger", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/d7/410f7b8109958405f6fb3d104f094e2a96f9d5b2670de73a68fb1fbc391f/html5tagger-2.0.0-py3-none-any.whl"}}, {"metadata": {"name": "httptools", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/f7/b4d41eaae2869d31356bc4bbf546f44fae83ff298af0a043ca0625b06773/httptools-0.8.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/42/0e7443c90310498561addf346e7d57fe3c6ba1914e1ba938b5464c7bbfd2/propcache-0.5.2-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-routing", "version": "23.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/e3/3425c9a8773807ac2c01d6a56c8521733f09b627e5827e733c5cd36b9ac5/sanic_routing-23.12.0-py3-none-any.whl"}}, {"metadata": {"name": "tracerite", "version": "2.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fc/ae/74457a0bfe83b45a951f5a4900cb4e5bb7cf201edc029fb5b2a2df9e4028/tracerite-2.6.3-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "5.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8e/d2/92e83af35cd65d3b7c47fb0e24927aa2b478897af8b0dd0ee19abcd50c03/ujson-5.13.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "uvloop", "version": "0.22.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/14/ecceb239b65adaaf7fde510aa8bd534075695d1e5f8dadfa32b5723d9cfb/uvloop-0.22.1-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}], "install_targets_hash": "76dabba8d81006345a2675957fd9dcbf"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "sanic", "version": "23.12.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/e6/5adc2ca570f165d6027a775a655c1c09b9b8432a6c4a6fcb4c43a08eac7e/sanic-23.12.2-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/7a/bd0ce7ac1cfafc76c84d6e8051bcbd0f7def8e45207230833bd6ff77a41d/websockets-10.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/31/5c/08c7f7fe311f32e83f7621cd3f99d805f45519cd06fafb247628b861da7d/multidict-6.7.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/c1/316c8f3549dbe5245f92bfd523ec6f32dd4d98cafe21df3f6a19b1184c75/aiohttp-3.14.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/8f/7b3ec212f1ea0683f55f978e3246bc313c38818664edfc97a9f349a4901e/yarl-1.24.2-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-testing", "version": "24.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/93/1d588f1cb9b710b9f22fa78b53d699a8062edc94204d50dd0d78c5f5b495/sanic_testing-24.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/70/26ca3f06aace16f2352796b08704338d74b6d1a24ca38f2771afbb7ed915/frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "html5tagger", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/12/2f5d43ee912ea14a6baba4b3db6d309b02d932e3b7074c3339b4aded98ff/html5tagger-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "httptools", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/f7/b4d41eaae2869d31356bc4bbf546f44fae83ff298af0a043ca0625b06773/httptools-0.8.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/42/0e7443c90310498561addf346e7d57fe3c6ba1914e1ba938b5464c7bbfd2/propcache-0.5.2-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-routing", "version": "23.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/e3/3425c9a8773807ac2c01d6a56c8521733f09b627e5827e733c5cd36b9ac5/sanic_routing-23.12.0-py3-none-any.whl"}}, {"metadata": {"name": "tracerite", "version": "2.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b6/62/3f385a67ff3cc91209f107d20bbebdecf7a4e4aba55a43f9f71bddc424a9/tracerite-2.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "5.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8e/d2/92e83af35cd65d3b7c47fb0e24927aa2b478897af8b0dd0ee19abcd50c03/ujson-5.13.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "uvloop", "version": "0.22.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/14/ecceb239b65adaaf7fde510aa8bd534075695d1e5f8dadfa32b5723d9cfb/uvloop-0.22.1-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}], "install_targets_hash": "76dabba8d81006345a2675957fd9dcbf"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "redis", "version": "4.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d3/2d/1aefc345181d53d618b48f7c2bdc491a6ec4f2be1923c37e04536ef2f9c4/redis-4.2.2-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.24.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/70/15/7db6bdc128638aa9e6d8ce2d744288674072566060ac0e7424495cff5c77/fakeredis-2.24.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "7.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ff/f6e8b8f39e08547faece4bd80f89d5a8de68a38b2d179cc1c4490ffa3286/pytest-7.4.4-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.23.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ee/82/62e2d63639ecb0fbe8a7ee59ef0bc69a4669ec50f6d3459f74ad4e4189a2/pytest_asyncio-0.23.8-py3-none-any.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "Deprecated", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/84/d0/205d54408c08b13550c733c4b85429e7ead111c7f0014309637425520a9a/deprecated-1.3.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "wrapt", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7a/5a/3c6117938be98754578ab83f5a40d7d0ea2cd2c487dc5cd6027ee7228229/wrapt-2.3.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}], "install_targets_hash": "7714b24b1f75f284b6047e417e725b9b"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "gql", "version": "4.4.0b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/97/00105a44b645f2234e4540027d2ae4ea34b6a95d40e45f9f01c020d0f5b0/gql-4.4.0b0-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9e/73b582c4dbbc3c12ef4473822475effaabf1f934b56f14f5b03fe5d3a2af/aiohttp-3.14.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.57"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/7a/1cfe9c296df0fa6e0143c8622b10f21fa8fb9cce25450e9a8e5cf6523e4b/botocore-1.43.57-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.3.0rc0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8c/89/efd877ac909125f050b9562afc1f4b1bc7c0a90bc2a03ed7b0cb21debca3/graphql_core-3.3.0rc0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/13/b8/cfd91c4ab9134d386d48f0b6ac662ff3d4be6efdee59ee1c67ebc3c0487c/httpx2-2.9.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9f/fb/46c52b781975c335a2bcf1072c7bbc007cbdc8d674217f5ee1daba2c848b/httpcore2-2.9.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/31/5c/08c7f7fe311f32e83f7621cd3f99d805f45519cd06fafb247628b861da7d/multidict-6.7.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/81/8e983840c6e5b93b33c2ba81aa3d52c2e42f0e9a690ce7607a2e61da4a5c/charset_normalizer-3.4.9-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "15.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d5/4f/b462242432d93ea45f297b6179c7333dd0402b855a912a04e7fc61c0d71f/websockets-15.0.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/59/1d/340d1a0db7bbce1f291afc044255ebf4ebbce2b25ab1b3f7d3d069080f5d/yarl-1.24.5-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "responses", "version": "0.26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/28/693e1d9ebf72baa062ded80d837a035b86ce75eda5a269379e9e2b1008a8/responses-0.26.2-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/70/26ca3f06aace16f2352796b08704338d74b6d1a24ca38f2771afbb7ed915/frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/42/0e7443c90310498561addf346e7d57fe3c6ba1914e1ba938b5464c7bbfd2/propcache-0.5.2-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}], "install_targets_hash": "7d9f37badbb06455849b77944a0bd79e"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "gql", "version": "4.4.0b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/97/00105a44b645f2234e4540027d2ae4ea34b6a95d40e45f9f01c020d0f5b0/gql-4.4.0b0-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9e/73b582c4dbbc3c12ef4473822475effaabf1f934b56f14f5b03fe5d3a2af/aiohttp-3.14.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.57"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/7a/1cfe9c296df0fa6e0143c8622b10f21fa8fb9cce25450e9a8e5cf6523e4b/botocore-1.43.57-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.3.0rc0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8c/89/efd877ac909125f050b9562afc1f4b1bc7c0a90bc2a03ed7b0cb21debca3/graphql_core-3.3.0rc0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/13/b8/cfd91c4ab9134d386d48f0b6ac662ff3d4be6efdee59ee1c67ebc3c0487c/httpx2-2.9.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9f/fb/46c52b781975c335a2bcf1072c7bbc007cbdc8d674217f5ee1daba2c848b/httpcore2-2.9.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/31/5c/08c7f7fe311f32e83f7621cd3f99d805f45519cd06fafb247628b861da7d/multidict-6.7.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/81/8e983840c6e5b93b33c2ba81aa3d52c2e42f0e9a690ce7607a2e61da4a5c/charset_normalizer-3.4.9-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "15.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d5/4f/b462242432d93ea45f297b6179c7333dd0402b855a912a04e7fc61c0d71f/websockets-15.0.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/59/1d/340d1a0db7bbce1f291afc044255ebf4ebbce2b25ab1b3f7d3d069080f5d/yarl-1.24.5-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "responses", "version": "0.26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/28/693e1d9ebf72baa062ded80d837a035b86ce75eda5a269379e9e2b1008a8/responses-0.26.2-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/70/26ca3f06aace16f2352796b08704338d74b6d1a24ca38f2771afbb7ed915/frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/42/0e7443c90310498561addf346e7d57fe3c6ba1914e1ba938b5464c7bbfd2/propcache-0.5.2-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}], "install_targets_hash": "7d9f37badbb06455849b77944a0bd79e"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "httpx2", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e6/a7/aea061b450d51cf448c1ccc8e1fc6f04c0d8fdc97c17524c7f835018bb92/httpx2-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2-pytest", "version": "1.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/46/ef/e9b6fb576f1f518f68e9f9cce9776870452ae2b8cfbba53b4127701b9a55/httpx2_pytest-1.0.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b7/76d6baa8c087cf5170f36dbeb92471e77c5c48f8f7ca8e5ba4ad613ea492/httpcore2-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}], "install_targets_hash": "81061e3f7fbd70089dc2dae262e96f28"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "openai", "version": "3.17.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/57/bc/5b80a0ca4069a6b5ba6c7d48ae7a4f8176b2c0bde0bebccdb867472ec6f6/openai-3.17.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.17.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ca/e9/5993079500530586655c6f2823e2926b3f5ceddd49918c5a86757eadba3a/jiter-0.17.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/bd/d0/c787604c71c2bdcda1a5656942fc822cd0f9cd879b9484bb84fc42172703/pydantic_core-2.46.5-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/18/e2/d39ae33d3dc30a0c229ff0cb683df961ebb5e7b8691feb2d08b3ee6ac327/tiktoken-0.14.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.9.10"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/cd/2f540fc813d1f71f18e1cc6861483133a0e6afb349a4e770fbdce4811d8d/regex-2026.9.10-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/aa/554e2614f38fc34c58ff1d0911ae8535ad2516440d5482d76fe59f1088b0/charset_normalizer-3.5.1-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "urllib3", "version": "2.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "828f8978f312e7020633b81adf747d24"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "pymongo", "version": "3.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1d/6f/06ad835f571f2a075073d75ed8d498e5ec7753a769630722e8a6727309fc/pymongo-3.13.0-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "mockupdb", "version": "1.8.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2f/c0/bc0c3e82bf91993bf2337b125c4d49c3cadae39f5a4c642baada958f976e/mockupdb-1.8.1-py2.py3-none-any.whl"}}], "install_targets_hash": "835b39253514cd495b485793c70e3bfd"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "dramatiq", "version": "2.2.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/8c/13/0550ff585ade7b423e2ecaac29c4ab88673a58ae92ef25b6629089a2b92c/dramatiq-2.2.1-py3-none-any.whl"}}], "install_targets_hash": "83dfbbed9bd8bc2ec0e6747a01c98300"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "dramatiq", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8c/13/0550ff585ade7b423e2ecaac29c4ab88673a58ae92ef25b6629089a2b92c/dramatiq-2.2.1-py3-none-any.whl"}}], "install_targets_hash": "83dfbbed9bd8bc2ec0e6747a01c98300"} -{"python_version": "3.10", "dependencies": [{"metadata": {"name": "fastapi", "version": "0.100.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/66/23/5db1adf057fc47f6575c4f317b98882a9312f59a7ec555ae38ca854aef42/fastapi-0.100.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"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"}}, {"metadata": {"name": "starlette", "version": "0.27.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/f8/e2cca22387965584a409795913b774235752be4176d276714e15e1a58884/starlette-0.27.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/5f/b98b8da398637b551e427e7be922bdec19177dc54d6811dcdaa503f23aac/charset_normalizer-3.4.9-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/af/cd/ce6e848bbf2c32314c9b237839119c5a564a59725b53157c856e90937b7a/markupsafe-3.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "84ca248e3427ba030c1b6637a02186cb"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "arq", "version": "0.23"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ff/f8/cec0e703750504d653fe048d79f4f97e555e2e3b89b9d8598a6aea368d12/arq-0.23-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "1.10.26"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/e6/10df5f08c105bcbb4adbee7d1108ff4b347702b110fed058f6a03f1c6b73/pydantic-1.10.26-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/4d/e6e40f93031adbf654d34e542bd396e9f3bc1c6209b40c920d58c9e1317a/fakeredis-2.36.2-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "redis", "version": "8.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/0a/c2345ebf1ebe70840ce3f6c6ee612f8fa749cfbd1b03069c53bf0c62aaad/redis-8.0.1-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}], "install_targets_hash": "861238b3e47ffcf341fe6a7baecfea04"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "arq", "version": "0.23"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ff/f8/cec0e703750504d653fe048d79f4f97e555e2e3b89b9d8598a6aea368d12/arq-0.23-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "1.10.26"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/e6/10df5f08c105bcbb4adbee7d1108ff4b347702b110fed058f6a03f1c6b73/pydantic-1.10.26-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/4d/e6e40f93031adbf654d34e542bd396e9f3bc1c6209b40c920d58c9e1317a/fakeredis-2.36.2-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "redis", "version": "8.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/0a/c2345ebf1ebe70840ce3f6c6ee612f8fa749cfbd1b03069c53bf0c62aaad/redis-8.0.1-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}], "install_targets_hash": "861238b3e47ffcf341fe6a7baecfea04"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "arq", "version": "0.23"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ff/f8/cec0e703750504d653fe048d79f4f97e555e2e3b89b9d8598a6aea368d12/arq-0.23-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "1.10.26"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/e6/10df5f08c105bcbb4adbee7d1108ff4b347702b110fed058f6a03f1c6b73/pydantic-1.10.26-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/4d/e6e40f93031adbf654d34e542bd396e9f3bc1c6209b40c920d58c9e1317a/fakeredis-2.36.2-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "redis", "version": "8.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/0a/c2345ebf1ebe70840ce3f6c6ee612f8fa749cfbd1b03069c53bf0c62aaad/redis-8.0.1-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}], "install_targets_hash": "861238b3e47ffcf341fe6a7baecfea04"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "arq", "version": "0.23"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ff/f8/cec0e703750504d653fe048d79f4f97e555e2e3b89b9d8598a6aea368d12/arq-0.23-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "1.10.26"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/e6/10df5f08c105bcbb4adbee7d1108ff4b347702b110fed058f6a03f1c6b73/pydantic-1.10.26-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/4d/e6e40f93031adbf654d34e542bd396e9f3bc1c6209b40c920d58c9e1317a/fakeredis-2.36.2-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "redis", "version": "8.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/0a/c2345ebf1ebe70840ce3f6c6ee612f8fa749cfbd1b03069c53bf0c62aaad/redis-8.0.1-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}], "install_targets_hash": "861238b3e47ffcf341fe6a7baecfea04"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "arq", "version": "0.23"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ff/f8/cec0e703750504d653fe048d79f4f97e555e2e3b89b9d8598a6aea368d12/arq-0.23-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "1.10.26"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/e6/10df5f08c105bcbb4adbee7d1108ff4b347702b110fed058f6a03f1c6b73/pydantic-1.10.26-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/4d/e6e40f93031adbf654d34e542bd396e9f3bc1c6209b40c920d58c9e1317a/fakeredis-2.36.2-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "redis", "version": "8.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/0a/c2345ebf1ebe70840ce3f6c6ee612f8fa749cfbd1b03069c53bf0c62aaad/redis-8.0.1-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}], "install_targets_hash": "861238b3e47ffcf341fe6a7baecfea04"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "arq", "version": "0.23"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ff/f8/cec0e703750504d653fe048d79f4f97e555e2e3b89b9d8598a6aea368d12/arq-0.23-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "1.10.26"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/e6/10df5f08c105bcbb4adbee7d1108ff4b347702b110fed058f6a03f1c6b73/pydantic-1.10.26-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/4d/e6e40f93031adbf654d34e542bd396e9f3bc1c6209b40c920d58c9e1317a/fakeredis-2.36.2-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "redis", "version": "8.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/0a/c2345ebf1ebe70840ce3f6c6ee612f8fa749cfbd1b03069c53bf0c62aaad/redis-8.0.1-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}], "install_targets_hash": "861238b3e47ffcf341fe6a7baecfea04"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "ray", "version": "2.58.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2f/41/760f9a076085d043d9fbb8f840436e1d21e47682c976d3620efbf02a3b9e/ray-2.58.0-cp310-cp310-macosx_12_0_arm64.whl"}}, {"metadata": {"name": "msgpack", "version": "1.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e4/3c/08ecd5cdfe4e2de43aec79062028ad0f7b2d9b1fea5430068c198ba570da/msgpack-1.2.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "protobuf", "version": "7.36.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8f/ae/58e3ca96cb2e118cc546b677359b3c6659f79a140935c08dec94c7998585/protobuf-7.36.0-cp310-abi3-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "filelock", "version": "3.32.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/a4/9b63d595d748e3aff8812b65eacc1a2c4bd90b7c2012e08e72373b4835eb/filelock-3.32.4-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "0.30.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/6a/4ba3d0fb7297ebae71171822554abe48d7cab29c28b8f9f2c04b79988c05/rpds_py-0.30.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/aa/554e2614f38fc34c58ff1d0911ae8535ad2516440d5482d76fe59f1088b0/charset_normalizer-3.5.1-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}], "install_targets_hash": "8cfb15039ed423e3572da8465f57e8cf"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "huggingface_hub", "version": "1.32.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/cf/d98dd561d6d0d7b7d7a64d1563f8aaaa7c235daee41c1c9bcc3da62420ed/huggingface_hub-1.32.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/4e/a28359bf1c1ecf11eba22123168c138698f7cb576ac678f5a2e16cd5da08/hf_xet-1.6.0-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "responses", "version": "0.26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6d/86/ca7958de70cb0752350575e98229368a3a2f746a2942034b3364e17312bb/responses-0.26.3-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/cd/4f564b8f132de25db594efc706897069f016790cea63a5669c9df2675f64/charset_normalizer-3.5.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-httpx", "version": "0.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/55/1fa65f8e4fceb19dd6daa867c162ad845d547f6058cd92b4b02384a44777/pytest_httpx-0.36.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "filelock", "version": "4.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/29/33/af0635ab07fe83b1788a1dbe370ff3e226062495a998335cb18a1cac81aa/filelock-4.0.1-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6c/c0/a98505f18594f1bce828bb159cec0fcf9860562f1a2c85913409fc8f3d9e/fsspec-2026.9.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7a/1e/7acc4f0e74c4b3d9531e24739e0ab832a5edf40e64fbae1a9c01941cabd7/pyyaml-6.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/03/921a3d3c75785aca9ebfbfcabfbc3a1be12e2ab5265deb026d55a5a3f83e/tqdm-4.70.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}], "install_targets_hash": "8d3f9781d86e000603a20c010acf0233"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "typer", "version": "0.27.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/dc/bf/205d0004930ede8f542fb58f601526fccf4ae7626075ca1e6c4de5d3d652/typer-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "shellingham", "version": "1.5.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}], "install_targets_hash": "8ea02a85ddecd330a24e7e8daff773d1"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "typer", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/bf/205d0004930ede8f542fb58f601526fccf4ae7626075ca1e6c4de5d3d652/typer-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "shellingham", "version": "1.5.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}], "install_targets_hash": "8ea02a85ddecd330a24e7e8daff773d1"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "mcp", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/ff/8e7eade68b8a28f7da0ed1085544341b51f9c935dbf6b95c76b7edfea6a0/mcp-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mcp-types", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8f/d7/6ffba5d8cd5dd9b8a19478875c50e04945314ba5074e84d749283f27f62d/mcp_types-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/95/411ba65569158e862368917aaf56597f3e5fa3b91b0502919638465a08f3/httpx2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/74/d370e55600d9bcfa0d9794b0166126d49291a3d2b20c268fc98c453a4948/httpcore2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/6f/a04e900f465ff3221ccc395522503e2d10e79fa21f2723c8e177aae1e0d1/opentelemetry_api-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/d0/c787604c71c2bdcda1a5656942fc822cd0f9cd879b9484bb84fc42172703/pydantic_core-2.46.5-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/97/672cb32ce0dfea44b740cb7b4f97038463b9cf7c0ead1aacf595572851d6/pyjwt-2.14.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/6a/2ba3ed4a69babf3afdddf7d8314a48d87562c0a442206bbc2a1b50d5efc0/sse_starlette-3.4.11-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.53.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/76/18/0eea75741ee812e9f598b687619ce2454f6c3a1c5cd21ea990ec6bd26f45/uvicorn-0.53.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/84/a9/ee16a903f13755e914d1eecc482fe64d1f10761c3960e5d8fa6837377aff/cryptography-50.0.1-cp39-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "0.30.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/6a/4ba3d0fb7297ebae71171822554abe48d7cab29c28b8f9f2c04b79988c05/rpds_py-0.30.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/1a/4b2f7c92293ba05cbd4a9a1b28faaf0326272d9488e6354657571c48a7aa/cffi-2.1.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "92894b9de86e2bb0e11c5c76350def3a"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "mcp", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/ff/8e7eade68b8a28f7da0ed1085544341b51f9c935dbf6b95c76b7edfea6a0/mcp-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mcp-types", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8f/d7/6ffba5d8cd5dd9b8a19478875c50e04945314ba5074e84d749283f27f62d/mcp_types-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/95/411ba65569158e862368917aaf56597f3e5fa3b91b0502919638465a08f3/httpx2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/74/d370e55600d9bcfa0d9794b0166126d49291a3d2b20c268fc98c453a4948/httpcore2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/6f/a04e900f465ff3221ccc395522503e2d10e79fa21f2723c8e177aae1e0d1/opentelemetry_api-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/34/a1/c8e6b66f499f510752c07a092dfe27621f9c255635e59d38704b5681c35a/pydantic_core-2.46.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/97/672cb32ce0dfea44b740cb7b4f97038463b9cf7c0ead1aacf595572851d6/pyjwt-2.14.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8c/eb/5d7124083e8d8cda8f5b348f544b71ad6f707ad63193758ef4d8e569da02/cryptography-50.0.1-cp39-abi3-manylinux_2_34_x86_64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/75/77/60bebf6f818bec84210ac5b6979ce4eeadce6fbbaabc9c7ab23e506d1ce5/cffi-2.1.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "0.30.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/61/b5/707f6cf0066a6412aacc11d17920ea2e19e5b2f04081c64526eb35b5c6e7/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/6a/2ba3ed4a69babf3afdddf7d8314a48d87562c0a442206bbc2a1b50d5efc0/sse_starlette-3.4.11-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.52.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/79/4a20b54ab0491485ccd8c077db2d39187c7f12b3e15485d38a7be37c81b4/uvicorn-0.52.4-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "92894b9de86e2bb0e11c5c76350def3a"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "httpx2", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/25/66215a750faeb79b698286c0d0b94894482cfae10371ae4968ef6e165a28/httpx2-2.0.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2-pytest", "version": "1.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/46/ef/e9b6fb576f1f518f68e9f9cce9776870452ae2b8cfbba53b4127701b9a55/httpx2_pytest-1.0.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ae/67/784fd58a5b4dbe8b2aee0cafc6959cb8b53c1b7e9d6e4281f8a4c6935c10/httpcore2-2.0.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}], "install_targets_hash": "9589a3ce6fa0bfc82a7f6fc685f97223"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "httpx2", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/25/66215a750faeb79b698286c0d0b94894482cfae10371ae4968ef6e165a28/httpx2-2.0.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2-pytest", "version": "1.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/46/ef/e9b6fb576f1f518f68e9f9cce9776870452ae2b8cfbba53b4127701b9a55/httpx2_pytest-1.0.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ae/67/784fd58a5b4dbe8b2aee0cafc6959cb8b53c1b7e9d6e4281f8a4c6935c10/httpcore2-2.0.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}], "install_targets_hash": "9589a3ce6fa0bfc82a7f6fc685f97223"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "strawberry-graphql", "version": "0.327.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/09/e0deac5d4f466f6ecae1b91a91d1a291aad1890960a5d891bb80bda3425c/strawberry_graphql-0.327.7-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "cross-web", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7a/4a/78b52ec2edcbd9b123638f4e0421fd8699ebe653ebf63ac5f82abd2665bc/cross_web-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "fastapi", "version": "0.141.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/03/10388a42375ee7e4ac9b94eb2c5c569c8b5795e377e701c9ac3ad63de890/fastapi-0.141.1-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.12"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/b6/304c572e79b9e82982dbd5091e26a89f5018e565868091d804c2142f6ba5/graphql_core-3.2.12-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/d0/c787604c71c2bdcda1a5656942fc822cd0f9cd879b9484bb84fc42172703/pydantic_core-2.46.5-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}], "install_targets_hash": "973f4a5847325907761d52b88b87e613"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "strawberry-graphql", "version": "0.327.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/09/e0deac5d4f466f6ecae1b91a91d1a291aad1890960a5d891bb80bda3425c/strawberry_graphql-0.327.7-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.12"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/b6/304c572e79b9e82982dbd5091e26a89f5018e565868091d804c2142f6ba5/graphql_core-3.2.12-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "cross-web", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7a/4a/78b52ec2edcbd9b123638f4e0421fd8699ebe653ebf63ac5f82abd2665bc/cross_web-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "fastapi", "version": "0.141.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/03/10388a42375ee7e4ac9b94eb2c5c569c8b5795e377e701c9ac3ad63de890/fastapi-0.141.1-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/af/cd/ce6e848bbf2c32314c9b237839119c5a564a59725b53157c856e90937b7a/markupsafe-3.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/34/a1/c8e6b66f499f510752c07a092dfe27621f9c255635e59d38704b5681c35a/pydantic_core-2.46.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}], "install_targets_hash": "973f4a5847325907761d52b88b87e613"} -{"python_version": "3.10", "dependencies": [{"metadata": {"name": "pydantic-ai", "version": "2.46.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/01/20a5fda50b3e30067450d43ecd7ac1ddf41055982540ee6a48626a4e748b/pydantic_ai-2.46.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-ai-slim", "version": "2.46.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8c/fc/6a28534bc4b27026225fec76b4a2cb97274a0bda601a90890676b09c5132/pydantic_ai_slim-2.46.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-evals", "version": "2.46.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/89/83921db264a4d76561c641dd785472e68877525848228876a949565dd6b2/pydantic_evals-2.46.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-graph", "version": "2.46.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8b/7d/711d5e3a1ca9f560a365080779858be76510ff615a5106121ba0430b5f55/pydantic_graph-2.46.0-py3-none-any.whl"}}, {"metadata": {"name": "fastmcp-slim", "version": "4.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ed/76/8dc551ef1f222bd146537ae100baf7441628aa1050494b567249ece997c2/fastmcp_slim-4.0.5-py3-none-any.whl"}}, {"metadata": {"name": "mcp", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/ff/8e7eade68b8a28f7da0ed1085544341b51f9c935dbf6b95c76b7edfea6a0/mcp-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mcp-types", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8f/d7/6ffba5d8cd5dd9b8a19478875c50e04945314ba5074e84d749283f27f62d/mcp_types-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "py-key-value-aio", "version": "0.4.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/46/12871550fb0613d149144bb9d41f22680d5f46717bc45a76eb5798c20c3f/py_key_value_aio-0.4.6-py3-none-any.whl"}}, {"metadata": {"name": "aiofile", "version": "3.8.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/76/ea/b6aae3275bb0991c43fff401e7b8db198047b6f692e8954520ec7aed3652/aiofile-3.8.8-py3-none-any.whl"}}, {"metadata": {"name": "caio", "version": "0.9.25"}, "download_info": {"url": "https://files.pythonhosted.org/packages/88/95/dd55757bb671eb4c376e006c04e83beb413486821f517792ea603ef216e9/caio-0.9.25-cp310-cp310-manylinux_2_34_x86_64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "anthropic", "version": "1.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c0/dc/74995efda028421917f4caabd24db1373ee0742573a2363fff1a21191441/anthropic-1.7.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/2c/af9ca503b38683a82b6732352a861515f28e2d46fe445aea57e07fc86e06/jiter-0.17.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/34/a1/c8e6b66f499f510752c07a092dfe27621f9c255635e59d38704b5681c35a/pydantic_core-2.46.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "argcomplete", "version": "3.7.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/46/bd/551ee6af426af84ca33e02622be722925c196608e9127d731ef17c47f06e/argcomplete-3.7.2-py3-none-any.whl"}}, {"metadata": {"name": "Authlib", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b8/c6/6f124bcfbbfb20fba22c939b4e43a06dccfc0e1ca20e5634ca573cb1e271/authlib-1.8.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "beartype", "version": "0.22.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/cc/18245721fa7747065ab478316c7fea7c74777d07f37ae60db2e84f8172e8/beartype-0.22.9-py3-none-any.whl"}}, {"metadata": {"name": "cachetools", "version": "7.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cc/bb/1c6e7a89b11da19f137e4ef5a5c5fe47a5bb686449ba343944ccf8fb34b2/cachetools-7.2.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8c/eb/5d7124083e8d8cda8f5b348f544b71ad6f707ad63193758ef4d8e569da02/cryptography-50.0.1-cp39-abi3-manylinux_2_34_x86_64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/75/77/60bebf6f818bec84210ac5b6979ce4eeadce6fbbaabc9c7ab23e506d1ce5/cffi-2.1.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "genai-prices", "version": "0.1.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d5/4a/9e04f3dca5ffe74133779ab5e9925ffb6411afbeac55d26fa0e148722599/genai_prices-0.1.7-py3-none-any.whl"}}, {"metadata": {"name": "google-genai", "version": "2.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/84/5b/87913fe392ba7b6402577259289ed3740c577956554a674b191a2971d33e/google_genai-2.24.0-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.58.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/59/13/477d90d09591b3938b45c4e11f4d8a51291682112cb5efcac961e815d562/google_auth-2.58.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/cd/4f564b8f132de25db594efc706897069f016790cea63a5669c9df2675f64/charset_normalizer-3.5.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f3/18/a17e2f0cde02dc10154c808deed7e1d8528afff93612f70d3f0a5b19b011/websockets-16.1.1-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "griffelib", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/63/e876e789525063c840ccfa8857febdabd6523bcef9ce7eb979b9305ea895/griffelib-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "joserfc", "version": "1.7.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/c5/82addfd375e5ee6520644e0553e4aadde92d668c4fc99cc716d337fe7bb3/joserfc-1.7.5-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "keyring", "version": "25.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/db/e655086b7f3a705df045bf0933bdd9c2f79bb3c97bfef1384598bb79a217/keyring-25.7.0-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "9.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/55/ecca97ae19075f1fac62def77731e7f535e6c1fb8f92ff08160c5e6dade8/importlib_metadata-9.0.1-py3-none-any.whl"}}, {"metadata": {"name": "jeepney", "version": "0.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b2/a3/e137168c9c44d18eff0376253da9f1e9234d0239e0ee230d2fee6cea8e55/jeepney-0.9.0-py3-none-any.whl"}}, {"metadata": {"name": "logfire", "version": "5.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cd/02/b32c3d5c298e4a9010694d261fb82c2c672747c0bf2b47bffda484aef349/logfire-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-exporter-otlp-proto-http", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cd/d0/fdeb1a98d8d3a6205f5f297c51b4a9bfe65126ab60339669bbe3dd54c2e2/opentelemetry_exporter_otlp_proto_http-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-exporter-otlp-proto-common", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5e/71/65fd9d54c10b860f87c045ccee1264cab7011268895d3528818a29c1172a/opentelemetry_exporter_otlp_proto_common-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-proto", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d1/7c/8be563d68e93bbefa5c8affb82ddcff91b3ad858ce49957ba7b16fd3e0ab/opentelemetry_proto-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "googleapis-common-protos", "version": "1.75.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1a/7a/7d79170c6ce6f12e109df2b3879d6b934010cf4f99aea8de8b7e5408c174/googleapis_common_protos-1.75.3-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/6f/a04e900f465ff3221ccc395522503e2d10e79fa21f2723c8e177aae1e0d1/opentelemetry_api-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-sdk", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e7/23/ff077e61886ee020a17ce9c8b6fa11c601c8d8345b09ea24f605445df62a/opentelemetry_sdk-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-semantic-conventions", "version": "0.65b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/0e/49df70d9b81fb5cbae4bbf2a49d865b09bcbcbc4eb53f5851b1027738d78/opentelemetry_semantic_conventions-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "protobuf", "version": "7.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/db/f3/3996583dd2906297a637af12114deddf7658af6e683fedb83be061983fb5/protobuf-7.36.2-cp310-abi3-manylinux2014_x86_64.whl"}}, {"metadata": {"name": "executing", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "logfire-api", "version": "5.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2d/51/123dab197fb08c0892e3bea1c2266bff159aa2ee82ad43bef93505859705/logfire_api-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "3.16.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/17/72/2b1fe3e303db76ab2ba0c2de2b57822869bcb588db82334d4ff3aea8acf2/openai-3.16.2-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-instrumentation", "version": "0.65b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/40/7b/85eab1215f72adf0e68d3dc4a679b9bff993fa679ff34cd8dd378e2659fd/opentelemetry_instrumentation-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "wrapt", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3c/e9/2c1a482052cfabd6906887096993099afa2db738e7597c30e4f2b9922718/wrapt-2.4.1-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl"}}, {"metadata": {"name": "opentelemetry-instrumentation-httpx", "version": "0.65b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/0f/c6144096b4914bbf44b43ba21c962e8f333ff045770b50a3e79ed8bd455f/opentelemetry_instrumentation_httpx-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-util-http", "version": "0.65b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/23/3f/ab8d29df207ce5f470a07fa96ebb48af4e95b7fab7e7635311b9a32f2fab/opentelemetry_util_http-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "platformdirs", "version": "4.11.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/39/be/3ae887e84c38c4dd1c549cd5825adc93f48069a94fe1cb8ac52a9da16f15/platformdirs-4.11.11-py3-none-any.whl"}}, {"metadata": {"name": "prompt_toolkit", "version": "3.0.53"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/6f/84908cad2d6aa5144abcf7b42709fe4fdb459bc640ec7ac5786e7693dabc/prompt_toolkit-3.0.53-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/3b/6163796d69c3977d1e4287bea4a6979161cbbdd170ebb430511e8e1999ce/pyasn1-0.6.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "email-validator", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "dnspython", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/97/672cb32ce0dfea44b740cb7b4f97038463b9cf7c0ead1aacf595572851d6/pyjwt-2.14.0-py3-none-any.whl"}}, {"metadata": {"name": "pyperclip", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/80/fc9d01d5ed37ba4c42ca2b55b4339ae6e200b456be3a1aaddf4a9fa99b8c/pyperclip-1.11.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7a/1e/7acc4f0e74c4b3d9531e24739e0ab832a5edf40e64fbae1a9c01941cabd7/pyyaml-6.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "0.30.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/61/b5/707f6cf0066a6412aacc11d17920ea2e19e5b2f04081c64526eb35b5c6e7/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "SecretStorage", "version": "3.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/46/f5af3402b579fd5e11573ce652019a67074317e18c1935cc0b4ba9b35552/secretstorage-3.5.0-py3-none-any.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/6a/2ba3ed4a69babf3afdddf7d8314a48d87562c0a442206bbc2a1b50d5efc0/sse_starlette-3.4.11-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/af/c8/051e7b72a816ff50eb34a1c7c5b185cd2429ffdf59a497baea35b2b6b2dd/tiktoken-0.14.0-cp310-cp310-manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.53.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/76/18/0eea75741ee812e9f598b687619ce2454f6c3a1c5cd21ea990ec6bd26f45/uvicorn-0.53.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/39/cc/9c0adc5861020de426ec71716b6c1bef8d90694b7d6d0a16202cdb1647f5/wcwidth-0.8.4-py3-none-any.whl"}}, {"metadata": {"name": "zipp", "version": "4.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.classes", "version": "3.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/66/b15ce62552d84bbfcec9a4873ab79d993a1dd4edb922cbfccae192bd5b5f/jaraco.classes-3.4.0-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.context", "version": "6.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f2/58/bc8954bda5fcda97bd7c19be11b85f91973d67a706ed4a3aec33e7de22db/jaraco_context-6.1.2-py3-none-any.whl"}}, {"metadata": {"name": "backports.tarfile", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/fa/123043af240e49752f1c4bd24da5053b6bd00cad78c2be53c0d1e8b975bc/backports.tarfile-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.functools", "version": "4.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/02/36/ecc85bc96c273dc8a11273ed4782272975e6338d4a3e9228621175edf0e3/jaraco_functools-4.6.0-py3-none-any.whl"}}, {"metadata": {"name": "more-itertools", "version": "11.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/3d/1087453384dbde46a8c7f9356eead2c58be8a7bf156bca40243377c85715/more_itertools-11.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.9.10"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/b2/be9fafe5e05888296fdd35d82ba9cbb67b0d352e9911fad3c458beb3a34a/regex-2026.9.10-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}], "install_targets_hash": "99070e5a015df9ed8efe12e4aa3cf88a"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "mistralai", "version": "2.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c0/ab/a565e4bec9b5496eb3b44b8799b6ad8378b2cd0be4cd5e6b7d098e8cedcc/mistralai-2.0.5-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "eval_type_backport", "version": "0.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/a7/bb99bf5e6f78736ddb53480f2c3ff3702ffe2196a7c5e1661c03081d398e/eval_type_backport-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-semantic-conventions", "version": "0.60b1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7a/5e/5958555e09635d09b75de3c4f8b9cae7335ca545d77392ffe7331534c402/opentelemetry_semantic_conventions-0.60b1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.39.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/df/d3f1ddf4bb4cb50ed9b1139cc7b1c54c34a1e7ce8fd1b9a37c0d1551a6bd/opentelemetry_api-1.39.1-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/d0/c787604c71c2bdcda1a5656942fc822cd0f9cd879b9484bb84fc42172703/pydantic_core-2.46.5-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fa/5e/f8e9a1d23b9c20a551a8a02ea3637b4642e22c2626e3a13a9a29cdea99eb/importlib_metadata-8.7.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "zipp", "version": "4.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl"}}], "install_targets_hash": "994d711e6ebda622f4cced8803ee9a73"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "strawberry-graphql", "version": "0.209.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f5/2a/0ff66cce0fbd42e232486f4e4d8ffa39395b7ce0086b06b02a5742f923b1/strawberry_graphql-0.209.8-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.10.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/3c/8cc1cc84deffa6e25d2d0c688ebb80635dfdbf1dbea3e30c541c8cf4d860/pydantic-2.10.6-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/2a/185aff24ce844e39abb8dd680f4e959f0006944f4a8a0ea372d9f9ae2e53/pydantic_core-2.27.2-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/15/b92b4e1d88d02c6eff9733c9eea21846ab435cc4d813d84ccc5d335955df/graphql_core-3.2.11-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b4/ff/b1e11d8bffb5e0e1b6d27f402eeedbeb9be6df2cdbc09356a1ae49806dbf/python_multipart-0.0.6-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "fastapi", "version": "0.139.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/7c/8e3c6ad324ea5cb36604fc3f968554887891c316d9dfde57761611d907ad/fastapi-0.139.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}], "install_targets_hash": "9a43a190bf43b9eff8ea17e64ecb9b7f"} -{"python_version": "3.10", "dependencies": [{"metadata": {"name": "httpx", "version": "0.24.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/91/e41f64f03d2a13aee7e8c819d82ee3aa7cdc484d18c0ae859742597d5aa0/httpx-0.24.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-httpx", "version": "0.22.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/23/a8438a0e11bc159d922a62c868593088b78285628e61f01c78bc1f1251e4/pytest_httpx-0.22.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "0.17.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/2c/2bde7ff8dd2064395555220cbf7cba79991172bf5315a07eb3ac7688d9f1/httpcore-0.17.3-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/04/ff642e65ad6b90db43e668d70ffb6736436c7ce41fcc549f4e9472234127/h11-0.14.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "7.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ff/f6e8b8f39e08547faece4bd80f89d5a8de68a38b2d179cc1c4490ffa3286/pytest-7.4.4-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.23.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ee/82/62e2d63639ecb0fbe8a7ee59ef0bc69a4669ec50f6d3459f74ad4e4189a2/pytest_asyncio-0.23.8-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}], "install_targets_hash": "9e9c7b973297953ce2add56028906265"} -{"python_version": "3.10", "dependencies": [{"metadata": {"name": "fastmcp", "version": "2.14.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/f1/56310847b0bdd5b14c2af8f0a39082af078deff60d0dc43efef4e366a83e/fastmcp-2.14.7-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.34.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/b5/82f89307d0d769cd9bf46a54fb9136be08e4e57c5570ae421db4c9a2ba62/fakeredis-2.34.1-py3-none-any.whl"}}, {"metadata": {"name": "mcp", "version": "1.29.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/c8/248b201f6d753d69fd5d6506011abbb35a946d9142b2ae311a948fd0be3d/mcp-1.29.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "py-key-value-aio", "version": "0.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/10/72f6f213b8f0bce36eff21fda0a13271834e9eeff7f9609b01afdc253c79/py_key_value_aio-0.3.0-py3-none-any.whl"}}, {"metadata": {"name": "py-key-value-shared", "version": "0.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/e4/b8b0a03ece72f47dce2307d36e1c34725b7223d209fc679315ffe6a4e2c3/py_key_value_shared-0.3.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/c6/65f646c7ff09bd257f660434adb45c4dfcbbcebcc030562fecf6f5bf887d/pydantic_core-2.46.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "Authlib", "version": "1.7.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/95/adcb68e20c34162e9135f370d6e31737719c2b6f94bc953fe7ed1f10fe21/authlib-1.7.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "beartype", "version": "0.22.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/cc/18245721fa7747065ab478316c7fea7c74777d07f37ae60db2e84f8172e8/beartype-0.22.9-py3-none-any.whl"}}, {"metadata": {"name": "cachetools", "version": "7.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9f/f2/2086ba18a925a73586c4d4e61d25f4a6058e56fd00d77ce8f1d361ab4c9b/cachetools-7.1.6-py3-none-any.whl"}}, {"metadata": {"name": "cyclopts", "version": "4.22.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/75/a11bfb5045e58b4ef69337b848985918e829fe9a90572a761d17c1a992f5/cyclopts-4.22.2-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "rich-rst", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/68/1fc93dd759605b5d00fc98b50200739e41ed32bd22d6ba35ca6c3932371b/rich_rst-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "diskcache", "version": "5.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/27/4570e78fc0bf5ea0ca45eb1de3818a23787af9b390c0b0a0033a1b8236f9/diskcache-5.6.3-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "joserfc", "version": "1.7.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/bf/249dcd99b3376375910b7fa922383b57792975c8758f50d44612e749226c/joserfc-1.7.4-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/2a/5bb823f5bedcf80718cea7fbc95ec5515cca3769633c4b01a32be7f30e7c/cryptography-49.0.0-cp39-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/aa/24580a278de21fd7322635556334d9b535f1cbc00b0a3919447cdf464c65/cffi-2.1.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "jsonref", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/ec/e1db9922bceb168197a558a2b8c03a7963f1afe93517ddd3cf99f202f996/jsonref-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-path", "version": "0.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/2c/9e69d73c4297508be9e3b64a970ea3971b3eb8db64ffc5802d40bd25981f/jsonschema_path-0.5.0-py3-none-any.whl"}}, {"metadata": {"name": "pathable", "version": "0.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a2/e8/6d75ffd9784bce2e93d1ae4415649427e39a53bb172d4672b2b59c6f0a7b/pathable-0.6.0-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "keyring", "version": "25.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/db/e655086b7f3a705df045bf0933bdd9c2f79bb3c97bfef1384598bb79a217/keyring-25.7.0-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "9.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/38/3d/2d244233ac4f76e38533cfcb2991c9eb4c7bf688ae0a036d30725b8faafe/importlib_metadata-9.0.0-py3-none-any.whl"}}, {"metadata": {"name": "lupa", "version": "2.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1c/34/05ce4745b191633f90ff1ab50f1a19a37da282bb0a41fb500d9157fc9b8f/lupa-2.8-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "openapi-pydantic", "version": "0.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/cf/03675d8bd8ecbf4445504d8071adab19f5f993676795708e36402ab38263/openapi_pydantic-0.5.1-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pathvalidate", "version": "3.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/70/875f4a23bfc4731703a5835487d0d2fb999031bd415e7d17c0ae615c18b7/pathvalidate-3.3.1-py3-none-any.whl"}}, {"metadata": {"name": "platformdirs", "version": "4.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7d/68/d8d58938dfb1370b266a1a729e6d77a985be23689a0496498ee17b2cbf90/platformdirs-4.11.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/77/c1/6e422f34e569cf8e18df68d1939c81c099d2b61e4f7d9621c8a77560799c/pydantic_settings-2.14.2-py3-none-any.whl"}}, {"metadata": {"name": "email-validator", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "dnspython", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "pydocket", "version": "0.23.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e6/67/b57ac7cfd2c2f30d58ff2c996591880d200078fc828cbbad8da69d634c0e/pydocket-0.23.1-py3-none-any.whl"}}, {"metadata": {"name": "burner-redis", "version": "0.1.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2f/4e/ce5c91b884ac37fcd380756402536f8810964014097950900517ce8bd30c/burner_redis-0.1.7-cp310-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cloudpickle", "version": "3.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/88/39/799be3f2f0f38cc727ee3b4f1445fe6d5e4133064ec2e4115069418a5bb6/cloudpickle-3.1.2-py3-none-any.whl"}}, {"metadata": {"name": "cronsim", "version": "2.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1a/02f105147f7f2e06ed4f734ff5a6439590bb275a53dd91fc73df6312298a/cronsim-2.7-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/6f/a04e900f465ff3221ccc395522503e2d10e79fa21f2723c8e177aae1e0d1/opentelemetry_api-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "prometheus_client", "version": "0.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/a3/b69efbf4143b5b9859b977770bbbabcc2796b702fa69dc40271e45cd5a56/prometheus_client-0.26.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "pyperclip", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/80/fc9d01d5ed37ba4c42ca2b55b4339ae6e200b456be3a1aaddf4a9fa99b8c/pyperclip-1.11.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl"}}, {"metadata": {"name": "python-json-logger", "version": "4.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/27/be/0631a861af4d1c875f096c07d34e9a63639560a717130e7a87cbc82b7e3f/python_json_logger-4.1.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "redis", "version": "8.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/0a/c2345ebf1ebe70840ce3f6c6ee612f8fa749cfbd1b03069c53bf0c62aaad/redis-8.0.1-py3-none-any.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "0.30.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/6a/4ba3d0fb7297ebae71171822554abe48d7cab29c28b8f9f2c04b79988c05/rpds_py-0.30.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/36/e10c1d1b7ca881d2625db2ec28508578499187bb1c389952c398474e1834/sse_starlette-3.4.6-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "taskgroup", "version": "0.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d1/b1/74babcc824a57904e919f3af16d86c08b524c0691504baf038ef2d7f655c/taskgroup-0.2.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typer", "version": "0.27.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/40/03/26a383c9e58c213199d1aad1c3d353cfc22d4444ec6d2c0bf8ad02523843/typer-0.27.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "shellingham", "version": "1.5.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "uncalled-for", "version": "0.3.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3b/25/2c87754f3a9e692315f7b811244090e68f362979fc8886b3fbd2985a1d8c/uncalled_for-0.3.2-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.52.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/39/e6/b5c0630ace9757232aec07112be8146b812787db52141ff9d50674aa7634/uvicorn-0.52.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/90/72/2f14b2e167170b8bf1c8bb7f9b0d78000f470d41a2085a91f33e3917b6c9/websockets-16.1.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "zipp", "version": "4.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.classes", "version": "3.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/66/b15ce62552d84bbfcec9a4873ab79d993a1dd4edb922cbfccae192bd5b5f/jaraco.classes-3.4.0-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.context", "version": "6.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f2/58/bc8954bda5fcda97bd7c19be11b85f91973d67a706ed4a3aec33e7de22db/jaraco_context-6.1.2-py3-none-any.whl"}}, {"metadata": {"name": "backports.tarfile", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/fa/123043af240e49752f1c4bd24da5053b6bd00cad78c2be53c0d1e8b975bc/backports.tarfile-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.functools", "version": "4.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/02/36/ecc85bc96c273dc8a11273ed4782272975e6338d4a3e9228621175edf0e3/jaraco_functools-4.6.0-py3-none-any.whl"}}, {"metadata": {"name": "more-itertools", "version": "11.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/3d/1087453384dbde46a8c7f9356eead2c58be8a7bf156bca40243377c85715/more_itertools-11.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "9f62a1568e3800b7daf4b86289b6cb6a"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "httpx", "version": "0.24.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/91/e41f64f03d2a13aee7e8c819d82ee3aa7cdc484d18c0ae859742597d5aa0/httpx-0.24.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-httpx", "version": "0.22.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/23/a8438a0e11bc159d922a62c868593088b78285628e61f01c78bc1f1251e4/pytest_httpx-0.22.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.23.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ee/82/62e2d63639ecb0fbe8a7ee59ef0bc69a4669ec50f6d3459f74ad4e4189a2/pytest_asyncio-0.23.8-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "0.17.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/2c/2bde7ff8dd2064395555220cbf7cba79991172bf5315a07eb3ac7688d9f1/httpcore-0.17.3-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "7.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ff/f6e8b8f39e08547faece4bd80f89d5a8de68a38b2d179cc1c4490ffa3286/pytest-7.4.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/04/ff642e65ad6b90db43e668d70ffb6736436c7ce41fcc549f4e9472234127/h11-0.14.0-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}], "install_targets_hash": "9e9c7b973297953ce2add56028906265"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "google-genai", "version": "1.75.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2d/b6/552d40e96da22921eb1fead7c14b00b5b5473a20e45959488660fab35ee2/google_genai-1.75.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.55.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/1d/f6d3ca1ad0725f2e08a1c6915640748a52de2e66596160a4d53b010cccf0/google_auth-2.55.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/c6/65f646c7ff09bd257f660434adb45c4dfcbbcebcc030562fecf6f5bf887d/pydantic_core-2.46.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/26/08/0f303cb0b529e456bb116f2d50565a482694fbb94340bf56d44677e7ed03/charset_normalizer-3.4.7-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/40/904a4cb30d9b61c0e278899bf36342e9b0208eb3c470324a9ecbaac2a30f/websockets-16.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/2a/5bb823f5bedcf80718cea7fbc95ec5515cca3769633c4b01a32be7f30e7c/cryptography-49.0.0-cp39-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/84/ad6a0b408daa859246f57c03efd28e5dd1b33c21737c2db84cae8c237aa5/cffi-2.0.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/a0/7d793dce3fa811fe047d6ae2431c672364b462850c6235ae306c0efd025f/pyasn1-0.6.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "a021ecf98104048960d17180bcdfc8fa"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "langchain", "version": "1.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/85/86/cc13651cfda820d96ca8c612538166334935e8cf4331a31f5dd369d27760/langchain-1.4.2-py3-none-any.whl"}}, {"metadata": {"name": "langchain-core", "version": "1.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e6/18/cf18cfec118b02e003f35300b54d6a1173dc6e4905cffdf5ea49e390a7f9/langchain_core-1.6.3-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "jsonpatch", "version": "1.33"}, "download_info": {"url": "https://files.pythonhosted.org/packages/73/07/02e16ed01e04a374e644b575638ec7987ae846d25ad97bcc9945a3ee4b0e/jsonpatch-1.33-py2.py3-none-any.whl"}}, {"metadata": {"name": "langgraph", "version": "1.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0a/7f/c5c30e4be99ff821029c7ac872a480676bb179c9f3df85ea3f38d13f86d4/langgraph-1.2.11-py3-none-any.whl"}}, {"metadata": {"name": "langgraph-checkpoint", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/71/3b475f09bd57d3a5649792c66353312b4432afd843f301739dfcebd157f0/langgraph_checkpoint-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "langgraph-prebuilt", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/43/3fe1a700b8490ed02679cdbbc8c915eb23a092faf496c9c1118abcd10be3/langgraph_prebuilt-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "langgraph-sdk", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/43/d5/2ad7f3a835c6fcebf58b6669552536ecd52d2dfe4cf49c6c36648fd83572/langgraph_sdk-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "langsmith", "version": "0.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/51/892ff5a2efc8e222ca114dd0e19b56978f78a5ee62d3b33783588dd8e6d4/langsmith-0.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/34/a1/c8e6b66f499f510752c07a092dfe27621f9c255635e59d38704b5681c35a/pydantic_core-2.46.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7a/1e/7acc4f0e74c4b3d9531e24739e0ab832a5edf40e64fbae1a9c01941cabd7/pyyaml-6.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "uuid_utils", "version": "0.17.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/76/6b/516183ba5f7d35521edf8cfaea9b1192da8b262587faa8106d1f73ab0eb1/uuid_utils-0.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f3/18/a17e2f0cde02dc10154c808deed7e1d8528afff93612f70d3f0a5b19b011/websockets-16.1.1-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "3.16.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/17/72/2b1fe3e303db76ab2ba0c2de2b57822869bcb588db82334d4ff3aea8acf2/openai-3.16.2-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/2c/af9ca503b38683a82b6732352a861515f28e2d46fe445aea57e07fc86e06/jiter-0.17.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/af/c8/051e7b72a816ff50eb34a1c7c5b185cd2429ffdf59a497baea35b2b6b2dd/tiktoken-0.14.0-cp310-cp310-manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "langchain-openai", "version": "1.6.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b2/47/b87a3c372e52678eb4408360eadbe04cdd5371e21fe2560b6efd66989624/langchain_openai-1.6.2-py3-none-any.whl"}}, {"metadata": {"name": "langchain-community", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8f/39/5d97e42a3e95dc2a6d71b2f902a3fae71786131e11d01bddb604accb0ebe/langchain_community-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "langchain-classic", "version": "1.0.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/9a/b8f5cb7490fdbf233088031fc69c9c747439d4097f67f196c1eb4869916d/langchain_classic-1.0.8-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/ff/cb36724e8c8d17f90ada567a9ff3efe1d6e9b549fba697a242aece180f21/aiohttp-3.14.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "async-timeout", "version": "4.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/fa/e01228c2938de91d47b307831c62ab9e4001e747789d0b05baf779a6488c/async_timeout-4.0.3-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "langchain-text-splitters", "version": "1.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d3/26/1ef06f56198d631296d646a6223de35bcc6cf9795ceb2442816bc963b84c/langchain_text_splitters-1.1.2-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ea/e4/4ea1ab36ab8ed969c945f1abdc350e5865043b7466789d917735213d2369/multidict-6.9.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/cd/4f564b8f132de25db594efc706897069f016790cea63a5669c9df2675f64/charset_normalizer-3.5.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "SQLAlchemy", "version": "2.0.54"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/93/9d26b109f5472017bf6e7a1b9dac12ac5f6165ba37a297834d0690c42cf3/sqlalchemy-2.0.54-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "urllib3", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.25.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/28/b9/7818ac6dec7fbcd16be2d19495807c01e2c38834e57d41c63356a75e786b/yarl-1.25.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "google-genai", "version": "2.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/84/5b/87913fe392ba7b6402577259289ed3740c577956554a674b191a2971d33e/google_genai-2.24.0-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.58.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/59/13/477d90d09591b3938b45c4e11f4d8a51291682112cb5efcac961e815d562/google_auth-2.58.0-py3-none-any.whl"}}, {"metadata": {"name": "langchain-google-genai", "version": "4.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/10/83bb535e78c2cf767a6193c2f3b00b2894c1581a36ef85911ebaa3b9a891/langchain_google_genai-4.4.0-py3-none-any.whl"}}, {"metadata": {"name": "filetype", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/18/79/1b8fa1bb3568781e84c9200f951c735f3f157429f44be0495da55894d620/filetype-1.2.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8c/eb/5d7124083e8d8cda8f5b348f544b71ad6f707ad63193758ef4d8e569da02/cryptography-50.0.1-cp39-abi3-manylinux_2_34_x86_64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/75/77/60bebf6f818bec84210ac5b6979ce4eeadce6fbbaabc9c7ab23e506d1ce5/cffi-2.1.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/ed/c7895fd2fde7f3ee70d248175f9b6cdf792fb741ab92dc59cd9ef3bd241b/frozenlist-1.8.0-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl"}}, {"metadata": {"name": "greenlet", "version": "3.5.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/5c/092682ae7ca1aadd44aa36b0bc35c48c9ed55f9ffebb5794980b1e2ae74b/greenlet-3.5.6-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonpointer", "version": "3.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/6a/a83720e953b1682d2d109d3c2dbb0bc9bf28cc1cbc205be4ef4be5da709d/jsonpointer-3.1.1-py3-none-any.whl"}}, {"metadata": {"name": "langchain-protocol", "version": "0.0.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/80/c9/f6cbf357d48ccbd18bb394433b1fd7ad9be004eed9377ad08bb85777e5e6/langchain_protocol-0.0.19-py3-none-any.whl"}}, {"metadata": {"name": "numpy", "version": "2.2.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b4/63/3de6a34ad7ad6646ac7d2f55ebc6ad439dbbf9c4370017c50cf403fb19b5/numpy-2.2.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "orjson", "version": "3.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/75/20/930824c07685c22af23f26818ed3853b0270488a412b6ab757904b7f787b/orjson-3.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "ormsgpack", "version": "1.12.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/72/30/a436be9ce27d693d4e19fa94900028067133779f09fc45776db3f689c822/ormsgpack-1.12.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f0/51/5adee15e12a7e314cece4543fbf295b0fe1b504dc78b32dff4c8eb1e29b0/propcache-0.5.4-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/3b/6163796d69c3977d1e4287bea4a6979161cbbdd170ebb430511e8e1999ce/pyasn1-0.6.4-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "xxhash", "version": "4.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5f/3b/e5d20b4f602d15fc5fc066f601052a7d6f5a401a50d67fac92098a5829a5/xxhash-4.0.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "zstandard", "version": "0.25.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/e5/6d36f92a197c3c17729a2125e29c169f460538a7d939a27eaaa6dcfcba8e/zstandard-0.25.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.9.10"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/b2/be9fafe5e05888296fdd35d82ba9cbb67b0d352e9911fad3c458beb3a34a/regex-2026.9.10-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}], "install_targets_hash": "a282ef4988626dc6ebb6ab9deadd8e4b"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "starlette", "version": "0.20.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/37/8ac52116984d6a0d8502ec2c7e4a4a78f862b76410cdb1a4bcb384c91cb3/starlette-0.20.4-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/81/8e983840c6e5b93b33c2ba81aa3d52c2e42f0e9a690ce7607a2e61da4a5c/charset_normalizer-3.4.9-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}], "install_targets_hash": "a344a2d6c61f7e17d28378a4c4d05102"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "huggingface-hub", "version": "0.24.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/28/a0b0dd3cca63908045edc300360d6cd8758d4d86eee3fd2b08f00c5a41c4/huggingface_hub-0.24.7-py3-none-any.whl"}}, {"metadata": {"name": "responses", "version": "0.26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/28/693e1d9ebf72baa062ded80d837a035b86ce75eda5a269379e9e2b1008a8/responses-0.26.2-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/26/08/0f303cb0b529e456bb116f2d50565a482694fbb94340bf56d44677e7ed03/charset_normalizer-3.4.7-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-httpx", "version": "0.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/55/1fa65f8e4fceb19dd6daa867c162ad845d547f6058cd92b4b02384a44777/pytest_httpx-0.36.2-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e5/22/4222d7ddf3da30f363edaa98e329c2bce6c65497c9cb2810931c8b2c0fbc/fsspec-2026.6.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.68.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d8/8e/bb97bb0c71802080bfc8952937d174e49cfc50de5c951dd47b2496f0dcdb/tqdm-4.68.3-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "filelock", "version": "3.29.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4a/e3/f1fae3647d170919c2cf2a898e77e7d1a4e5c7cae0aed7bb4bd3f5ebff6f/filelock-3.29.5-py3-none-any.whl"}}], "install_targets_hash": "a5a1524ef8f136e98c6e71cf45c35bd4"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "huggingface-hub", "version": "0.24.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/28/a0b0dd3cca63908045edc300360d6cd8758d4d86eee3fd2b08f00c5a41c4/huggingface_hub-0.24.7-py3-none-any.whl"}}, {"metadata": {"name": "responses", "version": "0.26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/28/693e1d9ebf72baa062ded80d837a035b86ce75eda5a269379e9e2b1008a8/responses-0.26.2-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/26/08/0f303cb0b529e456bb116f2d50565a482694fbb94340bf56d44677e7ed03/charset_normalizer-3.4.7-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-httpx", "version": "0.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/55/1fa65f8e4fceb19dd6daa867c162ad845d547f6058cd92b4b02384a44777/pytest_httpx-0.36.2-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e5/22/4222d7ddf3da30f363edaa98e329c2bce6c65497c9cb2810931c8b2c0fbc/fsspec-2026.6.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.68.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d8/8e/bb97bb0c71802080bfc8952937d174e49cfc50de5c951dd47b2496f0dcdb/tqdm-4.68.3-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "filelock", "version": "3.29.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4a/e3/f1fae3647d170919c2cf2a898e77e7d1a4e5c7cae0aed7bb4bd3f5ebff6f/filelock-3.29.5-py3-none-any.whl"}}], "install_targets_hash": "a5a1524ef8f136e98c6e71cf45c35bd4"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "trytond", "version": "8.0.10"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/db/57a3be9504273276216dde241d3bc3602c9cae62f60afb1944cf651fe638/trytond-8.0.10-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "lxml", "version": "6.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a1/ce/dbea34cd115ae9b8ef53816daa912563615adf4daed42531878a2fb29c77/lxml-6.1.3-cp310-cp310-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/af/cd/ce6e848bbf2c32314c9b237839119c5a564a59725b53157c856e90937b7a/markupsafe-3.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "pwdlib", "version": "0.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6b/2e/51979293b2337f508597d13ee20db1ac1d43e48086b2ed7de6da213ed46b/pwdlib-0.3.1-py3-none-any.whl"}}, {"metadata": {"name": "argon2-cffi", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/d3/a8b22fa575b297cd6e3e3b0155c7e25db170edf1c74783d6a31a2490b8d9/argon2_cffi-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "python-sql", "version": "1.8.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/77/ac/3603bbdde340f7354c975431c94b70ef3e99966c5b170fa121f8e64d269e/python_sql-1.8.1-py3-none-any.whl"}}, {"metadata": {"name": "relatorio", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/74/eb/798c426ebd54f52c27aed6593eaf96ed07dca3ca1d084822cc34f0db5159/relatorio-1.0.0-py3-none-any.whl"}}, {"metadata": {"name": "Genshi", "version": "0.7.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/27/503016bc329720ba2856eb4831d6ba36089cd6f15bc4fe85db69fea5b563/genshi-0.7.11-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "argon2-cffi-bindings", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6f/86/5363df11b86d02cf3662208e7406496327649cc90eb365bf6f4e8a54a41f/argon2_cffi_bindings-26.1.0-cp310-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/75/77/60bebf6f818bec84210ac5b6979ce4eeadce6fbbaabc9c7ab23e506d1ce5/cffi-2.1.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "defusedxml", "version": "0.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "polib", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6b/99/45bb1f9926efe370c6dbe324741c749658e44cb060124f28dad201202274/polib-1.2.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "puremagic", "version": "1.30"}, "download_info": {"url": "https://files.pythonhosted.org/packages/91/ed/1e347d85d05b37a8b9a039ca832e5747e1e5248d0bd66042783ef48b4a37/puremagic-1.30-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "simpleeval", "version": "1.0.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/33/d1ecd9f4f5f272b36ad7b268e307ba0a59c109d8ad134a231cda780baac9/simpleeval-1.0.8-py3-none-any.whl"}}], "install_targets_hash": "ab391832abd062e60ebbad762fe1f443"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "cohere", "version": "7.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/4a/c3/064a44c498bf6ae8621caa14307d3ef5471157f149e33cfd64417c8e9ad3/cohere-7.1.1-py3-none-any.whl"}}, {"metadata": {"name": "fastavro", "version": "1.12.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/3c/91/16c3508447e7cf9f413a6a01792a990ed94d17505fc80a7fb76027078aed/fastavro-1.12.2-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/aa/554e2614f38fc34c58ff1d0911ae8535ad2516440d5482d76fe59f1088b0/charset_normalizer-3.5.1-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "tokenizers", "version": "0.23.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e2/6a/068ed9f6e444c9d7e9d55ce134181325700f3d7f30410721bdc8f848d727/tokenizers-0.23.1-cp310-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "huggingface_hub", "version": "1.29.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/4e/a5/47c2ea9b228ccbcba8467e9a64823146e8ebbad29855e591d8f5eedcc9c7/huggingface_hub-1.29.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/4b/69/55b8dcf636142ae660fec1869fcac14c4da2e8412e14d6eee1523be77e9f/hf_xet-1.6.0-cp38-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "types-requests", "version": "2.33.0.20260712"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/62/e7/010c87f559e216d83f9dc51e939633fd0d0ead3377340181ab0e223cd3b5/types_requests-2.33.0.20260712-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "filelock", "version": "3.32.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/36/d2/b70a31e13d04456d28493f31d2aa087e99eeb2767ef0293b2625727ccb8c/filelock-3.32.5-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.7.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/fd/3c/6a2bf344106328fd04963664a60b9bb6496fc25df8e962fcdc1367285fb9/fsspec-2026.7.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/bd/d0/c787604c71c2bdcda1a5656942fc822cd0f9cd879b9484bb84fc42172703/pydantic_core-2.46.5-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "ab733f16537c82282cb23e3e0416c9fc"} -{"python_version": "3.10", "dependencies": [{"metadata": {"name": "openai", "version": "3.16.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/17/72/2b1fe3e303db76ab2ba0c2de2b57822869bcb588db82334d4ff3aea8acf2/openai-3.16.2-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/2c/af9ca503b38683a82b6732352a861515f28e2d46fe445aea57e07fc86e06/jiter-0.17.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/34/a1/c8e6b66f499f510752c07a092dfe27621f9c255635e59d38704b5681c35a/pydantic_core-2.46.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/af/c8/051e7b72a816ff50eb34a1c7c5b185cd2429ffdf59a497baea35b2b6b2dd/tiktoken-0.14.0-cp310-cp310-manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.9.10"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/b2/be9fafe5e05888296fdd35d82ba9cbb67b0d352e9911fad3c458beb3a34a/regex-2026.9.10-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/cd/4f564b8f132de25db594efc706897069f016790cea63a5669c9df2675f64/charset_normalizer-3.5.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "urllib3", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "ac0b70b42bbda50724e182bcf918e944"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "ray", "version": "2.7.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7a/3e/9c2a270cfd1351a5df513f45c000c21cd8bc4b22a98a514b6eca0d888f2e/ray-2.7.2-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "setuptools", "version": "81.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/e3/c164c88b2e5ce7b24d667b9bd83589cf4f3520d97cad01534cd3c4f55fdb/setuptools-81.0.0-py3-none-any.whl"}}, {"metadata": {"name": "msgpack", "version": "1.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e4/3c/08ecd5cdfe4e2de43aec79062028ad0f7b2d9b1fea5430068c198ba570da/msgpack-1.2.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "numpy", "version": "2.2.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/77/dc2fcfc66943c6410e2bf598062f5959372735ffda175b39906d54f02349/numpy-2.2.6-cp310-cp310-macosx_14_0_arm64.whl"}}, {"metadata": {"name": "protobuf", "version": "7.35.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/03/8aeeb7458d22546bf64b5250ca1daeb5ff757d900e8e4a7476c6f0db843e/protobuf-7.35.1-cp310-abi3-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/70/26ca3f06aace16f2352796b08704338d74b6d1a24ca38f2771afbb7ed915/frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "filelock", "version": "3.29.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4a/e3/f1fae3647d170919c2cf2a898e77e7d1a4e5c7cae0aed7bb4bd3f5ebff6f/filelock-3.29.5-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "0.30.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/6a/4ba3d0fb7297ebae71171822554abe48d7cab29c28b8f9f2c04b79988c05/rpds_py-0.30.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/26/08/0f303cb0b529e456bb116f2d50565a482694fbb94340bf56d44677e7ed03/charset_normalizer-3.4.7-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}], "install_targets_hash": "ad451cdabab2f03c19f03edf7f7b19e6"} -{"python_version": "3.10", "dependencies": [{"metadata": {"name": "fastapi", "version": "0.79.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/29/95/31db8826daec0bfc9a4bb6ceac3ceeb7e8e6c6b81b6d204aaec788445c8c/fastapi-0.79.1-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "0.19.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/9d/1fa96008b302dd3e398f89f3fc5afb19fb0b0f341fefa05c65b3a38d64cf/starlette-0.19.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "1.10.26"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/e6/10df5f08c105bcbb4adbee7d1108ff4b347702b110fed058f6a03f1c6b73/pydantic-1.10.26-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/26/08/0f303cb0b529e456bb116f2d50565a482694fbb94340bf56d44677e7ed03/charset_normalizer-3.4.7-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}], "install_targets_hash": "ad4cf39e76d2eefdf95ba4058faa7738"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "grpcio", "version": "1.84.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f7/41/90292bf55af7aa09de0e3ec928d1b8c56d477f85244f7928d2231630b781/grpcio-1.84.0-cp310-cp310-macosx_11_0_universal2.whl"}}, {"metadata": {"name": "protobuf", "version": "7.36.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f7/6c/3a54a58f2948b0f485df9ecdd06590f15d0a7abf46a89d50c3de709ff4ff/protobuf-7.36.1-cp310-abi3-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "mypy-protobuf", "version": "5.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/ec/5ffcf8f5f53757e01afdece10c664e694ac60d2f17c2036811b85b842a5b/mypy_protobuf-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "types-protobuf", "version": "7.35.1.20260906"}, "download_info": {"url": "https://files.pythonhosted.org/packages/44/4e/f63e826c68f77ef875506d72f225918800346545ee99847bc28f3394f18d/types_protobuf-7.35.1.20260906-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.7.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/18/f1/46d32fe4b9aae09fe397e768ff376d9b6bdbb4f11faaa727f163c3457b43/pytest_forked-1.7.5-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}], "install_targets_hash": "b000c682d30e09087f05bd957ebe7664"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "grpcio", "version": "1.84.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/7c/da97476f3c2e90e9f00bfb19def7cbb5f841b7661e3cd09c6a89beaa5b98/grpcio-1.84.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "protobuf", "version": "7.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/db/f3/3996583dd2906297a637af12114deddf7658af6e683fedb83be061983fb5/protobuf-7.36.2-cp310-abi3-manylinux2014_x86_64.whl"}}, {"metadata": {"name": "mypy-protobuf", "version": "5.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/ec/5ffcf8f5f53757e01afdece10c664e694ac60d2f17c2036811b85b842a5b/mypy_protobuf-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "types-protobuf", "version": "7.35.1.20260906"}, "download_info": {"url": "https://files.pythonhosted.org/packages/44/4e/f63e826c68f77ef875506d72f225918800346545ee99847bc28f3394f18d/types_protobuf-7.35.1.20260906-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.7.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/18/f1/46d32fe4b9aae09fe397e768ff376d9b6bdbb4f11faaa727f163c3457b43/pytest_forked-1.7.5-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}], "install_targets_hash": "b000c682d30e09087f05bd957ebe7664"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "apache-beam", "version": "2.77.0rc1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/95/0a/07ce3e91322bf7756e8ed156ec667c2108f49f60b44392931a5ab18d40db/apache_beam-2.77.0rc1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "betterproto", "version": "2.0.0b6"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/99/6d/007abe4bf14cd02a3c07710c22f0e3252b55b06678de2535ae5f03b7433a/betterproto-2.0.0b6-py3-none-any.whl"}}, {"metadata": {"name": "beartype", "version": "0.22.9"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/cc/18245721fa7747065ab478316c7fea7c74777d07f37ae60db2e84f8172e8/beartype-0.22.9-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/84/a9/ee16a903f13755e914d1eecc482fe64d1f10761c3960e5d8fa6837377aff/cryptography-50.0.1-cp39-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "fastavro", "version": "1.12.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/3c/91/16c3508447e7cf9f413a6a01792a990ed94d17505fc80a7fb76027078aed/fastavro-1.12.2-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "fasteners", "version": "0.20"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/51/ac/e5d886f892666d2d1e5cb8c1a41146e1d79ae8896477b1153a21711d3b44/fasteners-0.20-py3-none-any.whl"}}, {"metadata": {"name": "grpcio", "version": "1.84.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/f7/41/90292bf55af7aa09de0e3ec928d1b8c56d477f85244f7928d2231630b781/grpcio-1.84.0-cp310-cp310-macosx_11_0_universal2.whl"}}, {"metadata": {"name": "grpclib", "version": "0.4.9"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/5c/90/b0cbbd9efcc82816c58f31a34963071aa19fb792a212a5d9caf8e0fc3097/grpclib-0.4.9-py3-none-any.whl"}}, {"metadata": {"name": "h2", "version": "4.4.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/22/e85faf23bd72a92d1921e37d674ca56eb298a3c8be31fdecef0ff2b3aaac/h2-4.4.1-py3-none-any.whl"}}, {"metadata": {"name": "hpack", "version": "4.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/b4/4a9fcfb2aef6ba44d9073ecd301443aa00b3dac95de5619f2a7de7ec8a91/hpack-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "httplib2", "version": "0.32.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/33/a0/550eec327e5f5c7b732531c489f5307efec41f047b0d703bd4ca1e5ad2db/httplib2-0.32.0-py3-none-any.whl"}}, {"metadata": {"name": "hyperframe", "version": "6.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/48/30/47d0bf6072f7252e6521f3447ccfa40b421b6824517f82854703d0f5a98b/hyperframe-6.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonpickle", "version": "4.1.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a1/7b/fd3c7a09649aea9da1d3587aea624d8f9b29963dfd84a1bdb2aa93b36dac/jsonpickle-4.1.2-py3-none-any.whl"}}, {"metadata": {"name": "numpy", "version": "2.2.6"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/fd/77/dc2fcfc66943c6410e2bf598062f5959372735ffda175b39906d54f02349/numpy-2.2.6-cp310-cp310-macosx_14_0_arm64.whl"}}, {"metadata": {"name": "objsize", "version": "0.7.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/f3/a7/55f8f3853a4a654d3a6fbf63e646e0b469b52c174703a10db70a1cb06c7e/objsize-0.7.1-py3-none-any.whl"}}, {"metadata": {"name": "pillow", "version": "12.3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/6b/ba/3762f376a2948e3036488d773a146e0ae6ecc2ca03ac20e2615bd0b2ba02/pillow-12.3.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "proto-plus", "version": "1.28.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/41/5d/0f04b85dafdc3250ced7f2592efc17dce7f40712e941e9632202481e600d/proto_plus-1.28.4-py3-none-any.whl"}}, {"metadata": {"name": "protobuf", "version": "6.33.6"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/5c/01/a3c3ed5cd186f39e7880f8303cc51385a198a81469d53d0fdecf1f64d929/protobuf-6.33.6-cp39-abi3-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "pyarrow", "version": "25.0.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0a/3e/5cd70becb51e1d044c54ba5e627424a6e87df5b98008cbd22cc6abd409ca/pyarrow-25.0.1-cp310-cp310-macosx_12_0_arm64.whl"}}, {"metadata": {"name": "pymongo", "version": "4.18.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cc/fe/446e84df654150f0bb61005c1637f58571d2d2a82512a6c269fc7a617f3d/pymongo-4.18.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "dnspython", "version": "2.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "pyparsing", "version": "3.3.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/38/bb/d215ee7c73b61497b28a5503f9f53523f294fcc936762b7caf90e0c1c2b5/pyparsing-3.3.3-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/aa/554e2614f38fc34c58ff1d0911ae8535ad2516440d5482d76fe59f1088b0/charset_normalizer-3.5.1-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "zstandard", "version": "0.25.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/96/34/ef34ef77f1ee38fc8e4f9775217a613b452916e633c4f1d98f31db52c4a5/zstandard-0.25.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "dill", "version": "0.4.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/1e/77/dc8c558f7593132cf8fefec57c4f60c83b16941c574ac5f619abb3ae7933/dill-0.4.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/94/1a/4b2f7c92293ba05cbd4a9a1b28faaf0326272d9488e6354657571c48a7aa/cffi-2.1.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pytz", "version": "2026.3.post1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0f/7b/39c34ca613b0b198cb866466651b26b045e2009864c5183c979a3b83f383/pytz-2026.3.post1-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.9.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e0/89/b845535014a9ad50537ca50204aaf6351c5368822a3acd9da854fb2a5a34/multidict-6.9.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "b3a715bfab67760cac2023319d4ff7fc"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9e/73b582c4dbbc3c12ef4473822475effaabf1f934b56f14f5b03fe5d3a2af/aiohttp-3.14.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/31/5c/08c7f7fe311f32e83f7621cd3f99d805f45519cd06fafb247628b861da7d/multidict-6.7.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/59/1d/340d1a0db7bbce1f291afc044255ebf4ebbce2b25ab1b3f7d3d069080f5d/yarl-1.24.5-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-aiohttp", "version": "1.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fa/b0/5056ed4c3f68a4db2b4a39fb0ec61b1e4cf1d89ee14effe5261cc587264c/pytest_aiohttp-1.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/70/26ca3f06aace16f2352796b08704338d74b6d1a24ca38f2771afbb7ed915/frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/42/0e7443c90310498561addf346e7d57fe3c6ba1914e1ba938b5464c7bbfd2/propcache-0.5.2-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}], "install_targets_hash": "b580cd1bfd98254876a1e968bf8d9af2"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "ariadne", "version": "0.20.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e4/7c/6ca01607e6dc23472ab599507af67e9b4db9868e4baf8477fcafe958af00/ariadne-0.20.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/15/b92b4e1d88d02c6eff9733c9eea21846ab435cc4d813d84ccc5d335955df/graphql_core-3.2.11-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "0.52.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/0d/13d1d239a25cbfb19e740db83143e95c772a1fe10202dda4b76792b114dd/starlette-0.52.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "fastapi", "version": "0.139.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/7c/8e3c6ad324ea5cb36604fc3f968554887891c316d9dfde57761611d907ad/fastapi-0.139.0-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/c6/65f646c7ff09bd257f660434adb45c4dfcbbcebcc030562fecf6f5bf887d/pydantic_core-2.46.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "ba34689285beeef10583bc1d6faea8b5"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "ariadne", "version": "0.20.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e4/7c/6ca01607e6dc23472ab599507af67e9b4db9868e4baf8477fcafe958af00/ariadne-0.20.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/15/b92b4e1d88d02c6eff9733c9eea21846ab435cc4d813d84ccc5d335955df/graphql_core-3.2.11-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "0.52.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/0d/13d1d239a25cbfb19e740db83143e95c772a1fe10202dda4b76792b114dd/starlette-0.52.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "fastapi", "version": "0.139.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/7c/8e3c6ad324ea5cb36604fc3f968554887891c316d9dfde57761611d907ad/fastapi-0.139.0-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/c6/65f646c7ff09bd257f660434adb45c4dfcbbcebcc030562fecf6f5bf887d/pydantic_core-2.46.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "ba34689285beeef10583bc1d6faea8b5"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "ariadne", "version": "0.20.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e4/7c/6ca01607e6dc23472ab599507af67e9b4db9868e4baf8477fcafe958af00/ariadne-0.20.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/15/b92b4e1d88d02c6eff9733c9eea21846ab435cc4d813d84ccc5d335955df/graphql_core-3.2.11-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "0.52.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/0d/13d1d239a25cbfb19e740db83143e95c772a1fe10202dda4b76792b114dd/starlette-0.52.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "fastapi", "version": "0.139.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/7c/8e3c6ad324ea5cb36604fc3f968554887891c316d9dfde57761611d907ad/fastapi-0.139.0-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/c6/65f646c7ff09bd257f660434adb45c4dfcbbcebcc030562fecf6f5bf887d/pydantic_core-2.46.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "ba34689285beeef10583bc1d6faea8b5"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "ariadne", "version": "0.20.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e4/7c/6ca01607e6dc23472ab599507af67e9b4db9868e4baf8477fcafe958af00/ariadne-0.20.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/15/b92b4e1d88d02c6eff9733c9eea21846ab435cc4d813d84ccc5d335955df/graphql_core-3.2.11-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "0.52.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/0d/13d1d239a25cbfb19e740db83143e95c772a1fe10202dda4b76792b114dd/starlette-0.52.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "fastapi", "version": "0.139.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/7c/8e3c6ad324ea5cb36604fc3f968554887891c316d9dfde57761611d907ad/fastapi-0.139.0-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/c6/65f646c7ff09bd257f660434adb45c4dfcbbcebcc030562fecf6f5bf887d/pydantic_core-2.46.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "ba34689285beeef10583bc1d6faea8b5"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "ariadne", "version": "0.20.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e4/7c/6ca01607e6dc23472ab599507af67e9b4db9868e4baf8477fcafe958af00/ariadne-0.20.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/15/b92b4e1d88d02c6eff9733c9eea21846ab435cc4d813d84ccc5d335955df/graphql_core-3.2.11-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "0.52.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/0d/13d1d239a25cbfb19e740db83143e95c772a1fe10202dda4b76792b114dd/starlette-0.52.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "fastapi", "version": "0.139.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/7c/8e3c6ad324ea5cb36604fc3f968554887891c316d9dfde57761611d907ad/fastapi-0.139.0-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/c6/65f646c7ff09bd257f660434adb45c4dfcbbcebcc030562fecf6f5bf887d/pydantic_core-2.46.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "ba34689285beeef10583bc1d6faea8b5"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "ariadne", "version": "0.20.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e4/7c/6ca01607e6dc23472ab599507af67e9b4db9868e4baf8477fcafe958af00/ariadne-0.20.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/15/b92b4e1d88d02c6eff9733c9eea21846ab435cc4d813d84ccc5d335955df/graphql_core-3.2.11-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "0.52.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/0d/13d1d239a25cbfb19e740db83143e95c772a1fe10202dda4b76792b114dd/starlette-0.52.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "fastapi", "version": "0.139.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/7c/8e3c6ad324ea5cb36604fc3f968554887891c316d9dfde57761611d907ad/fastapi-0.139.0-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/c6/65f646c7ff09bd257f660434adb45c4dfcbbcebcc030562fecf6f5bf887d/pydantic_core-2.46.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "ba34689285beeef10583bc1d6faea8b5"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "ariadne", "version": "0.20.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e4/7c/6ca01607e6dc23472ab599507af67e9b4db9868e4baf8477fcafe958af00/ariadne-0.20.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/15/b92b4e1d88d02c6eff9733c9eea21846ab435cc4d813d84ccc5d335955df/graphql_core-3.2.11-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "0.52.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/0d/13d1d239a25cbfb19e740db83143e95c772a1fe10202dda4b76792b114dd/starlette-0.52.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "fastapi", "version": "0.139.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/7c/8e3c6ad324ea5cb36604fc3f968554887891c316d9dfde57761611d907ad/fastapi-0.139.0-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/c6/65f646c7ff09bd257f660434adb45c4dfcbbcebcc030562fecf6f5bf887d/pydantic_core-2.46.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "ba34689285beeef10583bc1d6faea8b5"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "sanic", "version": "25.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/91/5ecd9a91374a7b2831cf183357ceeb609fdfc8b390adb5cac90a261fe1f8/sanic-25.12.1-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/7a/bd0ce7ac1cfafc76c84d6e8051bcbd0f7def8e45207230833bd6ff77a41d/websockets-10.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/31/5c/08c7f7fe311f32e83f7621cd3f99d805f45519cd06fafb247628b861da7d/multidict-6.7.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/c1/316c8f3549dbe5245f92bfd523ec6f32dd4d98cafe21df3f6a19b1184c75/aiohttp-3.14.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/8f/7b3ec212f1ea0683f55f978e3246bc313c38818664edfc97a9f349a4901e/yarl-1.24.2-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-testing", "version": "24.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/93/1d588f1cb9b710b9f22fa78b53d699a8062edc94204d50dd0d78c5f5b495/sanic_testing-24.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/70/26ca3f06aace16f2352796b08704338d74b6d1a24ca38f2771afbb7ed915/frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "html5tagger", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/12/2f5d43ee912ea14a6baba4b3db6d309b02d932e3b7074c3339b4aded98ff/html5tagger-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "httptools", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/f7/b4d41eaae2869d31356bc4bbf546f44fae83ff298af0a043ca0625b06773/httptools-0.8.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/42/0e7443c90310498561addf346e7d57fe3c6ba1914e1ba938b5464c7bbfd2/propcache-0.5.2-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-routing", "version": "23.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/e3/3425c9a8773807ac2c01d6a56c8521733f09b627e5827e733c5cd36b9ac5/sanic_routing-23.12.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "83.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/40/e1e72872c6354b306daef1703549e8e83b4d43cfea356311bf722a043752/setuptools-83.0.0-py3-none-any.whl"}}, {"metadata": {"name": "tracerite", "version": "2.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b6/62/3f385a67ff3cc91209f107d20bbebdecf7a4e4aba55a43f9f71bddc424a9/tracerite-2.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "5.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8e/d2/92e83af35cd65d3b7c47fb0e24927aa2b478897af8b0dd0ee19abcd50c03/ujson-5.13.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "uvloop", "version": "0.22.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/14/ecceb239b65adaaf7fde510aa8bd534075695d1e5f8dadfa32b5723d9cfb/uvloop-0.22.1-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}], "install_targets_hash": "bdb1f2a8b2b051b4d694fd87001bee9b"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "sanic", "version": "25.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/91/5ecd9a91374a7b2831cf183357ceeb609fdfc8b390adb5cac90a261fe1f8/sanic-25.12.1-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/7a/bd0ce7ac1cfafc76c84d6e8051bcbd0f7def8e45207230833bd6ff77a41d/websockets-10.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/31/5c/08c7f7fe311f32e83f7621cd3f99d805f45519cd06fafb247628b861da7d/multidict-6.7.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/c1/316c8f3549dbe5245f92bfd523ec6f32dd4d98cafe21df3f6a19b1184c75/aiohttp-3.14.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/8f/7b3ec212f1ea0683f55f978e3246bc313c38818664edfc97a9f349a4901e/yarl-1.24.2-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-testing", "version": "24.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/93/1d588f1cb9b710b9f22fa78b53d699a8062edc94204d50dd0d78c5f5b495/sanic_testing-24.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/70/26ca3f06aace16f2352796b08704338d74b6d1a24ca38f2771afbb7ed915/frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "html5tagger", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/12/2f5d43ee912ea14a6baba4b3db6d309b02d932e3b7074c3339b4aded98ff/html5tagger-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "httptools", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/f7/b4d41eaae2869d31356bc4bbf546f44fae83ff298af0a043ca0625b06773/httptools-0.8.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/42/0e7443c90310498561addf346e7d57fe3c6ba1914e1ba938b5464c7bbfd2/propcache-0.5.2-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-routing", "version": "23.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/e3/3425c9a8773807ac2c01d6a56c8521733f09b627e5827e733c5cd36b9ac5/sanic_routing-23.12.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "83.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/40/e1e72872c6354b306daef1703549e8e83b4d43cfea356311bf722a043752/setuptools-83.0.0-py3-none-any.whl"}}, {"metadata": {"name": "tracerite", "version": "2.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b6/62/3f385a67ff3cc91209f107d20bbebdecf7a4e4aba55a43f9f71bddc424a9/tracerite-2.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "5.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8e/d2/92e83af35cd65d3b7c47fb0e24927aa2b478897af8b0dd0ee19abcd50c03/ujson-5.13.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "uvloop", "version": "0.22.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/14/ecceb239b65adaaf7fde510aa8bd534075695d1e5f8dadfa32b5723d9cfb/uvloop-0.22.1-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}], "install_targets_hash": "bdb1f2a8b2b051b4d694fd87001bee9b"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "sanic", "version": "25.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/91/5ecd9a91374a7b2831cf183357ceeb609fdfc8b390adb5cac90a261fe1f8/sanic-25.12.1-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/7a/bd0ce7ac1cfafc76c84d6e8051bcbd0f7def8e45207230833bd6ff77a41d/websockets-10.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/31/5c/08c7f7fe311f32e83f7621cd3f99d805f45519cd06fafb247628b861da7d/multidict-6.7.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/c1/316c8f3549dbe5245f92bfd523ec6f32dd4d98cafe21df3f6a19b1184c75/aiohttp-3.14.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/8f/7b3ec212f1ea0683f55f978e3246bc313c38818664edfc97a9f349a4901e/yarl-1.24.2-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-testing", "version": "24.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/93/1d588f1cb9b710b9f22fa78b53d699a8062edc94204d50dd0d78c5f5b495/sanic_testing-24.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/70/26ca3f06aace16f2352796b08704338d74b6d1a24ca38f2771afbb7ed915/frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "html5tagger", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/12/2f5d43ee912ea14a6baba4b3db6d309b02d932e3b7074c3339b4aded98ff/html5tagger-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "httptools", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/f7/b4d41eaae2869d31356bc4bbf546f44fae83ff298af0a043ca0625b06773/httptools-0.8.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/42/0e7443c90310498561addf346e7d57fe3c6ba1914e1ba938b5464c7bbfd2/propcache-0.5.2-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-routing", "version": "23.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/e3/3425c9a8773807ac2c01d6a56c8521733f09b627e5827e733c5cd36b9ac5/sanic_routing-23.12.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "83.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/40/e1e72872c6354b306daef1703549e8e83b4d43cfea356311bf722a043752/setuptools-83.0.0-py3-none-any.whl"}}, {"metadata": {"name": "tracerite", "version": "2.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b6/62/3f385a67ff3cc91209f107d20bbebdecf7a4e4aba55a43f9f71bddc424a9/tracerite-2.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "5.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8e/d2/92e83af35cd65d3b7c47fb0e24927aa2b478897af8b0dd0ee19abcd50c03/ujson-5.13.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "uvloop", "version": "0.22.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/14/ecceb239b65adaaf7fde510aa8bd534075695d1e5f8dadfa32b5723d9cfb/uvloop-0.22.1-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}], "install_targets_hash": "bdb1f2a8b2b051b4d694fd87001bee9b"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "sanic", "version": "25.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/91/5ecd9a91374a7b2831cf183357ceeb609fdfc8b390adb5cac90a261fe1f8/sanic-25.12.1-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/7a/bd0ce7ac1cfafc76c84d6e8051bcbd0f7def8e45207230833bd6ff77a41d/websockets-10.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/31/5c/08c7f7fe311f32e83f7621cd3f99d805f45519cd06fafb247628b861da7d/multidict-6.7.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/c1/316c8f3549dbe5245f92bfd523ec6f32dd4d98cafe21df3f6a19b1184c75/aiohttp-3.14.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/8f/7b3ec212f1ea0683f55f978e3246bc313c38818664edfc97a9f349a4901e/yarl-1.24.2-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-testing", "version": "24.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/93/1d588f1cb9b710b9f22fa78b53d699a8062edc94204d50dd0d78c5f5b495/sanic_testing-24.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/70/26ca3f06aace16f2352796b08704338d74b6d1a24ca38f2771afbb7ed915/frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "html5tagger", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/12/2f5d43ee912ea14a6baba4b3db6d309b02d932e3b7074c3339b4aded98ff/html5tagger-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "httptools", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/f7/b4d41eaae2869d31356bc4bbf546f44fae83ff298af0a043ca0625b06773/httptools-0.8.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/42/0e7443c90310498561addf346e7d57fe3c6ba1914e1ba938b5464c7bbfd2/propcache-0.5.2-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-routing", "version": "23.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/e3/3425c9a8773807ac2c01d6a56c8521733f09b627e5827e733c5cd36b9ac5/sanic_routing-23.12.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "83.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/40/e1e72872c6354b306daef1703549e8e83b4d43cfea356311bf722a043752/setuptools-83.0.0-py3-none-any.whl"}}, {"metadata": {"name": "tracerite", "version": "2.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b6/62/3f385a67ff3cc91209f107d20bbebdecf7a4e4aba55a43f9f71bddc424a9/tracerite-2.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "5.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8e/d2/92e83af35cd65d3b7c47fb0e24927aa2b478897af8b0dd0ee19abcd50c03/ujson-5.13.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "uvloop", "version": "0.22.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/14/ecceb239b65adaaf7fde510aa8bd534075695d1e5f8dadfa32b5723d9cfb/uvloop-0.22.1-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}], "install_targets_hash": "bdb1f2a8b2b051b4d694fd87001bee9b"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "sanic", "version": "25.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/91/5ecd9a91374a7b2831cf183357ceeb609fdfc8b390adb5cac90a261fe1f8/sanic-25.12.1-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/7a/bd0ce7ac1cfafc76c84d6e8051bcbd0f7def8e45207230833bd6ff77a41d/websockets-10.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/31/5c/08c7f7fe311f32e83f7621cd3f99d805f45519cd06fafb247628b861da7d/multidict-6.7.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/c1/316c8f3549dbe5245f92bfd523ec6f32dd4d98cafe21df3f6a19b1184c75/aiohttp-3.14.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/8f/7b3ec212f1ea0683f55f978e3246bc313c38818664edfc97a9f349a4901e/yarl-1.24.2-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-testing", "version": "24.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/93/1d588f1cb9b710b9f22fa78b53d699a8062edc94204d50dd0d78c5f5b495/sanic_testing-24.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/70/26ca3f06aace16f2352796b08704338d74b6d1a24ca38f2771afbb7ed915/frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "html5tagger", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/12/2f5d43ee912ea14a6baba4b3db6d309b02d932e3b7074c3339b4aded98ff/html5tagger-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "httptools", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/f7/b4d41eaae2869d31356bc4bbf546f44fae83ff298af0a043ca0625b06773/httptools-0.8.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/42/0e7443c90310498561addf346e7d57fe3c6ba1914e1ba938b5464c7bbfd2/propcache-0.5.2-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-routing", "version": "23.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/e3/3425c9a8773807ac2c01d6a56c8521733f09b627e5827e733c5cd36b9ac5/sanic_routing-23.12.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "83.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/40/e1e72872c6354b306daef1703549e8e83b4d43cfea356311bf722a043752/setuptools-83.0.0-py3-none-any.whl"}}, {"metadata": {"name": "tracerite", "version": "2.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b6/62/3f385a67ff3cc91209f107d20bbebdecf7a4e4aba55a43f9f71bddc424a9/tracerite-2.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "5.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8e/d2/92e83af35cd65d3b7c47fb0e24927aa2b478897af8b0dd0ee19abcd50c03/ujson-5.13.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "uvloop", "version": "0.22.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/14/ecceb239b65adaaf7fde510aa8bd534075695d1e5f8dadfa32b5723d9cfb/uvloop-0.22.1-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}], "install_targets_hash": "bdb1f2a8b2b051b4d694fd87001bee9b"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "sanic", "version": "25.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/91/5ecd9a91374a7b2831cf183357ceeb609fdfc8b390adb5cac90a261fe1f8/sanic-25.12.1-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/7a/bd0ce7ac1cfafc76c84d6e8051bcbd0f7def8e45207230833bd6ff77a41d/websockets-10.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/31/5c/08c7f7fe311f32e83f7621cd3f99d805f45519cd06fafb247628b861da7d/multidict-6.7.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/c1/316c8f3549dbe5245f92bfd523ec6f32dd4d98cafe21df3f6a19b1184c75/aiohttp-3.14.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/8f/7b3ec212f1ea0683f55f978e3246bc313c38818664edfc97a9f349a4901e/yarl-1.24.2-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-testing", "version": "24.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/93/1d588f1cb9b710b9f22fa78b53d699a8062edc94204d50dd0d78c5f5b495/sanic_testing-24.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/70/26ca3f06aace16f2352796b08704338d74b6d1a24ca38f2771afbb7ed915/frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "html5tagger", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/12/2f5d43ee912ea14a6baba4b3db6d309b02d932e3b7074c3339b4aded98ff/html5tagger-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "httptools", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/f7/b4d41eaae2869d31356bc4bbf546f44fae83ff298af0a043ca0625b06773/httptools-0.8.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/42/0e7443c90310498561addf346e7d57fe3c6ba1914e1ba938b5464c7bbfd2/propcache-0.5.2-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-routing", "version": "23.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/e3/3425c9a8773807ac2c01d6a56c8521733f09b627e5827e733c5cd36b9ac5/sanic_routing-23.12.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "83.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/40/e1e72872c6354b306daef1703549e8e83b4d43cfea356311bf722a043752/setuptools-83.0.0-py3-none-any.whl"}}, {"metadata": {"name": "tracerite", "version": "2.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b6/62/3f385a67ff3cc91209f107d20bbebdecf7a4e4aba55a43f9f71bddc424a9/tracerite-2.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "5.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8e/d2/92e83af35cd65d3b7c47fb0e24927aa2b478897af8b0dd0ee19abcd50c03/ujson-5.13.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "uvloop", "version": "0.22.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/14/ecceb239b65adaaf7fde510aa8bd534075695d1e5f8dadfa32b5723d9cfb/uvloop-0.22.1-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}], "install_targets_hash": "bdb1f2a8b2b051b4d694fd87001bee9b"} -{"python_version": "3.10", "dependencies": [{"metadata": {"name": "mcp", "version": "1.30.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f5/f4/e58bc33317c92a0203664daaf00bf6f41166cc0149e5d6870a03f7cd004a/mcp-1.30.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/34/a1/c8e6b66f499f510752c07a092dfe27621f9c255635e59d38704b5681c35a/pydantic_core-2.46.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/97/672cb32ce0dfea44b740cb7b4f97038463b9cf7c0ead1aacf595572851d6/pyjwt-2.14.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8c/eb/5d7124083e8d8cda8f5b348f544b71ad6f707ad63193758ef4d8e569da02/cryptography-50.0.1-cp39-abi3-manylinux_2_34_x86_64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/75/77/60bebf6f818bec84210ac5b6979ce4eeadce6fbbaabc9c7ab23e506d1ce5/cffi-2.1.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "0.30.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/61/b5/707f6cf0066a6412aacc11d17920ea2e19e5b2f04081c64526eb35b5c6e7/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/6a/2ba3ed4a69babf3afdddf7d8314a48d87562c0a442206bbc2a1b50d5efc0/sse_starlette-3.4.11-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.52.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/79/4a20b54ab0491485ccd8c077db2d39187c7f12b3e15485d38a7be37c81b4/uvicorn-0.52.4-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "c22f32eaa2bf5c7f62806b63fcde2d83"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "sanic", "version": "25.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/91/5ecd9a91374a7b2831cf183357ceeb609fdfc8b390adb5cac90a261fe1f8/sanic-25.12.1-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/7a/bd0ce7ac1cfafc76c84d6e8051bcbd0f7def8e45207230833bd6ff77a41d/websockets-10.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/31/5c/08c7f7fe311f32e83f7621cd3f99d805f45519cd06fafb247628b861da7d/multidict-6.7.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/c1/316c8f3549dbe5245f92bfd523ec6f32dd4d98cafe21df3f6a19b1184c75/aiohttp-3.14.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/8f/7b3ec212f1ea0683f55f978e3246bc313c38818664edfc97a9f349a4901e/yarl-1.24.2-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-testing", "version": "24.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/93/1d588f1cb9b710b9f22fa78b53d699a8062edc94204d50dd0d78c5f5b495/sanic_testing-24.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/70/26ca3f06aace16f2352796b08704338d74b6d1a24ca38f2771afbb7ed915/frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "html5tagger", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/12/2f5d43ee912ea14a6baba4b3db6d309b02d932e3b7074c3339b4aded98ff/html5tagger-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "httptools", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/f7/b4d41eaae2869d31356bc4bbf546f44fae83ff298af0a043ca0625b06773/httptools-0.8.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/42/0e7443c90310498561addf346e7d57fe3c6ba1914e1ba938b5464c7bbfd2/propcache-0.5.2-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-routing", "version": "23.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/e3/3425c9a8773807ac2c01d6a56c8521733f09b627e5827e733c5cd36b9ac5/sanic_routing-23.12.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "83.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/40/e1e72872c6354b306daef1703549e8e83b4d43cfea356311bf722a043752/setuptools-83.0.0-py3-none-any.whl"}}, {"metadata": {"name": "tracerite", "version": "2.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b6/62/3f385a67ff3cc91209f107d20bbebdecf7a4e4aba55a43f9f71bddc424a9/tracerite-2.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "5.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8e/d2/92e83af35cd65d3b7c47fb0e24927aa2b478897af8b0dd0ee19abcd50c03/ujson-5.13.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "uvloop", "version": "0.22.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/14/ecceb239b65adaaf7fde510aa8bd534075695d1e5f8dadfa32b5723d9cfb/uvloop-0.22.1-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}], "install_targets_hash": "bdb1f2a8b2b051b4d694fd87001bee9b"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "sanic", "version": "25.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/91/5ecd9a91374a7b2831cf183357ceeb609fdfc8b390adb5cac90a261fe1f8/sanic-25.12.1-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/7a/bd0ce7ac1cfafc76c84d6e8051bcbd0f7def8e45207230833bd6ff77a41d/websockets-10.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/31/5c/08c7f7fe311f32e83f7621cd3f99d805f45519cd06fafb247628b861da7d/multidict-6.7.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/c1/316c8f3549dbe5245f92bfd523ec6f32dd4d98cafe21df3f6a19b1184c75/aiohttp-3.14.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/8f/7b3ec212f1ea0683f55f978e3246bc313c38818664edfc97a9f349a4901e/yarl-1.24.2-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-testing", "version": "24.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/93/1d588f1cb9b710b9f22fa78b53d699a8062edc94204d50dd0d78c5f5b495/sanic_testing-24.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/70/26ca3f06aace16f2352796b08704338d74b6d1a24ca38f2771afbb7ed915/frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "html5tagger", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/12/2f5d43ee912ea14a6baba4b3db6d309b02d932e3b7074c3339b4aded98ff/html5tagger-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "httptools", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/f7/b4d41eaae2869d31356bc4bbf546f44fae83ff298af0a043ca0625b06773/httptools-0.8.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/42/0e7443c90310498561addf346e7d57fe3c6ba1914e1ba938b5464c7bbfd2/propcache-0.5.2-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-routing", "version": "23.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/e3/3425c9a8773807ac2c01d6a56c8521733f09b627e5827e733c5cd36b9ac5/sanic_routing-23.12.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "83.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/40/e1e72872c6354b306daef1703549e8e83b4d43cfea356311bf722a043752/setuptools-83.0.0-py3-none-any.whl"}}, {"metadata": {"name": "tracerite", "version": "2.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b6/62/3f385a67ff3cc91209f107d20bbebdecf7a4e4aba55a43f9f71bddc424a9/tracerite-2.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "5.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8e/d2/92e83af35cd65d3b7c47fb0e24927aa2b478897af8b0dd0ee19abcd50c03/ujson-5.13.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "uvloop", "version": "0.22.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/14/ecceb239b65adaaf7fde510aa8bd534075695d1e5f8dadfa32b5723d9cfb/uvloop-0.22.1-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}], "install_targets_hash": "bdb1f2a8b2b051b4d694fd87001bee9b"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "sanic", "version": "25.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/91/5ecd9a91374a7b2831cf183357ceeb609fdfc8b390adb5cac90a261fe1f8/sanic-25.12.1-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/7a/bd0ce7ac1cfafc76c84d6e8051bcbd0f7def8e45207230833bd6ff77a41d/websockets-10.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/31/5c/08c7f7fe311f32e83f7621cd3f99d805f45519cd06fafb247628b861da7d/multidict-6.7.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/c1/316c8f3549dbe5245f92bfd523ec6f32dd4d98cafe21df3f6a19b1184c75/aiohttp-3.14.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/8f/7b3ec212f1ea0683f55f978e3246bc313c38818664edfc97a9f349a4901e/yarl-1.24.2-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-testing", "version": "24.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/93/1d588f1cb9b710b9f22fa78b53d699a8062edc94204d50dd0d78c5f5b495/sanic_testing-24.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/70/26ca3f06aace16f2352796b08704338d74b6d1a24ca38f2771afbb7ed915/frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "html5tagger", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/12/2f5d43ee912ea14a6baba4b3db6d309b02d932e3b7074c3339b4aded98ff/html5tagger-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "httptools", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/f7/b4d41eaae2869d31356bc4bbf546f44fae83ff298af0a043ca0625b06773/httptools-0.8.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/42/0e7443c90310498561addf346e7d57fe3c6ba1914e1ba938b5464c7bbfd2/propcache-0.5.2-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-routing", "version": "23.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/e3/3425c9a8773807ac2c01d6a56c8521733f09b627e5827e733c5cd36b9ac5/sanic_routing-23.12.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "83.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/40/e1e72872c6354b306daef1703549e8e83b4d43cfea356311bf722a043752/setuptools-83.0.0-py3-none-any.whl"}}, {"metadata": {"name": "tracerite", "version": "2.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b6/62/3f385a67ff3cc91209f107d20bbebdecf7a4e4aba55a43f9f71bddc424a9/tracerite-2.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "5.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8e/d2/92e83af35cd65d3b7c47fb0e24927aa2b478897af8b0dd0ee19abcd50c03/ujson-5.13.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "uvloop", "version": "0.22.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/14/ecceb239b65adaaf7fde510aa8bd534075695d1e5f8dadfa32b5723d9cfb/uvloop-0.22.1-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}], "install_targets_hash": "bdb1f2a8b2b051b4d694fd87001bee9b"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "sanic", "version": "25.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/91/5ecd9a91374a7b2831cf183357ceeb609fdfc8b390adb5cac90a261fe1f8/sanic-25.12.1-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/7a/bd0ce7ac1cfafc76c84d6e8051bcbd0f7def8e45207230833bd6ff77a41d/websockets-10.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/31/5c/08c7f7fe311f32e83f7621cd3f99d805f45519cd06fafb247628b861da7d/multidict-6.7.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/c1/316c8f3549dbe5245f92bfd523ec6f32dd4d98cafe21df3f6a19b1184c75/aiohttp-3.14.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/8f/7b3ec212f1ea0683f55f978e3246bc313c38818664edfc97a9f349a4901e/yarl-1.24.2-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-testing", "version": "24.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/93/1d588f1cb9b710b9f22fa78b53d699a8062edc94204d50dd0d78c5f5b495/sanic_testing-24.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/70/26ca3f06aace16f2352796b08704338d74b6d1a24ca38f2771afbb7ed915/frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "html5tagger", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/12/2f5d43ee912ea14a6baba4b3db6d309b02d932e3b7074c3339b4aded98ff/html5tagger-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "httptools", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/f7/b4d41eaae2869d31356bc4bbf546f44fae83ff298af0a043ca0625b06773/httptools-0.8.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/42/0e7443c90310498561addf346e7d57fe3c6ba1914e1ba938b5464c7bbfd2/propcache-0.5.2-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-routing", "version": "23.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/e3/3425c9a8773807ac2c01d6a56c8521733f09b627e5827e733c5cd36b9ac5/sanic_routing-23.12.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "83.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/40/e1e72872c6354b306daef1703549e8e83b4d43cfea356311bf722a043752/setuptools-83.0.0-py3-none-any.whl"}}, {"metadata": {"name": "tracerite", "version": "2.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b6/62/3f385a67ff3cc91209f107d20bbebdecf7a4e4aba55a43f9f71bddc424a9/tracerite-2.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "5.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8e/d2/92e83af35cd65d3b7c47fb0e24927aa2b478897af8b0dd0ee19abcd50c03/ujson-5.13.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "uvloop", "version": "0.22.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/14/ecceb239b65adaaf7fde510aa8bd534075695d1e5f8dadfa32b5723d9cfb/uvloop-0.22.1-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}], "install_targets_hash": "bdb1f2a8b2b051b4d694fd87001bee9b"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "sanic", "version": "25.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/91/5ecd9a91374a7b2831cf183357ceeb609fdfc8b390adb5cac90a261fe1f8/sanic-25.12.1-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/7a/bd0ce7ac1cfafc76c84d6e8051bcbd0f7def8e45207230833bd6ff77a41d/websockets-10.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/31/5c/08c7f7fe311f32e83f7621cd3f99d805f45519cd06fafb247628b861da7d/multidict-6.7.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/c1/316c8f3549dbe5245f92bfd523ec6f32dd4d98cafe21df3f6a19b1184c75/aiohttp-3.14.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/8f/7b3ec212f1ea0683f55f978e3246bc313c38818664edfc97a9f349a4901e/yarl-1.24.2-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-testing", "version": "24.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/93/1d588f1cb9b710b9f22fa78b53d699a8062edc94204d50dd0d78c5f5b495/sanic_testing-24.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/70/26ca3f06aace16f2352796b08704338d74b6d1a24ca38f2771afbb7ed915/frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "html5tagger", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/12/2f5d43ee912ea14a6baba4b3db6d309b02d932e3b7074c3339b4aded98ff/html5tagger-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "httptools", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/f7/b4d41eaae2869d31356bc4bbf546f44fae83ff298af0a043ca0625b06773/httptools-0.8.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/42/0e7443c90310498561addf346e7d57fe3c6ba1914e1ba938b5464c7bbfd2/propcache-0.5.2-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-routing", "version": "23.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/e3/3425c9a8773807ac2c01d6a56c8521733f09b627e5827e733c5cd36b9ac5/sanic_routing-23.12.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "83.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/40/e1e72872c6354b306daef1703549e8e83b4d43cfea356311bf722a043752/setuptools-83.0.0-py3-none-any.whl"}}, {"metadata": {"name": "tracerite", "version": "2.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b6/62/3f385a67ff3cc91209f107d20bbebdecf7a4e4aba55a43f9f71bddc424a9/tracerite-2.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "5.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8e/d2/92e83af35cd65d3b7c47fb0e24927aa2b478897af8b0dd0ee19abcd50c03/ujson-5.13.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "uvloop", "version": "0.22.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/14/ecceb239b65adaaf7fde510aa8bd534075695d1e5f8dadfa32b5723d9cfb/uvloop-0.22.1-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}], "install_targets_hash": "bdb1f2a8b2b051b4d694fd87001bee9b"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "sanic", "version": "25.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/91/5ecd9a91374a7b2831cf183357ceeb609fdfc8b390adb5cac90a261fe1f8/sanic-25.12.1-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/7a/bd0ce7ac1cfafc76c84d6e8051bcbd0f7def8e45207230833bd6ff77a41d/websockets-10.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/31/5c/08c7f7fe311f32e83f7621cd3f99d805f45519cd06fafb247628b861da7d/multidict-6.7.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/c1/316c8f3549dbe5245f92bfd523ec6f32dd4d98cafe21df3f6a19b1184c75/aiohttp-3.14.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/8f/7b3ec212f1ea0683f55f978e3246bc313c38818664edfc97a9f349a4901e/yarl-1.24.2-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-testing", "version": "24.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/93/1d588f1cb9b710b9f22fa78b53d699a8062edc94204d50dd0d78c5f5b495/sanic_testing-24.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/70/26ca3f06aace16f2352796b08704338d74b6d1a24ca38f2771afbb7ed915/frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "html5tagger", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/12/2f5d43ee912ea14a6baba4b3db6d309b02d932e3b7074c3339b4aded98ff/html5tagger-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "httptools", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/f7/b4d41eaae2869d31356bc4bbf546f44fae83ff298af0a043ca0625b06773/httptools-0.8.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/42/0e7443c90310498561addf346e7d57fe3c6ba1914e1ba938b5464c7bbfd2/propcache-0.5.2-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-routing", "version": "23.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/e3/3425c9a8773807ac2c01d6a56c8521733f09b627e5827e733c5cd36b9ac5/sanic_routing-23.12.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "83.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/40/e1e72872c6354b306daef1703549e8e83b4d43cfea356311bf722a043752/setuptools-83.0.0-py3-none-any.whl"}}, {"metadata": {"name": "tracerite", "version": "2.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b6/62/3f385a67ff3cc91209f107d20bbebdecf7a4e4aba55a43f9f71bddc424a9/tracerite-2.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "5.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8e/d2/92e83af35cd65d3b7c47fb0e24927aa2b478897af8b0dd0ee19abcd50c03/ujson-5.13.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "uvloop", "version": "0.22.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/14/ecceb239b65adaaf7fde510aa8bd534075695d1e5f8dadfa32b5723d9cfb/uvloop-0.22.1-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}], "install_targets_hash": "bdb1f2a8b2b051b4d694fd87001bee9b"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/26/08/0f303cb0b529e456bb116f2d50565a482694fbb94340bf56d44677e7ed03/charset_normalizer-3.4.7-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}], "install_targets_hash": "c4e67585767bde6ea034db94a448f267"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/26/08/0f303cb0b529e456bb116f2d50565a482694fbb94340bf56d44677e7ed03/charset_normalizer-3.4.7-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}], "install_targets_hash": "c4e67585767bde6ea034db94a448f267"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/26/08/0f303cb0b529e456bb116f2d50565a482694fbb94340bf56d44677e7ed03/charset_normalizer-3.4.7-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}], "install_targets_hash": "c4e67585767bde6ea034db94a448f267"} -{"python_version": "3.10", "dependencies": [{"metadata": {"name": "fastmcp", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ac/14/6d950459cc831fa17fe2d1797926b6eb2d2f2af50f830e62d0c098cc1ec8/fastmcp-3.4.7-py3-none-any.whl"}}, {"metadata": {"name": "fastmcp-slim", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b4/97/e0e53642cd029a9a7635ae9c548f9f2cc995af5914e487b3df795664e4be/fastmcp_slim-3.4.7-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "mcp", "version": "1.29.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/c8/248b201f6d753d69fd5d6506011abbb35a946d9142b2ae311a948fd0be3d/mcp-1.29.0-py3-none-any.whl"}}, {"metadata": {"name": "py-key-value-aio", "version": "0.4.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/95/b8ba862968712caa12a19666175334fa979e1f198b896a430adb3bacfe87/py_key_value_aio-0.4.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/c6/65f646c7ff09bd257f660434adb45c4dfcbbcebcc030562fecf6f5bf887d/pydantic_core-2.46.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofile", "version": "3.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/25/da1f0b4dd970e52bf5a36c204c107e11a0c6d3ed195eba0bfbc664c312b2/aiofile-3.9.0-py3-none-any.whl"}}, {"metadata": {"name": "caio", "version": "0.9.25"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6a/80/ea4ead0c5d52a9828692e7df20f0eafe8d26e671ce4883a0a146bb91049e/caio-0.9.25-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "Authlib", "version": "1.7.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/95/adcb68e20c34162e9135f370d6e31737719c2b6f94bc953fe7ed1f10fe21/authlib-1.7.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "beartype", "version": "0.22.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/cc/18245721fa7747065ab478316c7fea7c74777d07f37ae60db2e84f8172e8/beartype-0.22.9-py3-none-any.whl"}}, {"metadata": {"name": "cachetools", "version": "7.1.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e4/d8/767faeda872075724b95dd675466a645f1b92aadcdcf2d1429dcfd76c176/cachetools-7.1.7-py3-none-any.whl"}}, {"metadata": {"name": "cyclopts", "version": "4.23.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/35/40/c17d731af4ddbf6dede1f1acb09e6335c2587e8b73b3d4742f3f9c6996d3/cyclopts-4.23.2-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "rich-rst", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/68/1fc93dd759605b5d00fc98b50200739e41ed32bd22d6ba35ca6c3932371b/rich_rst-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "griffelib", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/b6/f65ac785d4ac90dcf7c831ac6256f5dd4a19780f4e1575b2c0d6eeebe319/griffelib-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "joserfc", "version": "1.7.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/bf/249dcd99b3376375910b7fa922383b57792975c8758f50d44612e749226c/joserfc-1.7.4-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/37/73d005be173aff344af30e9fd2a576575cb2391a7101d9cd3842e1fa8cce/cryptography-50.0.0-cp39-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/1a/4b2f7c92293ba05cbd4a9a1b28faaf0326272d9488e6354657571c48a7aa/cffi-2.1.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "jsonref", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/ec/e1db9922bceb168197a558a2b8c03a7963f1afe93517ddd3cf99f202f996/jsonref-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-path", "version": "0.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/2c/9e69d73c4297508be9e3b64a970ea3971b3eb8db64ffc5802d40bd25981f/jsonschema_path-0.5.0-py3-none-any.whl"}}, {"metadata": {"name": "pathable", "version": "0.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a2/e8/6d75ffd9784bce2e93d1ae4415649427e39a53bb172d4672b2b59c6f0a7b/pathable-0.6.0-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "keyring", "version": "25.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/db/e655086b7f3a705df045bf0933bdd9c2f79bb3c97bfef1384598bb79a217/keyring-25.7.0-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "9.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/38/3d/2d244233ac4f76e38533cfcb2991c9eb4c7bf688ae0a036d30725b8faafe/importlib_metadata-9.0.0-py3-none-any.whl"}}, {"metadata": {"name": "openapi-pydantic", "version": "0.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/cf/03675d8bd8ecbf4445504d8071adab19f5f993676795708e36402ab38263/openapi_pydantic-0.5.1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/6f/a04e900f465ff3221ccc395522503e2d10e79fa21f2723c8e177aae1e0d1/opentelemetry_api-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "platformdirs", "version": "4.11.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/a9/c34aebedd3a4c9afe5101b1b8713710b3fec18087c8a36c35d2f909861bd/platformdirs-4.11.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "email-validator", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "dnspython", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "pyperclip", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/80/fc9d01d5ed37ba4c42ca2b55b4339ae6e200b456be3a1aaddf4a9fa99b8c/pyperclip-1.11.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "0.30.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/6a/4ba3d0fb7297ebae71171822554abe48d7cab29c28b8f9f2c04b79988c05/rpds_py-0.30.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/3a/764912c58293d95b6dcdf4cc255f9d10de310580ced547b082eb9d72018c/sse_starlette-3.4.8-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uncalled-for", "version": "0.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a2/40/97cec87c077eb3291fc7905e6633e08b7ca593c57d30238444bcb6bb3d53/uncalled_for-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.52.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/79/4a20b54ab0491485ccd8c077db2d39187c7f12b3e15485d38a7be37c81b4/uvicorn-0.52.4-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "watchfiles", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/70/dea1f6a0e76607841a60fb51af150e70124864673f61704abb62b90cdcc7/watchfiles-1.2.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/90/72/2f14b2e167170b8bf1c8bb7f9b0d78000f470d41a2085a91f33e3917b6c9/websockets-16.1.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "zipp", "version": "4.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.classes", "version": "3.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/66/b15ce62552d84bbfcec9a4873ab79d993a1dd4edb922cbfccae192bd5b5f/jaraco.classes-3.4.0-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.context", "version": "6.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f2/58/bc8954bda5fcda97bd7c19be11b85f91973d67a706ed4a3aec33e7de22db/jaraco_context-6.1.2-py3-none-any.whl"}}, {"metadata": {"name": "backports.tarfile", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/fa/123043af240e49752f1c4bd24da5053b6bd00cad78c2be53c0d1e8b975bc/backports.tarfile-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.functools", "version": "4.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/02/36/ecc85bc96c273dc8a11273ed4782272975e6338d4a3e9228621175edf0e3/jaraco_functools-4.6.0-py3-none-any.whl"}}, {"metadata": {"name": "more-itertools", "version": "11.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/3d/1087453384dbde46a8c7f9356eead2c58be8a7bf156bca40243377c85715/more_itertools-11.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "c7af9a5e09a115592eb42861d20f7b29"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/26/08/0f303cb0b529e456bb116f2d50565a482694fbb94340bf56d44677e7ed03/charset_normalizer-3.4.7-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}], "install_targets_hash": "c4e67585767bde6ea034db94a448f267"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/26/08/0f303cb0b529e456bb116f2d50565a482694fbb94340bf56d44677e7ed03/charset_normalizer-3.4.7-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}], "install_targets_hash": "c4e67585767bde6ea034db94a448f267"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/26/08/0f303cb0b529e456bb116f2d50565a482694fbb94340bf56d44677e7ed03/charset_normalizer-3.4.7-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}], "install_targets_hash": "c4e67585767bde6ea034db94a448f267"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/26/08/0f303cb0b529e456bb116f2d50565a482694fbb94340bf56d44677e7ed03/charset_normalizer-3.4.7-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}], "install_targets_hash": "c4e67585767bde6ea034db94a448f267"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/26/08/0f303cb0b529e456bb116f2d50565a482694fbb94340bf56d44677e7ed03/charset_normalizer-3.4.7-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}], "install_targets_hash": "c4e67585767bde6ea034db94a448f267"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "litellm", "version": "1.96.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b4/20/7f053a468632698545c6621e9969d5d24c2c58dbe3fe3319761661c434a8/litellm-1.96.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anthropic", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/5b/db4a854aebf5d33a5ab714c46af6eb85ee44f390ed29b7b325c00b9f11ed/anthropic-1.0.0-py3-none-any.whl"}}, {"metadata": {"name": "google-genai", "version": "2.19.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/e8/de0accd8cd004cf11252ca53fc5c3dda59bcf1856abfc7609842ceba7363/google_genai-2.19.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9e/73b582c4dbbc3c12ef4473822475effaabf1f934b56f14f5b03fe5d3a2af/aiohttp-3.14.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "fastuuid", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/c5/84c1eea05977c8ba5173555b0133e3558dc628bcf868d6bf1689ff14aedc/fastuuid-0.14.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "google-auth", "version": "2.56.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/b3/6117b2f24065cd7e2c4f140e9a193e215f089ca8ba314cf91eb9d0b7fe0a/google_auth-2.56.3-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/95/411ba65569158e862368917aaf56597f3e5fa3b91b0502919638465a08f3/httpx2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/74/d370e55600d9bcfa0d9794b0166126d49291a3d2b20c268fc98c453a4948/httpcore2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7d/f9/97f2ca8bb3ec6e4b1d64f983ebe98b9a192faddff67fac3d6303a537e670/importlib_metadata-8.9.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c6/3d/4d7f5667ea0e0548534ba880b84bb3d12924fd133aa83ad6c6c80fca3d76/jiter-0.16.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "2.54.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/a8/bb76c7356de8ad57f59d5ff993d434df0607f07f08bcc9c9a5c275e399c0/openai-2.54.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/c6/65f646c7ff09bd257f660434adb45c4dfcbbcebcc030562fecf6f5bf887d/pydantic_core-2.46.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/18/e2/d39ae33d3dc30a0c229ff0cb683df961ebb5e7b8691feb2d08b3ee6ac327/tiktoken-0.14.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tokenizers", "version": "0.23.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e2/6a/068ed9f6e444c9d7e9d55ce134181325700f3d7f30410721bdc8f848d727/tokenizers-0.23.1-cp310-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/90/72/2f14b2e167170b8bf1c8bb7f9b0d78000f470d41a2085a91f33e3917b6c9/websockets-16.1.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/aa/554e2614f38fc34c58ff1d0911ae8535ad2516440d5482d76fe59f1088b0/charset_normalizer-3.5.1-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/37/73d005be173aff344af30e9fd2a576575cb2391a7101d9cd3842e1fa8cce/cryptography-50.0.0-cp39-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/70/26ca3f06aace16f2352796b08704338d74b6d1a24ca38f2771afbb7ed915/frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "huggingface_hub", "version": "1.28.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/0e/eafef18f1a75e125e68395db21131db0cf868a128ecd2fce69b4df6c584b/huggingface_hub-1.28.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/31/5c/08c7f7fe311f32e83f7621cd3f99d805f45519cd06fafb247628b861da7d/multidict-6.7.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/42/0e7443c90310498561addf346e7d57fe3c6ba1914e1ba938b5464c7bbfd2/propcache-0.5.2-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "0.30.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/6a/4ba3d0fb7297ebae71171822554abe48d7cab29c28b8f9f2c04b79988c05/rpds_py-0.30.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/59/1d/340d1a0db7bbce1f291afc044255ebf4ebbce2b25ab1b3f7d3d069080f5d/yarl-1.24.5-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "zipp", "version": "4.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.7.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/16/01/cefe4f051302ca298d3f3e79ed6dbd933ac84485b9515acdd6a52d70cef7/regex-2026.7.19-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/1a/4b2f7c92293ba05cbd4a9a1b28faaf0326272d9488e6354657571c48a7aa/cffi-2.1.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "filelock", "version": "3.32.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/a4/9b63d595d748e3aff8812b65eacc1a2c4bd90b7c2012e08e72373b4835eb/filelock-3.32.4-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/3c/6a2bf344106328fd04963664a60b9bb6496fc25df8e962fcdc1367285fb9/fsspec-2026.7.0-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/69/55b8dcf636142ae660fec1869fcac14c4da2e8412e14d6eee1523be77e9f/hf_xet-1.6.0-cp38-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/3b/6163796d69c3977d1e4287bea4a6979161cbbdd170ebb430511e8e1999ce/pyasn1-0.6.4-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "c8297c467689232f577381977852ce9e"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "litellm", "version": "1.96.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b4/20/7f053a468632698545c6621e9969d5d24c2c58dbe3fe3319761661c434a8/litellm-1.96.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anthropic", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/5b/db4a854aebf5d33a5ab714c46af6eb85ee44f390ed29b7b325c00b9f11ed/anthropic-1.0.0-py3-none-any.whl"}}, {"metadata": {"name": "google-genai", "version": "2.19.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/e8/de0accd8cd004cf11252ca53fc5c3dda59bcf1856abfc7609842ceba7363/google_genai-2.19.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9e/73b582c4dbbc3c12ef4473822475effaabf1f934b56f14f5b03fe5d3a2af/aiohttp-3.14.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "fastuuid", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/c5/84c1eea05977c8ba5173555b0133e3558dc628bcf868d6bf1689ff14aedc/fastuuid-0.14.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "google-auth", "version": "2.56.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/b3/6117b2f24065cd7e2c4f140e9a193e215f089ca8ba314cf91eb9d0b7fe0a/google_auth-2.56.3-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/95/411ba65569158e862368917aaf56597f3e5fa3b91b0502919638465a08f3/httpx2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/74/d370e55600d9bcfa0d9794b0166126d49291a3d2b20c268fc98c453a4948/httpcore2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7d/f9/97f2ca8bb3ec6e4b1d64f983ebe98b9a192faddff67fac3d6303a537e670/importlib_metadata-8.9.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c6/3d/4d7f5667ea0e0548534ba880b84bb3d12924fd133aa83ad6c6c80fca3d76/jiter-0.16.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "2.54.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/a8/bb76c7356de8ad57f59d5ff993d434df0607f07f08bcc9c9a5c275e399c0/openai-2.54.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/c6/65f646c7ff09bd257f660434adb45c4dfcbbcebcc030562fecf6f5bf887d/pydantic_core-2.46.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/18/e2/d39ae33d3dc30a0c229ff0cb683df961ebb5e7b8691feb2d08b3ee6ac327/tiktoken-0.14.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tokenizers", "version": "0.23.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e2/6a/068ed9f6e444c9d7e9d55ce134181325700f3d7f30410721bdc8f848d727/tokenizers-0.23.1-cp310-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/90/72/2f14b2e167170b8bf1c8bb7f9b0d78000f470d41a2085a91f33e3917b6c9/websockets-16.1.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/aa/554e2614f38fc34c58ff1d0911ae8535ad2516440d5482d76fe59f1088b0/charset_normalizer-3.5.1-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/37/73d005be173aff344af30e9fd2a576575cb2391a7101d9cd3842e1fa8cce/cryptography-50.0.0-cp39-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/70/26ca3f06aace16f2352796b08704338d74b6d1a24ca38f2771afbb7ed915/frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "huggingface_hub", "version": "1.28.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/0e/eafef18f1a75e125e68395db21131db0cf868a128ecd2fce69b4df6c584b/huggingface_hub-1.28.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/31/5c/08c7f7fe311f32e83f7621cd3f99d805f45519cd06fafb247628b861da7d/multidict-6.7.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/42/0e7443c90310498561addf346e7d57fe3c6ba1914e1ba938b5464c7bbfd2/propcache-0.5.2-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "0.30.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/6a/4ba3d0fb7297ebae71171822554abe48d7cab29c28b8f9f2c04b79988c05/rpds_py-0.30.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/59/1d/340d1a0db7bbce1f291afc044255ebf4ebbce2b25ab1b3f7d3d069080f5d/yarl-1.24.5-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "zipp", "version": "4.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.7.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/16/01/cefe4f051302ca298d3f3e79ed6dbd933ac84485b9515acdd6a52d70cef7/regex-2026.7.19-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/1a/4b2f7c92293ba05cbd4a9a1b28faaf0326272d9488e6354657571c48a7aa/cffi-2.1.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "filelock", "version": "3.32.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/a4/9b63d595d748e3aff8812b65eacc1a2c4bd90b7c2012e08e72373b4835eb/filelock-3.32.4-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/3c/6a2bf344106328fd04963664a60b9bb6496fc25df8e962fcdc1367285fb9/fsspec-2026.7.0-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/69/55b8dcf636142ae660fec1869fcac14c4da2e8412e14d6eee1523be77e9f/hf_xet-1.6.0-cp38-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/3b/6163796d69c3977d1e4287bea4a6979161cbbdd170ebb430511e8e1999ce/pyasn1-0.6.4-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "c8297c467689232f577381977852ce9e"} -{"python_version": "3.10", "dependencies": [{"metadata": {"name": "starlette", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/74/4e60dbbf61567bf5adea89433068d5f7c18c86ca77617b5de5b3ddd83f62/starlette-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/26/08/0f303cb0b529e456bb116f2d50565a482694fbb94340bf56d44677e7ed03/charset_normalizer-3.4.7-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}], "install_targets_hash": "cbbd2c92dce74693f6b4444c00c5c36f"} -{"python_version": "3.10", "dependencies": [{"metadata": {"name": "fastmcp", "version": "0.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/0b/008a340435fe8f0879e9d608f48af2737ad48440e09bd33b83b3fd03798b/fastmcp-0.4.1-py3-none-any.whl"}}, {"metadata": {"name": "mcp", "version": "1.29.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/c8/248b201f6d753d69fd5d6506011abbb35a946d9142b2ae311a948fd0be3d/mcp-1.29.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/c6/65f646c7ff09bd257f660434adb45c4dfcbbcebcc030562fecf6f5bf887d/pydantic_core-2.46.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/77/c1/6e422f34e569cf8e18df68d1939c81c099d2b61e4f7d9621c8a77560799c/pydantic_settings-2.14.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/2a/5bb823f5bedcf80718cea7fbc95ec5515cca3769633c4b01a32be7f30e7c/cryptography-49.0.0-cp39-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/aa/24580a278de21fd7322635556334d9b535f1cbc00b0a3919447cdf464c65/cffi-2.1.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "0.30.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/6a/4ba3d0fb7297ebae71171822554abe48d7cab29c28b8f9f2c04b79988c05/rpds_py-0.30.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/36/e10c1d1b7ca881d2625db2ec28508578499187bb1c389952c398474e1834/sse_starlette-3.4.6-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typer", "version": "0.27.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/40/03/26a383c9e58c213199d1aad1c3d353cfc22d4444ec6d2c0bf8ad02523843/typer-0.27.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "shellingham", "version": "1.5.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.52.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/39/e6/b5c0630ace9757232aec07112be8146b812787db52141ff9d50674aa7634/uvicorn-0.52.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "d3ba412b13e2cfc8f79cd31c37175dca"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "mcp", "version": "2.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/75/20/312acf5fd37b90589269349b2c4d5c056b4603c964d181e91f9bf4a79f97/mcp-2.0.1-py3-none-any.whl"}}, {"metadata": {"name": "mcp-types", "version": "2.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b6/49/37a1f580d94ee0f16c1f3d1c6e32bbb264e607f1739a4c0cb9232619dfd9/mcp_types-2.0.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/6f/a04e900f465ff3221ccc395522503e2d10e79fa21f2723c8e177aae1e0d1/opentelemetry_api-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/d0/c787604c71c2bdcda1a5656942fc822cd0f9cd879b9484bb84fc42172703/pydantic_core-2.46.5-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/97/672cb32ce0dfea44b740cb7b4f97038463b9cf7c0ead1aacf595572851d6/pyjwt-2.14.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/6a/2ba3ed4a69babf3afdddf7d8314a48d87562c0a442206bbc2a1b50d5efc0/sse_starlette-3.4.11-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.53.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/76/18/0eea75741ee812e9f598b687619ce2454f6c3a1c5cd21ea990ec6bd26f45/uvicorn-0.53.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/84/a9/ee16a903f13755e914d1eecc482fe64d1f10761c3960e5d8fa6837377aff/cryptography-50.0.1-cp39-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "0.30.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/6a/4ba3d0fb7297ebae71171822554abe48d7cab29c28b8f9f2c04b79988c05/rpds_py-0.30.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/1a/4b2f7c92293ba05cbd4a9a1b28faaf0326272d9488e6354657571c48a7aa/cffi-2.1.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "cce7f3c3feff18eeb00efa85d75073cb"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "sanic", "version": "22.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/80/5c/91c44dd9daf62f0068a372d9c3a12945bfcb36eb22aa1b1bfc81ecc0e6e1/sanic-22.12.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/7a/bd0ce7ac1cfafc76c84d6e8051bcbd0f7def8e45207230833bd6ff77a41d/websockets-10.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/31/5c/08c7f7fe311f32e83f7621cd3f99d805f45519cd06fafb247628b861da7d/multidict-6.7.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9e/73b582c4dbbc3c12ef4473822475effaabf1f934b56f14f5b03fe5d3a2af/aiohttp-3.14.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/59/1d/340d1a0db7bbce1f291afc044255ebf4ebbce2b25ab1b3f7d3d069080f5d/yarl-1.24.5-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-testing", "version": "24.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/93/1d588f1cb9b710b9f22fa78b53d699a8062edc94204d50dd0d78c5f5b495/sanic_testing-24.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/70/26ca3f06aace16f2352796b08704338d74b6d1a24ca38f2771afbb7ed915/frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httptools", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/f7/b4d41eaae2869d31356bc4bbf546f44fae83ff298af0a043ca0625b06773/httptools-0.8.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/42/0e7443c90310498561addf346e7d57fe3c6ba1914e1ba938b5464c7bbfd2/propcache-0.5.2-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-routing", "version": "23.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/e3/3425c9a8773807ac2c01d6a56c8521733f09b627e5827e733c5cd36b9ac5/sanic_routing-23.12.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "5.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8e/d2/92e83af35cd65d3b7c47fb0e24927aa2b478897af8b0dd0ee19abcd50c03/ujson-5.13.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "uvloop", "version": "0.22.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/14/ecceb239b65adaaf7fde510aa8bd534075695d1e5f8dadfa32b5723d9cfb/uvloop-0.22.1-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}], "install_targets_hash": "d30b435a069bef886019e4dd69ce4c21"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "google-genai", "version": "2.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/84/5b/87913fe392ba7b6402577259289ed3740c577956554a674b191a2971d33e/google_genai-2.24.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.58.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/59/13/477d90d09591b3938b45c4e11f4d8a51291682112cb5efcac961e815d562/google_auth-2.58.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/34/a1/c8e6b66f499f510752c07a092dfe27621f9c255635e59d38704b5681c35a/pydantic_core-2.46.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/cd/4f564b8f132de25db594efc706897069f016790cea63a5669c9df2675f64/charset_normalizer-3.5.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f3/18/a17e2f0cde02dc10154c808deed7e1d8528afff93612f70d3f0a5b19b011/websockets-16.1.1-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8c/eb/5d7124083e8d8cda8f5b348f544b71ad6f707ad63193758ef4d8e569da02/cryptography-50.0.1-cp39-abi3-manylinux_2_34_x86_64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/75/77/60bebf6f818bec84210ac5b6979ce4eeadce6fbbaabc9c7ab23e506d1ce5/cffi-2.1.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/3b/6163796d69c3977d1e4287bea4a6979161cbbdd170ebb430511e8e1999ce/pyasn1-0.6.4-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "d5f17eff9efc836f1883edb6f7bfdfbc"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2-pytest", "version": "1.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/46/ef/e9b6fb576f1f518f68e9f9cce9776870452ae2b8cfbba53b4127701b9a55/httpx2_pytest-1.0.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}], "install_targets_hash": "d6da1d54536a49d0f25beda4d7a148f5"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "asyncpg", "version": "0.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e4/57/0a4c4d3f2307b12f633b28c370669d6115a1780416310ec536f01ace09ad/asyncpg-0.26.0.tar.gz"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}], "install_targets_hash": "d7d7d0053f539679c74eddc1935b5205"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "asyncpg", "version": "0.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e4/57/0a4c4d3f2307b12f633b28c370669d6115a1780416310ec536f01ace09ad/asyncpg-0.26.0.tar.gz"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}], "install_targets_hash": "d7d7d0053f539679c74eddc1935b5205"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "asyncpg", "version": "0.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e4/57/0a4c4d3f2307b12f633b28c370669d6115a1780416310ec536f01ace09ad/asyncpg-0.26.0.tar.gz"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}], "install_targets_hash": "d7d7d0053f539679c74eddc1935b5205"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "asyncpg", "version": "0.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e4/57/0a4c4d3f2307b12f633b28c370669d6115a1780416310ec536f01ace09ad/asyncpg-0.26.0.tar.gz"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}], "install_targets_hash": "d7d7d0053f539679c74eddc1935b5205"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "asyncpg", "version": "0.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e4/57/0a4c4d3f2307b12f633b28c370669d6115a1780416310ec536f01ace09ad/asyncpg-0.26.0.tar.gz"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}], "install_targets_hash": "d7d7d0053f539679c74eddc1935b5205"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "apache-beam", "version": "2.76.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/42/7d/d336c0072010b6dbd3cff3bb71c5693eaafb19c7e25cac5b682ccd863c5f/apache_beam-2.76.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "betterproto", "version": "2.0.0b6"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/99/6d/007abe4bf14cd02a3c07710c22f0e3252b55b06678de2535ae5f03b7433a/betterproto-2.0.0b6-py3-none-any.whl"}}, {"metadata": {"name": "beartype", "version": "0.22.9"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/cc/18245721fa7747065ab478316c7fea7c74777d07f37ae60db2e84f8172e8/beartype-0.22.9-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "48.0.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ca/6c/00fa2a95997164c8b2072ce327c23d4ab20809ccc323ea5fab91e53a4bba/cryptography-48.0.1-cp39-abi3-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "fastavro", "version": "1.12.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/3c/91/16c3508447e7cf9f413a6a01792a990ed94d17505fc80a7fb76027078aed/fastavro-1.12.2-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "fasteners", "version": "0.20"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/51/ac/e5d886f892666d2d1e5cb8c1a41146e1d79ae8896477b1153a21711d3b44/fasteners-0.20-py3-none-any.whl"}}, {"metadata": {"name": "grpcio", "version": "1.83.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/74/cd/9dd4c80dba1454c32c876d0b5f138b0b3f61323bea620984c47f3c62d0e6/grpcio-1.83.1-cp310-cp310-macosx_11_0_universal2.whl"}}, {"metadata": {"name": "grpclib", "version": "0.4.9"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/5c/90/b0cbbd9efcc82816c58f31a34963071aa19fb792a212a5d9caf8e0fc3097/grpclib-0.4.9-py3-none-any.whl"}}, {"metadata": {"name": "h2", "version": "4.4.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/22/e85faf23bd72a92d1921e37d674ca56eb298a3c8be31fdecef0ff2b3aaac/h2-4.4.1-py3-none-any.whl"}}, {"metadata": {"name": "hpack", "version": "4.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/b4/4a9fcfb2aef6ba44d9073ecd301443aa00b3dac95de5619f2a7de7ec8a91/hpack-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "httplib2", "version": "0.32.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/33/a0/550eec327e5f5c7b732531c489f5307efec41f047b0d703bd4ca1e5ad2db/httplib2-0.32.0-py3-none-any.whl"}}, {"metadata": {"name": "hyperframe", "version": "6.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/48/30/47d0bf6072f7252e6521f3447ccfa40b421b6824517f82854703d0f5a98b/hyperframe-6.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonpickle", "version": "4.1.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a1/7b/fd3c7a09649aea9da1d3587aea624d8f9b29963dfd84a1bdb2aa93b36dac/jsonpickle-4.1.2-py3-none-any.whl"}}, {"metadata": {"name": "numpy", "version": "2.2.6"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/fd/77/dc2fcfc66943c6410e2bf598062f5959372735ffda175b39906d54f02349/numpy-2.2.6-cp310-cp310-macosx_14_0_arm64.whl"}}, {"metadata": {"name": "objsize", "version": "0.7.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/f3/a7/55f8f3853a4a654d3a6fbf63e646e0b469b52c174703a10db70a1cb06c7e/objsize-0.7.1-py3-none-any.whl"}}, {"metadata": {"name": "pillow", "version": "12.3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/6b/ba/3762f376a2948e3036488d773a146e0ae6ecc2ca03ac20e2615bd0b2ba02/pillow-12.3.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "proto-plus", "version": "1.28.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/41/5d/0f04b85dafdc3250ced7f2592efc17dce7f40712e941e9632202481e600d/proto_plus-1.28.4-py3-none-any.whl"}}, {"metadata": {"name": "protobuf", "version": "6.33.6"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/5c/01/a3c3ed5cd186f39e7880f8303cc51385a198a81469d53d0fdecf1f64d929/protobuf-6.33.6-cp39-abi3-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "pyarrow", "version": "25.0.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0a/3e/5cd70becb51e1d044c54ba5e627424a6e87df5b98008cbd22cc6abd409ca/pyarrow-25.0.1-cp310-cp310-macosx_12_0_arm64.whl"}}, {"metadata": {"name": "pymongo", "version": "4.17.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/88/cf/5a70cee503ff9a2fea20607607f14d189f4d975960ac0945ec306ee7b695/pymongo-4.17.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "dnspython", "version": "2.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "pyparsing", "version": "3.3.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/aa/554e2614f38fc34c58ff1d0911ae8535ad2516440d5482d76fe59f1088b0/charset_normalizer-3.5.1-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "zstandard", "version": "0.25.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/96/34/ef34ef77f1ee38fc8e4f9775217a613b452916e633c4f1d98f31db52c4a5/zstandard-0.25.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "dill", "version": "0.4.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/1e/77/dc8c558f7593132cf8fefec57c4f60c83b16941c574ac5f619abb3ae7933/dill-0.4.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/94/1a/4b2f7c92293ba05cbd4a9a1b28faaf0326272d9488e6354657571c48a7aa/cffi-2.1.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pytz", "version": "2026.3.post1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0f/7b/39c34ca613b0b198cb866466651b26b045e2009864c5183c979a3b83f383/pytz-2026.3.post1-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/31/5c/08c7f7fe311f32e83f7621cd3f99d805f45519cd06fafb247628b861da7d/multidict-6.7.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "de59b66921db5839d863c7f55d15510f"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "graphene", "version": "3.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/70/96f6027cdfc9bb89fc07627b615cb43fb1c443c93498412beaeaf157e9f1/graphene-3.3-py2.py3-none-any.whl"}}, {"metadata": {"name": "aniso8601", "version": "9.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e3/04/e97c12dc034791d7b504860acfcdd2963fa21ae61eaca1c9d31245f812c3/aniso8601-9.0.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/15/b92b4e1d88d02c6eff9733c9eea21846ab435cc4d813d84ccc5d335955df/graphql_core-3.2.11-py3-none-any.whl"}}, {"metadata": {"name": "graphql-relay", "version": "3.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/74/16/a4cf06adbc711bd364a73ce043b0b08d8fa5aae3df11b6ee4248bcdad2e0/graphql_relay-3.2.0-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "fastapi", "version": "0.139.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/7c/8e3c6ad324ea5cb36604fc3f968554887891c316d9dfde57761611d907ad/fastapi-0.139.0-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/c6/65f646c7ff09bd257f660434adb45c4dfcbbcebcc030562fecf6f5bf887d/pydantic_core-2.46.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}], "install_targets_hash": "dff9e5a8db205ce5600a48e786aba109"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "graphene", "version": "3.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/70/96f6027cdfc9bb89fc07627b615cb43fb1c443c93498412beaeaf157e9f1/graphene-3.3-py2.py3-none-any.whl"}}, {"metadata": {"name": "aniso8601", "version": "9.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e3/04/e97c12dc034791d7b504860acfcdd2963fa21ae61eaca1c9d31245f812c3/aniso8601-9.0.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/15/b92b4e1d88d02c6eff9733c9eea21846ab435cc4d813d84ccc5d335955df/graphql_core-3.2.11-py3-none-any.whl"}}, {"metadata": {"name": "graphql-relay", "version": "3.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/74/16/a4cf06adbc711bd364a73ce043b0b08d8fa5aae3df11b6ee4248bcdad2e0/graphql_relay-3.2.0-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "fastapi", "version": "0.139.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/7c/8e3c6ad324ea5cb36604fc3f968554887891c316d9dfde57761611d907ad/fastapi-0.139.0-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/c6/65f646c7ff09bd257f660434adb45c4dfcbbcebcc030562fecf6f5bf887d/pydantic_core-2.46.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}], "install_targets_hash": "dff9e5a8db205ce5600a48e786aba109"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "graphene", "version": "3.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/70/96f6027cdfc9bb89fc07627b615cb43fb1c443c93498412beaeaf157e9f1/graphene-3.3-py2.py3-none-any.whl"}}, {"metadata": {"name": "aniso8601", "version": "9.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e3/04/e97c12dc034791d7b504860acfcdd2963fa21ae61eaca1c9d31245f812c3/aniso8601-9.0.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/15/b92b4e1d88d02c6eff9733c9eea21846ab435cc4d813d84ccc5d335955df/graphql_core-3.2.11-py3-none-any.whl"}}, {"metadata": {"name": "graphql-relay", "version": "3.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/74/16/a4cf06adbc711bd364a73ce043b0b08d8fa5aae3df11b6ee4248bcdad2e0/graphql_relay-3.2.0-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "fastapi", "version": "0.139.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/7c/8e3c6ad324ea5cb36604fc3f968554887891c316d9dfde57761611d907ad/fastapi-0.139.0-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/c6/65f646c7ff09bd257f660434adb45c4dfcbbcebcc030562fecf6f5bf887d/pydantic_core-2.46.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}], "install_targets_hash": "dff9e5a8db205ce5600a48e786aba109"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "graphene", "version": "3.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/70/96f6027cdfc9bb89fc07627b615cb43fb1c443c93498412beaeaf157e9f1/graphene-3.3-py2.py3-none-any.whl"}}, {"metadata": {"name": "aniso8601", "version": "9.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e3/04/e97c12dc034791d7b504860acfcdd2963fa21ae61eaca1c9d31245f812c3/aniso8601-9.0.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/15/b92b4e1d88d02c6eff9733c9eea21846ab435cc4d813d84ccc5d335955df/graphql_core-3.2.11-py3-none-any.whl"}}, {"metadata": {"name": "graphql-relay", "version": "3.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/74/16/a4cf06adbc711bd364a73ce043b0b08d8fa5aae3df11b6ee4248bcdad2e0/graphql_relay-3.2.0-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "fastapi", "version": "0.139.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/7c/8e3c6ad324ea5cb36604fc3f968554887891c316d9dfde57761611d907ad/fastapi-0.139.0-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/c6/65f646c7ff09bd257f660434adb45c4dfcbbcebcc030562fecf6f5bf887d/pydantic_core-2.46.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}], "install_targets_hash": "dff9e5a8db205ce5600a48e786aba109"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "grpcio", "version": "1.49.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/1c/c42834d4fee45c5cf2d9546e97e879a1cbcdecfd16eb1a12144dcb91edae/grpcio-1.49.1.tar.gz"}}, {"metadata": {"name": "protobuf", "version": "7.35.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/03/8aeeb7458d22546bf64b5250ca1daeb5ff757d900e8e4a7476c6f0db843e/protobuf-7.35.1-cp310-abi3-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "mypy-protobuf", "version": "5.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/ec/5ffcf8f5f53757e01afdece10c664e694ac60d2f17c2036811b85b842a5b/mypy_protobuf-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "types-protobuf", "version": "7.34.1.20260518"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/1f/ec5caf72c2e3b688ca3927e0979a04ddad19e1afc4bf1c199bd743e0f419/types_protobuf-7.34.1.20260518-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/af/9c0bda43e486a3c9bf1e0f876d0f241bc3f229d7d65d09331a0868db9629/pytest_forked-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "py", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl"}}], "install_targets_hash": "e0332f37695c3f450fdb05225a93e60d"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "grpcio", "version": "1.49.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/1c/c42834d4fee45c5cf2d9546e97e879a1cbcdecfd16eb1a12144dcb91edae/grpcio-1.49.1.tar.gz"}}, {"metadata": {"name": "protobuf", "version": "7.35.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/03/8aeeb7458d22546bf64b5250ca1daeb5ff757d900e8e4a7476c6f0db843e/protobuf-7.35.1-cp310-abi3-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "mypy-protobuf", "version": "5.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/ec/5ffcf8f5f53757e01afdece10c664e694ac60d2f17c2036811b85b842a5b/mypy_protobuf-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "types-protobuf", "version": "7.34.1.20260518"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/1f/ec5caf72c2e3b688ca3927e0979a04ddad19e1afc4bf1c199bd743e0f419/types_protobuf-7.34.1.20260518-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/af/9c0bda43e486a3c9bf1e0f876d0f241bc3f229d7d65d09331a0868db9629/pytest_forked-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "py", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl"}}], "install_targets_hash": "e0332f37695c3f450fdb05225a93e60d"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "grpcio", "version": "1.49.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/1c/c42834d4fee45c5cf2d9546e97e879a1cbcdecfd16eb1a12144dcb91edae/grpcio-1.49.1.tar.gz"}}, {"metadata": {"name": "protobuf", "version": "7.35.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/03/8aeeb7458d22546bf64b5250ca1daeb5ff757d900e8e4a7476c6f0db843e/protobuf-7.35.1-cp310-abi3-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "mypy-protobuf", "version": "5.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/ec/5ffcf8f5f53757e01afdece10c664e694ac60d2f17c2036811b85b842a5b/mypy_protobuf-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "types-protobuf", "version": "7.34.1.20260518"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/1f/ec5caf72c2e3b688ca3927e0979a04ddad19e1afc4bf1c199bd743e0f419/types_protobuf-7.34.1.20260518-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/af/9c0bda43e486a3c9bf1e0f876d0f241bc3f229d7d65d09331a0868db9629/pytest_forked-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "py", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl"}}], "install_targets_hash": "e0332f37695c3f450fdb05225a93e60d"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "launchdarkly-server-sdk", "version": "9.17.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c1/58/bcede9c0f11b5c37b492ea993ed0599099e15f803b9fe98452558cfd6e96/launchdarkly_server_sdk-9.17.0-py3-none-any.whl"}}, {"metadata": {"name": "launchdarkly-eventsource", "version": "1.7.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/49/8592c1d9c156d3c2d3f8c02e1c00260c3e0a7a10bcb50c942bd80c285c62/launchdarkly_eventsource-1.7.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "expiringdict", "version": "1.2.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cb/84/a04c59324445f4bcc98dc05b39a1cd07c242dde643c1a3c21e4f7beaf2f2/expiringdict-1.2.2-py3-none-any.whl"}}, {"metadata": {"name": "pyRFC3339", "version": "2.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/34/90/0200184d2124484f918054751ef997ed6409cb05b7e8dcbf5a22da4c4748/pyrfc3339-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "semver", "version": "3.0.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a6/24/4d91e05817e92e3a61c8a21e08fd0f390f5301f1c448b137c57c4bc6e543/semver-3.0.4-py3-none-any.whl"}}], "install_targets_hash": "e039dc9ecf1b28450bdeec6c73e7b68c"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "launchdarkly-server-sdk", "version": "9.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/58/bcede9c0f11b5c37b492ea993ed0599099e15f803b9fe98452558cfd6e96/launchdarkly_server_sdk-9.17.0-py3-none-any.whl"}}, {"metadata": {"name": "launchdarkly-eventsource", "version": "1.7.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/49/8592c1d9c156d3c2d3f8c02e1c00260c3e0a7a10bcb50c942bd80c285c62/launchdarkly_eventsource-1.7.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "expiringdict", "version": "1.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/84/a04c59324445f4bcc98dc05b39a1cd07c242dde643c1a3c21e4f7beaf2f2/expiringdict-1.2.2-py3-none-any.whl"}}, {"metadata": {"name": "pyRFC3339", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/34/90/0200184d2124484f918054751ef997ed6409cb05b7e8dcbf5a22da4c4748/pyrfc3339-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "semver", "version": "3.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/24/4d91e05817e92e3a61c8a21e08fd0f390f5301f1c448b137c57c4bc6e543/semver-3.0.4-py3-none-any.whl"}}], "install_targets_hash": "e039dc9ecf1b28450bdeec6c73e7b68c"} -{"python_version": "3.10", "dependencies": [{"metadata": {"name": "openai-agents", "version": "0.14.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/af/6e/1e9adcedcde7b163579b88a68f765a4915be4ead0713270386d9432cfd2f/openai_agents-0.14.8-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "2.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ae/f4/561ed79fd94876160018a5e75254cfcb9b0e62d4dded9dcb20072e86d623/openai-2.44.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "griffelib", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/b6/f65ac785d4ac90dcf7c831ac6256f5dd4a19780f4e1575b2c0d6eeebe319/griffelib-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c6/3d/4d7f5667ea0e0548534ba880b84bb3d12924fd133aa83ad6c6c80fca3d76/jiter-0.16.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "mcp", "version": "1.29.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/c8/248b201f6d753d69fd5d6506011abbb35a946d9142b2ae311a948fd0be3d/mcp-1.29.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/c6/65f646c7ff09bd257f660434adb45c4dfcbbcebcc030562fecf6f5bf887d/pydantic_core-2.46.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "types-requests", "version": "2.33.0.20260712"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/e7/010c87f559e216d83f9dc51e939633fd0d0ead3377340181ab0e223cd3b5/types_requests-2.33.0.20260712-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/90/72/2f14b2e167170b8bf1c8bb7f9b0d78000f470d41a2085a91f33e3917b6c9/websockets-16.1.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/aa/554e2614f38fc34c58ff1d0911ae8535ad2516440d5482d76fe59f1088b0/charset_normalizer-3.5.1-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/3a/764912c58293d95b6dcdf4cc255f9d10de310580ced547b082eb9d72018c/sse_starlette-3.4.8-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.52.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/79/4a20b54ab0491485ccd8c077db2d39187c7f12b3e15485d38a7be37c81b4/uvicorn-0.52.4-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/37/73d005be173aff344af30e9fd2a576575cb2391a7101d9cd3842e1fa8cce/cryptography-50.0.0-cp39-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "0.30.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/6a/4ba3d0fb7297ebae71171822554abe48d7cab29c28b8f9f2c04b79988c05/rpds_py-0.30.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/1a/4b2f7c92293ba05cbd4a9a1b28faaf0326272d9488e6354657571c48a7aa/cffi-2.1.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "e39da8a431d3f40f0c1638f060e9b600"} -{"python_version": "3.10", "dependencies": [{"metadata": {"name": "openai-agents", "version": "0.14.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/af/6e/1e9adcedcde7b163579b88a68f765a4915be4ead0713270386d9432cfd2f/openai_agents-0.14.8-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "2.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ae/f4/561ed79fd94876160018a5e75254cfcb9b0e62d4dded9dcb20072e86d623/openai-2.44.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "griffelib", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/b6/f65ac785d4ac90dcf7c831ac6256f5dd4a19780f4e1575b2c0d6eeebe319/griffelib-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c6/3d/4d7f5667ea0e0548534ba880b84bb3d12924fd133aa83ad6c6c80fca3d76/jiter-0.16.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "mcp", "version": "1.29.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/c8/248b201f6d753d69fd5d6506011abbb35a946d9142b2ae311a948fd0be3d/mcp-1.29.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/c6/65f646c7ff09bd257f660434adb45c4dfcbbcebcc030562fecf6f5bf887d/pydantic_core-2.46.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "types-requests", "version": "2.33.0.20260712"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/e7/010c87f559e216d83f9dc51e939633fd0d0ead3377340181ab0e223cd3b5/types_requests-2.33.0.20260712-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/90/72/2f14b2e167170b8bf1c8bb7f9b0d78000f470d41a2085a91f33e3917b6c9/websockets-16.1.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/aa/554e2614f38fc34c58ff1d0911ae8535ad2516440d5482d76fe59f1088b0/charset_normalizer-3.5.1-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/3a/764912c58293d95b6dcdf4cc255f9d10de310580ced547b082eb9d72018c/sse_starlette-3.4.8-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.52.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/79/4a20b54ab0491485ccd8c077db2d39187c7f12b3e15485d38a7be37c81b4/uvicorn-0.52.4-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/37/73d005be173aff344af30e9fd2a576575cb2391a7101d9cd3842e1fa8cce/cryptography-50.0.0-cp39-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "0.30.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/6a/4ba3d0fb7297ebae71171822554abe48d7cab29c28b8f9f2c04b79988c05/rpds_py-0.30.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/1a/4b2f7c92293ba05cbd4a9a1b28faaf0326272d9488e6354657571c48a7aa/cffi-2.1.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "e39da8a431d3f40f0c1638f060e9b600"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "openai-agents", "version": "0.14.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/af/6e/1e9adcedcde7b163579b88a68f765a4915be4ead0713270386d9432cfd2f/openai_agents-0.14.8-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "2.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ae/f4/561ed79fd94876160018a5e75254cfcb9b0e62d4dded9dcb20072e86d623/openai-2.44.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "griffelib", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/63/e876e789525063c840ccfa8857febdabd6523bcef9ce7eb979b9305ea895/griffelib-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/e9/5993079500530586655c6f2823e2926b3f5ceddd49918c5a86757eadba3a/jiter-0.17.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "mcp", "version": "1.30.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f5/f4/e58bc33317c92a0203664daaf00bf6f41166cc0149e5d6870a03f7cd004a/mcp-1.30.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/d0/c787604c71c2bdcda1a5656942fc822cd0f9cd879b9484bb84fc42172703/pydantic_core-2.46.5-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/03/921a3d3c75785aca9ebfbfcabfbc3a1be12e2ab5265deb026d55a5a3f83e/tqdm-4.70.1-py3-none-any.whl"}}, {"metadata": {"name": "types-requests", "version": "2.33.0.20260906"}, "download_info": {"url": "https://files.pythonhosted.org/packages/60/4c/51ec821d22a45b4162fa3f3e9e94ea4c0f8c49e82363b10955baa5438391/types_requests-2.33.0.20260906-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/90/72/2f14b2e167170b8bf1c8bb7f9b0d78000f470d41a2085a91f33e3917b6c9/websockets-16.1.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/aa/554e2614f38fc34c58ff1d0911ae8535ad2516440d5482d76fe59f1088b0/charset_normalizer-3.5.1-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/97/672cb32ce0dfea44b740cb7b4f97038463b9cf7c0ead1aacf595572851d6/pyjwt-2.14.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/6a/2ba3ed4a69babf3afdddf7d8314a48d87562c0a442206bbc2a1b50d5efc0/sse_starlette-3.4.11-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.52.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/79/4a20b54ab0491485ccd8c077db2d39187c7f12b3e15485d38a7be37c81b4/uvicorn-0.52.4-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/84/a9/ee16a903f13755e914d1eecc482fe64d1f10761c3960e5d8fa6837377aff/cryptography-50.0.1-cp39-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "0.30.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/6a/4ba3d0fb7297ebae71171822554abe48d7cab29c28b8f9f2c04b79988c05/rpds_py-0.30.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/1a/4b2f7c92293ba05cbd4a9a1b28faaf0326272d9488e6354657571c48a7aa/cffi-2.1.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "e39da8a431d3f40f0c1638f060e9b600"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "litellm", "version": "1.83.14"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/5c/1b5691575420135e90578543b2bf219497caa33cfd0af64cb38f30288450/litellm-1.83.14-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b4/e5/8f42033c7ce98b54dfd3791f03e60231cfe4a2db4471b5fc188df2b8a6ad/aiohttp-3.13.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "click", "version": "8.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl"}}, {"metadata": {"name": "fastuuid", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/c5/84c1eea05977c8ba5173555b0133e3558dc628bcf868d6bf1689ff14aedc/fastuuid-0.14.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/d9/a1e041c5e7caa9a05c925f4bdbdfb7f006d1f74996af53467bc394c97be7/importlib_metadata-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.23.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/4a/4f9dbeb84e8850557c02365a0eee0649abe5eb1d84af92a25731c6c0f922/jsonschema-4.23.0-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "2.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c9/30/844dc675ee6902579b8eef01ed23917cc9319a1c9c0c14ec6e39340c96d0/openai-2.24.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.12.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.41.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/a8/61c96a77fe28993d9a6fb0f4127e05430a267b235a124545d79fea46dd65/pydantic_core-2.41.5-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/27/0f/df139f1df5f6167194ee5ab24634582ba9a1b62c6b996472b0277ec80f66/tiktoken-0.12.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tokenizers", "version": "0.22.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2e/47/174dca0502ef88b28f1c9e06b73ce33500eedfac7a7692108aec220464e7/tokenizers-0.22.2-cp39-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "huggingface_hub", "version": "1.16.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/79/621a7dbb80c70974f73a597275351ebe03ce5bc65cb5f8f4acb5859252bc/huggingface_hub-1.16.1-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/69/55b8dcf636142ae660fec1869fcac14c4da2e8412e14d6eee1523be77e9f/hf_xet-1.6.0-cp38-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c6/3d/4d7f5667ea0e0548534ba880b84bb3d12924fd133aa83ad6c6c80fca3d76/jiter-0.16.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/31/5c/08c7f7fe311f32e83f7621cd3f99d805f45519cd06fafb247628b861da7d/multidict-6.7.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/59/1d/340d1a0db7bbce1f291afc044255ebf4ebbce2b25ab1b3f7d3d069080f5d/yarl-1.24.5-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anthropic", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/5b/db4a854aebf5d33a5ab714c46af6eb85ee44f390ed29b7b325c00b9f11ed/anthropic-1.0.0-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/95/411ba65569158e862368917aaf56597f3e5fa3b91b0502919638465a08f3/httpx2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/74/d370e55600d9bcfa0d9794b0166126d49291a3d2b20c268fc98c453a4948/httpcore2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "google-genai", "version": "2.19.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/e8/de0accd8cd004cf11252ca53fc5c3dda59bcf1856abfc7609842ceba7363/google_genai-2.19.0-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.56.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/b3/6117b2f24065cd7e2c4f140e9a193e215f089ca8ba314cf91eb9d0b7fe0a/google_auth-2.56.3-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/aa/554e2614f38fc34c58ff1d0911ae8535ad2516440d5482d76fe59f1088b0/charset_normalizer-3.5.1-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/90/72/2f14b2e167170b8bf1c8bb7f9b0d78000f470d41a2085a91f33e3917b6c9/websockets-16.1.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/37/73d005be173aff344af30e9fd2a576575cb2391a7101d9cd3842e1fa8cce/cryptography-50.0.0-cp39-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/1a/4b2f7c92293ba05cbd4a9a1b28faaf0326272d9488e6354657571c48a7aa/cffi-2.1.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "filelock", "version": "3.32.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/a4/9b63d595d748e3aff8812b65eacc1a2c4bd90b7c2012e08e72373b4835eb/filelock-3.32.4-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/70/26ca3f06aace16f2352796b08704338d74b6d1a24ca38f2771afbb7ed915/frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/3c/6a2bf344106328fd04963664a60b9bb6496fc25df8e962fcdc1367285fb9/fsspec-2026.7.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/42/0e7443c90310498561addf346e7d57fe3c6ba1914e1ba938b5464c7bbfd2/propcache-0.5.2-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/3b/6163796d69c3977d1e4287bea4a6979161cbbdd170ebb430511e8e1999ce/pyasn1-0.6.4-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.7.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/16/01/cefe4f051302ca298d3f3e79ed6dbd933ac84485b9515acdd6a52d70cef7/regex-2026.7.19-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "rpds-py", "version": "0.30.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/6a/4ba3d0fb7297ebae71171822554abe48d7cab29c28b8f9f2c04b79988c05/rpds_py-0.30.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typer", "version": "0.27.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/43/89/9518bc0c3929bee36b3a4a8e3daddd6e03f92f9961c66d4983b837160543/typer-0.27.1-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "shellingham", "version": "1.5.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "zipp", "version": "4.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "e4673157ab58986ef4f81da32839974c"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "litellm", "version": "1.83.14"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/5c/1b5691575420135e90578543b2bf219497caa33cfd0af64cb38f30288450/litellm-1.83.14-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b4/e5/8f42033c7ce98b54dfd3791f03e60231cfe4a2db4471b5fc188df2b8a6ad/aiohttp-3.13.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "click", "version": "8.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl"}}, {"metadata": {"name": "fastuuid", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/c5/84c1eea05977c8ba5173555b0133e3558dc628bcf868d6bf1689ff14aedc/fastuuid-0.14.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/d9/a1e041c5e7caa9a05c925f4bdbdfb7f006d1f74996af53467bc394c97be7/importlib_metadata-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.23.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/4a/4f9dbeb84e8850557c02365a0eee0649abe5eb1d84af92a25731c6c0f922/jsonschema-4.23.0-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "2.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c9/30/844dc675ee6902579b8eef01ed23917cc9319a1c9c0c14ec6e39340c96d0/openai-2.24.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.12.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/27/0f/df139f1df5f6167194ee5ab24634582ba9a1b62c6b996472b0277ec80f66/tiktoken-0.12.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tokenizers", "version": "0.22.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2e/47/174dca0502ef88b28f1c9e06b73ce33500eedfac7a7692108aec220464e7/tokenizers-0.22.2-cp39-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.41.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/a8/61c96a77fe28993d9a6fb0f4127e05430a267b235a124545d79fea46dd65/pydantic_core-2.41.5-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anthropic", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/5b/db4a854aebf5d33a5ab714c46af6eb85ee44f390ed29b7b325c00b9f11ed/anthropic-1.0.0-py3-none-any.whl"}}, {"metadata": {"name": "google-genai", "version": "2.19.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/e8/de0accd8cd004cf11252ca53fc5c3dda59bcf1856abfc7609842ceba7363/google_genai-2.19.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.56.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/b3/6117b2f24065cd7e2c4f140e9a193e215f089ca8ba314cf91eb9d0b7fe0a/google_auth-2.56.3-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/95/411ba65569158e862368917aaf56597f3e5fa3b91b0502919638465a08f3/httpx2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/74/d370e55600d9bcfa0d9794b0166126d49291a3d2b20c268fc98c453a4948/httpcore2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c6/3d/4d7f5667ea0e0548534ba880b84bb3d12924fd133aa83ad6c6c80fca3d76/jiter-0.16.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/90/72/2f14b2e167170b8bf1c8bb7f9b0d78000f470d41a2085a91f33e3917b6c9/websockets-16.1.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/aa/554e2614f38fc34c58ff1d0911ae8535ad2516440d5482d76fe59f1088b0/charset_normalizer-3.5.1-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/37/73d005be173aff344af30e9fd2a576575cb2391a7101d9cd3842e1fa8cce/cryptography-50.0.0-cp39-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/70/26ca3f06aace16f2352796b08704338d74b6d1a24ca38f2771afbb7ed915/frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "huggingface_hub", "version": "1.16.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/79/621a7dbb80c70974f73a597275351ebe03ce5bc65cb5f8f4acb5859252bc/huggingface_hub-1.16.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/31/5c/08c7f7fe311f32e83f7621cd3f99d805f45519cd06fafb247628b861da7d/multidict-6.7.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/42/0e7443c90310498561addf346e7d57fe3c6ba1914e1ba938b5464c7bbfd2/propcache-0.5.2-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.7.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/16/01/cefe4f051302ca298d3f3e79ed6dbd933ac84485b9515acdd6a52d70cef7/regex-2026.7.19-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "rpds-py", "version": "0.30.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/6a/4ba3d0fb7297ebae71171822554abe48d7cab29c28b8f9f2c04b79988c05/rpds_py-0.30.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/59/1d/340d1a0db7bbce1f291afc044255ebf4ebbce2b25ab1b3f7d3d069080f5d/yarl-1.24.5-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "zipp", "version": "4.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/1a/4b2f7c92293ba05cbd4a9a1b28faaf0326272d9488e6354657571c48a7aa/cffi-2.1.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "filelock", "version": "3.32.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/a4/9b63d595d748e3aff8812b65eacc1a2c4bd90b7c2012e08e72373b4835eb/filelock-3.32.4-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/3c/6a2bf344106328fd04963664a60b9bb6496fc25df8e962fcdc1367285fb9/fsspec-2026.7.0-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/69/55b8dcf636142ae660fec1869fcac14c4da2e8412e14d6eee1523be77e9f/hf_xet-1.6.0-cp38-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/3b/6163796d69c3977d1e4287bea4a6979161cbbdd170ebb430511e8e1999ce/pyasn1-0.6.4-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typer", "version": "0.27.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/43/89/9518bc0c3929bee36b3a4a8e3daddd6e03f92f9961c66d4983b837160543/typer-0.27.1-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "shellingham", "version": "1.5.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}], "install_targets_hash": "e4673157ab58986ef4f81da32839974c"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "litellm", "version": "1.83.14"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/5c/1b5691575420135e90578543b2bf219497caa33cfd0af64cb38f30288450/litellm-1.83.14-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b4/e5/8f42033c7ce98b54dfd3791f03e60231cfe4a2db4471b5fc188df2b8a6ad/aiohttp-3.13.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "click", "version": "8.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl"}}, {"metadata": {"name": "fastuuid", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/c5/84c1eea05977c8ba5173555b0133e3558dc628bcf868d6bf1689ff14aedc/fastuuid-0.14.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/d9/a1e041c5e7caa9a05c925f4bdbdfb7f006d1f74996af53467bc394c97be7/importlib_metadata-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.23.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/4a/4f9dbeb84e8850557c02365a0eee0649abe5eb1d84af92a25731c6c0f922/jsonschema-4.23.0-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "2.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c9/30/844dc675ee6902579b8eef01ed23917cc9319a1c9c0c14ec6e39340c96d0/openai-2.24.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.12.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/27/0f/df139f1df5f6167194ee5ab24634582ba9a1b62c6b996472b0277ec80f66/tiktoken-0.12.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tokenizers", "version": "0.22.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2e/47/174dca0502ef88b28f1c9e06b73ce33500eedfac7a7692108aec220464e7/tokenizers-0.22.2-cp39-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.41.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/a8/61c96a77fe28993d9a6fb0f4127e05430a267b235a124545d79fea46dd65/pydantic_core-2.41.5-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anthropic", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/5b/db4a854aebf5d33a5ab714c46af6eb85ee44f390ed29b7b325c00b9f11ed/anthropic-1.0.0-py3-none-any.whl"}}, {"metadata": {"name": "google-genai", "version": "2.19.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/e8/de0accd8cd004cf11252ca53fc5c3dda59bcf1856abfc7609842ceba7363/google_genai-2.19.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.56.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/b3/6117b2f24065cd7e2c4f140e9a193e215f089ca8ba314cf91eb9d0b7fe0a/google_auth-2.56.3-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/95/411ba65569158e862368917aaf56597f3e5fa3b91b0502919638465a08f3/httpx2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/74/d370e55600d9bcfa0d9794b0166126d49291a3d2b20c268fc98c453a4948/httpcore2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c6/3d/4d7f5667ea0e0548534ba880b84bb3d12924fd133aa83ad6c6c80fca3d76/jiter-0.16.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/90/72/2f14b2e167170b8bf1c8bb7f9b0d78000f470d41a2085a91f33e3917b6c9/websockets-16.1.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/aa/554e2614f38fc34c58ff1d0911ae8535ad2516440d5482d76fe59f1088b0/charset_normalizer-3.5.1-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/37/73d005be173aff344af30e9fd2a576575cb2391a7101d9cd3842e1fa8cce/cryptography-50.0.0-cp39-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/70/26ca3f06aace16f2352796b08704338d74b6d1a24ca38f2771afbb7ed915/frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "huggingface_hub", "version": "1.16.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/79/621a7dbb80c70974f73a597275351ebe03ce5bc65cb5f8f4acb5859252bc/huggingface_hub-1.16.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/31/5c/08c7f7fe311f32e83f7621cd3f99d805f45519cd06fafb247628b861da7d/multidict-6.7.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/42/0e7443c90310498561addf346e7d57fe3c6ba1914e1ba938b5464c7bbfd2/propcache-0.5.2-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.7.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/16/01/cefe4f051302ca298d3f3e79ed6dbd933ac84485b9515acdd6a52d70cef7/regex-2026.7.19-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "rpds-py", "version": "0.30.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/6a/4ba3d0fb7297ebae71171822554abe48d7cab29c28b8f9f2c04b79988c05/rpds_py-0.30.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/59/1d/340d1a0db7bbce1f291afc044255ebf4ebbce2b25ab1b3f7d3d069080f5d/yarl-1.24.5-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "zipp", "version": "4.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/1a/4b2f7c92293ba05cbd4a9a1b28faaf0326272d9488e6354657571c48a7aa/cffi-2.1.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "filelock", "version": "3.32.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/a4/9b63d595d748e3aff8812b65eacc1a2c4bd90b7c2012e08e72373b4835eb/filelock-3.32.4-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/3c/6a2bf344106328fd04963664a60b9bb6496fc25df8e962fcdc1367285fb9/fsspec-2026.7.0-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/69/55b8dcf636142ae660fec1869fcac14c4da2e8412e14d6eee1523be77e9f/hf_xet-1.6.0-cp38-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/3b/6163796d69c3977d1e4287bea4a6979161cbbdd170ebb430511e8e1999ce/pyasn1-0.6.4-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typer", "version": "0.27.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/43/89/9518bc0c3929bee36b3a4a8e3daddd6e03f92f9961c66d4983b837160543/typer-0.27.1-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "shellingham", "version": "1.5.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}], "install_targets_hash": "e4673157ab58986ef4f81da32839974c"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "litellm", "version": "1.83.14"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/5c/1b5691575420135e90578543b2bf219497caa33cfd0af64cb38f30288450/litellm-1.83.14-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b4/e5/8f42033c7ce98b54dfd3791f03e60231cfe4a2db4471b5fc188df2b8a6ad/aiohttp-3.13.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "click", "version": "8.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl"}}, {"metadata": {"name": "fastuuid", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/c5/84c1eea05977c8ba5173555b0133e3558dc628bcf868d6bf1689ff14aedc/fastuuid-0.14.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/d9/a1e041c5e7caa9a05c925f4bdbdfb7f006d1f74996af53467bc394c97be7/importlib_metadata-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.23.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/4a/4f9dbeb84e8850557c02365a0eee0649abe5eb1d84af92a25731c6c0f922/jsonschema-4.23.0-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "2.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c9/30/844dc675ee6902579b8eef01ed23917cc9319a1c9c0c14ec6e39340c96d0/openai-2.24.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.12.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/27/0f/df139f1df5f6167194ee5ab24634582ba9a1b62c6b996472b0277ec80f66/tiktoken-0.12.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tokenizers", "version": "0.22.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2e/47/174dca0502ef88b28f1c9e06b73ce33500eedfac7a7692108aec220464e7/tokenizers-0.22.2-cp39-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.41.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/a8/61c96a77fe28993d9a6fb0f4127e05430a267b235a124545d79fea46dd65/pydantic_core-2.41.5-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anthropic", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/5b/db4a854aebf5d33a5ab714c46af6eb85ee44f390ed29b7b325c00b9f11ed/anthropic-1.0.0-py3-none-any.whl"}}, {"metadata": {"name": "google-genai", "version": "2.19.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/e8/de0accd8cd004cf11252ca53fc5c3dda59bcf1856abfc7609842ceba7363/google_genai-2.19.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.56.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/b3/6117b2f24065cd7e2c4f140e9a193e215f089ca8ba314cf91eb9d0b7fe0a/google_auth-2.56.3-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/95/411ba65569158e862368917aaf56597f3e5fa3b91b0502919638465a08f3/httpx2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/74/d370e55600d9bcfa0d9794b0166126d49291a3d2b20c268fc98c453a4948/httpcore2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c6/3d/4d7f5667ea0e0548534ba880b84bb3d12924fd133aa83ad6c6c80fca3d76/jiter-0.16.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/90/72/2f14b2e167170b8bf1c8bb7f9b0d78000f470d41a2085a91f33e3917b6c9/websockets-16.1.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/aa/554e2614f38fc34c58ff1d0911ae8535ad2516440d5482d76fe59f1088b0/charset_normalizer-3.5.1-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/37/73d005be173aff344af30e9fd2a576575cb2391a7101d9cd3842e1fa8cce/cryptography-50.0.0-cp39-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/70/26ca3f06aace16f2352796b08704338d74b6d1a24ca38f2771afbb7ed915/frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "huggingface_hub", "version": "1.16.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/79/621a7dbb80c70974f73a597275351ebe03ce5bc65cb5f8f4acb5859252bc/huggingface_hub-1.16.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/31/5c/08c7f7fe311f32e83f7621cd3f99d805f45519cd06fafb247628b861da7d/multidict-6.7.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/42/0e7443c90310498561addf346e7d57fe3c6ba1914e1ba938b5464c7bbfd2/propcache-0.5.2-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.7.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/16/01/cefe4f051302ca298d3f3e79ed6dbd933ac84485b9515acdd6a52d70cef7/regex-2026.7.19-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "rpds-py", "version": "0.30.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/6a/4ba3d0fb7297ebae71171822554abe48d7cab29c28b8f9f2c04b79988c05/rpds_py-0.30.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/59/1d/340d1a0db7bbce1f291afc044255ebf4ebbce2b25ab1b3f7d3d069080f5d/yarl-1.24.5-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "zipp", "version": "4.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/1a/4b2f7c92293ba05cbd4a9a1b28faaf0326272d9488e6354657571c48a7aa/cffi-2.1.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "filelock", "version": "3.32.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/a4/9b63d595d748e3aff8812b65eacc1a2c4bd90b7c2012e08e72373b4835eb/filelock-3.32.4-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/3c/6a2bf344106328fd04963664a60b9bb6496fc25df8e962fcdc1367285fb9/fsspec-2026.7.0-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/69/55b8dcf636142ae660fec1869fcac14c4da2e8412e14d6eee1523be77e9f/hf_xet-1.6.0-cp38-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/3b/6163796d69c3977d1e4287bea4a6979161cbbdd170ebb430511e8e1999ce/pyasn1-0.6.4-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typer", "version": "0.27.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/43/89/9518bc0c3929bee36b3a4a8e3daddd6e03f92f9961c66d4983b837160543/typer-0.27.1-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "shellingham", "version": "1.5.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}], "install_targets_hash": "e4673157ab58986ef4f81da32839974c"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "litellm", "version": "1.83.14"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/5c/1b5691575420135e90578543b2bf219497caa33cfd0af64cb38f30288450/litellm-1.83.14-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b4/e5/8f42033c7ce98b54dfd3791f03e60231cfe4a2db4471b5fc188df2b8a6ad/aiohttp-3.13.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "click", "version": "8.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl"}}, {"metadata": {"name": "fastuuid", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/c5/84c1eea05977c8ba5173555b0133e3558dc628bcf868d6bf1689ff14aedc/fastuuid-0.14.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/d9/a1e041c5e7caa9a05c925f4bdbdfb7f006d1f74996af53467bc394c97be7/importlib_metadata-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.23.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/4a/4f9dbeb84e8850557c02365a0eee0649abe5eb1d84af92a25731c6c0f922/jsonschema-4.23.0-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "2.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c9/30/844dc675ee6902579b8eef01ed23917cc9319a1c9c0c14ec6e39340c96d0/openai-2.24.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.12.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/27/0f/df139f1df5f6167194ee5ab24634582ba9a1b62c6b996472b0277ec80f66/tiktoken-0.12.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tokenizers", "version": "0.22.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2e/47/174dca0502ef88b28f1c9e06b73ce33500eedfac7a7692108aec220464e7/tokenizers-0.22.2-cp39-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.41.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/a8/61c96a77fe28993d9a6fb0f4127e05430a267b235a124545d79fea46dd65/pydantic_core-2.41.5-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anthropic", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/5b/db4a854aebf5d33a5ab714c46af6eb85ee44f390ed29b7b325c00b9f11ed/anthropic-1.0.0-py3-none-any.whl"}}, {"metadata": {"name": "google-genai", "version": "2.19.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/e8/de0accd8cd004cf11252ca53fc5c3dda59bcf1856abfc7609842ceba7363/google_genai-2.19.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.56.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/b3/6117b2f24065cd7e2c4f140e9a193e215f089ca8ba314cf91eb9d0b7fe0a/google_auth-2.56.3-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/95/411ba65569158e862368917aaf56597f3e5fa3b91b0502919638465a08f3/httpx2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/74/d370e55600d9bcfa0d9794b0166126d49291a3d2b20c268fc98c453a4948/httpcore2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c6/3d/4d7f5667ea0e0548534ba880b84bb3d12924fd133aa83ad6c6c80fca3d76/jiter-0.16.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/90/72/2f14b2e167170b8bf1c8bb7f9b0d78000f470d41a2085a91f33e3917b6c9/websockets-16.1.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/aa/554e2614f38fc34c58ff1d0911ae8535ad2516440d5482d76fe59f1088b0/charset_normalizer-3.5.1-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/37/73d005be173aff344af30e9fd2a576575cb2391a7101d9cd3842e1fa8cce/cryptography-50.0.0-cp39-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/70/26ca3f06aace16f2352796b08704338d74b6d1a24ca38f2771afbb7ed915/frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "huggingface_hub", "version": "1.16.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/79/621a7dbb80c70974f73a597275351ebe03ce5bc65cb5f8f4acb5859252bc/huggingface_hub-1.16.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/31/5c/08c7f7fe311f32e83f7621cd3f99d805f45519cd06fafb247628b861da7d/multidict-6.7.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/42/0e7443c90310498561addf346e7d57fe3c6ba1914e1ba938b5464c7bbfd2/propcache-0.5.2-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.7.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/16/01/cefe4f051302ca298d3f3e79ed6dbd933ac84485b9515acdd6a52d70cef7/regex-2026.7.19-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "rpds-py", "version": "0.30.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/6a/4ba3d0fb7297ebae71171822554abe48d7cab29c28b8f9f2c04b79988c05/rpds_py-0.30.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/59/1d/340d1a0db7bbce1f291afc044255ebf4ebbce2b25ab1b3f7d3d069080f5d/yarl-1.24.5-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "zipp", "version": "4.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/1a/4b2f7c92293ba05cbd4a9a1b28faaf0326272d9488e6354657571c48a7aa/cffi-2.1.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "filelock", "version": "3.32.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/a4/9b63d595d748e3aff8812b65eacc1a2c4bd90b7c2012e08e72373b4835eb/filelock-3.32.4-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/3c/6a2bf344106328fd04963664a60b9bb6496fc25df8e962fcdc1367285fb9/fsspec-2026.7.0-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/69/55b8dcf636142ae660fec1869fcac14c4da2e8412e14d6eee1523be77e9f/hf_xet-1.6.0-cp38-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/3b/6163796d69c3977d1e4287bea4a6979161cbbdd170ebb430511e8e1999ce/pyasn1-0.6.4-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typer", "version": "0.27.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/43/89/9518bc0c3929bee36b3a4a8e3daddd6e03f92f9961c66d4983b837160543/typer-0.27.1-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "shellingham", "version": "1.5.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}], "install_targets_hash": "e4673157ab58986ef4f81da32839974c"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "Flask", "version": "2.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cd/77/59df23681f4fd19b7cbbb5e92484d46ad587554f5d490f33ef907e456132/Flask-2.0.3-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "2.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/f8/9da63c1617ae2a1dec2fbf6412f3a0cfe9d4ce029eccbda6e1e4258ca45f/Werkzeug-2.2.3-py3-none-any.whl"}}, {"metadata": {"name": "Flask-Login", "version": "0.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/59/f5/67e9cc5c2036f58115f9fe0f00d203cf6780c3ff8ae0e705e7a9d9e8ff9e/Flask_Login-0.6.3-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}], "install_targets_hash": "e7a6e5268797db2431fe5b6f53613732"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "pydantic-ai", "version": "1.76.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e5/c2/8f762847db3f76cafbfad18aea49305b82f15cd8c67f644d0abfc51fc92c/pydantic_ai-1.76.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-ai-slim", "version": "1.76.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/c6/7801af6853502bd53f00e88560f60270d8a2ab3bd8e19732d5ae8f261503/pydantic_ai_slim-1.76.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-evals", "version": "1.76.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e7/ab/14335e6c988ef2af23d33bb89cde4c737b904f84fb237758acf156bb0748/pydantic_evals-1.76.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-graph", "version": "1.76.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/4f/60b018568a33c907734613fb089ff288168faa6affb634e05e1a53f1f9e8/pydantic_graph-1.76.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ag-ui-protocol", "version": "0.1.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/be/6c/af3d577e68c9474c99600e65b2c6283772aae187edca6f0f2f5cbd9f565a/ag_ui_protocol-0.1.22-py3-none-any.whl"}}, {"metadata": {"name": "anthropic", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/e3/34a88f0e1e854022a352d67f72ca9baa8b952d4541315088411ba2bfbc2a/anthropic-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "argcomplete", "version": "3.7.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/46/bd/551ee6af426af84ca33e02622be722925c196608e9127d731ef17c47f06e/argcomplete-3.7.2-py3-none-any.whl"}}, {"metadata": {"name": "boto3", "version": "1.43.90"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/c3/1d5c5ea7f599e2b80d122beeb2a9c1a8daff78325ea2391521e5fd5af1fd/boto3-1.43.90-py3-none-any.whl"}}, {"metadata": {"name": "cohere", "version": "7.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4a/c3/064a44c498bf6ae8621caa14307d3ef5471157f149e33cfd64417c8e9ad3/cohere-7.1.1-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "mcp", "version": "1.30.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f5/f4/e58bc33317c92a0203664daaf00bf6f41166cc0149e5d6870a03f7cd004a/mcp-1.30.0-py3-none-any.whl"}}, {"metadata": {"name": "fastmcp", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ac/14/6d950459cc831fa17fe2d1797926b6eb2d2f2af50f830e62d0c098cc1ec8/fastmcp-3.4.7-py3-none-any.whl"}}, {"metadata": {"name": "fastmcp-slim", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b4/97/e0e53642cd029a9a7635ae9c548f9f2cc995af5914e487b3df795664e4be/fastmcp_slim-3.4.7-py3-none-any.whl"}}, {"metadata": {"name": "genai-prices", "version": "0.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/48/a1/43fa2a4c5557cd977e83eecec265b0b77b726b0c7b9f2f180b46c6fdb458/genai_prices-0.1.6-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.57.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3b/27/0f7247b8002a1404fdb5412aeb15fb0fe70288eb8f88a5873d1c0d8262cf/google_auth-2.57.1-py3-none-any.whl"}}, {"metadata": {"name": "google-genai", "version": "2.22.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/de/96/0120d214958cb54f2b9c48da9f564a0e6eae269e9dd702415fb1d0551cc7/google_genai-2.22.0-py3-none-any.whl"}}, {"metadata": {"name": "griffelib", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/63/e876e789525063c840ccfa8857febdabd6523bcef9ce7eb979b9305ea895/griffelib-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "groq", "version": "1.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/f6/c3d8ea3194d7d7d8292edd4dbb4b6832d29c2eab04887dda4a742e83902c/groq-1.7.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "huggingface_hub", "version": "1.30.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c3/0e/3e45bbe0dd48f4e56b1d46649d342de853cd1c7e815323472ab62687f153/huggingface_hub-1.30.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "logfire", "version": "5.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/a0/f3a6a31587b85283cbb878446b2e55c9152624586d8d7322adab124fbc96/logfire-5.0.0-py3-none-any.whl"}}, {"metadata": {"name": "mistralai", "version": "2.9.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ac/c6/ce6371bd7a56e8c01a8f59baf4bc16d134eed4f3e2c593b5733087012936/mistralai-2.9.4-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "3.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/50/0d796ada2d1222cfe609cf435ce7a688450735cee401b24737882c9b9612/openai-3.10.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/6f/a04e900f465ff3221ccc395522503e2d10e79fa21f2723c8e177aae1e0d1/opentelemetry_api-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "prompt_toolkit", "version": "3.0.53"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/6f/84908cad2d6aa5144abcf7b42709fe4fdb459bc640ec7ac5786e7693dabc/prompt_toolkit-3.0.53-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/d0/c787604c71c2bdcda1a5656942fc822cd0f9cd879b9484bb84fc42172703/pydantic_core-2.46.5-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic-handlebars", "version": "0.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/11/364bc401f1d8fdb3947079fc43ffdfbfc9132d065981a03a95d2e87440c4/pydantic_handlebars-0.2.1-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "pyperclip", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/80/fc9d01d5ed37ba4c42ca2b55b4339ae6e200b456be3a1aaddf4a9fa99b8c/pyperclip-1.11.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "temporalio", "version": "1.32.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d0/84/6cc96518a2aff3ce9fb132479811bb29db563fbcdc947c279df8f089721a/temporalio-1.32.0-cp310-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "nexus-rpc", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/11/52/6327a5f4fda01207205038a106a99848a41c83e933cd23ea2cab3d2ebc6c/nexus_rpc-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/18/e2/d39ae33d3dc30a0c229ff0cb683df961ebb5e7b8691feb2d08b3ee6ac327/tiktoken-0.14.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "xai-sdk", "version": "1.19.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/b5/6f6783b97fb3a5498eb852ccaa706e1a2c0de2409480e3c99428e85234fe/xai_sdk-1.19.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "25.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9e/73b582c4dbbc3c12ef4473822475effaabf1f934b56f14f5b03fe5d3a2af/aiohttp-3.14.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.90"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/b8/65cbd0d65553c3e51d27159de4c74308ea008c652b05ed3f830f32667efb/botocore-1.43.90-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/aa/554e2614f38fc34c58ff1d0911ae8535ad2516440d5482d76fe59f1088b0/charset_normalizer-3.5.1-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/84/a9/ee16a903f13755e914d1eecc482fe64d1f10761c3960e5d8fa6837377aff/cryptography-50.0.1-cp39-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "eval_type_backport", "version": "0.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/a7/bb99bf5e6f78736ddb53480f2c3ff3702ffe2196a7c5e1661c03081d398e/eval_type_backport-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "executing", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "fastavro", "version": "1.12.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3c/91/16c3508447e7cf9f413a6a01792a990ed94d17505fc80a7fb76027078aed/fastavro-1.12.2-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "filelock", "version": "3.32.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cc/06/4f138f618dbea66803291274f228f01daf29f306fe8b96bc30dab765df75/filelock-3.32.6-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/3c/6a2bf344106328fd04963664a60b9bb6496fc25df8e962fcdc1367285fb9/fsspec-2026.7.0-py3-none-any.whl"}}, {"metadata": {"name": "googleapis-common-protos", "version": "1.75.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1a/7a/7d79170c6ce6f12e109df2b3879d6b934010cf4f99aea8de8b7e5408c174/googleapis_common_protos-1.75.3-py3-none-any.whl"}}, {"metadata": {"name": "grpcio", "version": "1.83.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/74/cd/9dd4c80dba1454c32c876d0b5f138b0b3f61323bea620984c47f3c62d0e6/grpcio-1.83.1-cp310-cp310-macosx_11_0_universal2.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/69/55b8dcf636142ae660fec1869fcac14c4da2e8412e14d6eee1523be77e9f/hf_xet-1.6.0-cp38-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/95/411ba65569158e862368917aaf56597f3e5fa3b91b0502919638465a08f3/httpx2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/74/d370e55600d9bcfa0d9794b0166126d49291a3d2b20c268fc98c453a4948/httpcore2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c6/3d/4d7f5667ea0e0548534ba880b84bb3d12924fd133aa83ad6c6c80fca3d76/jiter-0.16.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonpath-python", "version": "1.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/8a/1270a6803bd821cbfcdda387eaa13cb41a7b1f7b9bd145979b3bfb9d6cb7/jsonpath_python-1.1.6-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "logfire-api", "version": "5.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/36/67/282646935c5af564ca89447f745aa292e2d36b554fac3d1effe5c75495ca/logfire_api-5.0.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-exporter-otlp-proto-http", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cd/d0/fdeb1a98d8d3a6205f5f297c51b4a9bfe65126ab60339669bbe3dd54c2e2/opentelemetry_exporter_otlp_proto_http-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-exporter-otlp-proto-common", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5e/71/65fd9d54c10b860f87c045ccee1264cab7011268895d3528818a29c1172a/opentelemetry_exporter_otlp_proto_common-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-proto", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d1/7c/8be563d68e93bbefa5c8affb82ddcff91b3ad858ce49957ba7b16fd3e0ab/opentelemetry_proto-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-instrumentation", "version": "0.65b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/40/7b/85eab1215f72adf0e68d3dc4a679b9bff993fa679ff34cd8dd378e2659fd/opentelemetry_instrumentation-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-semantic-conventions", "version": "0.65b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/0e/49df70d9b81fb5cbae4bbf2a49d865b09bcbcbc4eb53f5851b1027738d78/opentelemetry_semantic_conventions-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-instrumentation-httpx", "version": "0.65b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/0f/c6144096b4914bbf44b43ba21c962e8f333ff045770b50a3e79ed8bd455f/opentelemetry_instrumentation_httpx-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-util-http", "version": "0.65b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/23/3f/ab8d29df207ce5f470a07fa96ebb48af4e95b7fab7e7635311b9a32f2fab/opentelemetry_util_http-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-sdk", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e7/23/ff077e61886ee020a17ce9c8b6fa11c601c8d8345b09ea24f605445df62a/opentelemetry_sdk-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "protobuf", "version": "6.33.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5c/01/a3c3ed5cd186f39e7880f8303cc51385a198a81469d53d0fdecf1f64d929/protobuf-6.33.6-cp39-abi3-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "s3transfer", "version": "0.19.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/e7/5c595c75e9f41a44f30e526eda465ea0b4eec93470e074e4a111b253f13a/s3transfer-0.19.2-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/6a/2ba3ed4a69babf3afdddf7d8314a48d87562c0a442206bbc2a1b50d5efc0/sse_starlette-3.4.11-py3-none-any.whl"}}, {"metadata": {"name": "tokenizers", "version": "0.23.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/49/22da045a91732384d3a3771816bf188dc5a1f702c32e635afa7c679c0bef/tokenizers-0.23.2-cp310-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "types-protobuf", "version": "7.35.1.20260906"}, "download_info": {"url": "https://files.pythonhosted.org/packages/44/4e/f63e826c68f77ef875506d72f225918800346545ee99847bc28f3394f18d/types_protobuf-7.35.1.20260906-py3-none-any.whl"}}, {"metadata": {"name": "types-requests", "version": "2.33.0.20260906"}, "download_info": {"url": "https://files.pythonhosted.org/packages/60/4c/51ec821d22a45b4162fa3f3e9e94ea4c0f8c49e82363b10955baa5438391/types_requests-2.33.0.20260906-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.52.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/79/4a20b54ab0491485ccd8c077db2d39187c7f12b3e15485d38a7be37c81b4/uvicorn-0.52.4-py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c4/0e/57f6bb3024a597b2e8ec4aee710ffe62ddc95af2e2bb1ee7a7abdc22c68c/wcwidth-0.8.3-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/90/72/2f14b2e167170b8bf1c8bb7f9b0d78000f470d41a2085a91f33e3917b6c9/websockets-16.1.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "regex", "version": "2026.9.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/b1/a35c61819ddd788bca7dc7a1be48a6bf5456044e3bb681553a15611879a3/regex-2026.9.3-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "Authlib", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b8/c6/6f124bcfbbfb20fba22c939b4e43a06dccfc0e1ca20e5634ca573cb1e271/authlib-1.8.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/1a/4b2f7c92293ba05cbd4a9a1b28faaf0326272d9488e6354657571c48a7aa/cffi-2.1.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cyclopts", "version": "4.25.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/0e/eadf712ca776fd96982c09348dd8f141ae6f96746a4eabc3e3fb54dea738/cyclopts-4.25.2-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/70/26ca3f06aace16f2352796b08704338d74b6d1a24ca38f2771afbb7ed915/frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "joserfc", "version": "1.7.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/c5/82addfd375e5ee6520644e0553e4aadde92d668c4fc99cc716d337fe7bb3/joserfc-1.7.5-py3-none-any.whl"}}, {"metadata": {"name": "jsonref", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/ec/e1db9922bceb168197a558a2b8c03a7963f1afe93517ddd3cf99f202f996/jsonref-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-path", "version": "0.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/2c/9e69d73c4297508be9e3b64a970ea3971b3eb8db64ffc5802d40bd25981f/jsonschema_path-0.5.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/31/5c/08c7f7fe311f32e83f7621cd3f99d805f45519cd06fafb247628b861da7d/multidict-6.7.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "openapi-pydantic", "version": "0.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/cf/03675d8bd8ecbf4445504d8071adab19f5f993676795708e36402ab38263/openapi_pydantic-0.5.1-py3-none-any.whl"}}, {"metadata": {"name": "platformdirs", "version": "4.11.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/e1/5b7b8bbb55084d1425bcb9bc823ff519e1b2be05f6ebb0089e2eacc38413/platformdirs-4.11.8-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/42/0e7443c90310498561addf346e7d57fe3c6ba1914e1ba938b5464c7bbfd2/propcache-0.5.2-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "py-key-value-aio", "version": "0.4.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/95/b8ba862968712caa12a19666175334fa979e1f198b896a430adb3bacfe87/py_key_value_aio-0.4.5-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/3b/6163796d69c3977d1e4287bea4a6979161cbbdd170ebb430511e8e1999ce/pyasn1-0.6.4-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "0.30.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/6a/4ba3d0fb7297ebae71171822554abe48d7cab29c28b8f9f2c04b79988c05/rpds_py-0.30.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "uncalled-for", "version": "0.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a2/40/97cec87c077eb3291fc7905e6633e08b7ca593c57d30238444bcb6bb3d53/uncalled_for-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "watchfiles", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/70/dea1f6a0e76607841a60fb51af150e70124864673f61704abb62b90cdcc7/watchfiles-1.2.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "wrapt", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c0/3c/a4620a03518eb133131aa54ae6973ba273a6f7244f2f771002be5f2db938/wrapt-2.4.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/59/1d/340d1a0db7bbce1f291afc044255ebf4ebbce2b25ab1b3f7d3d069080f5d/yarl-1.24.5-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiofile", "version": "3.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/25/da1f0b4dd970e52bf5a36c204c107e11a0c6d3ed195eba0bfbc664c312b2/aiofile-3.9.0-py3-none-any.whl"}}, {"metadata": {"name": "beartype", "version": "0.22.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/cc/18245721fa7747065ab478316c7fea7c74777d07f37ae60db2e84f8172e8/beartype-0.22.9-py3-none-any.whl"}}, {"metadata": {"name": "cachetools", "version": "7.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/3d/9487690d0e937854db587205c66bab3c3cf88d9f00ed380b74cb88cc94ee/cachetools-7.1.8-py3-none-any.whl"}}, {"metadata": {"name": "email-validator", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "keyring", "version": "25.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/db/e655086b7f3a705df045bf0933bdd9c2f79bb3c97bfef1384598bb79a217/keyring-25.7.0-py3-none-any.whl"}}, {"metadata": {"name": "pathable", "version": "0.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a2/e8/6d75ffd9784bce2e93d1ae4415649427e39a53bb172d4672b2b59c6f0a7b/pathable-0.6.0-py3-none-any.whl"}}, {"metadata": {"name": "rich-rst", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/68/1fc93dd759605b5d00fc98b50200739e41ed32bd22d6ba35ca6c3932371b/rich_rst-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "caio", "version": "0.9.25"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6a/80/ea4ead0c5d52a9828692e7df20f0eafe8d26e671ce4883a0a146bb91049e/caio-0.9.25-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "dnspython", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "9.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/55/ecca97ae19075f1fac62def77731e7f535e6c1fb8f92ff08160c5e6dade8/importlib_metadata-9.0.1-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.classes", "version": "3.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/66/b15ce62552d84bbfcec9a4873ab79d993a1dd4edb922cbfccae192bd5b5f/jaraco.classes-3.4.0-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.context", "version": "6.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f2/58/bc8954bda5fcda97bd7c19be11b85f91973d67a706ed4a3aec33e7de22db/jaraco_context-6.1.2-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.functools", "version": "4.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/02/36/ecc85bc96c273dc8a11273ed4782272975e6338d4a3e9228621175edf0e3/jaraco_functools-4.6.0-py3-none-any.whl"}}, {"metadata": {"name": "zipp", "version": "4.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.tarfile", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/fa/123043af240e49752f1c4bd24da5053b6bd00cad78c2be53c0d1e8b975bc/backports.tarfile-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "more-itertools", "version": "11.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/3d/1087453384dbde46a8c7f9356eead2c58be8a7bf156bca40243377c85715/more_itertools-11.1.0-py3-none-any.whl"}}], "install_targets_hash": "e7b1126e413bef21402b41f19a1e7222"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "httpx", "version": "0.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/05/148ebadb30f498754a738bab07fa88e39b6e401bcd86710f9b36b1cd737d/httpx-0.20.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-httpx", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/43/f1fd8c7f972af4dc95cc9f293515671d826e8960b8fbfe6092840436cf71/pytest_httpx-0.14.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "6.2.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/40/76/86f886e750b81a4357b6ed606b2bcf0ce6d6c27ad3c09ebf63ed674fc86e/pytest-6.2.5-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.20.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/45/74/9421cfde8def10c265b4f9ae19c95b8f4dc227f639cb8b89287d4946ac97/pytest_asyncio-0.20.3-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "0.13.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/73/a1/e347135b0ebb4d4c29a4258cb6d2e03c2d0c4ea207bf9ce5d255d7887a56/httpcore-0.13.7-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "rfc3986", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c4/e5/63ca2c4edf4e00657584608bee1001302bbf8c5f569340b78304f2f446cb/rfc3986-1.5.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/aa/554e2614f38fc34c58ff1d0911ae8535ad2516440d5482d76fe59f1088b0/charset_normalizer-3.5.1-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/60/0f/7a0eeea938eaf61074f29fed9717f2010e8d0e0905d36b38d3275a1e4622/h11-0.12.0-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "py", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "toml", "version": "0.10.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/44/6f/7120676b6d73228c96e17f1f794d8ab046fc910d781c8d151120c3f1569e/toml-0.10.2-py2.py3-none-any.whl"}}], "install_targets_hash": "eaa16b0c40489ad714b5873dabc2a800"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "httpx", "version": "0.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/05/148ebadb30f498754a738bab07fa88e39b6e401bcd86710f9b36b1cd737d/httpx-0.20.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-httpx", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/43/f1fd8c7f972af4dc95cc9f293515671d826e8960b8fbfe6092840436cf71/pytest_httpx-0.14.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "0.13.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/73/a1/e347135b0ebb4d4c29a4258cb6d2e03c2d0c4ea207bf9ce5d255d7887a56/httpcore-0.13.7-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/60/0f/7a0eeea938eaf61074f29fed9717f2010e8d0e0905d36b38d3275a1e4622/h11-0.12.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "6.2.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/40/76/86f886e750b81a4357b6ed606b2bcf0ce6d6c27ad3c09ebf63ed674fc86e/pytest-6.2.5-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "rfc3986", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c4/e5/63ca2c4edf4e00657584608bee1001302bbf8c5f569340b78304f2f446cb/rfc3986-1.5.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.20.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/45/74/9421cfde8def10c265b4f9ae19c95b8f4dc227f639cb8b89287d4946ac97/pytest_asyncio-0.20.3-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "py", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/81/8e983840c6e5b93b33c2ba81aa3d52c2e42f0e9a690ce7607a2e61da4a5c/charset_normalizer-3.4.9-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "toml", "version": "0.10.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/44/6f/7120676b6d73228c96e17f1f794d8ab046fc910d781c8d151120c3f1569e/toml-0.10.2-py2.py3-none-any.whl"}}], "install_targets_hash": "eaa16b0c40489ad714b5873dabc2a800"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "httpx", "version": "0.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/05/148ebadb30f498754a738bab07fa88e39b6e401bcd86710f9b36b1cd737d/httpx-0.20.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-httpx", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/43/f1fd8c7f972af4dc95cc9f293515671d826e8960b8fbfe6092840436cf71/pytest_httpx-0.14.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "0.13.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/73/a1/e347135b0ebb4d4c29a4258cb6d2e03c2d0c4ea207bf9ce5d255d7887a56/httpcore-0.13.7-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/60/0f/7a0eeea938eaf61074f29fed9717f2010e8d0e0905d36b38d3275a1e4622/h11-0.12.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "6.2.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/40/76/86f886e750b81a4357b6ed606b2bcf0ce6d6c27ad3c09ebf63ed674fc86e/pytest-6.2.5-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "rfc3986", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c4/e5/63ca2c4edf4e00657584608bee1001302bbf8c5f569340b78304f2f446cb/rfc3986-1.5.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.20.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/45/74/9421cfde8def10c265b4f9ae19c95b8f4dc227f639cb8b89287d4946ac97/pytest_asyncio-0.20.3-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "py", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/81/8e983840c6e5b93b33c2ba81aa3d52c2e42f0e9a690ce7607a2e61da4a5c/charset_normalizer-3.4.9-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "toml", "version": "0.10.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/44/6f/7120676b6d73228c96e17f1f794d8ab046fc910d781c8d151120c3f1569e/toml-0.10.2-py2.py3-none-any.whl"}}], "install_targets_hash": "eaa16b0c40489ad714b5873dabc2a800"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "httpx", "version": "0.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/05/148ebadb30f498754a738bab07fa88e39b6e401bcd86710f9b36b1cd737d/httpx-0.20.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-httpx", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/43/f1fd8c7f972af4dc95cc9f293515671d826e8960b8fbfe6092840436cf71/pytest_httpx-0.14.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "0.13.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/73/a1/e347135b0ebb4d4c29a4258cb6d2e03c2d0c4ea207bf9ce5d255d7887a56/httpcore-0.13.7-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/60/0f/7a0eeea938eaf61074f29fed9717f2010e8d0e0905d36b38d3275a1e4622/h11-0.12.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "6.2.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/40/76/86f886e750b81a4357b6ed606b2bcf0ce6d6c27ad3c09ebf63ed674fc86e/pytest-6.2.5-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "rfc3986", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c4/e5/63ca2c4edf4e00657584608bee1001302bbf8c5f569340b78304f2f446cb/rfc3986-1.5.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.20.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/45/74/9421cfde8def10c265b4f9ae19c95b8f4dc227f639cb8b89287d4946ac97/pytest_asyncio-0.20.3-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "py", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/81/8e983840c6e5b93b33c2ba81aa3d52c2e42f0e9a690ce7607a2e61da4a5c/charset_normalizer-3.4.9-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "toml", "version": "0.10.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/44/6f/7120676b6d73228c96e17f1f794d8ab046fc910d781c8d151120c3f1569e/toml-0.10.2-py2.py3-none-any.whl"}}], "install_targets_hash": "eaa16b0c40489ad714b5873dabc2a800"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "httpx", "version": "0.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/05/148ebadb30f498754a738bab07fa88e39b6e401bcd86710f9b36b1cd737d/httpx-0.20.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-httpx", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/43/f1fd8c7f972af4dc95cc9f293515671d826e8960b8fbfe6092840436cf71/pytest_httpx-0.14.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "0.13.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/73/a1/e347135b0ebb4d4c29a4258cb6d2e03c2d0c4ea207bf9ce5d255d7887a56/httpcore-0.13.7-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/60/0f/7a0eeea938eaf61074f29fed9717f2010e8d0e0905d36b38d3275a1e4622/h11-0.12.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "6.2.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/40/76/86f886e750b81a4357b6ed606b2bcf0ce6d6c27ad3c09ebf63ed674fc86e/pytest-6.2.5-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "rfc3986", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c4/e5/63ca2c4edf4e00657584608bee1001302bbf8c5f569340b78304f2f446cb/rfc3986-1.5.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.20.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/45/74/9421cfde8def10c265b4f9ae19c95b8f4dc227f639cb8b89287d4946ac97/pytest_asyncio-0.20.3-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "py", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/81/8e983840c6e5b93b33c2ba81aa3d52c2e42f0e9a690ce7607a2e61da4a5c/charset_normalizer-3.4.9-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "toml", "version": "0.10.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/44/6f/7120676b6d73228c96e17f1f794d8ab046fc910d781c8d151120c3f1569e/toml-0.10.2-py2.py3-none-any.whl"}}], "install_targets_hash": "eaa16b0c40489ad714b5873dabc2a800"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "gql", "version": "3.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/1c/2facac9c192d4470960537cf8cdf92d41af10e300a8095ebc37740b4df38/gql-3.4.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.8.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/a9/61f60723b20f9accdf4c9dc812ad4a61c1c63bdc732bc4e81fde9e6c40a9/aiohttp-3.8.6-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "async-timeout", "version": "4.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/fa/e01228c2938de91d47b307831c62ab9e4001e747789d0b05baf779a6488c/async_timeout-4.0.3-py3-none-any.whl"}}, {"metadata": {"name": "backoff", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/73/b6e24bd22e6720ca8ee9a85a0c4a2971af8497d8f3193fa05390cbd46e09/backoff-2.2.1-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.40"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/8c/5f7e73fd66b28f0705bc55d7060d41ef72328b656b86ca53e75765b3ba2c/botocore-1.43.40-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/26/08/0f303cb0b529e456bb116f2d50565a482694fbb94340bf56d44677e7ed03/charset_normalizer-3.4.7-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/15/b92b4e1d88d02c6eff9733c9eea21846ab435cc4d813d84ccc5d335955df/graphql_core-3.2.11-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/31/5c/08c7f7fe311f32e83f7621cd3f99d805f45519cd06fafb247628b861da7d/multidict-6.7.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "0.10.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/d3/bf87a36bff1cb88fd30a509fd366c70ec30676517ee791b2f77e0e29817a/requests_toolbelt-0.10.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "1.26.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/33/cf/8435d5a7159e2a9c83a95896ed596f68cf798005fe107cc655b5c5c14704/urllib3-1.26.20-py2.py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/7a/bd0ce7ac1cfafc76c84d6e8051bcbd0f7def8e45207230833bd6ff77a41d/websockets-10.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/8f/7b3ec212f1ea0683f55f978e3246bc313c38818664edfc97a9f349a4901e/yarl-1.24.2-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "responses", "version": "0.26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/28/693e1d9ebf72baa062ded80d837a035b86ce75eda5a269379e9e2b1008a8/responses-0.26.2-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/70/26ca3f06aace16f2352796b08704338d74b6d1a24ca38f2771afbb7ed915/frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/42/0e7443c90310498561addf346e7d57fe3c6ba1914e1ba938b5464c7bbfd2/propcache-0.5.2-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}], "install_targets_hash": "ec03e83b12e89730c3e80a2126d3d0ca"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "gql", "version": "3.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/1c/2facac9c192d4470960537cf8cdf92d41af10e300a8095ebc37740b4df38/gql-3.4.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.8.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/a9/61f60723b20f9accdf4c9dc812ad4a61c1c63bdc732bc4e81fde9e6c40a9/aiohttp-3.8.6-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "async-timeout", "version": "4.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/fa/e01228c2938de91d47b307831c62ab9e4001e747789d0b05baf779a6488c/async_timeout-4.0.3-py3-none-any.whl"}}, {"metadata": {"name": "backoff", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/73/b6e24bd22e6720ca8ee9a85a0c4a2971af8497d8f3193fa05390cbd46e09/backoff-2.2.1-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.40"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/8c/5f7e73fd66b28f0705bc55d7060d41ef72328b656b86ca53e75765b3ba2c/botocore-1.43.40-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/26/08/0f303cb0b529e456bb116f2d50565a482694fbb94340bf56d44677e7ed03/charset_normalizer-3.4.7-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/15/b92b4e1d88d02c6eff9733c9eea21846ab435cc4d813d84ccc5d335955df/graphql_core-3.2.11-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/31/5c/08c7f7fe311f32e83f7621cd3f99d805f45519cd06fafb247628b861da7d/multidict-6.7.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "0.10.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/d3/bf87a36bff1cb88fd30a509fd366c70ec30676517ee791b2f77e0e29817a/requests_toolbelt-0.10.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "1.26.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/33/cf/8435d5a7159e2a9c83a95896ed596f68cf798005fe107cc655b5c5c14704/urllib3-1.26.20-py2.py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/7a/bd0ce7ac1cfafc76c84d6e8051bcbd0f7def8e45207230833bd6ff77a41d/websockets-10.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/8f/7b3ec212f1ea0683f55f978e3246bc313c38818664edfc97a9f349a4901e/yarl-1.24.2-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "responses", "version": "0.26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/28/693e1d9ebf72baa062ded80d837a035b86ce75eda5a269379e9e2b1008a8/responses-0.26.2-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/70/26ca3f06aace16f2352796b08704338d74b6d1a24ca38f2771afbb7ed915/frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/42/0e7443c90310498561addf346e7d57fe3c6ba1914e1ba938b5464c7bbfd2/propcache-0.5.2-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}], "install_targets_hash": "ec03e83b12e89730c3e80a2126d3d0ca"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "gql", "version": "3.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/1c/2facac9c192d4470960537cf8cdf92d41af10e300a8095ebc37740b4df38/gql-3.4.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.8.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/a9/61f60723b20f9accdf4c9dc812ad4a61c1c63bdc732bc4e81fde9e6c40a9/aiohttp-3.8.6-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "async-timeout", "version": "4.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/fa/e01228c2938de91d47b307831c62ab9e4001e747789d0b05baf779a6488c/async_timeout-4.0.3-py3-none-any.whl"}}, {"metadata": {"name": "backoff", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/73/b6e24bd22e6720ca8ee9a85a0c4a2971af8497d8f3193fa05390cbd46e09/backoff-2.2.1-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.40"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/8c/5f7e73fd66b28f0705bc55d7060d41ef72328b656b86ca53e75765b3ba2c/botocore-1.43.40-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/26/08/0f303cb0b529e456bb116f2d50565a482694fbb94340bf56d44677e7ed03/charset_normalizer-3.4.7-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/15/b92b4e1d88d02c6eff9733c9eea21846ab435cc4d813d84ccc5d335955df/graphql_core-3.2.11-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/31/5c/08c7f7fe311f32e83f7621cd3f99d805f45519cd06fafb247628b861da7d/multidict-6.7.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "0.10.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/d3/bf87a36bff1cb88fd30a509fd366c70ec30676517ee791b2f77e0e29817a/requests_toolbelt-0.10.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "1.26.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/33/cf/8435d5a7159e2a9c83a95896ed596f68cf798005fe107cc655b5c5c14704/urllib3-1.26.20-py2.py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/7a/bd0ce7ac1cfafc76c84d6e8051bcbd0f7def8e45207230833bd6ff77a41d/websockets-10.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/8f/7b3ec212f1ea0683f55f978e3246bc313c38818664edfc97a9f349a4901e/yarl-1.24.2-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "responses", "version": "0.26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/28/693e1d9ebf72baa062ded80d837a035b86ce75eda5a269379e9e2b1008a8/responses-0.26.2-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/70/26ca3f06aace16f2352796b08704338d74b6d1a24ca38f2771afbb7ed915/frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/42/0e7443c90310498561addf346e7d57fe3c6ba1914e1ba938b5464c7bbfd2/propcache-0.5.2-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}], "install_targets_hash": "ec03e83b12e89730c3e80a2126d3d0ca"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "gql", "version": "3.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/1c/2facac9c192d4470960537cf8cdf92d41af10e300a8095ebc37740b4df38/gql-3.4.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.8.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/a9/61f60723b20f9accdf4c9dc812ad4a61c1c63bdc732bc4e81fde9e6c40a9/aiohttp-3.8.6-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "async-timeout", "version": "4.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/fa/e01228c2938de91d47b307831c62ab9e4001e747789d0b05baf779a6488c/async_timeout-4.0.3-py3-none-any.whl"}}, {"metadata": {"name": "backoff", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/73/b6e24bd22e6720ca8ee9a85a0c4a2971af8497d8f3193fa05390cbd46e09/backoff-2.2.1-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.40"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/8c/5f7e73fd66b28f0705bc55d7060d41ef72328b656b86ca53e75765b3ba2c/botocore-1.43.40-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/26/08/0f303cb0b529e456bb116f2d50565a482694fbb94340bf56d44677e7ed03/charset_normalizer-3.4.7-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/15/b92b4e1d88d02c6eff9733c9eea21846ab435cc4d813d84ccc5d335955df/graphql_core-3.2.11-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/31/5c/08c7f7fe311f32e83f7621cd3f99d805f45519cd06fafb247628b861da7d/multidict-6.7.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "0.10.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/d3/bf87a36bff1cb88fd30a509fd366c70ec30676517ee791b2f77e0e29817a/requests_toolbelt-0.10.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "1.26.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/33/cf/8435d5a7159e2a9c83a95896ed596f68cf798005fe107cc655b5c5c14704/urllib3-1.26.20-py2.py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/7a/bd0ce7ac1cfafc76c84d6e8051bcbd0f7def8e45207230833bd6ff77a41d/websockets-10.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/8f/7b3ec212f1ea0683f55f978e3246bc313c38818664edfc97a9f349a4901e/yarl-1.24.2-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "responses", "version": "0.26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/28/693e1d9ebf72baa062ded80d837a035b86ce75eda5a269379e9e2b1008a8/responses-0.26.2-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/70/26ca3f06aace16f2352796b08704338d74b6d1a24ca38f2771afbb7ed915/frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/42/0e7443c90310498561addf346e7d57fe3c6ba1914e1ba938b5464c7bbfd2/propcache-0.5.2-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}], "install_targets_hash": "ec03e83b12e89730c3e80a2126d3d0ca"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "gql", "version": "3.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/1c/2facac9c192d4470960537cf8cdf92d41af10e300a8095ebc37740b4df38/gql-3.4.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.8.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/a9/61f60723b20f9accdf4c9dc812ad4a61c1c63bdc732bc4e81fde9e6c40a9/aiohttp-3.8.6-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "async-timeout", "version": "4.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/fa/e01228c2938de91d47b307831c62ab9e4001e747789d0b05baf779a6488c/async_timeout-4.0.3-py3-none-any.whl"}}, {"metadata": {"name": "backoff", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/73/b6e24bd22e6720ca8ee9a85a0c4a2971af8497d8f3193fa05390cbd46e09/backoff-2.2.1-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.40"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/8c/5f7e73fd66b28f0705bc55d7060d41ef72328b656b86ca53e75765b3ba2c/botocore-1.43.40-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/26/08/0f303cb0b529e456bb116f2d50565a482694fbb94340bf56d44677e7ed03/charset_normalizer-3.4.7-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/15/b92b4e1d88d02c6eff9733c9eea21846ab435cc4d813d84ccc5d335955df/graphql_core-3.2.11-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/31/5c/08c7f7fe311f32e83f7621cd3f99d805f45519cd06fafb247628b861da7d/multidict-6.7.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "0.10.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/d3/bf87a36bff1cb88fd30a509fd366c70ec30676517ee791b2f77e0e29817a/requests_toolbelt-0.10.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "1.26.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/33/cf/8435d5a7159e2a9c83a95896ed596f68cf798005fe107cc655b5c5c14704/urllib3-1.26.20-py2.py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/7a/bd0ce7ac1cfafc76c84d6e8051bcbd0f7def8e45207230833bd6ff77a41d/websockets-10.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/8f/7b3ec212f1ea0683f55f978e3246bc313c38818664edfc97a9f349a4901e/yarl-1.24.2-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "responses", "version": "0.26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/28/693e1d9ebf72baa062ded80d837a035b86ce75eda5a269379e9e2b1008a8/responses-0.26.2-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/70/26ca3f06aace16f2352796b08704338d74b6d1a24ca38f2771afbb7ed915/frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/42/0e7443c90310498561addf346e7d57fe3c6ba1914e1ba938b5464c7bbfd2/propcache-0.5.2-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}], "install_targets_hash": "ec03e83b12e89730c3e80a2126d3d0ca"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "litestar", "version": "2.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/b5/ad040f923f1661240eaae883b7d3fec29ea6614d7e732d051fc16400998f/litestar-2.0.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/26/08/0f303cb0b529e456bb116f2d50565a482694fbb94340bf56d44677e7ed03/charset_normalizer-3.4.7-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/2a/5bb823f5bedcf80718cea7fbc95ec5515cca3769633c4b01a32be7f30e7c/cryptography-49.0.0-cp39-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/84/ad6a0b408daa859246f57c03efd28e5dd1b33c21737c2db84cae8c237aa5/cffi-2.0.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "fast-query-parsers", "version": "1.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/21/c8c160f61a740efc4577079eb5747a6b2cb8d1168a84a0bfda6044113768/fast_query_parsers-1.0.3-cp38-abi3-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "msgspec", "version": "0.21.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/1a/6899188b5982ec1324e0c629b7801eed2db987f6634fab58abd9fc82d317/msgspec-0.21.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/31/5c/08c7f7fe311f32e83f7621cd3f99d805f45519cd06fafb247628b861da7d/multidict-6.7.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "polyfactory", "version": "3.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/34/b6f19941adcdaf415b5e8a8d577499f5b6a76b59cbae37f9b125a9ffe9f2/polyfactory-3.3.0-py3-none-any.whl"}}, {"metadata": {"name": "Faker", "version": "40.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/a6/6111b9f13c1564b0e2f5dbeeb611fd00dc731e6add2336f62b798598c73d/faker-40.28.1-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}], "install_targets_hash": "eff25fb572d2faba9c895f2319049fe6"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "litestar", "version": "2.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/b5/ad040f923f1661240eaae883b7d3fec29ea6614d7e732d051fc16400998f/litestar-2.0.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/26/08/0f303cb0b529e456bb116f2d50565a482694fbb94340bf56d44677e7ed03/charset_normalizer-3.4.7-cp310-cp310-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/2a/5bb823f5bedcf80718cea7fbc95ec5515cca3769633c4b01a32be7f30e7c/cryptography-49.0.0-cp39-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/84/ad6a0b408daa859246f57c03efd28e5dd1b33c21737c2db84cae8c237aa5/cffi-2.0.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "fast-query-parsers", "version": "1.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/21/c8c160f61a740efc4577079eb5747a6b2cb8d1168a84a0bfda6044113768/fast_query_parsers-1.0.3-cp38-abi3-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "msgspec", "version": "0.21.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/1a/6899188b5982ec1324e0c629b7801eed2db987f6634fab58abd9fc82d317/msgspec-0.21.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/31/5c/08c7f7fe311f32e83f7621cd3f99d805f45519cd06fafb247628b861da7d/multidict-6.7.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "polyfactory", "version": "3.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/34/b6f19941adcdaf415b5e8a8d577499f5b6a76b59cbae37f9b125a9ffe9f2/polyfactory-3.3.0-py3-none-any.whl"}}, {"metadata": {"name": "Faker", "version": "40.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/a6/6111b9f13c1564b0e2f5dbeeb611fd00dc731e6add2336f62b798598c73d/faker-40.28.1-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl"}}], "install_targets_hash": "eff25fb572d2faba9c895f2319049fe6"} +{"python_version": "3.10", "dependencies": [{"metadata": {"name": "mcp", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/af/8644cc5fa26a59afd2df2e98eeb19e72926887fa4b7441aba4ff661140db/mcp-2.1.1-py3-none-any.whl"}}, {"metadata": {"name": "mcp-types", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/d0/242e63c510f4a17381f55b1549a3f94f5687a0595984febd2b6f87a687a0/mcp_types-2.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/6f/a04e900f465ff3221ccc395522503e2d10e79fa21f2723c8e177aae1e0d1/opentelemetry_api-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/d0/c787604c71c2bdcda1a5656942fc822cd0f9cd879b9484bb84fc42172703/pydantic_core-2.46.5-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/97/672cb32ce0dfea44b740cb7b4f97038463b9cf7c0ead1aacf595572851d6/pyjwt-2.14.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/6a/2ba3ed4a69babf3afdddf7d8314a48d87562c0a442206bbc2a1b50d5efc0/sse_starlette-3.4.11-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.53.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/76/18/0eea75741ee812e9f598b687619ce2454f6c3a1c5cd21ea990ec6bd26f45/uvicorn-0.53.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/84/a9/ee16a903f13755e914d1eecc482fe64d1f10761c3960e5d8fa6837377aff/cryptography-50.0.1-cp39-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "0.30.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/6a/4ba3d0fb7297ebae71171822554abe48d7cab29c28b8f9f2c04b79988c05/rpds_py-0.30.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/1a/4b2f7c92293ba05cbd4a9a1b28faaf0326272d9488e6354657571c48a7aa/cffi-2.1.1-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "f0d2472e8e45f37ecbb75fd658385dd5"} {"python_version": "3.10", "dependencies": [{"metadata": {"name": "mistralai", "version": "2.10.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/98/f64b54166a607ece4e5c8494c843ac1f9c7c0af6f1014272cc420fe1d519/mistralai-2.10.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "eval_type_backport", "version": "0.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/a7/bb99bf5e6f78736ddb53480f2c3ff3702ffe2196a7c5e1661c03081d398e/eval_type_backport-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonpath-python", "version": "1.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/8a/1270a6803bd821cbfcdda387eaa13cb41a7b1f7b9bd145979b3bfb9d6cb7/jsonpath_python-1.1.6-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/6f/a04e900f465ff3221ccc395522503e2d10e79fa21f2723c8e177aae1e0d1/opentelemetry_api-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-semantic-conventions", "version": "0.65b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/0e/49df70d9b81fb5cbae4bbf2a49d865b09bcbcbc4eb53f5851b1027738d78/opentelemetry_semantic_conventions-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/d0/c787604c71c2bdcda1a5656942fc822cd0f9cd879b9484bb84fc42172703/pydantic_core-2.46.5-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}], "install_targets_hash": "f60e32909a4363f0d8cc05916d4da67a"} -{"python_version": "3.10", "dependencies": [{"metadata": {"name": "mcp", "version": "1.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c9/82/4d0df23d5ff5bb982a59ad597bc7cb9920f2650278ccefb8e0d85c5ce3d4/mcp-1.15.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/c6/65f646c7ff09bd257f660434adb45c4dfcbbcebcc030562fecf6f5bf887d/pydantic_core-2.46.4-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/77/c1/6e422f34e569cf8e18df68d1939c81c099d2b61e4f7d9621c8a77560799c/pydantic_settings-2.14.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "0.30.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/6a/4ba3d0fb7297ebae71171822554abe48d7cab29c28b8f9f2c04b79988c05/rpds_py-0.30.0-cp310-cp310-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/36/e10c1d1b7ca881d2625db2ec28508578499187bb1c389952c398474e1834/sse_starlette-3.4.6-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.51.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/45/ec/dbb7e5a6b91f86bfb9eb7d2988a2730907b6a729875b949c7f022e8b88fa/uvicorn-0.51.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}], "install_targets_hash": "f86dcfa82da844a490c00542989aac98"} {"python_version": "3.11", "dependencies": [{"metadata": {"name": "pyreqwest", "version": "0.12.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/28/e8/104a9cfc918adcae70230438ccea8757d19db065da5257ecde917c192427/pyreqwest-0.12.4-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}], "install_targets_hash": "00e5416511b26b0d583fe31710cc73eb"} {"python_version": "3.11", "dependencies": [{"metadata": {"name": "redis", "version": "5.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/26/5c5fa0e83c3621db835cfc1f1d789b37e7fa99ed54423b5f519beb931aa7/redis-5.3.1-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/4d/e6e40f93031adbf654d34e542bd396e9f3bc1c6209b40c920d58c9e1317a/fakeredis-2.36.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "7.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ff/f6e8b8f39e08547faece4bd80f89d5a8de68a38b2d179cc1c4490ffa3286/pytest-7.4.4-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.23.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ee/82/62e2d63639ecb0fbe8a7ee59ef0bc69a4669ec50f6d3459f74ad4e4189a2/pytest_asyncio-0.23.8-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}], "install_targets_hash": "035482a3571a63ab1772e66597b1b19f"} {"python_version": "3.11", "dependencies": [{"metadata": {"name": "anthropic", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/b4/0f37ca7ba43ec390f363fac20ae04c53b5db23a153e08251f214ac8eda7a/anthropic-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ae/6f/aa064a3e74b5745afbdf250594f38e7ead05e2d651bcb35994b9417a0d4d/pydantic_core-2.46.4-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "tokenizers", "version": "0.23.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e2/6a/068ed9f6e444c9d7e9d55ce134181325700f3d7f30410721bdc8f848d727/tokenizers-0.23.1-cp310-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "huggingface_hub", "version": "1.28.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/0e/eafef18f1a75e125e68395db21131db0cf868a128ecd2fce69b4df6c584b/huggingface_hub-1.28.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "filelock", "version": "3.32.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/a4/9b63d595d748e3aff8812b65eacc1a2c4bd90b7c2012e08e72373b4835eb/filelock-3.32.4-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/3c/6a2bf344106328fd04963664a60b9bb6496fc25df8e962fcdc1367285fb9/fsspec-2026.7.0-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/69/55b8dcf636142ae660fec1869fcac14c4da2e8412e14d6eee1523be77e9f/hf_xet-1.6.0-cp38-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/16/19/13de8e4377ed53079ee996e1ab0a9c33ec2faf808a4647b7b4c0d46dd239/pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}], "install_targets_hash": "04466a6e41bf5a66655ab84cf9b9a43d"} +{"python_version": "3.11", "dependencies": [{"metadata": {"name": "pyramid", "version": "2.0.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/db/41/a2114b8dd2187ae007e022a2baabdc7937cc78211cefc0c01fc5452193af/pyramid-2.0.2-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "2.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/f3/22afbdb20cc4654b10c98043414a14057cd27fdba9d4ae61cea596000ba2/Werkzeug-2.0.3-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "81.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/e3/c164c88b2e5ce7b24d667b9bd83589cf4f3520d97cad01534cd3c4f55fdb/setuptools-81.0.0-py3-none-any.whl"}}, {"metadata": {"name": "hupper", "version": "1.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/86/7d/3888833e4f5ea56af4a9935066ec09a83228e533d7b8877f65889d706ee4/hupper-1.12.1-py3-none-any.whl"}}, {"metadata": {"name": "translationstring", "version": "1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3b/98/36187601a15e3d37e9bfcf0e0e1055532b39d044353b06861c3a519737a9/translationstring-1.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "venusian", "version": "3.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5a/4b/34d926eba40db81b204066a60b4efdc5d8867a8efcbfe44d69b634b1c907/venusian-3.1.1-py3-none-any.whl"}}, {"metadata": {"name": "WebOb", "version": "1.8.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/71/370a65bc7726a1cbf478445c898c7affe907aa42e2e9e5bb38319db74115/webob-1.8.11-py2.py3-none-any.whl"}}, {"metadata": {"name": "zope.deprecation", "version": "6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/ed/da7f8b1c73caf989a0ff7096cc73c59e6c36f35a8f967c51104098602e2d/zope_deprecation-6.0-py3-none-any.whl"}}, {"metadata": {"name": "zope.interface", "version": "8.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bb/a7/6b6e0c31ac240cb9fc015ae9ed45ca54be886c18fcf7bfa2377a4d7a8785/zope_interface-8.5-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "plaster", "version": "1.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e7/8b/3f98db1448e3b4d2d142716874a7e02f6101685fdaa0f55a8668e9ffa048/plaster-1.1.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "plaster-pastedeploy", "version": "1.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/30/2d4cf89035c22a89bf0e34dbc50fdc07c42c9bdc90fd972d495257ad2b6e/plaster_pastedeploy-1.0.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "PasteDeploy", "version": "3.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/85/30/cdddd9a88969683a59222a6d61cd6dce923977f2e9f9ffba38e1324149cd/PasteDeploy-3.1.0-py3-none-any.whl"}}], "install_targets_hash": "051f4fcff8eeaa999798b3c8bbc76a3b"} +{"python_version": "3.11", "dependencies": [{"metadata": {"name": "rq", "version": "1.16.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/46/35/db396caf7cfe71a9e661cea520b276f1472df25015e7cb9143c65a1dca6d/rq-1.16.2-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.35.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6f/27/b8b057a23f7777177e92d3a602fd866751b6b45014964548997e92e048fd/fakeredis-2.35.1-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "redis", "version": "8.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/0a/c2345ebf1ebe70840ce3f6c6ee612f8fa749cfbd1b03069c53bf0c62aaad/redis-8.0.1-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}], "install_targets_hash": "09963eb19b6d3c77fefe09bd2af175bd"} {"python_version": "3.11", "dependencies": [{"metadata": {"name": "rq", "version": "1.16.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/46/35/db396caf7cfe71a9e661cea520b276f1472df25015e7cb9143c65a1dca6d/rq-1.16.2-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.35.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6f/27/b8b057a23f7777177e92d3a602fd866751b6b45014964548997e92e048fd/fakeredis-2.35.1-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "redis", "version": "8.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/0a/c2345ebf1ebe70840ce3f6c6ee612f8fa749cfbd1b03069c53bf0c62aaad/redis-8.0.1-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}], "install_targets_hash": "09963eb19b6d3c77fefe09bd2af175bd"} -{"python_version": "3.11", "dependencies": [{"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-httpx", "version": "0.35.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/ed/026d467c1853dd83102411a78126b4842618e86c895f93528b0528c7a620/pytest_httpx-0.35.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "0bb79de8dbba0e02df12fe5e7e7fd9b6"} +{"python_version": "3.11", "dependencies": [{"metadata": {"name": "rq", "version": "1.16.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/46/35/db396caf7cfe71a9e661cea520b276f1472df25015e7cb9143c65a1dca6d/rq-1.16.2-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.35.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6f/27/b8b057a23f7777177e92d3a602fd866751b6b45014964548997e92e048fd/fakeredis-2.35.1-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "redis", "version": "8.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/0a/c2345ebf1ebe70840ce3f6c6ee612f8fa749cfbd1b03069c53bf0c62aaad/redis-8.0.1-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}], "install_targets_hash": "09963eb19b6d3c77fefe09bd2af175bd"} +{"python_version": "3.11", "dependencies": [{"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-httpx", "version": "0.35.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/ed/026d467c1853dd83102411a78126b4842618e86c895f93528b0528c7a620/pytest_httpx-0.35.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}], "install_targets_hash": "0bb79de8dbba0e02df12fe5e7e7fd9b6"} +{"python_version": "3.11", "dependencies": [{"metadata": {"name": "openai", "version": "1.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/94/99a674bd1dd3a74d5b679bfdd9e1396f08407f933eb15672207e5a8abf1d/openai-1.0.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2d/a9/d94302340304328961d6f0c35ca4e60617fbb57a5cf667e2ed1692cb9e57/tiktoken-0.14.0-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ae/6f/aa064a3e74b5745afbdf250594f38e7ead05e2d651bcb35994b9417a0d4d/pydantic_core-2.46.4-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.7.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/2e/2360c41d8080a3d9ec7e5c90fad6eab3b50192869d10e9a5609e48c8177b/regex-2026.7.19-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6a/b6/034f6802e9c3f6418966cfabb7db8c9252cc2429c5098f41cc43af804149/charset_normalizer-3.5.1-cp311-cp311-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}], "install_targets_hash": "12df249d83810baf33b2334b64611de2"} {"python_version": "3.11", "dependencies": [{"metadata": {"name": "openai", "version": "1.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/94/99a674bd1dd3a74d5b679bfdd9e1396f08407f933eb15672207e5a8abf1d/openai-1.0.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2d/a9/d94302340304328961d6f0c35ca4e60617fbb57a5cf667e2ed1692cb9e57/tiktoken-0.14.0-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ae/6f/aa064a3e74b5745afbdf250594f38e7ead05e2d651bcb35994b9417a0d4d/pydantic_core-2.46.4-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.7.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/2e/2360c41d8080a3d9ec7e5c90fad6eab3b50192869d10e9a5609e48c8177b/regex-2026.7.19-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6a/b6/034f6802e9c3f6418966cfabb7db8c9252cc2429c5098f41cc43af804149/charset_normalizer-3.5.1-cp311-cp311-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}], "install_targets_hash": "12df249d83810baf33b2334b64611de2"} +{"python_version": "3.11", "dependencies": [{"metadata": {"name": "requests", "version": "2.30.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/80/034ffeca15c0f4e01b7b9c6ad0fb704b44e190cde4e757edbd60be404c41/requests-2.30.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/e3/85ec501f206fb049259288c1f3506e53876937fb00edb47009348e66756b/charset_normalizer-3.4.9-cp311-cp311-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}], "install_targets_hash": "12f06a29703c12e613113f5e51de4e73"} +{"python_version": "3.11", "dependencies": [{"metadata": {"name": "fastapi", "version": "0.104.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f3/4f/0ce34195b63240b6693086496c9bab4ef23999112184399a3e88854c7674/fastapi-0.104.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/e3/85ec501f206fb049259288c1f3506e53876937fb00edb47009348e66756b/charset_normalizer-3.4.9-cp311-cp311-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/2e/5898933336b61975ce9dc04decbc0a7f2fee78c30353c5efba7f2d6ff27a/markupsafe-3.0.3-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ae/6f/aa064a3e74b5745afbdf250594f38e7ead05e2d651bcb35994b9417a0d4d/pydantic_core-2.46.4-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "0.27.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/f8/e2cca22387965584a409795913b774235752be4176d276714e15e1a58884/starlette-0.27.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}], "install_targets_hash": "169e3a84c7fb134352fce11f7e68103c"} {"python_version": "3.11", "dependencies": [{"metadata": {"name": "pyspark", "version": "3.5.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/ce/81e53e729790556e3983e95de1a7d5df91a34adfcd34b5a5ab0e0c6e9b33/pyspark-3.5.9.tar.gz"}}, {"metadata": {"name": "py4j", "version": "0.10.9.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/db/ea0203e495be491c85af87b66e37acfd3bf756fd985f87e46fc5e3bf022c/py4j-0.10.9.9-py2.py3-none-any.whl"}}], "install_targets_hash": "1a79880f834ae1c486d6aca78b08c546"} {"python_version": "3.11", "dependencies": [{"metadata": {"name": "boto3", "version": "1.24.96"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e2/53/e9c9f18f97f1565d9194c0ebbfb8bd9bd4bbb93a54569d2e7af256980511/boto3-1.24.96-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.27.96"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/73/aa345e22ce21e86fa99e8dc25ab7ae4fd73eedc4c365282c82fa6ba3f66f/botocore-1.27.96-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "s3transfer", "version": "0.6.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d9/17/a3b666f5ef9543cfd3c661d39d1e193abb9649d0cfbbfee3cf3b51d5af02/s3transfer-0.6.2-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "1.26.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/33/cf/8435d5a7159e2a9c83a95896ed596f68cf798005fe107cc655b5c5c14704/urllib3-1.26.20-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}], "install_targets_hash": "1c0ddec7e53a8ba50dcb4c9c41d77fc6"} +{"python_version": "3.11", "dependencies": [{"metadata": {"name": "aiohttp", "version": "3.9.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/266be6e31daad1a2dc99c777dfb12b62044691ec573b6e48409a0d804fc7/aiohttp-3.9.5-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-aiohttp", "version": "1.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/a7/6e50ba2c0a27a34859a952162e63362a13142ce3c646e925b76de440e102/pytest_aiohttp-1.0.5-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/ef/0e8f1fe32f8a53dd26bdd1f9347efe0778b0fddf62789ea683f4cc7d787d/frozenlist-1.8.0-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/a4/d45caf2b97b035c57267791ecfaafbd59c68212004b3842830954bb4b02e/multidict-6.7.1-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ce/97/10b939c44d7b28d1dbc389cfc7012306d1ea8dba01eaef44b39fffaee52a/yarl-1.24.5-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/15/a8/8ede85d6aa1f79fc7dc2f8fd2c8d65920b8272c3892903c8a1affde48cfb/propcache-0.5.2-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "233113f80ecbd02cde8c7f1f523c1af4"} {"python_version": "3.11", "dependencies": [{"metadata": {"name": "cohere", "version": "5.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/8d/67ea6917f6ec6a094858c7b2514cd3be3e1fed45b8b9769e2571d781704b/cohere-5.4.0-py3-none-any.whl"}}, {"metadata": {"name": "boto3", "version": "1.43.40"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/3b/2abcc7f47e955a8cb45a6378ec69cd8ed2dcb3d14ceb67717dea020a794a/boto3-1.43.40-py3-none-any.whl"}}, {"metadata": {"name": "fastavro", "version": "1.12.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/77/058f3c93348624cb695399b27f3f0c1c3d1190586065797e4a48f75d4147/fastavro-1.12.2-cp311-cp311-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ae/6f/aa064a3e74b5745afbdf250594f38e7ead05e2d651bcb35994b9417a0d4d/pydantic_core-2.46.4-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "tokenizers", "version": "0.19.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/90/79/d17a0f491d10817cd30f1121a07aa09c8e97a81114b116e473baf1577f09/tokenizers-0.19.1-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "types-requests", "version": "2.33.0.20260518"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1c/bc/b139710a3b6018f7fb2b9508b35c8af564e61bf2bf4fa619d088f3e16f85/types_requests-2.33.0.20260518-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.40"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/8c/5f7e73fd66b28f0705bc55d7060d41ef72328b656b86ca53e75765b3ba2c/botocore-1.43.40-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c2/d7/b5b7020a0565c2e9fa8c09f4b5fa6232feb326b8c20081ccded47ea368fd/charset_normalizer-3.4.7-cp311-cp311-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "huggingface_hub", "version": "0.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/af/48ac8483240de756d2438c380746e7130d1c6f75802ef22f3c6d49982787/huggingface_hub-0.36.2-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "s3transfer", "version": "0.19.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/46/5f/4c174edad94f82de888ac00a5ddd8d07b35609b6c94f0bdf4d74af57703e/s3transfer-0.19.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e5/22/4222d7ddf3da30f363edaa98e329c2bce6c65497c9cb2810931c8b2c0fbc/fsspec-2026.6.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/35/94/4b2ecfbad8f8b04701a23aefb62f540b9137d058b7e1dbef16a32676f0e9/hf_xet-1.5.1-cp37-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/16/19/13de8e4377ed53079ee996e1ab0a9c33ec2faf808a4647b7b4c0d46dd239/pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tqdm", "version": "4.68.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d8/8e/bb97bb0c71802080bfc8952937d174e49cfc50de5c951dd47b2496f0dcdb/tqdm-4.68.3-py3-none-any.whl"}}, {"metadata": {"name": "filelock", "version": "3.29.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4a/e3/f1fae3647d170919c2cf2a898e77e7d1a4e5c7cae0aed7bb4bd3f5ebff6f/filelock-3.29.5-py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}], "install_targets_hash": "2d88f925409259ac1c50c7222be95be6"} {"python_version": "3.11", "dependencies": [{"metadata": {"name": "starlite", "version": "1.51.16"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f3/02/664dda98e4f715ef0cba583f53dabddb3f42667d464d38156e1837ed4ce2/starlite-1.51.16-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/22/adf66990e63584a68dfb50c24f48a125c07b1699899381c8151e63ed458c/cryptography-49.0.0-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "1.10.26"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/08/f4b804a00c16e3ea994cb640a7c25c579b4f1fa674cde6a19fa0dfb0ae4f/pydantic-1.10.26-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/8b/f0e4c441227ba756aafbe78f117485b25bb26b1c059d01f137fa6d14896b/cffi-2.0.0-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c2/d7/b5b7020a0565c2e9fa8c09f4b5fa6232feb326b8c20081ccded47ea368fd/charset_normalizer-3.4.7-cp311-cp311-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "Mako", "version": "1.3.12"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/b1/a0ec7a5a9db730a08daef1fdfb8090435b82465abbf758a596f0ea88727e/mako-1.3.12-py3-none-any.whl"}}, {"metadata": {"name": "msgspec", "version": "0.21.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/60/504886af1aaf854112663b842d5eea9a15d9588f9bf7d0d2df736424b84d/msgspec-0.21.1-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/a4/d45caf2b97b035c57267791ecfaafbd59c68212004b3842830954bb4b02e/multidict-6.7.1-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic-openapi-schema", "version": "1.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bb/a1/9b906584055e2a9ee48368e2ad7148625e06594fb0f81f8656c6e71eb672/pydantic_openapi_schema-1.5.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "fast-query-parsers", "version": "1.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/21/c8c160f61a740efc4577079eb5747a6b2cb8d1168a84a0bfda6044113768/fast_query_parsers-1.0.3-cp38-abi3-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl"}}, {"metadata": {"name": "pydantic-factories", "version": "1.17.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/40/49/81bbfccaf7174e7a94be1fa95d9ed46da6663372b2a7cd597c1c6fdfcabe/pydantic_factories-1.17.3-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/16/19/13de8e4377ed53079ee996e1ab0a9c33ec2faf808a4647b7b4c0d46dd239/pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/2e/5898933336b61975ce9dc04decbc0a7f2fee78c30353c5efba7f2d6ff27a/markupsafe-3.0.3-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "email-validator", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "Faker", "version": "40.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/a6/6111b9f13c1564b0e2f5dbeeb611fd00dc731e6add2336f62b798598c73d/faker-40.28.1-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "dnspython", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl"}}], "install_targets_hash": "33d6741d45d5018c097d63500582c5d9"} -{"python_version": "3.11", "dependencies": [{"metadata": {"name": "redis", "version": "4.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/2e/409703d645363352a20c944f5d119bdae3eb3034051a53724a7c5fee12b8/redis-4.6.0-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.30.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f7/26/16ab46747e1aeed6c021da72bae500b6c42c0a5bb9d25d1af97c6f74d61f/fakeredis-2.30.3-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "7.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ff/f6e8b8f39e08547faece4bd80f89d5a8de68a38b2d179cc1c4490ffa3286/pytest-7.4.4-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.23.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ee/82/62e2d63639ecb0fbe8a7ee59ef0bc69a4669ec50f6d3459f74ad4e4189a2/pytest_asyncio-0.23.8-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}], "install_targets_hash": "36c1a312b04d12e5bc3f2de14c48e482"} {"python_version": "3.11", "dependencies": [{"metadata": {"name": "asyncpg", "version": "0.29.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4a/13/f96284d7014dd06db2e78bea15706443d7895548bf74cf34f0c3ee1863fd/asyncpg-0.29.0-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "37b71e639b9f2205d095eed9add52c09"} {"python_version": "3.11", "dependencies": [{"metadata": {"name": "starlite", "version": "1.48.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/46/84/fdfb336bf788e52a5fead1e9e302ac5a0b8a5a0094bdd2c491d6162cd147/starlite-1.48.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/22/adf66990e63584a68dfb50c24f48a125c07b1699899381c8151e63ed458c/cryptography-49.0.0-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "1.10.26"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/08/f4b804a00c16e3ea994cb640a7c25c579b4f1fa674cde6a19fa0dfb0ae4f/pydantic-1.10.26-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/8b/f0e4c441227ba756aafbe78f117485b25bb26b1c059d01f137fa6d14896b/cffi-2.0.0-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c2/d7/b5b7020a0565c2e9fa8c09f4b5fa6232feb326b8c20081ccded47ea368fd/charset_normalizer-3.4.7-cp311-cp311-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "Mako", "version": "1.3.12"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/b1/a0ec7a5a9db730a08daef1fdfb8090435b82465abbf758a596f0ea88727e/mako-1.3.12-py3-none-any.whl"}}, {"metadata": {"name": "msgspec", "version": "0.21.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/60/504886af1aaf854112663b842d5eea9a15d9588f9bf7d0d2df736424b84d/msgspec-0.21.1-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/a4/d45caf2b97b035c57267791ecfaafbd59c68212004b3842830954bb4b02e/multidict-6.7.1-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic-openapi-schema", "version": "1.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bb/a1/9b906584055e2a9ee48368e2ad7148625e06594fb0f81f8656c6e71eb672/pydantic_openapi_schema-1.5.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "fast-query-parsers", "version": "1.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/21/c8c160f61a740efc4577079eb5747a6b2cb8d1168a84a0bfda6044113768/fast_query_parsers-1.0.3-cp38-abi3-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl"}}, {"metadata": {"name": "pydantic-factories", "version": "1.17.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/40/49/81bbfccaf7174e7a94be1fa95d9ed46da6663372b2a7cd597c1c6fdfcabe/pydantic_factories-1.17.3-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/16/19/13de8e4377ed53079ee996e1ab0a9c33ec2faf808a4647b7b4c0d46dd239/pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/2e/5898933336b61975ce9dc04decbc0a7f2fee78c30353c5efba7f2d6ff27a/markupsafe-3.0.3-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "email-validator", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "Faker", "version": "40.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/a6/6111b9f13c1564b0e2f5dbeeb611fd00dc731e6add2336f62b798598c73d/faker-40.28.1-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "dnspython", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl"}}], "install_targets_hash": "3907d2f6a755b140082148b91c7e757f"} -{"python_version": "3.11", "dependencies": [{"metadata": {"name": "SQLAlchemy", "version": "2.1.0rc2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2b/d2/496bd785d5a430ffe2fed646aa69005f778ff42157b526801060b0a55b81/sqlalchemy-2.1.0rc2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}], "install_targets_hash": "3f216279dfc7a16b8b146f00ed33cb9a"} +{"python_version": "3.11", "dependencies": [{"metadata": {"name": "redis", "version": "4.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/2e/409703d645363352a20c944f5d119bdae3eb3034051a53724a7c5fee12b8/redis-4.6.0-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.30.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f7/26/16ab46747e1aeed6c021da72bae500b6c42c0a5bb9d25d1af97c6f74d61f/fakeredis-2.30.3-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "7.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ff/f6e8b8f39e08547faece4bd80f89d5a8de68a38b2d179cc1c4490ffa3286/pytest-7.4.4-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.23.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ee/82/62e2d63639ecb0fbe8a7ee59ef0bc69a4669ec50f6d3459f74ad4e4189a2/pytest_asyncio-0.23.8-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}], "install_targets_hash": "3a7e93f79584af54dfef58a62cafb907"} +{"python_version": "3.11", "dependencies": [{"metadata": {"name": "SQLAlchemy", "version": "2.1.0rc2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/27/9cd84d2b4b4414d958ec3a397489c950efc5c5bf5db5a042a337f843fed5/sqlalchemy-2.1.0rc2-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}], "install_targets_hash": "3f216279dfc7a16b8b146f00ed33cb9a"} {"python_version": "3.11", "dependencies": [{"metadata": {"name": "falcon", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d9/e1/d94630cd9b225315513b44e2055d916dfde2b923bdadaf2053625fef96e3/falcon-3.1.3-cp311-cp311-macosx_10_9_universal2.whl"}}], "install_targets_hash": "495bed059580b4655ded3469bb5a9f7f"} {"python_version": "3.11", "dependencies": [{"metadata": {"name": "trytond", "version": "6.8.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/13/b994f377d1896f70ca6edbfb0c068f8f9739fe706485b2d0759d96c798d1/trytond-6.8.17-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "lxml", "version": "6.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/b0/83f481780d1548750b8ce2ec824073deef2f452d9cd1a6faff8507e3d16d/lxml-6.1.1-cp311-cp311-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/2e/5898933336b61975ce9dc04decbc0a7f2fee78c30353c5efba7f2d6ff27a/markupsafe-3.0.3-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "passlib", "version": "1.7.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3b/a4/ab6b7589382ca3df236e03faa71deac88cae040af60c071a78d254a62172/passlib-1.7.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "python-sql", "version": "1.8.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/77/ac/3603bbdde340f7354c975431c94b70ef3e99966c5b170fa121f8e64d269e/python_sql-1.8.1-py3-none-any.whl"}}, {"metadata": {"name": "relatorio", "version": "0.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4d/4c/ab43c3a35a402f17a153a66c27c3dce184e4ff511a8a414d208dfaa4c5bf/relatorio-0.12.1-py3-none-any.whl"}}, {"metadata": {"name": "Genshi", "version": "0.7.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/27/503016bc329720ba2856eb4831d6ba36089cd6f15bc4fe85db69fea5b563/genshi-0.7.11-py3-none-any.whl"}}, {"metadata": {"name": "defusedxml", "version": "0.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "polib", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6b/99/45bb1f9926efe370c6dbe324741c749658e44cb060124f28dad201202274/polib-1.2.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "python-magic", "version": "0.4.27"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6c/73/9f872cb81fc5c3bb48f7227872c28975f998f3e7c2b1c16e95e6432bbb90/python_magic-0.4.27-py2.py3-none-any.whl"}}], "install_targets_hash": "4a8a27395c61752c0a56a6636507732c"} -{"python_version": "3.11", "dependencies": [{"metadata": {"name": "openai-agents", "version": "0.0.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/69/899b33c97d5ee6ce454d5cdf89ddddcec9100bece4ed508229b06b1a07ca/openai_agents-0.0.19-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "2.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ae/f4/561ed79fd94876160018a5e75254cfcb9b0e62d4dded9dcb20072e86d623/openai-2.44.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "griffe", "version": "1.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/83/3b1d03d36f224edded98e9affd0467630fc09d766c0e56fb1498cbb04a9b/griffe-1.15.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/e3/97c6c3562c077f6247d6e6ce5c82562500b6316c0d928e97e106b7a1321a/jiter-0.16.0-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "mcp", "version": "1.29.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/c8/248b201f6d753d69fd5d6506011abbb35a946d9142b2ae311a948fd0be3d/mcp-1.29.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ae/6f/aa064a3e74b5745afbdf250594f38e7ead05e2d651bcb35994b9417a0d4d/pydantic_core-2.46.4-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "types-requests", "version": "2.33.0.20260712"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/e7/010c87f559e216d83f9dc51e939633fd0d0ead3377340181ab0e223cd3b5/types_requests-2.33.0.20260712-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6a/b6/034f6802e9c3f6418966cfabb7db8c9252cc2429c5098f41cc43af804149/charset_normalizer-3.5.1-cp311-cp311-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "colorama", "version": "0.4.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/3a/764912c58293d95b6dcdf4cc255f9d10de310580ced547b082eb9d72018c/sse_starlette-3.4.8-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.52.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/79/4a20b54ab0491485ccd8c077db2d39187c7f12b3e15485d38a7be37c81b4/uvicorn-0.52.4-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/5c/59086b4aac5e879d38ddbcf74e4be7ade89cebc3eb199a55da998c3bb46a/cryptography-50.0.0-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4d/dc/323d08583c0832911768663d1944f0107fcd4088704858d84b5e06d105a0/rpds_py-2026.6.3-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cd/95/31b535a9f0220ae9f357de4a08d57ce89cb417653c2fd9f075f50822a388/cffi-2.1.1-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "516bab83ca4281a985cea82f50b07b4c"} {"python_version": "3.11", "dependencies": [{"metadata": {"name": "SQLAlchemy", "version": "1.4.54"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/49/fb98983b5568e93696a25fd5bec1b789095b79a72d5f57c6effddaa81d0a/SQLAlchemy-1.4.54-cp311-cp311-macosx_10_9_universal2.whl"}}], "install_targets_hash": "59058833bef885053056cb808e01f81f"} {"python_version": "3.11", "dependencies": [{"metadata": {"name": "falcon", "version": "4.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5f/f9/c4d672e28d76ed6c1676fb21254ab70f3665d99d00c43fcd50d18547fbac/falcon-4.3.1-cp311-cp311-macosx_11_0_arm64.whl"}}], "install_targets_hash": "5935d22936c24189f0d18cf0311cca5c"} -{"python_version": "3.11", "dependencies": [{"metadata": {"name": "pyreqwest", "version": "0.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/73/91/a93553cd8c892bc9c3e4e650b6a3f62ca8a5440b22cb3c77b972192050c1/pyreqwest-0.13.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}], "install_targets_hash": "6f61e0b03332a8ab3c901a7f00b7fa71"} +{"python_version": "3.11", "dependencies": [{"metadata": {"name": "pyreqwest", "version": "0.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/72/c4/b0fecc333b00ca83f24f900f722a724b98154970dd91f3316c92f2c81872/pyreqwest-0.13.0-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}], "install_targets_hash": "6f61e0b03332a8ab3c901a7f00b7fa71"} +{"python_version": "3.11", "dependencies": [{"metadata": {"name": "sanic", "version": "23.12.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/e6/5adc2ca570f165d6027a775a655c1c09b9b8432a6c4a6fcb4c43a08eac7e/sanic-23.12.2-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cc/19/2f003f9f81c0fab2eabb81d8fc2fce5fb5b5714f1b4abfe897cb209e031d/websockets-10.4-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/3f/01264f820ee2e3712a827892b1cd6ff80f3300c1fcbffbb45714a915d47a/aiohttp-3.14.3-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-testing", "version": "24.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/93/1d588f1cb9b710b9f22fa78b53d699a8062edc94204d50dd0d78c5f5b495/sanic_testing-24.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/ef/0e8f1fe32f8a53dd26bdd1f9347efe0778b0fddf62789ea683f4cc7d787d/frozenlist-1.8.0-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "html5tagger", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/d7/410f7b8109958405f6fb3d104f094e2a96f9d5b2670de73a68fb1fbc391f/html5tagger-2.0.0-py3-none-any.whl"}}, {"metadata": {"name": "httptools", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/94/dfe435d90d0ef61ec0f2cc3d480eef78c59727c6c2ce039f433882f6131a/httptools-0.8.0-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/a4/d45caf2b97b035c57267791ecfaafbd59c68212004b3842830954bb4b02e/multidict-6.7.1-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/15/a8/8ede85d6aa1f79fc7dc2f8fd2c8d65920b8272c3892903c8a1affde48cfb/propcache-0.5.2-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-routing", "version": "23.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/e3/3425c9a8773807ac2c01d6a56c8521733f09b627e5827e733c5cd36b9ac5/sanic_routing-23.12.0-py3-none-any.whl"}}, {"metadata": {"name": "tracerite", "version": "2.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fc/ae/74457a0bfe83b45a951f5a4900cb4e5bb7cf201edc029fb5b2a2df9e4028/tracerite-2.6.3-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "5.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b5/c6/83db69f96dc12509c9510084c0389c4aff4dcf427f9b613d1a23abd446ce/ujson-5.13.0-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "uvloop", "version": "0.22.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c7/d5/69900f7883235562f1f50d8184bb7dd84a2fb61e9ec63f3782546fdbd057/uvloop-0.22.1-cp311-cp311-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ce/97/10b939c44d7b28d1dbc389cfc7012306d1ea8dba01eaef44b39fffaee52a/yarl-1.24.5-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}], "install_targets_hash": "76dabba8d81006345a2675957fd9dcbf"} {"python_version": "3.11", "dependencies": [{"metadata": {"name": "sanic", "version": "23.12.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/e6/5adc2ca570f165d6027a775a655c1c09b9b8432a6c4a6fcb4c43a08eac7e/sanic-23.12.2-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cc/19/2f003f9f81c0fab2eabb81d8fc2fce5fb5b5714f1b4abfe897cb209e031d/websockets-10.4-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/e7/c60c7b209e509cc787de3cea0550a518538cfc08003e1c1e14c1c63fff71/aiohttp-3.14.1-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-testing", "version": "24.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/93/1d588f1cb9b710b9f22fa78b53d699a8062edc94204d50dd0d78c5f5b495/sanic_testing-24.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/ef/0e8f1fe32f8a53dd26bdd1f9347efe0778b0fddf62789ea683f4cc7d787d/frozenlist-1.8.0-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "html5tagger", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/12/2f5d43ee912ea14a6baba4b3db6d309b02d932e3b7074c3339b4aded98ff/html5tagger-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "httptools", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/94/dfe435d90d0ef61ec0f2cc3d480eef78c59727c6c2ce039f433882f6131a/httptools-0.8.0-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/a4/d45caf2b97b035c57267791ecfaafbd59c68212004b3842830954bb4b02e/multidict-6.7.1-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/15/a8/8ede85d6aa1f79fc7dc2f8fd2c8d65920b8272c3892903c8a1affde48cfb/propcache-0.5.2-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-routing", "version": "23.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/e3/3425c9a8773807ac2c01d6a56c8521733f09b627e5827e733c5cd36b9ac5/sanic_routing-23.12.0-py3-none-any.whl"}}, {"metadata": {"name": "tracerite", "version": "2.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b6/62/3f385a67ff3cc91209f107d20bbebdecf7a4e4aba55a43f9f71bddc424a9/tracerite-2.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "5.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b5/c6/83db69f96dc12509c9510084c0389c4aff4dcf427f9b613d1a23abd446ce/ujson-5.13.0-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "uvloop", "version": "0.22.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c7/d5/69900f7883235562f1f50d8184bb7dd84a2fb61e9ec63f3782546fdbd057/uvloop-0.22.1-cp311-cp311-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/31/d0/1fb0c1cd27288f39f6974da4318c32768d72c9890984541fdf1e2e32a51d/yarl-1.24.2-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}], "install_targets_hash": "76dabba8d81006345a2675957fd9dcbf"} +{"python_version": "3.11", "dependencies": [{"metadata": {"name": "celery", "version": "5.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/90/c4/6a4d3772e5407622feb93dd25c86ce3c0fee746fa822a777a627d56b4f2a/celery-5.4.0-py3-none-any.whl"}}, {"metadata": {"name": "newrelic", "version": "10.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d4/71/07c41fd5e8c94e95216b000d00c3cf735f769cb406c0f33c6ff83b7b7418/newrelic-10.16.0.tar.gz"}}, {"metadata": {"name": "redis", "version": "8.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/66/9d/c5731f6e3608663d4d3656fd8d3aecee8b509c3082818f5a13eae925baea/redis-8.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/af/9c0bda43e486a3c9bf1e0f876d0f241bc3f229d7d65d09331a0868db9629/pytest_forked-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "billiard", "version": "4.2.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/87/8bab77b323f16d67be364031220069f79159117dd5e43eeb4be2fef1ac9b/billiard-4.2.4-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "click-didyoumean", "version": "0.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/5b/974430b5ffdb7a4f1941d13d83c64a0395114503cc357c6b9ae4ce5047ed/click_didyoumean-0.3.1-py3-none-any.whl"}}, {"metadata": {"name": "click-plugins", "version": "1.1.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/9a/2abecb28ae875e39c8cad711eb1186d8d14eab564705325e77e4e6ab9ae5/click_plugins-1.1.1.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "click-repl", "version": "0.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/52/40/9d857001228658f0d59e97ebd4c346fe73e138c6de1bce61dc568a57c7f8/click_repl-0.3.0-py3-none-any.whl"}}, {"metadata": {"name": "kombu", "version": "5.6.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/0f/834427d8c03ff1d7e867d3db3d176470c64871753252b21b4f4897d1fa45/kombu-5.6.2-py3-none-any.whl"}}, {"metadata": {"name": "vine", "version": "5.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/ff/7c0c86c43b3cbb927e0ccc0255cb4057ceba4799cd44ae95174ce8e8b5b2/vine-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tzdata", "version": "2026.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e5/6d/b53b99a9f2766d095985947a5782f1702cabb129a34f7a802d7197af832f/tzdata-2026.3-py2.py3-none-any.whl"}}, {"metadata": {"name": "py", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "amqp", "version": "5.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/26/99/fc813cd978842c26c82534010ea849eee9ab3a13ea2b74e95cb9c99e747b/amqp-5.3.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "prompt_toolkit", "version": "3.0.53"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/6f/84908cad2d6aa5144abcf7b42709fe4fdb459bc640ec7ac5786e7693dabc/prompt_toolkit-3.0.53-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl"}}], "install_targets_hash": "7bc432e5912a9b6ade7f1ac7ce46a30a"} +{"python_version": "3.11", "dependencies": [{"metadata": {"name": "pymongo", "version": "3.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/30/c6fba6f336c43f2c7961a949cb1bab2a08082faefb90174f223b22664632/pymongo-3.13.0-cp311-cp311-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "mockupdb", "version": "1.8.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2f/c0/bc0c3e82bf91993bf2337b125c4d49c3cadae39f5a4c642baada958f976e/mockupdb-1.8.1-py2.py3-none-any.whl"}}], "install_targets_hash": "835b39253514cd495b485793c70e3bfd"} +{"python_version": "3.11", "dependencies": [{"metadata": {"name": "pymongo", "version": "3.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/30/c6fba6f336c43f2c7961a949cb1bab2a08082faefb90174f223b22664632/pymongo-3.13.0-cp311-cp311-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "mockupdb", "version": "1.8.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2f/c0/bc0c3e82bf91993bf2337b125c4d49c3cadae39f5a4c642baada958f976e/mockupdb-1.8.1-py2.py3-none-any.whl"}}], "install_targets_hash": "835b39253514cd495b485793c70e3bfd"} +{"python_version": "3.11", "dependencies": [{"metadata": {"name": "pymongo", "version": "3.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/30/c6fba6f336c43f2c7961a949cb1bab2a08082faefb90174f223b22664632/pymongo-3.13.0-cp311-cp311-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "mockupdb", "version": "1.8.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2f/c0/bc0c3e82bf91993bf2337b125c4d49c3cadae39f5a4c642baada958f976e/mockupdb-1.8.1-py2.py3-none-any.whl"}}], "install_targets_hash": "835b39253514cd495b485793c70e3bfd"} +{"python_version": "3.11", "dependencies": [{"metadata": {"name": "pymongo", "version": "3.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/30/c6fba6f336c43f2c7961a949cb1bab2a08082faefb90174f223b22664632/pymongo-3.13.0-cp311-cp311-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "mockupdb", "version": "1.8.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2f/c0/bc0c3e82bf91993bf2337b125c4d49c3cadae39f5a4c642baada958f976e/mockupdb-1.8.1-py2.py3-none-any.whl"}}], "install_targets_hash": "835b39253514cd495b485793c70e3bfd"} +{"python_version": "3.11", "dependencies": [{"metadata": {"name": "pymongo", "version": "3.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/30/c6fba6f336c43f2c7961a949cb1bab2a08082faefb90174f223b22664632/pymongo-3.13.0-cp311-cp311-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "mockupdb", "version": "1.8.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2f/c0/bc0c3e82bf91993bf2337b125c4d49c3cadae39f5a4c642baada958f976e/mockupdb-1.8.1-py2.py3-none-any.whl"}}], "install_targets_hash": "835b39253514cd495b485793c70e3bfd"} {"python_version": "3.11", "dependencies": [{"metadata": {"name": "pymongo", "version": "3.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/30/c6fba6f336c43f2c7961a949cb1bab2a08082faefb90174f223b22664632/pymongo-3.13.0-cp311-cp311-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "mockupdb", "version": "1.8.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2f/c0/bc0c3e82bf91993bf2337b125c4d49c3cadae39f5a4c642baada958f976e/mockupdb-1.8.1-py2.py3-none-any.whl"}}], "install_targets_hash": "835b39253514cd495b485793c70e3bfd"} -{"python_version": "3.11", "dependencies": [{"metadata": {"name": "fastapi", "version": "0.100.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/66/23/5db1adf057fc47f6575c4f317b98882a9312f59a7ec555ae38ca854aef42/fastapi-0.100.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"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"}}, {"metadata": {"name": "starlette", "version": "0.27.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/f8/e2cca22387965584a409795913b774235752be4176d276714e15e1a58884/starlette-0.27.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a5/34/49b9060e8418b14fb5cba9cf6bfb383111e2538a03a1fb18e66a95aeb3d5/charset_normalizer-3.4.9-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/ac/0273f6fcb5f42e314c6d8cd99effae6a5354604d461b8d392b5ec9530a54/markupsafe-3.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "84ca248e3427ba030c1b6637a02186cb"} {"python_version": "3.11", "dependencies": [{"metadata": {"name": "langchain", "version": "0.1.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/28/da40a6b12e7842a0c8b443f8cc5c6f59e49d7a9071cfad064b9639c6b044/langchain-0.1.20-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2d/a9/d94302340304328961d6f0c35ca4e60617fbb57a5cf667e2ed1692cb9e57/tiktoken-0.14.0-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "langchain-openai", "version": "0.1.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/27/43f785670a340363fe46e2893a80293fa12448584f19ba4f9e6d03673552/langchain_openai-0.1.7-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "1.109.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1d/2a/7dd3d207ec669cacc1f186fd856a0f61dbc255d24f6fdc1a6715d6051b0f/openai-1.109.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/3f/01264f820ee2e3712a827892b1cd6ff80f3300c1fcbffbb45714a915d47a/aiohttp-3.14.3-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "dataclasses-json", "version": "0.6.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c3/be/d0d44e092656fe7a06b55e6103cbce807cdbdee17884a5367c68c9860853/dataclasses_json-0.6.7-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/e3/97c6c3562c077f6247d6e6ce5c82562500b6316c0d928e97e106b7a1321a/jiter-0.16.0-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "langchain-community", "version": "0.0.38"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/d3/1f4d1941ae5a627299c8ea052847b99ad6674b97b699d8a08fc4faf25d3e/langchain_community-0.0.38-py3-none-any.whl"}}, {"metadata": {"name": "langchain-core", "version": "0.1.53"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6a/10/285fa149ce95300d91ea0bb124eec28889e5ebbcb59434d1fe2f31098d72/langchain_core-0.1.53-py3-none-any.whl"}}, {"metadata": {"name": "langchain-text-splitters", "version": "0.0.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/68/6a/804fe5ca07129046a4cedc0697222ddde6156cd874c4c4ba29e4d271828a/langchain_text_splitters-0.0.2-py3-none-any.whl"}}, {"metadata": {"name": "langsmith", "version": "0.1.147"}, "download_info": {"url": "https://files.pythonhosted.org/packages/de/f0/63b06b99b730b9954f8709f6f7d9b8d076fa0a973e472efe278089bde42b/langsmith-0.1.147-py3-none-any.whl"}}, {"metadata": {"name": "numpy", "version": "1.26.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1a/2e/151484f49fd03944c4a3ad9c418ed193cfd02724e138ac8a9505d056c582/numpy-1.26.4-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ae/6f/aa064a3e74b5745afbdf250594f38e7ead05e2d651bcb35994b9417a0d4d/pydantic_core-2.46.4-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/16/19/13de8e4377ed53079ee996e1ab0a9c33ec2faf808a4647b7b4c0d46dd239/pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "SQLAlchemy", "version": "2.0.52"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6b/08/cc5f7627b92f1456bc0b5fb7e98af4600248abe422a44da0d17a3fe6a448/sqlalchemy-2.0.52-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tenacity", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/3f/8ba87d9e287b9d385a02a7114ddcef61b26f86411e121c9003eb509a1773/tenacity-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.7.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/2e/2360c41d8080a3d9ec7e5c90fad6eab3b50192869d10e9a5609e48c8177b/regex-2026.7.19-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6a/b6/034f6802e9c3f6418966cfabb7db8c9252cc2429c5098f41cc43af804149/charset_normalizer-3.5.1-cp311-cp311-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/ef/0e8f1fe32f8a53dd26bdd1f9347efe0778b0fddf62789ea683f4cc7d787d/frozenlist-1.8.0-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonpatch", "version": "1.33"}, "download_info": {"url": "https://files.pythonhosted.org/packages/73/07/02e16ed01e04a374e644b575638ec7987ae846d25ad97bcc9945a3ee4b0e/jsonpatch-1.33-py2.py3-none-any.whl"}}, {"metadata": {"name": "marshmallow", "version": "3.26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/be/2f/5108cb3ee4ba6501748c4908b908e55f42a5b66245b4cfe0c99326e1ef6e/marshmallow-3.26.2-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/a4/d45caf2b97b035c57267791ecfaafbd59c68212004b3842830954bb4b02e/multidict-6.7.1-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "orjson", "version": "3.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/34/c2eb3b2900e5597db7841a4c6416ac2d90081bd956b02d4dd1833fa2b96b/orjson-3.12.0-cp311-cp311-macosx_15_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "23.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/1a/610693ac4ee14fcdf2d9bf3c493370e4f2ef7ae2e19217d7a237ff42367d/packaging-23.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/15/a8/8ede85d6aa1f79fc7dc2f8fd2c8d65920b8272c3892903c8a1affde48cfb/propcache-0.5.2-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing-inspect", "version": "0.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/f3/107a22063bf27bdccf2024833d3445f4eea42b2e598abfbd46f6a63b6cb0/typing_inspect-0.9.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ce/97/10b939c44d7b28d1dbc389cfc7012306d1ea8dba01eaef44b39fffaee52a/yarl-1.24.5-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "jsonpointer", "version": "3.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/6a/a83720e953b1682d2d109d3c2dbb0bc9bf28cc1cbc205be4ef4be5da709d/jsonpointer-3.1.1-py3-none-any.whl"}}, {"metadata": {"name": "mypy_extensions", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl"}}], "install_targets_hash": "877a90b1b55e01d25a299fb8949b9fd9"} {"python_version": "3.11", "dependencies": [{"metadata": {"name": "strawberry-graphql", "version": "0.209.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f5/2a/0ff66cce0fbd42e232486f4e4d8ffa39395b7ce0086b06b02a5742f923b1/strawberry_graphql-0.209.8-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.10.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/3c/8cc1cc84deffa6e25d2d0c688ebb80635dfdbf1dbea3e30c541c8cf4d860/pydantic-2.10.6-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/e3/71fe85af2021f3f386da42d291412e5baf6ce7716bd7101ea49c810eda90/pydantic_core-2.27.2-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "fastapi", "version": "0.139.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/7c/8e3c6ad324ea5cb36604fc3f968554887891c316d9dfde57761611d907ad/fastapi-0.139.0-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/15/b92b4e1d88d02c6eff9733c9eea21846ab435cc4d813d84ccc5d335955df/graphql_core-3.2.11-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b4/ff/b1e11d8bffb5e0e1b6d27f402eeedbeb9be6df2cdbc09356a1ae49806dbf/python_multipart-0.0.6-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/2e/5898933336b61975ce9dc04decbc0a7f2fee78c30353c5efba7f2d6ff27a/markupsafe-3.0.3-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}], "install_targets_hash": "9a43a190bf43b9eff8ea17e64ecb9b7f"} -{"python_version": "3.11", "dependencies": [{"metadata": {"name": "httpx", "version": "0.24.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/91/e41f64f03d2a13aee7e8c819d82ee3aa7cdc484d18c0ae859742597d5aa0/httpx-0.24.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-httpx", "version": "0.22.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/23/a8438a0e11bc159d922a62c868593088b78285628e61f01c78bc1f1251e4/pytest_httpx-0.22.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.23.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ee/82/62e2d63639ecb0fbe8a7ee59ef0bc69a4669ec50f6d3459f74ad4e4189a2/pytest_asyncio-0.23.8-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "0.17.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/2c/2bde7ff8dd2064395555220cbf7cba79991172bf5315a07eb3ac7688d9f1/httpcore-0.17.3-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "7.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ff/f6e8b8f39e08547faece4bd80f89d5a8de68a38b2d179cc1c4490ffa3286/pytest-7.4.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/04/ff642e65ad6b90db43e668d70ffb6736436c7ce41fcc549f4e9472234127/h11-0.14.0-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}], "install_targets_hash": "9e9c7b973297953ce2add56028906265"} +{"python_version": "3.11", "dependencies": [{"metadata": {"name": "httpx", "version": "0.24.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/91/e41f64f03d2a13aee7e8c819d82ee3aa7cdc484d18c0ae859742597d5aa0/httpx-0.24.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-httpx", "version": "0.22.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/23/a8438a0e11bc159d922a62c868593088b78285628e61f01c78bc1f1251e4/pytest_httpx-0.22.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.23.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ee/82/62e2d63639ecb0fbe8a7ee59ef0bc69a4669ec50f6d3459f74ad4e4189a2/pytest_asyncio-0.23.8-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "0.17.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/2c/2bde7ff8dd2064395555220cbf7cba79991172bf5315a07eb3ac7688d9f1/httpcore-0.17.3-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "7.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ff/f6e8b8f39e08547faece4bd80f89d5a8de68a38b2d179cc1c4490ffa3286/pytest-7.4.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/04/ff642e65ad6b90db43e668d70ffb6736436c7ce41fcc549f4e9472234127/h11-0.14.0-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}], "install_targets_hash": "9e9c7b973297953ce2add56028906265"} {"python_version": "3.11", "dependencies": [{"metadata": {"name": "huggingface-hub", "version": "0.24.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/28/a0b0dd3cca63908045edc300360d6cd8758d4d86eee3fd2b08f00c5a41c4/huggingface_hub-0.24.7-py3-none-any.whl"}}, {"metadata": {"name": "responses", "version": "0.26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/28/693e1d9ebf72baa062ded80d837a035b86ce75eda5a269379e9e2b1008a8/responses-0.26.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest-httpx", "version": "0.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/55/1fa65f8e4fceb19dd6daa867c162ad845d547f6058cd92b4b02384a44777/pytest_httpx-0.36.2-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e5/22/4222d7ddf3da30f363edaa98e329c2bce6c65497c9cb2810931c8b2c0fbc/fsspec-2026.6.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/16/19/13de8e4377ed53079ee996e1ab0a9c33ec2faf808a4647b7b4c0d46dd239/pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.68.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d8/8e/bb97bb0c71802080bfc8952937d174e49cfc50de5c951dd47b2496f0dcdb/tqdm-4.68.3-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "filelock", "version": "3.29.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4a/e3/f1fae3647d170919c2cf2a898e77e7d1a4e5c7cae0aed7bb4bd3f5ebff6f/filelock-3.29.5-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c2/d7/b5b7020a0565c2e9fa8c09f4b5fa6232feb326b8c20081ccded47ea368fd/charset_normalizer-3.4.7-cp311-cp311-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}], "install_targets_hash": "a5a1524ef8f136e98c6e71cf45c35bd4"} {"python_version": "3.11", "dependencies": [{"metadata": {"name": "langchain", "version": "0.1.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/28/da40a6b12e7842a0c8b443f8cc5c6f59e49d7a9071cfad064b9639c6b044/langchain-0.1.20-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "langchain-openai", "version": "0.1.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/27/43f785670a340363fe46e2893a80293fa12448584f19ba4f9e6d03673552/langchain_openai-0.1.7-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "1.109.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1d/2a/7dd3d207ec669cacc1f186fd856a0f61dbc255d24f6fdc1a6715d6051b0f/openai-1.109.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/3f/01264f820ee2e3712a827892b1cd6ff80f3300c1fcbffbb45714a915d47a/aiohttp-3.14.3-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "dataclasses-json", "version": "0.6.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c3/be/d0d44e092656fe7a06b55e6103cbce807cdbdee17884a5367c68c9860853/dataclasses_json-0.6.7-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/e3/97c6c3562c077f6247d6e6ce5c82562500b6316c0d928e97e106b7a1321a/jiter-0.16.0-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "langchain-community", "version": "0.0.38"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/d3/1f4d1941ae5a627299c8ea052847b99ad6674b97b699d8a08fc4faf25d3e/langchain_community-0.0.38-py3-none-any.whl"}}, {"metadata": {"name": "langchain-core", "version": "0.1.53"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6a/10/285fa149ce95300d91ea0bb124eec28889e5ebbcb59434d1fe2f31098d72/langchain_core-0.1.53-py3-none-any.whl"}}, {"metadata": {"name": "langchain-text-splitters", "version": "0.0.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/68/6a/804fe5ca07129046a4cedc0697222ddde6156cd874c4c4ba29e4d271828a/langchain_text_splitters-0.0.2-py3-none-any.whl"}}, {"metadata": {"name": "langsmith", "version": "0.1.147"}, "download_info": {"url": "https://files.pythonhosted.org/packages/de/f0/63b06b99b730b9954f8709f6f7d9b8d076fa0a973e472efe278089bde42b/langsmith-0.1.147-py3-none-any.whl"}}, {"metadata": {"name": "numpy", "version": "1.26.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1a/2e/151484f49fd03944c4a3ad9c418ed193cfd02724e138ac8a9505d056c582/numpy-1.26.4-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ae/6f/aa064a3e74b5745afbdf250594f38e7ead05e2d651bcb35994b9417a0d4d/pydantic_core-2.46.4-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/16/19/13de8e4377ed53079ee996e1ab0a9c33ec2faf808a4647b7b4c0d46dd239/pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "SQLAlchemy", "version": "2.0.52"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6b/08/cc5f7627b92f1456bc0b5fb7e98af4600248abe422a44da0d17a3fe6a448/sqlalchemy-2.0.52-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tenacity", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/3f/8ba87d9e287b9d385a02a7114ddcef61b26f86411e121c9003eb509a1773/tenacity-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2d/a9/d94302340304328961d6f0c35ca4e60617fbb57a5cf667e2ed1692cb9e57/tiktoken-0.14.0-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6a/b6/034f6802e9c3f6418966cfabb7db8c9252cc2429c5098f41cc43af804149/charset_normalizer-3.5.1-cp311-cp311-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/ef/0e8f1fe32f8a53dd26bdd1f9347efe0778b0fddf62789ea683f4cc7d787d/frozenlist-1.8.0-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonpatch", "version": "1.33"}, "download_info": {"url": "https://files.pythonhosted.org/packages/73/07/02e16ed01e04a374e644b575638ec7987ae846d25ad97bcc9945a3ee4b0e/jsonpatch-1.33-py2.py3-none-any.whl"}}, {"metadata": {"name": "marshmallow", "version": "3.26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/be/2f/5108cb3ee4ba6501748c4908b908e55f42a5b66245b4cfe0c99326e1ef6e/marshmallow-3.26.2-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/a4/d45caf2b97b035c57267791ecfaafbd59c68212004b3842830954bb4b02e/multidict-6.7.1-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "orjson", "version": "3.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/34/c2eb3b2900e5597db7841a4c6416ac2d90081bd956b02d4dd1833fa2b96b/orjson-3.12.0-cp311-cp311-macosx_15_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "23.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/1a/610693ac4ee14fcdf2d9bf3c493370e4f2ef7ae2e19217d7a237ff42367d/packaging-23.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/15/a8/8ede85d6aa1f79fc7dc2f8fd2c8d65920b8272c3892903c8a1affde48cfb/propcache-0.5.2-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing-inspect", "version": "0.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/f3/107a22063bf27bdccf2024833d3445f4eea42b2e598abfbd46f6a63b6cb0/typing_inspect-0.9.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ce/97/10b939c44d7b28d1dbc389cfc7012306d1ea8dba01eaef44b39fffaee52a/yarl-1.24.5-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "regex", "version": "2026.7.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/2e/2360c41d8080a3d9ec7e5c90fad6eab3b50192869d10e9a5609e48c8177b/regex-2026.7.19-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "jsonpointer", "version": "3.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/6a/a83720e953b1682d2d109d3c2dbb0bc9bf28cc1cbc205be4ef4be5da709d/jsonpointer-3.1.1-py3-none-any.whl"}}, {"metadata": {"name": "mypy_extensions", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl"}}], "install_targets_hash": "aa1fb60a0df2b501cda6dfe6922f3f17"} {"python_version": "3.11", "dependencies": [{"metadata": {"name": "litestar", "version": "2.8.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/e7/3d7ca62d6c48ff4c8162e2f03264c3202d8a76cb6a4987eac67f27af1de5/litestar-2.8.3-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/22/adf66990e63584a68dfb50c24f48a125c07b1699899381c8151e63ed458c/cryptography-49.0.0-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/8b/f0e4c441227ba756aafbe78f117485b25bb26b1c059d01f137fa6d14896b/cffi-2.0.0-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c2/d7/b5b7020a0565c2e9fa8c09f4b5fa6232feb326b8c20081ccded47ea368fd/charset_normalizer-3.4.7-cp311-cp311-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "msgspec", "version": "0.21.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/60/504886af1aaf854112663b842d5eea9a15d9588f9bf7d0d2df736424b84d/msgspec-0.21.1-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/a4/d45caf2b97b035c57267791ecfaafbd59c68212004b3842830954bb4b02e/multidict-6.7.1-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "polyfactory", "version": "3.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/34/b6f19941adcdaf415b5e8a8d577499f5b6a76b59cbae37f9b125a9ffe9f2/polyfactory-3.3.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/16/19/13de8e4377ed53079ee996e1ab0a9c33ec2faf808a4647b7b4c0d46dd239/pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "rich-click", "version": "1.9.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6d/97/a87901aef6b7e7e4a34c6dd6cc17dca8594a592ef9d9dd765fca2b7facf7/rich_click-1.9.8-py3-none-any.whl"}}, {"metadata": {"name": "Faker", "version": "40.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/a6/6111b9f13c1564b0e2f5dbeeb611fd00dc731e6add2336f62b798598c73d/faker-40.28.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}], "install_targets_hash": "aad339208686a05fcf6dfa07b8c6ba47"} {"python_version": "3.11", "dependencies": [{"metadata": {"name": "Django", "version": "4.2.30"}, "download_info": {"url": "https://files.pythonhosted.org/packages/39/b7/a7c96f239cf91313a6589233fed55111c7063b26683b226802732c455dbc/django-4.2.30-py3-none-any.whl"}}, {"metadata": {"name": "psycopg2-binary", "version": "2.9.12"}, "download_info": {"url": "https://files.pythonhosted.org/packages/53/71/c85409ee0d78890f0660eff262e815e7dd2bb741a17611d82e9e8cd9dc5e/psycopg2_binary-2.9.12-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "djangorestframework", "version": "3.17.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5a/e1/2c516bdc83652b1a60c6119366ac2c0607b479ed05cd6093f916ca8928f8/djangorestframework-3.17.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-django", "version": "4.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/83/a5/41d091f697c09609e7ef1d5d61925494e0454ebf51de7de05f0f0a728f1d/pytest_django-4.12.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/af/9c0bda43e486a3c9bf1e0f876d0f241bc3f229d7d65d09331a0868db9629/pytest_forked-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "executing", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "asgiref", "version": "3.11.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5c/0a/a72d10ed65068e115044937873362e6e32fab1b7dce0046aeb224682c989/asgiref-3.11.1-py3-none-any.whl"}}, {"metadata": {"name": "daphne", "version": "4.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/ab/85534d9cbca09f3c10f58fc2093659062280ed5703707c0b41dbca8ec297/daphne-4.2.2-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/2e/5898933336b61975ce9dc04decbc0a7f2fee78c30353c5efba7f2d6ff27a/markupsafe-3.0.3-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "sqlparse", "version": "0.5.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/4b/359f28a903c13438ef59ebeee215fb25da53066db67b305c125f1c6d2a25/sqlparse-0.5.5-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "channels", "version": "4.3.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/16/34/c32915288b7ef482377b6adc401192f98c6a99b3a145423d3b8aed807898/channels-4.3.2-py3-none-any.whl"}}, {"metadata": {"name": "py", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "autobahn", "version": "26.6.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/86/11/baddfc389933b3db1e83041ccde5f63f2fac4d1b3c292715c7b58e66f837/autobahn-26.6.2-cp311-cp311-macosx_15_0_arm64.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "Twisted", "version": "26.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/57/bcf4e2370dd218c9aa68a9140a65d86729c73f1d529f7e94786c2766fc72/twisted-26.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "Automat", "version": "25.4.16"}, "download_info": {"url": "https://files.pythonhosted.org/packages/02/ff/1175b0b7371e46244032d43a56862d0af455823b5280a50c63d99cc50f18/automat-25.4.16-py3-none-any.whl"}}, {"metadata": {"name": "cbor2", "version": "6.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f8/2e/013b2c478c41585bf5c8f9659328412eda4fe8ed30ffeb8e4fde87f8b9a3/cbor2-6.1.3-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/8b/f0e4c441227ba756aafbe78f117485b25bb26b1c059d01f137fa6d14896b/cffi-2.0.0-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "constantly", "version": "23.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b8/40/c199d095151addf69efdb4b9ca3a4f20f70e20508d6222bffb9b76f58573/constantly-23.10.4-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/22/adf66990e63584a68dfb50c24f48a125c07b1699899381c8151e63ed458c/cryptography-49.0.0-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "hyperlink", "version": "21.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/aa/8caf6a0a3e62863cbb9dab27135660acba46903b703e224f14f447e57934/hyperlink-21.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "Incremental", "version": "24.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1d/55/0f4df2a44053867ea9cbea73fc588b03c55605cd695cee0a3d86f0029cb2/incremental-24.11.0-py3-none-any.whl"}}, {"metadata": {"name": "msgpack", "version": "1.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/3a/dd518a1bf78ed1e9ad8afe57307c079a00eafe4b3068932a27ca1ea56b4f/msgpack-1.2.1-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pyOpenSSL", "version": "26.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/18/1dd71c9b43192ab83f1d531ad6002dc81108ac36c475f79fb7a295abe2f4/pyopenssl-26.3.0-py3-none-any.whl"}}, {"metadata": {"name": "service-identity", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/eb/2433e1af4ff903499144de4846569fb3300b816179ae99a03c2f011b666a/service_identity-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "txaio", "version": "26.6.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/91/68/075bf851e11c9ef65bd6a0426791f0d9a0c7dae0e7f6e0b16ca67334b456/txaio-26.6.1-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "5.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b5/c6/83db69f96dc12509c9510084c0389c4aff4dcf427f9b613d1a23abd446ce/ujson-5.13.0-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "zope.interface", "version": "8.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bb/a7/6b6e0c31ac240cb9fc015ae9ed45ca54be886c18fcf7bfa2377a4d7a8785/zope_interface-8.5-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "b0d4ec08daf07a9aba63eb1306f8fbf7"} +{"python_version": "3.11", "dependencies": [{"metadata": {"name": "tornado", "version": "6.6a1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/6d/a5/8d2a0673aa45376dc0d16a593abee707313ff919a22c10b33d02a7347e8b/tornado-6.6a1-cp311-abi3-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}], "install_targets_hash": "b883316dda3824a719a7fb8ca38112ff"} {"python_version": "3.11", "dependencies": [{"metadata": {"name": "ariadne", "version": "0.20.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e4/7c/6ca01607e6dc23472ab599507af67e9b4db9868e4baf8477fcafe958af00/ariadne-0.20.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "fastapi", "version": "0.139.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/7c/8e3c6ad324ea5cb36604fc3f968554887891c316d9dfde57761611d907ad/fastapi-0.139.0-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/15/b92b4e1d88d02c6eff9733c9eea21846ab435cc4d813d84ccc5d335955df/graphql_core-3.2.11-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/2e/5898933336b61975ce9dc04decbc0a7f2fee78c30353c5efba7f2d6ff27a/markupsafe-3.0.3-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ae/6f/aa064a3e74b5745afbdf250594f38e7ead05e2d651bcb35994b9417a0d4d/pydantic_core-2.46.4-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "starlette", "version": "0.52.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/0d/13d1d239a25cbfb19e740db83143e95c772a1fe10202dda4b76792b114dd/starlette-0.52.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}], "install_targets_hash": "ba34689285beeef10583bc1d6faea8b5"} +{"python_version": "3.11", "dependencies": [{"metadata": {"name": "sanic", "version": "22.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/80/5c/91c44dd9daf62f0068a372d9c3a12945bfcb36eb22aa1b1bfc81ecc0e6e1/sanic-22.12.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cc/19/2f003f9f81c0fab2eabb81d8fc2fce5fb5b5714f1b4abfe897cb209e031d/websockets-10.4-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/3f/01264f820ee2e3712a827892b1cd6ff80f3300c1fcbffbb45714a915d47a/aiohttp-3.14.3-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-testing", "version": "24.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/93/1d588f1cb9b710b9f22fa78b53d699a8062edc94204d50dd0d78c5f5b495/sanic_testing-24.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/ef/0e8f1fe32f8a53dd26bdd1f9347efe0778b0fddf62789ea683f4cc7d787d/frozenlist-1.8.0-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httptools", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/94/dfe435d90d0ef61ec0f2cc3d480eef78c59727c6c2ce039f433882f6131a/httptools-0.8.0-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/a4/d45caf2b97b035c57267791ecfaafbd59c68212004b3842830954bb4b02e/multidict-6.7.1-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/15/a8/8ede85d6aa1f79fc7dc2f8fd2c8d65920b8272c3892903c8a1affde48cfb/propcache-0.5.2-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-routing", "version": "23.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/e3/3425c9a8773807ac2c01d6a56c8521733f09b627e5827e733c5cd36b9ac5/sanic_routing-23.12.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "5.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b5/c6/83db69f96dc12509c9510084c0389c4aff4dcf427f9b613d1a23abd446ce/ujson-5.13.0-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "uvloop", "version": "0.22.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c7/d5/69900f7883235562f1f50d8184bb7dd84a2fb61e9ec63f3782546fdbd057/uvloop-0.22.1-cp311-cp311-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ce/97/10b939c44d7b28d1dbc389cfc7012306d1ea8dba01eaef44b39fffaee52a/yarl-1.24.5-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}], "install_targets_hash": "d30b435a069bef886019e4dd69ce4c21"} +{"python_version": "3.11", "dependencies": [{"metadata": {"name": "pyreqwest", "version": "0.11.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/4d/1d2f533d175ca35375c986778a83afceadd617ac2844972d837bf7094adb/pyreqwest-0.11.8-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "ddbeddd6367dc3ba2a81dfa0d1d7c186"} +{"python_version": "3.11", "dependencies": [{"metadata": {"name": "pyreqwest", "version": "0.11.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/4d/1d2f533d175ca35375c986778a83afceadd617ac2844972d837bf7094adb/pyreqwest-0.11.8-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "ddbeddd6367dc3ba2a81dfa0d1d7c186"} {"python_version": "3.11", "dependencies": [{"metadata": {"name": "pyreqwest", "version": "0.11.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/4d/1d2f533d175ca35375c986778a83afceadd617ac2844972d837bf7094adb/pyreqwest-0.11.8-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "ddbeddd6367dc3ba2a81dfa0d1d7c186"} {"python_version": "3.11", "dependencies": [{"metadata": {"name": "grpcio", "version": "1.49.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4d/ea/359a98f8b3b4ff9a2f457a0d20ed81775a64149fbb7617177ed23d9d10c9/grpcio-1.49.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "protobuf", "version": "7.35.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e4/be/5b3cfe508bfab6761414ff944e3366eb13be4fd71efcd69450f89ba39f43/protobuf-7.35.1-cp310-abi3-manylinux2014_x86_64.whl"}}, {"metadata": {"name": "mypy-protobuf", "version": "5.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/ec/5ffcf8f5f53757e01afdece10c664e694ac60d2f17c2036811b85b842a5b/mypy_protobuf-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "types-protobuf", "version": "7.34.1.20260518"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/1f/ec5caf72c2e3b688ca3927e0979a04ddad19e1afc4bf1c199bd743e0f419/types_protobuf-7.34.1.20260518-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/af/9c0bda43e486a3c9bf1e0f876d0f241bc3f229d7d65d09331a0868db9629/pytest_forked-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "py", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl"}}], "install_targets_hash": "e0332f37695c3f450fdb05225a93e60d"} +{"python_version": "3.11", "dependencies": [{"metadata": {"name": "grpcio", "version": "1.49.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4d/ea/359a98f8b3b4ff9a2f457a0d20ed81775a64149fbb7617177ed23d9d10c9/grpcio-1.49.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "protobuf", "version": "7.35.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e4/be/5b3cfe508bfab6761414ff944e3366eb13be4fd71efcd69450f89ba39f43/protobuf-7.35.1-cp310-abi3-manylinux2014_x86_64.whl"}}, {"metadata": {"name": "mypy-protobuf", "version": "5.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/ec/5ffcf8f5f53757e01afdece10c664e694ac60d2f17c2036811b85b842a5b/mypy_protobuf-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "types-protobuf", "version": "7.34.1.20260518"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/1f/ec5caf72c2e3b688ca3927e0979a04ddad19e1afc4bf1c199bd743e0f419/types_protobuf-7.34.1.20260518-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/af/9c0bda43e486a3c9bf1e0f876d0f241bc3f229d7d65d09331a0868db9629/pytest_forked-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "py", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl"}}], "install_targets_hash": "e0332f37695c3f450fdb05225a93e60d"} +{"python_version": "3.11", "dependencies": [{"metadata": {"name": "litestar", "version": "2.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/b5/ad040f923f1661240eaae883b7d3fec29ea6614d7e732d051fc16400998f/litestar-2.0.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/22/adf66990e63584a68dfb50c24f48a125c07b1699899381c8151e63ed458c/cryptography-49.0.0-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/8b/f0e4c441227ba756aafbe78f117485b25bb26b1c059d01f137fa6d14896b/cffi-2.0.0-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c2/d7/b5b7020a0565c2e9fa8c09f4b5fa6232feb326b8c20081ccded47ea368fd/charset_normalizer-3.4.7-cp311-cp311-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "fast-query-parsers", "version": "1.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/21/c8c160f61a740efc4577079eb5747a6b2cb8d1168a84a0bfda6044113768/fast_query_parsers-1.0.3-cp38-abi3-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "msgspec", "version": "0.21.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/60/504886af1aaf854112663b842d5eea9a15d9588f9bf7d0d2df736424b84d/msgspec-0.21.1-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/a4/d45caf2b97b035c57267791ecfaafbd59c68212004b3842830954bb4b02e/multidict-6.7.1-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "polyfactory", "version": "3.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/34/b6f19941adcdaf415b5e8a8d577499f5b6a76b59cbae37f9b125a9ffe9f2/polyfactory-3.3.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/16/19/13de8e4377ed53079ee996e1ab0a9c33ec2faf808a4647b7b4c0d46dd239/pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "Faker", "version": "40.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/a6/6111b9f13c1564b0e2f5dbeeb611fd00dc731e6add2336f62b798598c73d/faker-40.28.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "eff25fb572d2faba9c895f2319049fe6"} +{"python_version": "3.11", "dependencies": [{"metadata": {"name": "litestar", "version": "2.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/b5/ad040f923f1661240eaae883b7d3fec29ea6614d7e732d051fc16400998f/litestar-2.0.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/22/adf66990e63584a68dfb50c24f48a125c07b1699899381c8151e63ed458c/cryptography-49.0.0-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/8b/f0e4c441227ba756aafbe78f117485b25bb26b1c059d01f137fa6d14896b/cffi-2.0.0-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c2/d7/b5b7020a0565c2e9fa8c09f4b5fa6232feb326b8c20081ccded47ea368fd/charset_normalizer-3.4.7-cp311-cp311-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "fast-query-parsers", "version": "1.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/21/c8c160f61a740efc4577079eb5747a6b2cb8d1168a84a0bfda6044113768/fast_query_parsers-1.0.3-cp38-abi3-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "msgspec", "version": "0.21.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/60/504886af1aaf854112663b842d5eea9a15d9588f9bf7d0d2df736424b84d/msgspec-0.21.1-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/a4/d45caf2b97b035c57267791ecfaafbd59c68212004b3842830954bb4b02e/multidict-6.7.1-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "polyfactory", "version": "3.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/34/b6f19941adcdaf415b5e8a8d577499f5b6a76b59cbae37f9b125a9ffe9f2/polyfactory-3.3.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/16/19/13de8e4377ed53079ee996e1ab0a9c33ec2faf808a4647b7b4c0d46dd239/pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "Faker", "version": "40.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/a6/6111b9f13c1564b0e2f5dbeeb611fd00dc731e6add2336f62b798598c73d/faker-40.28.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "eff25fb572d2faba9c895f2319049fe6"} +{"python_version": "3.11", "dependencies": [{"metadata": {"name": "litestar", "version": "2.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/b5/ad040f923f1661240eaae883b7d3fec29ea6614d7e732d051fc16400998f/litestar-2.0.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/22/adf66990e63584a68dfb50c24f48a125c07b1699899381c8151e63ed458c/cryptography-49.0.0-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/8b/f0e4c441227ba756aafbe78f117485b25bb26b1c059d01f137fa6d14896b/cffi-2.0.0-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c2/d7/b5b7020a0565c2e9fa8c09f4b5fa6232feb326b8c20081ccded47ea368fd/charset_normalizer-3.4.7-cp311-cp311-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "fast-query-parsers", "version": "1.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/21/c8c160f61a740efc4577079eb5747a6b2cb8d1168a84a0bfda6044113768/fast_query_parsers-1.0.3-cp38-abi3-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "msgspec", "version": "0.21.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/60/504886af1aaf854112663b842d5eea9a15d9588f9bf7d0d2df736424b84d/msgspec-0.21.1-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/a4/d45caf2b97b035c57267791ecfaafbd59c68212004b3842830954bb4b02e/multidict-6.7.1-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "polyfactory", "version": "3.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/34/b6f19941adcdaf415b5e8a8d577499f5b6a76b59cbae37f9b125a9ffe9f2/polyfactory-3.3.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/16/19/13de8e4377ed53079ee996e1ab0a9c33ec2faf808a4647b7b4c0d46dd239/pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "Faker", "version": "40.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/a6/6111b9f13c1564b0e2f5dbeeb611fd00dc731e6add2336f62b798598c73d/faker-40.28.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "eff25fb572d2faba9c895f2319049fe6"} +{"python_version": "3.11", "dependencies": [{"metadata": {"name": "litestar", "version": "2.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/b5/ad040f923f1661240eaae883b7d3fec29ea6614d7e732d051fc16400998f/litestar-2.0.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/22/adf66990e63584a68dfb50c24f48a125c07b1699899381c8151e63ed458c/cryptography-49.0.0-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/8b/f0e4c441227ba756aafbe78f117485b25bb26b1c059d01f137fa6d14896b/cffi-2.0.0-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c2/d7/b5b7020a0565c2e9fa8c09f4b5fa6232feb326b8c20081ccded47ea368fd/charset_normalizer-3.4.7-cp311-cp311-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "fast-query-parsers", "version": "1.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/21/c8c160f61a740efc4577079eb5747a6b2cb8d1168a84a0bfda6044113768/fast_query_parsers-1.0.3-cp38-abi3-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "msgspec", "version": "0.21.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/60/504886af1aaf854112663b842d5eea9a15d9588f9bf7d0d2df736424b84d/msgspec-0.21.1-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/a4/d45caf2b97b035c57267791ecfaafbd59c68212004b3842830954bb4b02e/multidict-6.7.1-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "polyfactory", "version": "3.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/34/b6f19941adcdaf415b5e8a8d577499f5b6a76b59cbae37f9b125a9ffe9f2/polyfactory-3.3.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/16/19/13de8e4377ed53079ee996e1ab0a9c33ec2faf808a4647b7b4c0d46dd239/pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "Faker", "version": "40.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/a6/6111b9f13c1564b0e2f5dbeeb611fd00dc731e6add2336f62b798598c73d/faker-40.28.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "eff25fb572d2faba9c895f2319049fe6"} +{"python_version": "3.11", "dependencies": [{"metadata": {"name": "litestar", "version": "2.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/b5/ad040f923f1661240eaae883b7d3fec29ea6614d7e732d051fc16400998f/litestar-2.0.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/22/adf66990e63584a68dfb50c24f48a125c07b1699899381c8151e63ed458c/cryptography-49.0.0-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/8b/f0e4c441227ba756aafbe78f117485b25bb26b1c059d01f137fa6d14896b/cffi-2.0.0-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c2/d7/b5b7020a0565c2e9fa8c09f4b5fa6232feb326b8c20081ccded47ea368fd/charset_normalizer-3.4.7-cp311-cp311-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "fast-query-parsers", "version": "1.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/21/c8c160f61a740efc4577079eb5747a6b2cb8d1168a84a0bfda6044113768/fast_query_parsers-1.0.3-cp38-abi3-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "msgspec", "version": "0.21.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/60/504886af1aaf854112663b842d5eea9a15d9588f9bf7d0d2df736424b84d/msgspec-0.21.1-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/a4/d45caf2b97b035c57267791ecfaafbd59c68212004b3842830954bb4b02e/multidict-6.7.1-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "polyfactory", "version": "3.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/34/b6f19941adcdaf415b5e8a8d577499f5b6a76b59cbae37f9b125a9ffe9f2/polyfactory-3.3.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/16/19/13de8e4377ed53079ee996e1ab0a9c33ec2faf808a4647b7b4c0d46dd239/pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "Faker", "version": "40.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/a6/6111b9f13c1564b0e2f5dbeeb611fd00dc731e6add2336f62b798598c73d/faker-40.28.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "eff25fb572d2faba9c895f2319049fe6"} +{"python_version": "3.11", "dependencies": [{"metadata": {"name": "litestar", "version": "2.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/b5/ad040f923f1661240eaae883b7d3fec29ea6614d7e732d051fc16400998f/litestar-2.0.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/22/adf66990e63584a68dfb50c24f48a125c07b1699899381c8151e63ed458c/cryptography-49.0.0-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/8b/f0e4c441227ba756aafbe78f117485b25bb26b1c059d01f137fa6d14896b/cffi-2.0.0-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c2/d7/b5b7020a0565c2e9fa8c09f4b5fa6232feb326b8c20081ccded47ea368fd/charset_normalizer-3.4.7-cp311-cp311-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "fast-query-parsers", "version": "1.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/21/c8c160f61a740efc4577079eb5747a6b2cb8d1168a84a0bfda6044113768/fast_query_parsers-1.0.3-cp38-abi3-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "msgspec", "version": "0.21.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/60/504886af1aaf854112663b842d5eea9a15d9588f9bf7d0d2df736424b84d/msgspec-0.21.1-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/a4/d45caf2b97b035c57267791ecfaafbd59c68212004b3842830954bb4b02e/multidict-6.7.1-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "polyfactory", "version": "3.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/34/b6f19941adcdaf415b5e8a8d577499f5b6a76b59cbae37f9b125a9ffe9f2/polyfactory-3.3.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/16/19/13de8e4377ed53079ee996e1ab0a9c33ec2faf808a4647b7b4c0d46dd239/pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "Faker", "version": "40.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/a6/6111b9f13c1564b0e2f5dbeeb611fd00dc731e6add2336f62b798598c73d/faker-40.28.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "eff25fb572d2faba9c895f2319049fe6"} {"python_version": "3.11", "dependencies": [{"metadata": {"name": "litestar", "version": "2.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/b5/ad040f923f1661240eaae883b7d3fec29ea6614d7e732d051fc16400998f/litestar-2.0.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/22/adf66990e63584a68dfb50c24f48a125c07b1699899381c8151e63ed458c/cryptography-49.0.0-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/8b/f0e4c441227ba756aafbe78f117485b25bb26b1c059d01f137fa6d14896b/cffi-2.0.0-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c2/d7/b5b7020a0565c2e9fa8c09f4b5fa6232feb326b8c20081ccded47ea368fd/charset_normalizer-3.4.7-cp311-cp311-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "fast-query-parsers", "version": "1.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/21/c8c160f61a740efc4577079eb5747a6b2cb8d1168a84a0bfda6044113768/fast_query_parsers-1.0.3-cp38-abi3-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "msgspec", "version": "0.21.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/60/504886af1aaf854112663b842d5eea9a15d9588f9bf7d0d2df736424b84d/msgspec-0.21.1-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/a4/d45caf2b97b035c57267791ecfaafbd59c68212004b3842830954bb4b02e/multidict-6.7.1-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "polyfactory", "version": "3.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/34/b6f19941adcdaf415b5e8a8d577499f5b6a76b59cbae37f9b125a9ffe9f2/polyfactory-3.3.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/16/19/13de8e4377ed53079ee996e1ab0a9c33ec2faf808a4647b7b4c0d46dd239/pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "Faker", "version": "40.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/a6/6111b9f13c1564b0e2f5dbeeb611fd00dc731e6add2336f62b798598c73d/faker-40.28.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "eff25fb572d2faba9c895f2319049fe6"} {"python_version": "3.11", "dependencies": [{"metadata": {"name": "openai", "version": "1.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/94/99a674bd1dd3a74d5b679bfdd9e1396f08407f933eb15672207e5a8abf1d/openai-1.0.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ae/6f/aa064a3e74b5745afbdf250594f38e7ead05e2d651bcb35994b9417a0d4d/pydantic_core-2.46.4-cp311-cp311-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}], "install_targets_hash": "f61ada90175867ade45a2b9f33f30ae0"} {"python_version": "3.12", "dependencies": [{"metadata": {"name": "redis", "version": "5.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/26/5c5fa0e83c3621db835cfc1f1d789b37e7fa99ed54423b5f519beb931aa7/redis-5.3.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "7.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ff/f6e8b8f39e08547faece4bd80f89d5a8de68a38b2d179cc1c4490ffa3286/pytest-7.4.4-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/4d/e6e40f93031adbf654d34e542bd396e9f3bc1c6209b40c920d58c9e1317a/fakeredis-2.36.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.23.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ee/82/62e2d63639ecb0fbe8a7ee59ef0bc69a4669ec50f6d3459f74ad4e4189a2/pytest_asyncio-0.23.8-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}], "install_targets_hash": "035482a3571a63ab1772e66597b1b19f"} {"python_version": "3.12", "dependencies": [{"metadata": {"name": "anthropic", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/b4/0f37ca7ba43ec390f363fac20ae04c53b5db23a153e08251f214ac8eda7a/anthropic-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/95/6195171e385007300f0f5574592e467c568becce2d937a0b6804f218bc49/pydantic_core-2.46.4-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "tokenizers", "version": "0.23.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e2/6a/068ed9f6e444c9d7e9d55ce134181325700f3d7f30410721bdc8f848d727/tokenizers-0.23.1-cp310-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "huggingface_hub", "version": "1.28.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/0e/eafef18f1a75e125e68395db21131db0cf868a128ecd2fce69b4df6c584b/huggingface_hub-1.28.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/69/55b8dcf636142ae660fec1869fcac14c4da2e8412e14d6eee1523be77e9f/hf_xet-1.6.0-cp38-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "filelock", "version": "3.32.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/a4/9b63d595d748e3aff8812b65eacc1a2c4bd90b7c2012e08e72373b4835eb/filelock-3.32.4-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/3c/6a2bf344106328fd04963664a60b9bb6496fc25df8e962fcdc1367285fb9/fsspec-2026.7.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "04466a6e41bf5a66655ab84cf9b9a43d"} {"python_version": "3.12", "dependencies": [{"metadata": {"name": "rq", "version": "1.16.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/46/35/db396caf7cfe71a9e661cea520b276f1472df25015e7cb9143c65a1dca6d/rq-1.16.2-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.35.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6f/27/b8b057a23f7777177e92d3a602fd866751b6b45014964548997e92e048fd/fakeredis-2.35.1-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "redis", "version": "8.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/0a/c2345ebf1ebe70840ce3f6c6ee612f8fa749cfbd1b03069c53bf0c62aaad/redis-8.0.1-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}], "install_targets_hash": "09963eb19b6d3c77fefe09bd2af175bd"} -{"python_version": "3.12", "dependencies": [{"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-httpx", "version": "0.35.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/ed/026d467c1853dd83102411a78126b4842618e86c895f93528b0528c7a620/pytest_httpx-0.35.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}], "install_targets_hash": "0bb79de8dbba0e02df12fe5e7e7fd9b6"} +{"python_version": "3.12", "dependencies": [{"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-httpx", "version": "0.35.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/ed/026d467c1853dd83102411a78126b4842618e86c895f93528b0528c7a620/pytest_httpx-0.35.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}], "install_targets_hash": "0bb79de8dbba0e02df12fe5e7e7fd9b6"} {"python_version": "3.12", "dependencies": [{"metadata": {"name": "openai", "version": "1.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/94/99a674bd1dd3a74d5b679bfdd9e1396f08407f933eb15672207e5a8abf1d/openai-1.0.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/95/6195171e385007300f0f5574592e467c568becce2d937a0b6804f218bc49/pydantic_core-2.46.4-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/9f/fe6b1aca23331aa5271df5a4bd07bf68a7059254d47faee1b8272592a777/tiktoken-0.14.0-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.7.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/63/4cab4d7f2d384a144d420b763d97674cb70619c878ea6fcd7640d0e62143/regex-2026.7.19-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/27/78873dc8b6a56357517b74b6bb9568b80450e7bb4f6ef7e3fa9d22aa0bd7/charset_normalizer-3.5.1-cp312-cp312-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}], "install_targets_hash": "12df249d83810baf33b2334b64611de2"} +{"python_version": "3.12", "dependencies": [{"metadata": {"name": "Quart", "version": "0.19.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/01/e5d6127f6304c7e596e5c8eec5accdec0f698ec65fe342d8474ad5223717/quart-0.19.9-py3-none-any.whl"}}, {"metadata": {"name": "quart-auth", "version": "0.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/a3/8ca9235569f39e471a9a319ba1665a27cb9cea8c48c688966460db67d48f/quart_auth-0.11.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/af/9c0bda43e486a3c9bf1e0f876d0f241bc3f229d7d65d09331a0868db9629/pytest_forked-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "quart-flask-patch", "version": "0.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/ce/ad2b19e3a26d2c611aa883b8500e8b4eb08f8a2d1595e28c37864e54e99c/quart_flask_patch-0.3.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "Hypercorn", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/35/850277d1b17b206bd10874c8a9a3f52e059452fb49bb0d22cbb908f6038b/hypercorn-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "h2", "version": "4.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/22/e85faf23bd72a92d1921e37d674ca56eb298a3c8be31fdecef0ff2b3aaac/h2-4.4.1-py3-none-any.whl"}}, {"metadata": {"name": "hpack", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/b4/4a9fcfb2aef6ba44d9073ecd301443aa00b3dac95de5619f2a7de7ec8a91/hpack-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "hyperframe", "version": "6.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/48/30/47d0bf6072f7252e6521f3447ccfa40b421b6824517f82854703d0f5a98b/hyperframe-6.1.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "wsproto", "version": "1.3.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a4/f5/10b68b7b1544245097b2a1b8238f66f2fc6dcaeb24ba5d917f52bd2eed4f/wsproto-1.3.2-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "priority", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5e/5f/82c8074f7e84978129347c2c6ec8b6c59f3584ff1a20bc3c940a3e061790/priority-2.0.0-py3-none-any.whl"}}, {"metadata": {"name": "py", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl"}}], "install_targets_hash": "1878488984d6daa9f6c4336c0c223b5b"} +{"python_version": "3.12", "dependencies": [{"metadata": {"name": "aiohttp", "version": "3.9.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/28/2080ed3140b7d25c406f77fe2d5776edd9c7a25228f7f905d7058a6e2d61/aiohttp-3.9.5-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/65/1caac9d4cd32e8433908683446eebc953e82d22b03d10d41a5f0fefe991b/multidict-6.7.1-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ea/b4/05b4131c407006cd1e410e9c6539f16a0945724677e5364447313c15ea3e/yarl-1.24.5-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-aiohttp", "version": "1.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/a7/6e50ba2c0a27a34859a952162e63362a13142ce3c646e925b76de440e102/pytest_aiohttp-1.0.5-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2b/94/5c8a2b50a496b11dd519f4a24cb5496cf125681dd99e94c604ccdea9419a/frozenlist-1.8.0-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/7d/49777a3e20b55863d4794384a38acd460c04157b0a00f8602b0d508b8431/propcache-0.5.2-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}], "install_targets_hash": "233113f80ecbd02cde8c7f1f523c1af4"} +{"python_version": "3.12", "dependencies": [{"metadata": {"name": "langgraph", "version": "1.2.12"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/52/27/5a02054c535ed6fcfb2ab1e5c33c51c810cf1e773194ad28c928f0473509/langgraph-1.2.12-py3-none-any.whl"}}, {"metadata": {"name": "langchain-core", "version": "1.6.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c4/f2/41435d9a5448c52a0388f75741edb979fde7415eaa820d6a42878cad7e38/langchain_core-1.6.4-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "jsonpatch", "version": "1.33"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/73/07/02e16ed01e04a374e644b575638ec7987ae846d25ad97bcc9945a3ee4b0e/jsonpatch-1.33-py2.py3-none-any.whl"}}, {"metadata": {"name": "langgraph-checkpoint", "version": "4.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/05/71/3b475f09bd57d3a5649792c66353312b4432afd843f301739dfcebd157f0/langgraph_checkpoint-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "langgraph-prebuilt", "version": "1.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e9/43/3fe1a700b8490ed02679cdbbc8c915eb23a092faf496c9c1118abcd10be3/langgraph_prebuilt-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "langgraph-sdk", "version": "0.4.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/a9/71a6499f3481bc00bf4f42a17cb81caf19a02fce762db356626d7214e2c2/langgraph_sdk-0.4.5-py3-none-any.whl"}}, {"metadata": {"name": "langsmith", "version": "0.14.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/4d/be/d55279f7bfc43763fd479aa526d6f952fa93aaf4d86a40919f78726691cc/langsmith-0.14.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/db/50/26b091836076ce4cb2fac264186936acc069e0595772cfd02a563bc4761a/pydantic_core-2.46.5-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "uuid_utils", "version": "0.17.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/97/82/a509ef8b3c24b48099a4fba00f9e1b3f38417e0a7bda39cefd4b1e841388/uuid_utils-0.17.1-cp312-cp312-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/73/e3/fe2d498c64dea0095c9a9f9a351af4cd6eef31b618395582bc1f38ba45ff/websockets-16.1.1-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "jsonpointer", "version": "3.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/9e/6a/a83720e953b1682d2d109d3c2dbb0bc9bf28cc1cbc205be4ef4be5da709d/jsonpointer-3.1.1-py3-none-any.whl"}}, {"metadata": {"name": "langchain-protocol", "version": "0.0.19"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/80/c9/f6cbf357d48ccbd18bb394433b1fd7ad9be004eed9377ad08bb85777e5e6/langchain_protocol-0.0.19-py3-none-any.whl"}}, {"metadata": {"name": "orjson", "version": "3.12.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/29/98/758cf90fbeaaafb7f8141bfac75a432099959f3a2f5db93a412e876415d8/orjson-3.12.0-cp312-cp312-macosx_15_0_arm64.whl"}}, {"metadata": {"name": "ormsgpack", "version": "1.12.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/4c/36/16c4b1921c308a92cef3bf6663226ae283395aa0ff6e154f925c32e91ff5/ormsgpack-1.12.2-cp312-cp312-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/30/27/78873dc8b6a56357517b74b6bb9568b80450e7bb4f6ef7e3fa9d22aa0bd7/charset_normalizer-3.5.1-cp312-cp312-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "urllib3", "version": "2.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "xxhash", "version": "4.0.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/75/c9/cf736f6db8c3273af18925061572db0d4357818a9ce425f4b5fb0021918e/xxhash-4.0.1-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "zstandard", "version": "0.25.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/aa/1c/d920d64b22f8dd028a8b90e2d756e431a5d86194caa78e3819c7bf53b4b3/zstandard-0.25.0-cp312-cp312-macosx_11_0_arm64.whl"}}], "install_targets_hash": "26d1a3b577a5cb444398332d2ce874d0"} {"python_version": "3.12", "dependencies": [{"metadata": {"name": "gql", "version": "4.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ac/94/30bbd09e8d45339fa77a48f5778d74d47e9242c11b3cd1093b3d994770a5/gql-4.0.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/b2/2aac325583aaa1353045f96dffa586d8a34e8322e14a7ba49cffeb103ab4/aiohttp-3.14.1-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "backoff", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/73/b6e24bd22e6720ca8ee9a85a0c4a2971af8497d8f3193fa05390cbd46e09/backoff-2.2.1-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.40"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/8c/5f7e73fd66b28f0705bc55d7060d41ef72328b656b86ca53e75765b3ba2c/botocore-1.43.40-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/15/b92b4e1d88d02c6eff9733c9eea21846ab435cc4d813d84ccc5d335955df/graphql_core-3.2.11-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/65/1caac9d4cd32e8433908683446eebc953e82d22b03d10d41a5f0fefe991b/multidict-6.7.1-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/eb/4fc8d0a7110eb5fc9cc161723a34a8a6c200ce3b4fbf681bc86feee22308/charset_normalizer-3.4.7-cp312-cp312-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "15.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/69/1a681dd6f02180916f116894181eab8b2e25b31e484c5d0eae637ec01f7c/websockets-15.0.1-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/29/b6/170e2b8d4e3bc30e6bfdcca53556537f5bf595e938632dfcb059311f3ff6/yarl-1.24.2-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "responses", "version": "0.26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/28/693e1d9ebf72baa062ded80d837a035b86ce75eda5a269379e9e2b1008a8/responses-0.26.2-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2b/94/5c8a2b50a496b11dd519f4a24cb5496cf125681dd99e94c604ccdea9419a/frozenlist-1.8.0-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/7d/49777a3e20b55863d4794384a38acd460c04157b0a00f8602b0d508b8431/propcache-0.5.2-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl"}}], "install_targets_hash": "2de3e70bcf4f337f5ecb64d5671c312a"} {"python_version": "3.12", "dependencies": [{"metadata": {"name": "aiomysql", "version": "0.3.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4c/af/aae0153c3e28712adaf462328f6c7a3c196a1c1c27b491de4377dd3e6b52/aiomysql-0.3.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/22/adf66990e63584a68dfb50c24f48a125c07b1699899381c8151e63ed458c/cryptography-49.0.0-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "PyMySQL", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c4/bd/2534e130295c8cfd4f0a2e31623baab7502278f1e97bcfe61db75656a77f/pymysql-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "3680161bd7dab16c5a7cb3161b3427a9"} {"python_version": "3.12", "dependencies": [{"metadata": {"name": "asyncpg", "version": "0.29.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/0b/d128b57f7e994a6d71253d0a6a8c949fc50c969785010d46b87d8491be24/asyncpg-0.29.0-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}], "install_targets_hash": "37b71e639b9f2205d095eed9add52c09"} -{"python_version": "3.12", "dependencies": [{"metadata": {"name": "aiohttp", "version": "3.10.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/70/bf/903df5cd739dfaf5b827b3d8c9d68ff4fcea16a0ca1aeb948c9da30f56c8/aiohttp-3.10.11-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/65/1caac9d4cd32e8433908683446eebc953e82d22b03d10d41a5f0fefe991b/multidict-6.7.1-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/29/b6/170e2b8d4e3bc30e6bfdcca53556537f5bf595e938632dfcb059311f3ff6/yarl-1.24.2-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-aiohttp", "version": "1.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/a7/6e50ba2c0a27a34859a952162e63362a13142ce3c646e925b76de440e102/pytest_aiohttp-1.0.5-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2b/94/5c8a2b50a496b11dd519f4a24cb5496cf125681dd99e94c604ccdea9419a/frozenlist-1.8.0-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/7d/49777a3e20b55863d4794384a38acd460c04157b0a00f8602b0d508b8431/propcache-0.5.2-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}], "install_targets_hash": "38bb936208e4e77b6875b0856d10553a"} {"python_version": "3.12", "dependencies": [{"metadata": {"name": "launchdarkly-server-sdk", "version": "9.8.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/aa/b7/e5eed9ec95341d2fe8f9c78377b951045dd8afc9dcdb4f0c9391be02a030/launchdarkly_server_sdk-9.8.1-py3-none-any.whl"}}, {"metadata": {"name": "launchdarkly-eventsource", "version": "1.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/e5/450c31e70e8f5f8cf6b6f3bab68475677eaab2d56b5dd1f3bfd436defdc9/launchdarkly_eventsource-1.7.1-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "expiringdict", "version": "1.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/84/a04c59324445f4bcc98dc05b39a1cd07c242dde643c1a3c21e4f7beaf2f2/expiringdict-1.2.2-py3-none-any.whl"}}, {"metadata": {"name": "pyRFC3339", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/34/90/0200184d2124484f918054751ef997ed6409cb05b7e8dcbf5a22da4c4748/pyrfc3339-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "semver", "version": "3.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/24/4d91e05817e92e3a61c8a21e08fd0f390f5301f1c448b137c57c4bc6e543/semver-3.0.4-py3-none-any.whl"}}], "install_targets_hash": "39e38f320060d087837513360056dd40"} {"python_version": "3.12", "dependencies": [{"metadata": {"name": "bottle", "version": "0.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/83/f6/b55ec74cfe68c6584163faa311503c20b0da4c09883a41e8e00d6726c954/bottle-0.13.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "2.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/f3/22afbdb20cc4654b10c98043414a14057cd27fdba9d4ae61cea596000ba2/Werkzeug-2.0.3-py3-none-any.whl"}}], "install_targets_hash": "3cb07bf1e9768637334d5ad3e34bfe02"} -{"python_version": "3.12", "dependencies": [{"metadata": {"name": "Django", "version": "6.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8d/ca/c1040a4fd15754ede7df15fd72fc2e123045b473b253ab5f5284e11c651e/django-6.1.1-py3-none-any.whl"}}, {"metadata": {"name": "psycopg2-binary", "version": "2.9.12"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/55/44df3965b5f297c50cc0b1b594a31c67d6127a9d133045b8a66611b14dfb/psycopg2_binary-2.9.12-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "djangorestframework", "version": "3.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/d7/7461738e819b853275b35fd35712a85806c09a327e1fd5f8ff766bdd317e/djangorestframework-3.18.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-django", "version": "4.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/03/850bffad2b581c440ca51c039d74504d5a422c94bda0bdb8a8ba5068d48b/pytest_django-4.14.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.7.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/18/f1/46d32fe4b9aae09fe397e768ff376d9b6bdbb4f11faaa727f163c3457b43/pytest_forked-1.7.5-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "channels", "version": "4.3.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/16/34/c32915288b7ef482377b6adc401192f98c6a99b3a145423d3b8aed807898/channels-4.3.2-py3-none-any.whl"}}, {"metadata": {"name": "asgiref", "version": "3.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c0/1b/54f4ad77cd8a584fa70746c47df988e002cf1ee1eba43364d46f87803647/asgiref-3.12.1-py3-none-any.whl"}}, {"metadata": {"name": "executing", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "daphne", "version": "4.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/0c/59e966c167880904f2e6a235c63169760dce58ba8062a7a153a6183539cc/daphne-4.2.3-py3-none-any.whl"}}, {"metadata": {"name": "autobahn", "version": "26.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b2/4c/00553ee9d57ee11df47bc9867d120cfe721a73bec0b58fb3a3b91cd7c797/autobahn-26.7.1-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "cbor2", "version": "6.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f0/a5/10c6c126d59b07f2bd005094dd12a20afa46146f7e2673ed6f61a57641a7/cbor2-6.1.4-cp312-cp312-manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/db/dceb9dd5b231e1da801793f8acc9f3c52a7e1afe40bb1aae37e02b0faad5/cffi-2.1.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/85/66/6ccca4722987ddedaa7fc9c3f4708af7431f5535666c174350830888c6b7/cryptography-50.0.1-cp311-abi3-manylinux_2_34_x86_64.whl"}}, {"metadata": {"name": "hyperlink", "version": "21.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/aa/8caf6a0a3e62863cbb9dab27135660acba46903b703e224f14f447e57934/hyperlink-21.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3c/2e/8d0c2ab90a8c1d9a24f0399058ab8519a3279d1bd4289511d74e909f060e/markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "msgpack", "version": "1.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/f0/29f591bea185616cf417645ac03bd3ad9b317483ad8572160e325f7fe777/msgpack-1.2.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "sqlparse", "version": "0.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d9/50/f00935da0ec7cbf325f8dc4f772ae46fbc7b672dd62876e73f0a94adda57/sqlparse-0.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Twisted", "version": "26.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/57/bcf4e2370dd218c9aa68a9140a65d86729c73f1d529f7e94786c2766fc72/twisted-26.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "Automat", "version": "25.4.16"}, "download_info": {"url": "https://files.pythonhosted.org/packages/02/ff/1175b0b7371e46244032d43a56862d0af455823b5280a50c63d99cc50f18/automat-25.4.16-py3-none-any.whl"}}, {"metadata": {"name": "constantly", "version": "23.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b8/40/c199d095151addf69efdb4b9ca3a4f20f70e20508d6222bffb9b76f58573/constantly-23.10.4-py3-none-any.whl"}}, {"metadata": {"name": "Incremental", "version": "24.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1d/55/0f4df2a44053867ea9cbea73fc588b03c55605cd695cee0a3d86f0029cb2/incremental-24.11.0-py3-none-any.whl"}}, {"metadata": {"name": "pyOpenSSL", "version": "26.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ad/2cf6d3fa2fae5c79e1ed9960c0d42badd0f94d81dd12b50604cdc839e648/pyopenssl-26.4.0-py3-none-any.whl"}}, {"metadata": {"name": "service-identity", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/eb/2433e1af4ff903499144de4846569fb3300b816179ae99a03c2f011b666a/service_identity-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "txaio", "version": "26.6.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/91/68/075bf851e11c9ef65bd6a0426791f0d9a0c7dae0e7f6e0b16ca67334b456/txaio-26.6.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "6.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/09/be/4ddd61b3d4beb21eced10d0d100a4dca26f13303d4952e48fb5e89167869/ujson-6.0.0-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "zope.interface", "version": "8.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/5a/126eeee4da016f5cca4db2297496069d5f1ba901fb53ebf104f9c087a113/zope_interface-8.6-cp312-cp312-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "4542a2577ed3296f75e33c4dd3e42bcc"} +{"python_version": "3.12", "dependencies": [{"metadata": {"name": "Django", "version": "6.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8d/ca/c1040a4fd15754ede7df15fd72fc2e123045b473b253ab5f5284e11c651e/django-6.1.1-py3-none-any.whl"}}, {"metadata": {"name": "psycopg2-binary", "version": "2.9.13"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/a5/b5a73d0910555e38ee12c49c1740855f8a1e9776e87d65f0c51e1bab762a/psycopg2_binary-2.9.13-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "djangorestframework", "version": "3.18.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/83/5ed615e47339d8e65f62eb1a8133f8f046492eb3a25ad40d90acb9a208b3/djangorestframework-3.18.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-django", "version": "4.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/03/850bffad2b581c440ca51c039d74504d5a422c94bda0bdb8a8ba5068d48b/pytest_django-4.14.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.7.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/18/f1/46d32fe4b9aae09fe397e768ff376d9b6bdbb4f11faaa727f163c3457b43/pytest_forked-1.7.5-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "channels", "version": "4.3.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/16/34/c32915288b7ef482377b6adc401192f98c6a99b3a145423d3b8aed807898/channels-4.3.2-py3-none-any.whl"}}, {"metadata": {"name": "asgiref", "version": "3.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c0/1b/54f4ad77cd8a584fa70746c47df988e002cf1ee1eba43364d46f87803647/asgiref-3.12.1-py3-none-any.whl"}}, {"metadata": {"name": "executing", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "daphne", "version": "4.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/0c/59e966c167880904f2e6a235c63169760dce58ba8062a7a153a6183539cc/daphne-4.2.3-py3-none-any.whl"}}, {"metadata": {"name": "autobahn", "version": "26.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/23/0769ef39e1cfb0bec15bacdd7f407aaedfda14c0ca3f7e818b856f2ed1a1/autobahn-26.7.1-cp312-cp312-macosx_15_0_arm64.whl"}}, {"metadata": {"name": "cbor2", "version": "6.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2e/76/fb64293c19cafb860060310c57b768fd9cfb7cf592449660b756538cc116/cbor2-6.1.4-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/7d/16e5a096677b5e313ca80cd5e5170efa3ea44624a82bb111925522da64b1/cffi-2.1.1-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/19/797e2aaac9df6a66f1550f49979dc1b1e39ecd2077501c30efa81e8d5d67/cryptography-50.0.1-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "hyperlink", "version": "21.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/aa/8caf6a0a3e62863cbb9dab27135660acba46903b703e224f14f447e57934/hyperlink-21.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "msgpack", "version": "1.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/88/88/c2b6d8e81571da87aa232c0e34a3f3a0e618e6235892065ec82d1d81fc7a/msgpack-1.2.2-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "sqlparse", "version": "0.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d9/50/f00935da0ec7cbf325f8dc4f772ae46fbc7b672dd62876e73f0a94adda57/sqlparse-0.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Twisted", "version": "26.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/57/bcf4e2370dd218c9aa68a9140a65d86729c73f1d529f7e94786c2766fc72/twisted-26.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "Automat", "version": "25.4.16"}, "download_info": {"url": "https://files.pythonhosted.org/packages/02/ff/1175b0b7371e46244032d43a56862d0af455823b5280a50c63d99cc50f18/automat-25.4.16-py3-none-any.whl"}}, {"metadata": {"name": "constantly", "version": "23.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b8/40/c199d095151addf69efdb4b9ca3a4f20f70e20508d6222bffb9b76f58573/constantly-23.10.4-py3-none-any.whl"}}, {"metadata": {"name": "Incremental", "version": "24.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1d/55/0f4df2a44053867ea9cbea73fc588b03c55605cd695cee0a3d86f0029cb2/incremental-24.11.0-py3-none-any.whl"}}, {"metadata": {"name": "pyOpenSSL", "version": "26.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ad/2cf6d3fa2fae5c79e1ed9960c0d42badd0f94d81dd12b50604cdc839e648/pyopenssl-26.4.0-py3-none-any.whl"}}, {"metadata": {"name": "service-identity", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/eb/2433e1af4ff903499144de4846569fb3300b816179ae99a03c2f011b666a/service_identity-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "txaio", "version": "26.6.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/91/68/075bf851e11c9ef65bd6a0426791f0d9a0c7dae0e7f6e0b16ca67334b456/txaio-26.6.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "6.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/84/b0/454f4a6aea48fd580eaaceb9d692cfa219b41e197c6bbfd534ee8945dad9/ujson-6.0.0-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "zope.interface", "version": "8.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/17/4f/41bde1796fa8cbb32f50facd261dd4124daa850c29666270e85e2bb8e91a/zope_interface-8.6-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "4542a2577ed3296f75e33c4dd3e42bcc"} {"python_version": "3.12", "dependencies": [{"metadata": {"name": "falcon", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/79/22b82ba69466c2def59c0ea82e6db64cff75e64b2f912aa6be1764ad2ce6/falcon-3.1.3-cp312-cp312-macosx_10_9_universal2.whl"}}], "install_targets_hash": "495bed059580b4655ded3469bb5a9f7f"} {"python_version": "3.12", "dependencies": [{"metadata": {"name": "trytond", "version": "7.8.16"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d8/05/24ac74eee184cc503c8ab1f39c0b16e17ebd4a5a7622b5517ecbec665db8/trytond-7.8.16-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "lxml", "version": "6.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0a/20/e022dbc6b4753a9bc9fc5fb28a27163430c1731b9913997f6544c1b2518c/lxml-6.1.3-cp312-cp312-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3c/2e/8d0c2ab90a8c1d9a24f0399058ab8519a3279d1bd4289511d74e909f060e/markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "pwdlib", "version": "0.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6b/2e/51979293b2337f508597d13ee20db1ac1d43e48086b2ed7de6da213ed46b/pwdlib-0.3.1-py3-none-any.whl"}}, {"metadata": {"name": "argon2-cffi", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/d3/a8b22fa575b297cd6e3e3b0155c7e25db170edf1c74783d6a31a2490b8d9/argon2_cffi-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "python-sql", "version": "1.8.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/77/ac/3603bbdde340f7354c975431c94b70ef3e99966c5b170fa121f8e64d269e/python_sql-1.8.1-py3-none-any.whl"}}, {"metadata": {"name": "relatorio", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/74/eb/798c426ebd54f52c27aed6593eaf96ed07dca3ca1d084822cc34f0db5159/relatorio-1.0.0-py3-none-any.whl"}}, {"metadata": {"name": "Genshi", "version": "0.7.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/27/503016bc329720ba2856eb4831d6ba36089cd6f15bc4fe85db69fea5b563/genshi-0.7.11-py3-none-any.whl"}}, {"metadata": {"name": "argon2-cffi-bindings", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6f/86/5363df11b86d02cf3662208e7406496327649cc90eb365bf6f4e8a54a41f/argon2_cffi_bindings-26.1.0-cp310-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/db/dceb9dd5b231e1da801793f8acc9f3c52a7e1afe40bb1aae37e02b0faad5/cffi-2.1.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "defusedxml", "version": "0.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "polib", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6b/99/45bb1f9926efe370c6dbe324741c749658e44cb060124f28dad201202274/polib-1.2.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "puremagic", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/81/314320aeffd88dadeac553ff9eb10f54507ab41deccd0c69f6221d254a0a/puremagic-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "simpleeval", "version": "1.0.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/33/d1ecd9f4f5f272b36ad7b268e307ba0a59c109d8ad134a231cda780baac9/simpleeval-1.0.8-py3-none-any.whl"}}], "install_targets_hash": "4a8515036fcaf8193b6feebd535cc37d"} -{"python_version": "3.12", "dependencies": [{"metadata": {"name": "langgraph", "version": "1.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0a/7f/c5c30e4be99ff821029c7ac872a480676bb179c9f3df85ea3f38d13f86d4/langgraph-1.2.11-py3-none-any.whl"}}, {"metadata": {"name": "langchain-core", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/84/4c/508a90b9d2e3bd7738fd93cb2ac2178ce734662c75e69b3b81c445f1b360/langchain_core-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "jsonpatch", "version": "1.33"}, "download_info": {"url": "https://files.pythonhosted.org/packages/73/07/02e16ed01e04a374e644b575638ec7987ae846d25ad97bcc9945a3ee4b0e/jsonpatch-1.33-py2.py3-none-any.whl"}}, {"metadata": {"name": "langgraph-checkpoint", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/71/3b475f09bd57d3a5649792c66353312b4432afd843f301739dfcebd157f0/langgraph_checkpoint-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "langgraph-prebuilt", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/43/3fe1a700b8490ed02679cdbbc8c915eb23a092faf496c9c1118abcd10be3/langgraph_prebuilt-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "langgraph-sdk", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5a/a0/f3bc44b46ef730588f66fdf9e9ddc54189db78482a9e914ae6a554a2b2e0/langgraph_sdk-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "langsmith", "version": "0.11.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/85/0ad6df25588122760b2b40ec182eafc55532c9e66015c83e16675bd34a29/langsmith-0.11.1-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/95/6195171e385007300f0f5574592e467c568becce2d937a0b6804f218bc49/pydantic_core-2.46.4-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "uuid_utils", "version": "0.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/80/a7e685968e3cec99d6fe2fb25d0f5726310e1bba356da68c13dfd8b7d140/uuid_utils-0.17.0-cp312-cp312-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/73/e3/fe2d498c64dea0095c9a9f9a351af4cd6eef31b618395582bc1f38ba45ff/websockets-16.1.1-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "jsonpointer", "version": "3.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/6a/a83720e953b1682d2d109d3c2dbb0bc9bf28cc1cbc205be4ef4be5da709d/jsonpointer-3.1.1-py3-none-any.whl"}}, {"metadata": {"name": "langchain-protocol", "version": "0.0.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/2e/d82db9eec13ad0f72e7aaad5c4bc730ab111934fdc83c85523206eb9b0a0/langchain_protocol-0.0.18-py3-none-any.whl"}}, {"metadata": {"name": "orjson", "version": "3.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/29/98/758cf90fbeaaafb7f8141bfac75a432099959f3a2f5db93a412e876415d8/orjson-3.12.0-cp312-cp312-macosx_15_0_arm64.whl"}}, {"metadata": {"name": "ormsgpack", "version": "1.12.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4c/36/16c4b1921c308a92cef3bf6663226ae283395aa0ff6e154f925c32e91ff5/ormsgpack-1.12.2-cp312-cp312-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/27/78873dc8b6a56357517b74b6bb9568b80450e7bb4f6ef7e3fa9d22aa0bd7/charset_normalizer-3.5.1-cp312-cp312-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "xxhash", "version": "4.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/75/c9/cf736f6db8c3273af18925061572db0d4357818a9ce425f4b5fb0021918e/xxhash-4.0.1-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "zstandard", "version": "0.25.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/aa/1c/d920d64b22f8dd028a8b90e2d756e431a5d86194caa78e3819c7bf53b4b3/zstandard-0.25.0-cp312-cp312-macosx_11_0_arm64.whl"}}], "install_targets_hash": "4ded69ebfc3885a149b764fa94a36954"} +{"python_version": "3.12", "dependencies": [{"metadata": {"name": "aiohttp", "version": "3.11.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/70/84/19edcf0b22933932faa6e0be0d933a27bd173da02dc125b7354dff4d8da4/aiohttp-3.11.18-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/65/1caac9d4cd32e8433908683446eebc953e82d22b03d10d41a5f0fefe991b/multidict-6.7.1-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ea/b4/05b4131c407006cd1e410e9c6539f16a0945724677e5364447313c15ea3e/yarl-1.24.5-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-aiohttp", "version": "1.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fa/b0/5056ed4c3f68a4db2b4a39fb0ec61b1e4cf1d89ee14effe5261cc587264c/pytest_aiohttp-1.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2b/94/5c8a2b50a496b11dd519f4a24cb5496cf125681dd99e94c604ccdea9419a/frozenlist-1.8.0-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/7d/49777a3e20b55863d4794384a38acd460c04157b0a00f8602b0d508b8431/propcache-0.5.2-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}], "install_targets_hash": "4dcb68c9e098057b61d8630a385f1e96"} {"python_version": "3.12", "dependencies": [{"metadata": {"name": "fastmcp", "version": "4.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/c0/1f985175c9eee7725ebef1be5a7c210787ad0c7649f56dab5c5af5185816/fastmcp-4.0.5-py3-none-any.whl"}}, {"metadata": {"name": "fastmcp-slim", "version": "4.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ed/76/8dc551ef1f222bd146537ae100baf7441628aa1050494b567249ece997c2/fastmcp_slim-4.0.5-py3-none-any.whl"}}, {"metadata": {"name": "mcp", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/ff/8e7eade68b8a28f7da0ed1085544341b51f9c935dbf6b95c76b7edfea6a0/mcp-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mcp-types", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8f/d7/6ffba5d8cd5dd9b8a19478875c50e04945314ba5074e84d749283f27f62d/mcp_types-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "py-key-value-aio", "version": "0.4.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/46/12871550fb0613d149144bb9d41f22680d5f46717bc45a76eb5798c20c3f/py_key_value_aio-0.4.6-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "aiofile", "version": "3.12.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/79/6e45e778c4c3cab39e0937b007b720c15f76c50c6453d153282d0fcc3588/aiofile-3.12.3-py3-none-any.whl"}}, {"metadata": {"name": "caio", "version": "0.12.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7a/11/519e40a1da4d18515ab5ddb54e75cdd896532339010f2dcee7e798e4edab/caio-0.12.4-cp312-cp312-manylinux_2_34_x86_64.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "Authlib", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b8/c6/6f124bcfbbfb20fba22c939b4e43a06dccfc0e1ca20e5634ca573cb1e271/authlib-1.8.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "beartype", "version": "0.22.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/cc/18245721fa7747065ab478316c7fea7c74777d07f37ae60db2e84f8172e8/beartype-0.22.9-py3-none-any.whl"}}, {"metadata": {"name": "cachetools", "version": "7.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cc/bb/1c6e7a89b11da19f137e4ef5a5c5fe47a5bb686449ba343944ccf8fb34b2/cachetools-7.2.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/85/66/6ccca4722987ddedaa7fc9c3f4708af7431f5535666c174350830888c6b7/cryptography-50.0.1-cp311-abi3-manylinux_2_34_x86_64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/db/dceb9dd5b231e1da801793f8acc9f3c52a7e1afe40bb1aae37e02b0faad5/cffi-2.1.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "cyclopts", "version": "4.25.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/cc/e879da3d54cf727f90e6d90118e132672c3913338b566740486f8797190d/cyclopts-4.25.3-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "rich-rst", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/68/1fc93dd759605b5d00fc98b50200739e41ed32bd22d6ba35ca6c3932371b/rich_rst-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "griffelib", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/63/e876e789525063c840ccfa8857febdabd6523bcef9ce7eb979b9305ea895/griffelib-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "joserfc", "version": "1.7.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/c5/82addfd375e5ee6520644e0553e4aadde92d668c4fc99cc716d337fe7bb3/joserfc-1.7.5-py3-none-any.whl"}}, {"metadata": {"name": "jsonref", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/ec/e1db9922bceb168197a558a2b8c03a7963f1afe93517ddd3cf99f202f996/jsonref-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-path", "version": "0.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/2c/9e69d73c4297508be9e3b64a970ea3971b3eb8db64ffc5802d40bd25981f/jsonschema_path-0.5.0-py3-none-any.whl"}}, {"metadata": {"name": "pathable", "version": "0.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a2/e8/6d75ffd9784bce2e93d1ae4415649427e39a53bb172d4672b2b59c6f0a7b/pathable-0.6.0-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "keyring", "version": "25.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/db/e655086b7f3a705df045bf0933bdd9c2f79bb3c97bfef1384598bb79a217/keyring-25.7.0-py3-none-any.whl"}}, {"metadata": {"name": "jeepney", "version": "0.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b2/a3/e137168c9c44d18eff0376253da9f1e9234d0239e0ee230d2fee6cea8e55/jeepney-0.9.0-py3-none-any.whl"}}, {"metadata": {"name": "openapi-pydantic", "version": "0.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/cf/03675d8bd8ecbf4445504d8071adab19f5f993676795708e36402ab38263/openapi_pydantic-0.5.1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/6f/a04e900f465ff3221ccc395522503e2d10e79fa21f2723c8e177aae1e0d1/opentelemetry_api-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "platformdirs", "version": "4.11.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/39/be/3ae887e84c38c4dd1c549cd5825adc93f48069a94fe1cb8ac52a9da16f15/platformdirs-4.11.11-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c0/a4/eb9409ec0736e50aa70a412f16c204ed149516846912f7e6724d4c73ee53/pydantic_core-2.46.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "email-validator", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "dnspython", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/97/672cb32ce0dfea44b740cb7b4f97038463b9cf7c0ead1aacf595572851d6/pyjwt-2.14.0-py3-none-any.whl"}}, {"metadata": {"name": "pyperclip", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/80/fc9d01d5ed37ba4c42ca2b55b4339ae6e200b456be3a1aaddf4a9fa99b8c/pyperclip-1.11.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/8f/d2f3f532616be4d06c316ef119683e832bd3d41e112bf3a88f4151c95b17/rpds_py-2026.6.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "SecretStorage", "version": "3.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/46/f5af3402b579fd5e11573ce652019a67074317e18c1935cc0b4ba9b35552/secretstorage-3.5.0-py3-none-any.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/6a/2ba3ed4a69babf3afdddf7d8314a48d87562c0a442206bbc2a1b50d5efc0/sse_starlette-3.4.11-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uncalled-for", "version": "0.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a2/40/97cec87c077eb3291fc7905e6633e08b7ca593c57d30238444bcb6bb3d53/uncalled_for-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.53.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/76/18/0eea75741ee812e9f598b687619ce2454f6c3a1c5cd21ea990ec6bd26f45/uvicorn-0.53.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "watchfiles", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/22/24/ed72f68cbc1333ca9b9f2200aa048bb6658ae41709bc1caad4310f4bdffd/watchfiles-1.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "websockets", "version": "17.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/05/9f82d090c8d2d861604147ef6dfb938a90b039f9358d5193f1df62558593/websockets-17.1-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.classes", "version": "3.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/66/b15ce62552d84bbfcec9a4873ab79d993a1dd4edb922cbfccae192bd5b5f/jaraco.classes-3.4.0-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.context", "version": "6.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f2/58/bc8954bda5fcda97bd7c19be11b85f91973d67a706ed4a3aec33e7de22db/jaraco_context-6.1.2-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.functools", "version": "4.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/02/36/ecc85bc96c273dc8a11273ed4782272975e6338d4a3e9228621175edf0e3/jaraco_functools-4.6.0-py3-none-any.whl"}}, {"metadata": {"name": "more-itertools", "version": "11.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/3d/1087453384dbde46a8c7f9356eead2c58be8a7bf156bca40243377c85715/more_itertools-11.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "4ea2151a96fd3708d6bee248d6499707"} -{"python_version": "3.12", "dependencies": [{"metadata": {"name": "openai-agents", "version": "0.0.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/69/899b33c97d5ee6ce454d5cdf89ddddcec9100bece4ed508229b06b1a07ca/openai_agents-0.0.19-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "2.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ae/f4/561ed79fd94876160018a5e75254cfcb9b0e62d4dded9dcb20072e86d623/openai-2.44.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "griffe", "version": "1.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/83/3b1d03d36f224edded98e9affd0467630fc09d766c0e56fb1498cbb04a9b/griffe-1.15.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/2e/34957c2c1b661c252ba9bcc60ae0bddc27e0f7202c6073326a13c5390eec/jiter-0.16.0-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "mcp", "version": "1.29.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/c8/248b201f6d753d69fd5d6506011abbb35a946d9142b2ae311a948fd0be3d/mcp-1.29.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/95/6195171e385007300f0f5574592e467c568becce2d937a0b6804f218bc49/pydantic_core-2.46.4-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/27/78873dc8b6a56357517b74b6bb9568b80450e7bb4f6ef7e3fa9d22aa0bd7/charset_normalizer-3.5.1-cp312-cp312-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "types-requests", "version": "2.33.0.20260712"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/e7/010c87f559e216d83f9dc51e939633fd0d0ead3377340181ab0e223cd3b5/types_requests-2.33.0.20260712-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "colorama", "version": "0.4.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/5c/59086b4aac5e879d38ddbcf74e4be7ade89cebc3eb199a55da998c3bb46a/cryptography-50.0.0-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/7d/16e5a096677b5e313ca80cd5e5170efa3ea44624a82bb111925522da64b1/cffi-2.1.1-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a4/73/319dfa745dd668efe89309141ded489126461fcecd2b8f3a3cda185129b6/rpds_py-2026.6.3-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/3a/764912c58293d95b6dcdf4cc255f9d10de310580ced547b082eb9d72018c/sse_starlette-3.4.8-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.52.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/79/4a20b54ab0491485ccd8c077db2d39187c7f12b3e15485d38a7be37c81b4/uvicorn-0.52.4-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "516bab83ca4281a985cea82f50b07b4c"} {"python_version": "3.12", "dependencies": [{"metadata": {"name": "SQLAlchemy", "version": "1.4.54"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a5/1b/aa9b99be95d1615f058b5827447c18505b7b3f1dfcbd6ce1b331c2107152/SQLAlchemy-1.4.54-cp312-cp312-macosx_10_9_universal2.whl"}}], "install_targets_hash": "59058833bef885053056cb808e01f81f"} +{"python_version": "3.12", "dependencies": [{"metadata": {"name": "SQLAlchemy", "version": "1.4.54"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a5/1b/aa9b99be95d1615f058b5827447c18505b7b3f1dfcbd6ce1b331c2107152/SQLAlchemy-1.4.54-cp312-cp312-macosx_10_9_universal2.whl"}}], "install_targets_hash": "59058833bef885053056cb808e01f81f"} +{"python_version": "3.12", "dependencies": [{"metadata": {"name": "SQLAlchemy", "version": "1.4.54"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a5/1b/aa9b99be95d1615f058b5827447c18505b7b3f1dfcbd6ce1b331c2107152/SQLAlchemy-1.4.54-cp312-cp312-macosx_10_9_universal2.whl"}}], "install_targets_hash": "59058833bef885053056cb808e01f81f"} +{"python_version": "3.12", "dependencies": [{"metadata": {"name": "falcon", "version": "4.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/15/80a2d45ed40963eda6fd4e37f636203de2c89ec31ce87d1a718abce9358c/falcon-4.3.1-cp312-cp312-macosx_11_0_arm64.whl"}}], "install_targets_hash": "5935d22936c24189f0d18cf0311cca5c"} {"python_version": "3.12", "dependencies": [{"metadata": {"name": "falcon", "version": "4.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/15/80a2d45ed40963eda6fd4e37f636203de2c89ec31ce87d1a718abce9358c/falcon-4.3.1-cp312-cp312-macosx_11_0_arm64.whl"}}], "install_targets_hash": "5935d22936c24189f0d18cf0311cca5c"} +{"python_version": "3.12", "dependencies": [{"metadata": {"name": "falcon", "version": "4.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/15/80a2d45ed40963eda6fd4e37f636203de2c89ec31ce87d1a718abce9358c/falcon-4.3.1-cp312-cp312-macosx_11_0_arm64.whl"}}], "install_targets_hash": "5935d22936c24189f0d18cf0311cca5c"} +{"python_version": "3.12", "dependencies": [{"metadata": {"name": "openai", "version": "1.109.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1d/2a/7dd3d207ec669cacc1f186fd856a0f61dbc255d24f6fdc1a6715d6051b0f/openai-1.109.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/2e/34957c2c1b661c252ba9bcc60ae0bddc27e0f7202c6073326a13c5390eec/jiter-0.16.0-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/95/6195171e385007300f0f5574592e467c568becce2d937a0b6804f218bc49/pydantic_core-2.46.4-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/9f/fe6b1aca23331aa5271df5a4bd07bf68a7059254d47faee1b8272592a777/tiktoken-0.14.0-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.7.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/63/4cab4d7f2d384a144d420b763d97674cb70619c878ea6fcd7640d0e62143/regex-2026.7.19-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/27/78873dc8b6a56357517b74b6bb9568b80450e7bb4f6ef7e3fa9d22aa0bd7/charset_normalizer-3.5.1-cp312-cp312-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "5c15f7294f49ccda5d519b89114a1254"} {"python_version": "3.12", "dependencies": [{"metadata": {"name": "openai", "version": "1.109.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1d/2a/7dd3d207ec669cacc1f186fd856a0f61dbc255d24f6fdc1a6715d6051b0f/openai-1.109.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/2e/34957c2c1b661c252ba9bcc60ae0bddc27e0f7202c6073326a13c5390eec/jiter-0.16.0-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/95/6195171e385007300f0f5574592e467c568becce2d937a0b6804f218bc49/pydantic_core-2.46.4-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/9f/fe6b1aca23331aa5271df5a4bd07bf68a7059254d47faee1b8272592a777/tiktoken-0.14.0-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.7.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/63/4cab4d7f2d384a144d420b763d97674cb70619c878ea6fcd7640d0e62143/regex-2026.7.19-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/27/78873dc8b6a56357517b74b6bb9568b80450e7bb4f6ef7e3fa9d22aa0bd7/charset_normalizer-3.5.1-cp312-cp312-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "5c15f7294f49ccda5d519b89114a1254"} {"python_version": "3.12", "dependencies": [{"metadata": {"name": "celery", "version": "5.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/c9/6eccdda96e098f7ae843162db2d3c149c6931a24fda69fe4ab84d0027eb5/celery-5.6.3-py3-none-any.whl"}}, {"metadata": {"name": "newrelic", "version": "10.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d4/71/07c41fd5e8c94e95216b000d00c3cf735f769cb406c0f33c6ff83b7b7418/newrelic-10.16.0.tar.gz"}}, {"metadata": {"name": "billiard", "version": "4.2.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/87/8bab77b323f16d67be364031220069f79159117dd5e43eeb4be2fef1ac9b/billiard-4.2.4-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "vine", "version": "5.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/ff/7c0c86c43b3cbb927e0ccc0255cb4057ceba4799cd44ae95174ce8e8b5b2/vine-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "redis", "version": "8.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/0a/c2345ebf1ebe70840ce3f6c6ee612f8fa749cfbd1b03069c53bf0c62aaad/redis-8.0.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/af/9c0bda43e486a3c9bf1e0f876d0f241bc3f229d7d65d09331a0868db9629/pytest_forked-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "click-didyoumean", "version": "0.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/5b/974430b5ffdb7a4f1941d13d83c64a0395114503cc357c6b9ae4ce5047ed/click_didyoumean-0.3.1-py3-none-any.whl"}}, {"metadata": {"name": "click-plugins", "version": "1.1.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/9a/2abecb28ae875e39c8cad711eb1186d8d14eab564705325e77e4e6ab9ae5/click_plugins-1.1.1.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "click-repl", "version": "0.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/52/40/9d857001228658f0d59e97ebd4c346fe73e138c6de1bce61dc568a57c7f8/click_repl-0.3.0-py3-none-any.whl"}}, {"metadata": {"name": "kombu", "version": "5.6.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/0f/834427d8c03ff1d7e867d3db3d176470c64871753252b21b4f4897d1fa45/kombu-5.6.2-py3-none-any.whl"}}, {"metadata": {"name": "amqp", "version": "5.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/26/99/fc813cd978842c26c82534010ea849eee9ab3a13ea2b74e95cb9c99e747b/amqp-5.3.1-py3-none-any.whl"}}, {"metadata": {"name": "prompt_toolkit", "version": "3.0.52"}, "download_info": {"url": "https://files.pythonhosted.org/packages/84/03/0d3ce49e2505ae70cf43bc5bb3033955d2fc9f932163e84dc0779cc47f48/prompt_toolkit-3.0.52-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tzdata", "version": "2026.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ce/e4/dccd7f47c4b64213ac01ef921a1337ee6e30e8c6466046018326977efd95/tzdata-2026.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "py", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tzlocal", "version": "5.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/a4/017a7a6cbe387d961a688ec31364ae60a5c4e22c96ae9921b79a947c855d/tzlocal-5.4.4-py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl"}}], "install_targets_hash": "68a613b2517fdb654276eddecbf135d5"} +{"python_version": "3.12", "dependencies": [{"metadata": {"name": "celery", "version": "5.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/c9/6eccdda96e098f7ae843162db2d3c149c6931a24fda69fe4ab84d0027eb5/celery-5.6.3-py3-none-any.whl"}}, {"metadata": {"name": "newrelic", "version": "10.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d4/71/07c41fd5e8c94e95216b000d00c3cf735f769cb406c0f33c6ff83b7b7418/newrelic-10.16.0.tar.gz"}}, {"metadata": {"name": "billiard", "version": "4.2.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/87/8bab77b323f16d67be364031220069f79159117dd5e43eeb4be2fef1ac9b/billiard-4.2.4-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "vine", "version": "5.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/ff/7c0c86c43b3cbb927e0ccc0255cb4057ceba4799cd44ae95174ce8e8b5b2/vine-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "redis", "version": "8.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/0a/c2345ebf1ebe70840ce3f6c6ee612f8fa749cfbd1b03069c53bf0c62aaad/redis-8.0.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/af/9c0bda43e486a3c9bf1e0f876d0f241bc3f229d7d65d09331a0868db9629/pytest_forked-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "click-didyoumean", "version": "0.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/5b/974430b5ffdb7a4f1941d13d83c64a0395114503cc357c6b9ae4ce5047ed/click_didyoumean-0.3.1-py3-none-any.whl"}}, {"metadata": {"name": "click-plugins", "version": "1.1.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/9a/2abecb28ae875e39c8cad711eb1186d8d14eab564705325e77e4e6ab9ae5/click_plugins-1.1.1.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "click-repl", "version": "0.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/52/40/9d857001228658f0d59e97ebd4c346fe73e138c6de1bce61dc568a57c7f8/click_repl-0.3.0-py3-none-any.whl"}}, {"metadata": {"name": "kombu", "version": "5.6.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/0f/834427d8c03ff1d7e867d3db3d176470c64871753252b21b4f4897d1fa45/kombu-5.6.2-py3-none-any.whl"}}, {"metadata": {"name": "amqp", "version": "5.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/26/99/fc813cd978842c26c82534010ea849eee9ab3a13ea2b74e95cb9c99e747b/amqp-5.3.1-py3-none-any.whl"}}, {"metadata": {"name": "prompt_toolkit", "version": "3.0.52"}, "download_info": {"url": "https://files.pythonhosted.org/packages/84/03/0d3ce49e2505ae70cf43bc5bb3033955d2fc9f932163e84dc0779cc47f48/prompt_toolkit-3.0.52-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tzdata", "version": "2026.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ce/e4/dccd7f47c4b64213ac01ef921a1337ee6e30e8c6466046018326977efd95/tzdata-2026.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "py", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tzlocal", "version": "5.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/a4/017a7a6cbe387d961a688ec31364ae60a5c4e22c96ae9921b79a947c855d/tzlocal-5.4.4-py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl"}}], "install_targets_hash": "68a613b2517fdb654276eddecbf135d5"} +{"python_version": "3.12", "dependencies": [{"metadata": {"name": "celery", "version": "5.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/c9/6eccdda96e098f7ae843162db2d3c149c6931a24fda69fe4ab84d0027eb5/celery-5.6.3-py3-none-any.whl"}}, {"metadata": {"name": "newrelic", "version": "10.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d4/71/07c41fd5e8c94e95216b000d00c3cf735f769cb406c0f33c6ff83b7b7418/newrelic-10.16.0.tar.gz"}}, {"metadata": {"name": "billiard", "version": "4.2.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/87/8bab77b323f16d67be364031220069f79159117dd5e43eeb4be2fef1ac9b/billiard-4.2.4-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "vine", "version": "5.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/ff/7c0c86c43b3cbb927e0ccc0255cb4057ceba4799cd44ae95174ce8e8b5b2/vine-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "redis", "version": "8.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/0a/c2345ebf1ebe70840ce3f6c6ee612f8fa749cfbd1b03069c53bf0c62aaad/redis-8.0.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/af/9c0bda43e486a3c9bf1e0f876d0f241bc3f229d7d65d09331a0868db9629/pytest_forked-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "click-didyoumean", "version": "0.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/5b/974430b5ffdb7a4f1941d13d83c64a0395114503cc357c6b9ae4ce5047ed/click_didyoumean-0.3.1-py3-none-any.whl"}}, {"metadata": {"name": "click-plugins", "version": "1.1.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/9a/2abecb28ae875e39c8cad711eb1186d8d14eab564705325e77e4e6ab9ae5/click_plugins-1.1.1.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "click-repl", "version": "0.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/52/40/9d857001228658f0d59e97ebd4c346fe73e138c6de1bce61dc568a57c7f8/click_repl-0.3.0-py3-none-any.whl"}}, {"metadata": {"name": "kombu", "version": "5.6.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/0f/834427d8c03ff1d7e867d3db3d176470c64871753252b21b4f4897d1fa45/kombu-5.6.2-py3-none-any.whl"}}, {"metadata": {"name": "amqp", "version": "5.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/26/99/fc813cd978842c26c82534010ea849eee9ab3a13ea2b74e95cb9c99e747b/amqp-5.3.1-py3-none-any.whl"}}, {"metadata": {"name": "prompt_toolkit", "version": "3.0.52"}, "download_info": {"url": "https://files.pythonhosted.org/packages/84/03/0d3ce49e2505ae70cf43bc5bb3033955d2fc9f932163e84dc0779cc47f48/prompt_toolkit-3.0.52-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tzdata", "version": "2026.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ce/e4/dccd7f47c4b64213ac01ef921a1337ee6e30e8c6466046018326977efd95/tzdata-2026.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "py", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tzlocal", "version": "5.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/a4/017a7a6cbe387d961a688ec31364ae60a5c4e22c96ae9921b79a947c855d/tzlocal-5.4.4-py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl"}}], "install_targets_hash": "68a613b2517fdb654276eddecbf135d5"} +{"python_version": "3.12", "dependencies": [{"metadata": {"name": "celery", "version": "5.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/c9/6eccdda96e098f7ae843162db2d3c149c6931a24fda69fe4ab84d0027eb5/celery-5.6.3-py3-none-any.whl"}}, {"metadata": {"name": "newrelic", "version": "10.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d4/71/07c41fd5e8c94e95216b000d00c3cf735f769cb406c0f33c6ff83b7b7418/newrelic-10.16.0.tar.gz"}}, {"metadata": {"name": "billiard", "version": "4.2.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/87/8bab77b323f16d67be364031220069f79159117dd5e43eeb4be2fef1ac9b/billiard-4.2.4-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "vine", "version": "5.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/ff/7c0c86c43b3cbb927e0ccc0255cb4057ceba4799cd44ae95174ce8e8b5b2/vine-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "redis", "version": "8.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/0a/c2345ebf1ebe70840ce3f6c6ee612f8fa749cfbd1b03069c53bf0c62aaad/redis-8.0.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/af/9c0bda43e486a3c9bf1e0f876d0f241bc3f229d7d65d09331a0868db9629/pytest_forked-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "click-didyoumean", "version": "0.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/5b/974430b5ffdb7a4f1941d13d83c64a0395114503cc357c6b9ae4ce5047ed/click_didyoumean-0.3.1-py3-none-any.whl"}}, {"metadata": {"name": "click-plugins", "version": "1.1.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/9a/2abecb28ae875e39c8cad711eb1186d8d14eab564705325e77e4e6ab9ae5/click_plugins-1.1.1.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "click-repl", "version": "0.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/52/40/9d857001228658f0d59e97ebd4c346fe73e138c6de1bce61dc568a57c7f8/click_repl-0.3.0-py3-none-any.whl"}}, {"metadata": {"name": "kombu", "version": "5.6.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/0f/834427d8c03ff1d7e867d3db3d176470c64871753252b21b4f4897d1fa45/kombu-5.6.2-py3-none-any.whl"}}, {"metadata": {"name": "amqp", "version": "5.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/26/99/fc813cd978842c26c82534010ea849eee9ab3a13ea2b74e95cb9c99e747b/amqp-5.3.1-py3-none-any.whl"}}, {"metadata": {"name": "prompt_toolkit", "version": "3.0.52"}, "download_info": {"url": "https://files.pythonhosted.org/packages/84/03/0d3ce49e2505ae70cf43bc5bb3033955d2fc9f932163e84dc0779cc47f48/prompt_toolkit-3.0.52-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tzdata", "version": "2026.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ce/e4/dccd7f47c4b64213ac01ef921a1337ee6e30e8c6466046018326977efd95/tzdata-2026.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "py", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tzlocal", "version": "5.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/a4/017a7a6cbe387d961a688ec31364ae60a5c4e22c96ae9921b79a947c855d/tzlocal-5.4.4-py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl"}}], "install_targets_hash": "68a613b2517fdb654276eddecbf135d5"} +{"python_version": "3.12", "dependencies": [{"metadata": {"name": "litellm", "version": "1.89.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/1a/f087e0555d91ab5f93fb8c740447423aa785468b8edca9987724815b51ec/litellm-1.89.7-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/07/4bbc222cc8dbe31d4c3e8a5baad2286e4d42026ac0c570027b89afce6344/aiohttp-3.14.3-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "fastuuid", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/ea/682551030f8c4fa9a769d9825570ad28c0c71e30cf34020b85c1f7ee7382/fastuuid-0.14.0-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7d/f9/97f2ca8bb3ec6e4b1d64f983ebe98b9a192faddff67fac3d6303a537e670/importlib_metadata-8.9.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/65/1caac9d4cd32e8433908683446eebc953e82d22b03d10d41a5f0fefe991b/multidict-6.7.1-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "openai", "version": "2.54.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/a8/bb76c7356de8ad57f59d5ff993d434df0607f07f08bcc9c9a5c275e399c0/openai-2.54.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/2e/34957c2c1b661c252ba9bcc60ae0bddc27e0f7202c6073326a13c5390eec/jiter-0.16.0-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/95/6195171e385007300f0f5574592e467c568becce2d937a0b6804f218bc49/pydantic_core-2.46.4-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/9f/fe6b1aca23331aa5271df5a4bd07bf68a7059254d47faee1b8272592a777/tiktoken-0.14.0-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tokenizers", "version": "0.23.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e2/6a/068ed9f6e444c9d7e9d55ce134181325700f3d7f30410721bdc8f848d727/tokenizers-0.23.1-cp310-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "huggingface_hub", "version": "1.28.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/0e/eafef18f1a75e125e68395db21131db0cf868a128ecd2fce69b4df6c584b/huggingface_hub-1.28.0-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/69/55b8dcf636142ae660fec1869fcac14c4da2e8412e14d6eee1523be77e9f/hf_xet-1.6.0-cp38-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ea/b4/05b4131c407006cd1e410e9c6539f16a0945724677e5364447313c15ea3e/yarl-1.24.5-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anthropic", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/5b/db4a854aebf5d33a5ab714c46af6eb85ee44f390ed29b7b325c00b9f11ed/anthropic-1.0.0-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/95/411ba65569158e862368917aaf56597f3e5fa3b91b0502919638465a08f3/httpx2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/74/d370e55600d9bcfa0d9794b0166126d49291a3d2b20c268fc98c453a4948/httpcore2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "google-genai", "version": "2.19.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/e8/de0accd8cd004cf11252ca53fc5c3dda59bcf1856abfc7609842ceba7363/google_genai-2.19.0-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.56.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/b3/6117b2f24065cd7e2c4f140e9a193e215f089ca8ba314cf91eb9d0b7fe0a/google_auth-2.56.3-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/27/78873dc8b6a56357517b74b6bb9568b80450e7bb4f6ef7e3fa9d22aa0bd7/charset_normalizer-3.5.1-cp312-cp312-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/73/e3/fe2d498c64dea0095c9a9f9a351af4cd6eef31b618395582bc1f38ba45ff/websockets-16.1.1-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/5c/59086b4aac5e879d38ddbcf74e4be7ade89cebc3eb199a55da998c3bb46a/cryptography-50.0.0-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/7d/16e5a096677b5e313ca80cd5e5170efa3ea44624a82bb111925522da64b1/cffi-2.1.1-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "filelock", "version": "3.32.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/a4/9b63d595d748e3aff8812b65eacc1a2c4bd90b7c2012e08e72373b4835eb/filelock-3.32.4-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2b/94/5c8a2b50a496b11dd519f4a24cb5496cf125681dd99e94c604ccdea9419a/frozenlist-1.8.0-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/3c/6a2bf344106328fd04963664a60b9bb6496fc25df8e962fcdc1367285fb9/fsspec-2026.7.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/7d/49777a3e20b55863d4794384a38acd460c04157b0a00f8602b0d508b8431/propcache-0.5.2-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/3b/6163796d69c3977d1e4287bea4a6979161cbbdd170ebb430511e8e1999ce/pyasn1-0.6.4-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a4/73/319dfa745dd668efe89309141ded489126461fcecd2b8f3a3cda185129b6/rpds_py-2026.6.3-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "zipp", "version": "4.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.7.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/63/4cab4d7f2d384a144d420b763d97674cb70619c878ea6fcd7640d0e62143/regex-2026.7.19-cp312-cp312-macosx_11_0_arm64.whl"}}], "install_targets_hash": "6ecbfdc651853ff775d0f1f4b1d21bec"} {"python_version": "3.12", "dependencies": [{"metadata": {"name": "litellm", "version": "1.89.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/1a/f087e0555d91ab5f93fb8c740447423aa785468b8edca9987724815b51ec/litellm-1.89.7-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/07/4bbc222cc8dbe31d4c3e8a5baad2286e4d42026ac0c570027b89afce6344/aiohttp-3.14.3-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "fastuuid", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/ea/682551030f8c4fa9a769d9825570ad28c0c71e30cf34020b85c1f7ee7382/fastuuid-0.14.0-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7d/f9/97f2ca8bb3ec6e4b1d64f983ebe98b9a192faddff67fac3d6303a537e670/importlib_metadata-8.9.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/65/1caac9d4cd32e8433908683446eebc953e82d22b03d10d41a5f0fefe991b/multidict-6.7.1-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "openai", "version": "2.54.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/a8/bb76c7356de8ad57f59d5ff993d434df0607f07f08bcc9c9a5c275e399c0/openai-2.54.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/2e/34957c2c1b661c252ba9bcc60ae0bddc27e0f7202c6073326a13c5390eec/jiter-0.16.0-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/95/6195171e385007300f0f5574592e467c568becce2d937a0b6804f218bc49/pydantic_core-2.46.4-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/9f/fe6b1aca23331aa5271df5a4bd07bf68a7059254d47faee1b8272592a777/tiktoken-0.14.0-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tokenizers", "version": "0.23.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e2/6a/068ed9f6e444c9d7e9d55ce134181325700f3d7f30410721bdc8f848d727/tokenizers-0.23.1-cp310-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "huggingface_hub", "version": "1.28.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/0e/eafef18f1a75e125e68395db21131db0cf868a128ecd2fce69b4df6c584b/huggingface_hub-1.28.0-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/69/55b8dcf636142ae660fec1869fcac14c4da2e8412e14d6eee1523be77e9f/hf_xet-1.6.0-cp38-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ea/b4/05b4131c407006cd1e410e9c6539f16a0945724677e5364447313c15ea3e/yarl-1.24.5-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anthropic", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/5b/db4a854aebf5d33a5ab714c46af6eb85ee44f390ed29b7b325c00b9f11ed/anthropic-1.0.0-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/95/411ba65569158e862368917aaf56597f3e5fa3b91b0502919638465a08f3/httpx2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/74/d370e55600d9bcfa0d9794b0166126d49291a3d2b20c268fc98c453a4948/httpcore2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "google-genai", "version": "2.19.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/e8/de0accd8cd004cf11252ca53fc5c3dda59bcf1856abfc7609842ceba7363/google_genai-2.19.0-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.56.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/b3/6117b2f24065cd7e2c4f140e9a193e215f089ca8ba314cf91eb9d0b7fe0a/google_auth-2.56.3-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/27/78873dc8b6a56357517b74b6bb9568b80450e7bb4f6ef7e3fa9d22aa0bd7/charset_normalizer-3.5.1-cp312-cp312-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/73/e3/fe2d498c64dea0095c9a9f9a351af4cd6eef31b618395582bc1f38ba45ff/websockets-16.1.1-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/5c/59086b4aac5e879d38ddbcf74e4be7ade89cebc3eb199a55da998c3bb46a/cryptography-50.0.0-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/7d/16e5a096677b5e313ca80cd5e5170efa3ea44624a82bb111925522da64b1/cffi-2.1.1-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "filelock", "version": "3.32.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/a4/9b63d595d748e3aff8812b65eacc1a2c4bd90b7c2012e08e72373b4835eb/filelock-3.32.4-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2b/94/5c8a2b50a496b11dd519f4a24cb5496cf125681dd99e94c604ccdea9419a/frozenlist-1.8.0-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/3c/6a2bf344106328fd04963664a60b9bb6496fc25df8e962fcdc1367285fb9/fsspec-2026.7.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/7d/49777a3e20b55863d4794384a38acd460c04157b0a00f8602b0d508b8431/propcache-0.5.2-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/3b/6163796d69c3977d1e4287bea4a6979161cbbdd170ebb430511e8e1999ce/pyasn1-0.6.4-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a4/73/319dfa745dd668efe89309141ded489126461fcecd2b8f3a3cda185129b6/rpds_py-2026.6.3-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "zipp", "version": "4.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.7.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/63/4cab4d7f2d384a144d420b763d97674cb70619c878ea6fcd7640d0e62143/regex-2026.7.19-cp312-cp312-macosx_11_0_arm64.whl"}}], "install_targets_hash": "6ecbfdc651853ff775d0f1f4b1d21bec"} -{"python_version": "3.12", "dependencies": [{"metadata": {"name": "pydantic-ai", "version": "1.0.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/c3/0237cba693b26fd3d78acdb9c97b07c3cdd7c807c6fadbbba6abede4a7b7/pydantic_ai-1.0.18-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-ai-slim", "version": "1.0.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/18/45/0f6b98ce09d1cdf9403ef228c57d8251c6682713dc1c8870708c6a17378a/pydantic_ai_slim-1.0.18-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-evals", "version": "1.0.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4d/84/1008d2c9e66ab93d132a67f85770f2e58eb9e70d1b76ee2a88f6cefac90a/pydantic_evals-1.0.18-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-graph", "version": "1.0.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/68/8a/b6fa505b12fdd5bfcd846bb52087c30003c925e9820f91dd930a6500e5a9/pydantic_graph-1.0.18-py3-none-any.whl"}}, {"metadata": {"name": "temporalio", "version": "1.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/be/94/24bd903b5594420a4d131bfa3de965313f9a409af77b47e9a9a56d85bb9e/temporalio-1.18.0-cp39-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "nexus-rpc", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bf/2f/9e9d0dcaa4c6ffa22b7aa31069a8a264c753ff8027b36af602cce038c92f/nexus_rpc-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "protobuf", "version": "6.33.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5c/01/a3c3ed5cd186f39e7880f8303cc51385a198a81469d53d0fdecf1f64d929/protobuf-6.33.6-cp39-abi3-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "ag-ui-protocol", "version": "0.1.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4c/0a/bcad8116eb058e4b4a305e3fc37ebd7efc879deeb86b854f1c5b8b6e97dd/ag_ui_protocol-0.1.19-py3-none-any.whl"}}, {"metadata": {"name": "anthropic", "version": "0.116.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c7/dd/2a1e81cf1b163acc340afc4ec74ed1d86f5eed1a809fabdeed3e0997b346/anthropic-0.116.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/2e/34957c2c1b661c252ba9bcc60ae0bddc27e0f7202c6073326a13c5390eec/jiter-0.16.0-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/95/6195171e385007300f0f5574592e467c568becce2d937a0b6804f218bc49/pydantic_core-2.46.4-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "argcomplete", "version": "3.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/f6/5b8ec087cd9cfa9449491ec83f76fb6b7006b4dff57d2ba8aaab330fe8e4/argcomplete-3.7.0-py3-none-any.whl"}}, {"metadata": {"name": "boto3", "version": "1.43.40"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/3b/2abcc7f47e955a8cb45a6378ec69cd8ed2dcb3d14ceb67717dea020a794a/boto3-1.43.40-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.40"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/8c/5f7e73fd66b28f0705bc55d7060d41ef72328b656b86ca53e75765b3ba2c/botocore-1.43.40-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "s3transfer", "version": "0.19.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/46/5f/4c174edad94f82de888ac00a5ddd8d07b35609b6c94f0bdf4d74af57703e/s3transfer-0.19.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "cohere", "version": "7.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e6/eb/64ca464baa34d0fa8144fc09ec7a35c8fcdeea1be878a518e901b0a6032b/cohere-7.0.5-py3-none-any.whl"}}, {"metadata": {"name": "fastavro", "version": "1.12.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0e/bc/fe5731d6724d978694fbd3196bc1c0d7cab3fd0766e9551c40c39f798b52/fastavro-1.12.2-cp312-cp312-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/eb/4fc8d0a7110eb5fc9cc161723a34a8a6c200ce3b4fbf681bc86feee22308/charset_normalizer-3.4.7-cp312-cp312-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "tokenizers", "version": "0.23.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e2/6a/068ed9f6e444c9d7e9d55ce134181325700f3d7f30410721bdc8f848d727/tokenizers-0.23.1-cp310-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "huggingface_hub", "version": "1.22.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/9c/a1a377265abd8b823a2c661c665028ccb6b9fba1ca9d08e52ff679c20ecd/huggingface_hub-1.22.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/35/94/4b2ecfbad8f8b04701a23aefb62f540b9137d058b7e1dbef16a32676f0e9/hf_xet-1.5.1-cp37-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "types-requests", "version": "2.33.0.20260518"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1c/bc/b139710a3b6018f7fb2b9508b35c8af564e61bf2bf4fa619d088f3e16f85/types_requests-2.33.0.20260518-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "filelock", "version": "3.29.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4a/e3/f1fae3647d170919c2cf2a898e77e7d1a4e5c7cae0aed7bb4bd3f5ebff6f/filelock-3.29.5-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e5/22/4222d7ddf3da30f363edaa98e329c2bce6c65497c9cb2810931c8b2c0fbc/fsspec-2026.6.0-py3-none-any.whl"}}, {"metadata": {"name": "genai-prices", "version": "0.0.69"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/05/6bb176d603210b61d2bf4585c7119dcf5491bbcae195e21254668c5ee07a/genai_prices-0.0.69-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.55.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/1d/f6d3ca1ad0725f2e08a1c6915640748a52de2e66596160a4d53b010cccf0/google_auth-2.55.1-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/22/adf66990e63584a68dfb50c24f48a125c07b1699899381c8151e63ed458c/cryptography-49.0.0-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "google-genai", "version": "2.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/39/00bcfd94de255d24249401efff4f48d77bf6066b46447e519fa193c0c299/google_genai-2.10.0-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/40/1e/9771421ac2286eaab95b8575b0cb701ae3663abf8b5e1f64f1fd90d0a673/websockets-16.0-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "griffe", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6b/fb/3c65d392feae6c36dc2b55a14dd8270b7b35a3171c93b71a4d2ee4abf241/griffe-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "griffecli", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/80/2f/513232ec1d5f5da182e4ce45a11427e37dd210844a9e2bca451fc9661fb3/griffecli-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "griffelib", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e4/d3/5268aeabf2ad82658c4e2ff3a060648d0f02f3926cb53247c0e4d0dab49e/griffelib-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "colorama", "version": "0.4.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl"}}, {"metadata": {"name": "groq", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ce/c3/cac2aee75198c0382a2e6070619a798de2288e01850abb6e999746bb92e3/groq-1.5.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/31/22/859d8252dad9bc9adee34b52e62cde621ece07b042ccb2ab4da1be46695f/httpx2-2.5.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c9/a1/7564199d1a8728fe737b0a72e5b3f8d92dfe085a74ddf7cdd83bce5f206d/httpcore2-2.5.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "logfire", "version": "4.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7a/08/1805d2f26955671115aae555d78cc4c72a6fe733f332d44d69756bc1737b/logfire-4.37.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-exporter-otlp-proto-http", "version": "1.42.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d3/96/82cb223a1502f0787d4bbff12907f5f8d870a50731febcd5818d93ef9555/opentelemetry_exporter_otlp_proto_http-1.42.1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-exporter-otlp-proto-common", "version": "1.42.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d6/43/2375e7612e1121a4518c17603b6e0b03ad94f565aafad53f464dc5be2bf6/opentelemetry_exporter_otlp_proto_common-1.42.1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-proto", "version": "1.42.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/9d/171c02c84a76940b7e601805b3bb536985aded9168fbcc9ba52f0a730fa2/opentelemetry_proto-1.42.1-py3-none-any.whl"}}, {"metadata": {"name": "googleapis-common-protos", "version": "1.75.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e7/c8/e2645aa8ed02fd4c7a2f59d68783b65b1f3cbdfe39a6308e156509d1fee8/googleapis_common_protos-1.75.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-sdk", "version": "1.42.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8f/6b/4287766cfbde577ae2272e8884abac325aeaac0d64f41c61d5b8cc595105/opentelemetry_sdk-1.42.1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.42.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/ca/9520cc1f3dfbbd03ac5903bbf55833e257bc64b1cf30fa8b0d6df374d821/opentelemetry_api-1.42.1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-semantic-conventions", "version": "0.63b1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/7a/7fe66f5f3682b1dd47d88cc4e11f1c6c0966b737de2d16671146e23c39a5/opentelemetry_semantic_conventions-0.63b1-py3-none-any.whl"}}, {"metadata": {"name": "executing", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "logfire-api", "version": "4.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/2f/23e5b8fa22f75f73965c72e5c29e6fb8715263457394601e254fe26fbe31/logfire_api-4.37.0-py3-none-any.whl"}}, {"metadata": {"name": "mcp", "version": "1.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e2/5e/d118fce19f87a2e7d8101c35c8ae0ec289098a4df0ff244cec23e415aca0/mcp-1.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "mistralai", "version": "1.12.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c9/f9/98d825105c450b9c67c27026caa374112b7e466c18331601d02ca278a01b/mistralai-1.12.4-py3-none-any.whl"}}, {"metadata": {"name": "invoke", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/4b/b99e37f88336009971405cbb7630610322ed6fbfa31e1d7ab3fbf3049a2d/invoke-2.2.1-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "eval_type_backport", "version": "0.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/a7/bb99bf5e6f78736ddb53480f2c3ff3702ffe2196a7c5e1661c03081d398e/eval_type_backport-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "2.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ae/f4/561ed79fd94876160018a5e75254cfcb9b0e62d4dded9dcb20072e86d623/openai-2.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-instrumentation", "version": "0.63b1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/35/a1/9314e621c143e4d82a5bf7a43c2ff7a745d31023506336857607c8c543cc/opentelemetry_instrumentation-0.63b1-py3-none-any.whl"}}, {"metadata": {"name": "wrapt", "version": "2.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/f2/21c90f2a16689702e2aaff45795b11018dff2c9b1242bac10d225483f676/wrapt-2.2.2-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "opentelemetry-instrumentation-httpx", "version": "0.63b1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/b8/f536780996195c3b9f2354998554671e05a7a262df8c043f63fe9e5a6f0b/opentelemetry_instrumentation_httpx-0.63b1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-util-http", "version": "0.63b1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e5/f1/34e047e8f6a3c67e5220acf1af7b9f62868c25d77791bca74457bd2180a6/opentelemetry_util_http-0.63b1-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "prompt_toolkit", "version": "3.0.52"}, "download_info": {"url": "https://files.pythonhosted.org/packages/84/03/0d3ce49e2505ae70cf43bc5bb3033955d2fc9f932163e84dc0779cc47f48/prompt_toolkit-3.0.52-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/a0/7d793dce3fa811fe047d6ae2431c672364b462850c6235ae306c0efd025f/pyasn1-0.6.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/77/c1/6e422f34e569cf8e18df68d1939c81c099d2b61e4f7d9621c8a77560799c/pydantic_settings-2.14.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "pyperclip", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/80/fc9d01d5ed37ba4c42ca2b55b4339ae6e200b456be3a1aaddf4a9fa99b8c/pyperclip-1.11.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a4/73/319dfa745dd668efe89309141ded489126461fcecd2b8f3a3cda185129b6/rpds_py-2026.6.3-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/75/c88d3f5dafd59c791da1ce27650d30bf5b70cbf1cbf01cd00e5f9e360915/sse_starlette-3.4.5-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.68.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d8/8e/bb97bb0c71802080bfc8952937d174e49cfc50de5c951dd47b2496f0dcdb/tqdm-4.68.3-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "types-protobuf", "version": "7.34.1.20260518"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/1f/ec5caf72c2e3b688ca3927e0979a04ddad19e1afc4bf1c199bd743e0f419/types_protobuf-7.34.1.20260518-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.50.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f2/59/02c7859295b001e77b8079fc9df9f8161b7c872cbf7ea8dab70cf51d61f1/uvicorn-0.50.1-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl"}}], "install_targets_hash": "76bc8d4da920add2d6433f5bd69d9ec8"} +{"python_version": "3.12", "dependencies": [{"metadata": {"name": "celery", "version": "5.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/90/c4/6a4d3772e5407622feb93dd25c86ce3c0fee746fa822a777a627d56b4f2a/celery-5.4.0-py3-none-any.whl"}}, {"metadata": {"name": "newrelic", "version": "10.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d4/71/07c41fd5e8c94e95216b000d00c3cf735f769cb406c0f33c6ff83b7b7418/newrelic-10.16.0.tar.gz"}}, {"metadata": {"name": "billiard", "version": "4.2.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/87/8bab77b323f16d67be364031220069f79159117dd5e43eeb4be2fef1ac9b/billiard-4.2.4-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "kombu", "version": "5.6.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/0f/834427d8c03ff1d7e867d3db3d176470c64871753252b21b4f4897d1fa45/kombu-5.6.2-py3-none-any.whl"}}, {"metadata": {"name": "vine", "version": "5.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/ff/7c0c86c43b3cbb927e0ccc0255cb4057ceba4799cd44ae95174ce8e8b5b2/vine-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "amqp", "version": "5.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/26/99/fc813cd978842c26c82534010ea849eee9ab3a13ea2b74e95cb9c99e747b/amqp-5.3.1-py3-none-any.whl"}}, {"metadata": {"name": "redis", "version": "8.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/66/9d/c5731f6e3608663d4d3656fd8d3aecee8b509c3082818f5a13eae925baea/redis-8.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/af/9c0bda43e486a3c9bf1e0f876d0f241bc3f229d7d65d09331a0868db9629/pytest_forked-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "click-didyoumean", "version": "0.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/5b/974430b5ffdb7a4f1941d13d83c64a0395114503cc357c6b9ae4ce5047ed/click_didyoumean-0.3.1-py3-none-any.whl"}}, {"metadata": {"name": "click-plugins", "version": "1.1.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/9a/2abecb28ae875e39c8cad711eb1186d8d14eab564705325e77e4e6ab9ae5/click_plugins-1.1.1.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "click-repl", "version": "0.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/52/40/9d857001228658f0d59e97ebd4c346fe73e138c6de1bce61dc568a57c7f8/click_repl-0.3.0-py3-none-any.whl"}}, {"metadata": {"name": "prompt_toolkit", "version": "3.0.53"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/6f/84908cad2d6aa5144abcf7b42709fe4fdb459bc640ec7ac5786e7693dabc/prompt_toolkit-3.0.53-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tzdata", "version": "2026.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e5/6d/b53b99a9f2766d095985947a5782f1702cabb129a34f7a802d7197af832f/tzdata-2026.3-py2.py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl"}}, {"metadata": {"name": "py", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl"}}], "install_targets_hash": "7bc432e5912a9b6ade7f1ac7ce46a30a"} {"python_version": "3.12", "dependencies": [{"metadata": {"name": "UnleashClient", "version": "6.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f3/52/2f9da0f81dba2323409e291dc32975bf20d245d493e22c8295461d8025e3/unleashclient-6.8.0-py3-none-any.whl"}}, {"metadata": {"name": "APScheduler", "version": "3.11.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/42/c9/8638db32514dbb9157b3d82680c6faea89283523edf9ed2415ea3884f2ae/apscheduler-3.11.3-py3-none-any.whl"}}, {"metadata": {"name": "semver", "version": "3.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/24/4d91e05817e92e3a61c8a21e08fd0f390f5301f1c448b137c57c4bc6e543/semver-3.0.4-py3-none-any.whl"}}, {"metadata": {"name": "tzlocal", "version": "5.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/a4/017a7a6cbe387d961a688ec31364ae60a5c4e22c96ae9921b79a947c855d/tzlocal-5.4.4-py3-none-any.whl"}}, {"metadata": {"name": "yggdrasil-engine", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/5d/952ef9374c364f7e2a14ee56643ff93b4e24ca2607760cffa67e5c16b030/yggdrasil_engine-1.3.1-cp312-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "fcache", "version": "0.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/84/0c/ababd9fed96d865463f95f897c48a8781bc831f9e08cdc8124b96964f92c/fcache-0.6.0-py3-none-any.whl"}}, {"metadata": {"name": "platformdirs", "version": "3.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/29/3ec311dc18804409ecf0d2b09caa976f3ae6215559306b5b530004e11156/platformdirs-3.11.0-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "9.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/38/3d/2d244233ac4f76e38533cfcb2991c9eb4c7bf688ae0a036d30725b8faafe/importlib_metadata-9.0.0-py3-none-any.whl"}}, {"metadata": {"name": "zipp", "version": "4.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl"}}, {"metadata": {"name": "launchdarkly-eventsource", "version": "1.7.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/49/8592c1d9c156d3c2d3f8c02e1c00260c3e0a7a10bcb50c942bd80c285c62/launchdarkly_eventsource-1.7.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "mmh3", "version": "5.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8b/72/e6d6602ce18adf4ddcd0e48f2e13590cc92a536199e52109f46f259d3c46/mmh3-5.2.1-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/70/4a/ecbd131485c07fcdfad54e28946d513e3da22ef3b4bd854dcafae54ec739/charset_normalizer-3.4.9-cp312-cp312-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}], "install_targets_hash": "80f0bee8c3b3234399e0317b74ba4c5a"} {"python_version": "3.12", "dependencies": [{"metadata": {"name": "boto3", "version": "1.35.99"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/77/8bbca82f70b062181cf0ae53fd43f1ac6556f3078884bfef9da2269c06a3/boto3-1.35.99-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.35.99"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fc/dd/d87e2a145fad9e08d0ec6edcf9d71f838ccc7acdd919acc4c0d4a93515f8/botocore-1.35.99-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "s3transfer", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/66/05/7957af15543b8c9799209506df4660cba7afc4cf94bfb60513827e96bed6/s3transfer-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}], "install_targets_hash": "82e93b805ffcefdca457780864f9fb29"} {"python_version": "3.12", "dependencies": [{"metadata": {"name": "loguru", "version": "0.7.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/29/0348de65b8cc732daa3e33e67806420b2ae89bdce2b04af740289c5c6c8c/loguru-0.7.3-py3-none-any.whl"}}], "install_targets_hash": "835a301f2aad710918099958aaa42343"} {"python_version": "3.12", "dependencies": [{"metadata": {"name": "langchain", "version": "0.1.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/28/da40a6b12e7842a0c8b443f8cc5c6f59e49d7a9071cfad064b9639c6b044/langchain-0.1.20-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/07/4bbc222cc8dbe31d4c3e8a5baad2286e4d42026ac0c570027b89afce6344/aiohttp-3.14.3-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "dataclasses-json", "version": "0.6.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c3/be/d0d44e092656fe7a06b55e6103cbce807cdbdee17884a5367c68c9860853/dataclasses_json-0.6.7-py3-none-any.whl"}}, {"metadata": {"name": "langchain-community", "version": "0.0.38"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/d3/1f4d1941ae5a627299c8ea052847b99ad6674b97b699d8a08fc4faf25d3e/langchain_community-0.0.38-py3-none-any.whl"}}, {"metadata": {"name": "langchain-core", "version": "0.1.53"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6a/10/285fa149ce95300d91ea0bb124eec28889e5ebbcb59434d1fe2f31098d72/langchain_core-0.1.53-py3-none-any.whl"}}, {"metadata": {"name": "jsonpatch", "version": "1.33"}, "download_info": {"url": "https://files.pythonhosted.org/packages/73/07/02e16ed01e04a374e644b575638ec7987ae846d25ad97bcc9945a3ee4b0e/jsonpatch-1.33-py2.py3-none-any.whl"}}, {"metadata": {"name": "langchain-text-splitters", "version": "0.0.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/68/6a/804fe5ca07129046a4cedc0697222ddde6156cd874c4c4ba29e4d271828a/langchain_text_splitters-0.0.2-py3-none-any.whl"}}, {"metadata": {"name": "langsmith", "version": "0.1.147"}, "download_info": {"url": "https://files.pythonhosted.org/packages/de/f0/63b06b99b730b9954f8709f6f7d9b8d076fa0a973e472efe278089bde42b/langsmith-0.1.147-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "marshmallow", "version": "3.26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/be/2f/5108cb3ee4ba6501748c4908b908e55f42a5b66245b4cfe0c99326e1ef6e/marshmallow-3.26.2-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/65/1caac9d4cd32e8433908683446eebc953e82d22b03d10d41a5f0fefe991b/multidict-6.7.1-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "numpy", "version": "1.26.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/75/5b/ca6c8bd14007e5ca171c7c03102d17b4f4e0ceb53957e8c44343a9546dcc/numpy-1.26.4-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "orjson", "version": "3.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/29/98/758cf90fbeaaafb7f8141bfac75a432099959f3a2f5db93a412e876415d8/orjson-3.12.0-cp312-cp312-macosx_15_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "23.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/1a/610693ac4ee14fcdf2d9bf3c493370e4f2ef7ae2e19217d7a237ff42367d/packaging-23.2-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/95/6195171e385007300f0f5574592e467c568becce2d937a0b6804f218bc49/pydantic_core-2.46.4-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/27/78873dc8b6a56357517b74b6bb9568b80450e7bb4f6ef7e3fa9d22aa0bd7/charset_normalizer-3.5.1-cp312-cp312-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "SQLAlchemy", "version": "2.0.52"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/d5/1b77a026d161f98a08f11af1a5f6c47b98ee7c7e2648af525a1004826c78/sqlalchemy-2.0.52-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tenacity", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/3f/8ba87d9e287b9d385a02a7114ddcef61b26f86411e121c9003eb509a1773/tenacity-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspect", "version": "0.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/f3/107a22063bf27bdccf2024833d3445f4eea42b2e598abfbd46f6a63b6cb0/typing_inspect-0.9.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ea/b4/05b4131c407006cd1e410e9c6539f16a0945724677e5364447313c15ea3e/yarl-1.24.5-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/2e/34957c2c1b661c252ba9bcc60ae0bddc27e0f7202c6073326a13c5390eec/jiter-0.16.0-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/9f/fe6b1aca23331aa5271df5a4bd07bf68a7059254d47faee1b8272592a777/tiktoken-0.14.0-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "langchain-openai", "version": "0.1.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/27/43f785670a340363fe46e2893a80293fa12448584f19ba4f9e6d03673552/langchain_openai-0.1.7-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "1.109.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1d/2a/7dd3d207ec669cacc1f186fd856a0f61dbc255d24f6fdc1a6715d6051b0f/openai-1.109.1-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2b/94/5c8a2b50a496b11dd519f4a24cb5496cf125681dd99e94c604ccdea9419a/frozenlist-1.8.0-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonpointer", "version": "3.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/6a/a83720e953b1682d2d109d3c2dbb0bc9bf28cc1cbc205be4ef4be5da709d/jsonpointer-3.1.1-py3-none-any.whl"}}, {"metadata": {"name": "mypy_extensions", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/7d/49777a3e20b55863d4794384a38acd460c04157b0a00f8602b0d508b8431/propcache-0.5.2-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.7.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/63/4cab4d7f2d384a144d420b763d97674cb70619c878ea6fcd7640d0e62143/regex-2026.7.19-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "877a90b1b55e01d25a299fb8949b9fd9"} {"python_version": "3.12", "dependencies": [{"metadata": {"name": "httpx2", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/25/66215a750faeb79b698286c0d0b94894482cfae10371ae4968ef6e165a28/httpx2-2.0.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2-pytest", "version": "1.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/46/ef/e9b6fb576f1f518f68e9f9cce9776870452ae2b8cfbba53b4127701b9a55/httpx2_pytest-1.0.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ae/67/784fd58a5b4dbe8b2aee0cafc6959cb8b53c1b7e9d6e4281f8a4c6935c10/httpcore2-2.0.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}], "install_targets_hash": "9589a3ce6fa0bfc82a7f6fc685f97223"} {"python_version": "3.12", "dependencies": [{"metadata": {"name": "grpcio", "version": "1.66.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/d5/b631445dff250a5301f51ff56c5fc917c7f955cd02fa55379f158a89abeb/grpcio-1.66.2-cp312-cp312-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "protobuf", "version": "7.35.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/03/8aeeb7458d22546bf64b5250ca1daeb5ff757d900e8e4a7476c6f0db843e/protobuf-7.35.1-cp310-abi3-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "mypy-protobuf", "version": "5.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/ec/5ffcf8f5f53757e01afdece10c664e694ac60d2f17c2036811b85b842a5b/mypy_protobuf-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "types-protobuf", "version": "7.34.1.20260518"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/1f/ec5caf72c2e3b688ca3927e0979a04ddad19e1afc4bf1c199bd743e0f419/types_protobuf-7.34.1.20260518-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/af/9c0bda43e486a3c9bf1e0f876d0f241bc3f229d7d65d09331a0868db9629/pytest_forked-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "py", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl"}}], "install_targets_hash": "9664bc6c25b7664cbf0e53ad567cc109"} -{"python_version": "3.12", "dependencies": [{"metadata": {"name": "fastmcp", "version": "2.14.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/f1/56310847b0bdd5b14c2af8f0a39082af078deff60d0dc43efef4e366a83e/fastmcp-2.14.7-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.34.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/b5/82f89307d0d769cd9bf46a54fb9136be08e4e57c5570ae421db4c9a2ba62/fakeredis-2.34.1-py3-none-any.whl"}}, {"metadata": {"name": "mcp", "version": "1.29.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/c8/248b201f6d753d69fd5d6506011abbb35a946d9142b2ae311a948fd0be3d/mcp-1.29.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "py-key-value-aio", "version": "0.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/10/72f6f213b8f0bce36eff21fda0a13271834e9eeff7f9609b01afdc253c79/py_key_value_aio-0.3.0-py3-none-any.whl"}}, {"metadata": {"name": "py-key-value-shared", "version": "0.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/e4/b8b0a03ece72f47dce2307d36e1c34725b7223d209fc679315ffe6a4e2c3/py_key_value_shared-0.3.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/95/6195171e385007300f0f5574592e467c568becce2d937a0b6804f218bc49/pydantic_core-2.46.4-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "Authlib", "version": "1.7.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/95/adcb68e20c34162e9135f370d6e31737719c2b6f94bc953fe7ed1f10fe21/authlib-1.7.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "beartype", "version": "0.22.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/cc/18245721fa7747065ab478316c7fea7c74777d07f37ae60db2e84f8172e8/beartype-0.22.9-py3-none-any.whl"}}, {"metadata": {"name": "cachetools", "version": "7.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9f/f2/2086ba18a925a73586c4d4e61d25f4a6058e56fd00d77ce8f1d361ab4c9b/cachetools-7.1.6-py3-none-any.whl"}}, {"metadata": {"name": "cyclopts", "version": "4.22.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/75/a11bfb5045e58b4ef69337b848985918e829fe9a90572a761d17c1a992f5/cyclopts-4.22.2-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "rich-rst", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/68/1fc93dd759605b5d00fc98b50200739e41ed32bd22d6ba35ca6c3932371b/rich_rst-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "diskcache", "version": "5.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/27/4570e78fc0bf5ea0ca45eb1de3818a23787af9b390c0b0a0033a1b8236f9/diskcache-5.6.3-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "joserfc", "version": "1.7.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/bf/249dcd99b3376375910b7fa922383b57792975c8758f50d44612e749226c/joserfc-1.7.4-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/22/adf66990e63584a68dfb50c24f48a125c07b1699899381c8151e63ed458c/cryptography-49.0.0-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/92/e7bb136ad6b5352603732cf907ef862ca103f20f2031c1735a46300c20c9/cffi-2.1.0-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "jsonref", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/ec/e1db9922bceb168197a558a2b8c03a7963f1afe93517ddd3cf99f202f996/jsonref-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-path", "version": "0.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/2c/9e69d73c4297508be9e3b64a970ea3971b3eb8db64ffc5802d40bd25981f/jsonschema_path-0.5.0-py3-none-any.whl"}}, {"metadata": {"name": "pathable", "version": "0.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a2/e8/6d75ffd9784bce2e93d1ae4415649427e39a53bb172d4672b2b59c6f0a7b/pathable-0.6.0-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "keyring", "version": "25.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/db/e655086b7f3a705df045bf0933bdd9c2f79bb3c97bfef1384598bb79a217/keyring-25.7.0-py3-none-any.whl"}}, {"metadata": {"name": "lupa", "version": "2.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4d/17/fa834b6b09ad17e7df5d0f7715d64877a125a3776ada689751a1f9dc2959/lupa-2.8-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "openapi-pydantic", "version": "0.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/cf/03675d8bd8ecbf4445504d8071adab19f5f993676795708e36402ab38263/openapi_pydantic-0.5.1-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pathvalidate", "version": "3.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/70/875f4a23bfc4731703a5835487d0d2fb999031bd415e7d17c0ae615c18b7/pathvalidate-3.3.1-py3-none-any.whl"}}, {"metadata": {"name": "platformdirs", "version": "4.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7d/68/d8d58938dfb1370b266a1a729e6d77a985be23689a0496498ee17b2cbf90/platformdirs-4.11.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/77/c1/6e422f34e569cf8e18df68d1939c81c099d2b61e4f7d9621c8a77560799c/pydantic_settings-2.14.2-py3-none-any.whl"}}, {"metadata": {"name": "email-validator", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "dnspython", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "pydocket", "version": "0.23.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e6/67/b57ac7cfd2c2f30d58ff2c996591880d200078fc828cbbad8da69d634c0e/pydocket-0.23.1-py3-none-any.whl"}}, {"metadata": {"name": "burner-redis", "version": "0.1.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2f/4e/ce5c91b884ac37fcd380756402536f8810964014097950900517ce8bd30c/burner_redis-0.1.7-cp310-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cloudpickle", "version": "3.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/88/39/799be3f2f0f38cc727ee3b4f1445fe6d5e4133064ec2e4115069418a5bb6/cloudpickle-3.1.2-py3-none-any.whl"}}, {"metadata": {"name": "cronsim", "version": "2.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1a/02f105147f7f2e06ed4f734ff5a6439590bb275a53dd91fc73df6312298a/cronsim-2.7-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/6f/a04e900f465ff3221ccc395522503e2d10e79fa21f2723c8e177aae1e0d1/opentelemetry_api-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "prometheus_client", "version": "0.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/a3/b69efbf4143b5b9859b977770bbbabcc2796b702fa69dc40271e45cd5a56/prometheus_client-0.26.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "pyperclip", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/80/fc9d01d5ed37ba4c42ca2b55b4339ae6e200b456be3a1aaddf4a9fa99b8c/pyperclip-1.11.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl"}}, {"metadata": {"name": "python-json-logger", "version": "4.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/27/be/0631a861af4d1c875f096c07d34e9a63639560a717130e7a87cbc82b7e3f/python_json_logger-4.1.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "redis", "version": "8.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/0a/c2345ebf1ebe70840ce3f6c6ee612f8fa749cfbd1b03069c53bf0c62aaad/redis-8.0.1-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a4/73/319dfa745dd668efe89309141ded489126461fcecd2b8f3a3cda185129b6/rpds_py-2026.6.3-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/36/e10c1d1b7ca881d2625db2ec28508578499187bb1c389952c398474e1834/sse_starlette-3.4.6-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typer", "version": "0.27.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/40/03/26a383c9e58c213199d1aad1c3d353cfc22d4444ec6d2c0bf8ad02523843/typer-0.27.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "shellingham", "version": "1.5.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "uncalled-for", "version": "0.3.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3b/25/2c87754f3a9e692315f7b811244090e68f362979fc8886b3fbd2985a1d8c/uncalled_for-0.3.2-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.52.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/39/e6/b5c0630ace9757232aec07112be8146b812787db52141ff9d50674aa7634/uvicorn-0.52.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/73/e3/fe2d498c64dea0095c9a9f9a351af4cd6eef31b618395582bc1f38ba45ff/websockets-16.1.1-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.classes", "version": "3.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/66/b15ce62552d84bbfcec9a4873ab79d993a1dd4edb922cbfccae192bd5b5f/jaraco.classes-3.4.0-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.context", "version": "6.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f2/58/bc8954bda5fcda97bd7c19be11b85f91973d67a706ed4a3aec33e7de22db/jaraco_context-6.1.2-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.functools", "version": "4.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/02/36/ecc85bc96c273dc8a11273ed4782272975e6338d4a3e9228621175edf0e3/jaraco_functools-4.6.0-py3-none-any.whl"}}, {"metadata": {"name": "more-itertools", "version": "11.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/3d/1087453384dbde46a8c7f9356eead2c58be8a7bf156bca40243377c85715/more_itertools-11.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "9f62a1568e3800b7daf4b86289b6cb6a"} {"python_version": "3.12", "dependencies": [{"metadata": {"name": "google-genai", "version": "1.29.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/33/9b22b0b3734f93655d0d28cfcd64496ef46dd68efe8ae19278f3b1297998/google_genai-1.29.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.55.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/1d/f6d3ca1ad0725f2e08a1c6915640748a52de2e66596160a4d53b010cccf0/google_auth-2.55.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/95/6195171e385007300f0f5574592e467c568becce2d937a0b6804f218bc49/pydantic_core-2.46.4-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/eb/4fc8d0a7110eb5fc9cc161723a34a8a6c200ce3b4fbf681bc86feee22308/charset_normalizer-3.4.7-cp312-cp312-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "15.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/69/1a681dd6f02180916f116894181eab8b2e25b31e484c5d0eae637ec01f7c/websockets-15.0.1-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/22/adf66990e63584a68dfb50c24f48a125c07b1699899381c8151e63ed458c/cryptography-49.0.0-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/a0/7d793dce3fa811fe047d6ae2431c672364b462850c6235ae306c0efd025f/pyasn1-0.6.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "a43cdff61ea105e2cfc9e159c1a78f1a"} {"python_version": "3.12", "dependencies": [{"metadata": {"name": "typer", "version": "0.15.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c9/62/d4ba7afe2096d5659ec3db8b15d8665bdcb92a3c6ff0b95e99895b335a9c/typer-0.15.4-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "shellingham", "version": "1.5.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}], "install_targets_hash": "a84f9aca2b9546e22b929cce508b9110"} {"python_version": "3.12", "dependencies": [{"metadata": {"name": "langchain", "version": "0.1.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/28/da40a6b12e7842a0c8b443f8cc5c6f59e49d7a9071cfad064b9639c6b044/langchain-0.1.20-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/07/4bbc222cc8dbe31d4c3e8a5baad2286e4d42026ac0c570027b89afce6344/aiohttp-3.14.3-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "dataclasses-json", "version": "0.6.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c3/be/d0d44e092656fe7a06b55e6103cbce807cdbdee17884a5367c68c9860853/dataclasses_json-0.6.7-py3-none-any.whl"}}, {"metadata": {"name": "langchain-community", "version": "0.0.38"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/d3/1f4d1941ae5a627299c8ea052847b99ad6674b97b699d8a08fc4faf25d3e/langchain_community-0.0.38-py3-none-any.whl"}}, {"metadata": {"name": "langchain-core", "version": "0.1.53"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6a/10/285fa149ce95300d91ea0bb124eec28889e5ebbcb59434d1fe2f31098d72/langchain_core-0.1.53-py3-none-any.whl"}}, {"metadata": {"name": "jsonpatch", "version": "1.33"}, "download_info": {"url": "https://files.pythonhosted.org/packages/73/07/02e16ed01e04a374e644b575638ec7987ae846d25ad97bcc9945a3ee4b0e/jsonpatch-1.33-py2.py3-none-any.whl"}}, {"metadata": {"name": "langchain-text-splitters", "version": "0.0.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/68/6a/804fe5ca07129046a4cedc0697222ddde6156cd874c4c4ba29e4d271828a/langchain_text_splitters-0.0.2-py3-none-any.whl"}}, {"metadata": {"name": "langsmith", "version": "0.1.147"}, "download_info": {"url": "https://files.pythonhosted.org/packages/de/f0/63b06b99b730b9954f8709f6f7d9b8d076fa0a973e472efe278089bde42b/langsmith-0.1.147-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "marshmallow", "version": "3.26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/be/2f/5108cb3ee4ba6501748c4908b908e55f42a5b66245b4cfe0c99326e1ef6e/marshmallow-3.26.2-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/65/1caac9d4cd32e8433908683446eebc953e82d22b03d10d41a5f0fefe991b/multidict-6.7.1-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "numpy", "version": "1.26.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/75/5b/ca6c8bd14007e5ca171c7c03102d17b4f4e0ceb53957e8c44343a9546dcc/numpy-1.26.4-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "orjson", "version": "3.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/29/98/758cf90fbeaaafb7f8141bfac75a432099959f3a2f5db93a412e876415d8/orjson-3.12.0-cp312-cp312-macosx_15_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "23.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/1a/610693ac4ee14fcdf2d9bf3c493370e4f2ef7ae2e19217d7a237ff42367d/packaging-23.2-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/95/6195171e385007300f0f5574592e467c568becce2d937a0b6804f218bc49/pydantic_core-2.46.4-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/27/78873dc8b6a56357517b74b6bb9568b80450e7bb4f6ef7e3fa9d22aa0bd7/charset_normalizer-3.5.1-cp312-cp312-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "SQLAlchemy", "version": "2.0.52"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/d5/1b77a026d161f98a08f11af1a5f6c47b98ee7c7e2648af525a1004826c78/sqlalchemy-2.0.52-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tenacity", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/3f/8ba87d9e287b9d385a02a7114ddcef61b26f86411e121c9003eb509a1773/tenacity-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspect", "version": "0.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/f3/107a22063bf27bdccf2024833d3445f4eea42b2e598abfbd46f6a63b6cb0/typing_inspect-0.9.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ea/b4/05b4131c407006cd1e410e9c6539f16a0945724677e5364447313c15ea3e/yarl-1.24.5-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/2e/34957c2c1b661c252ba9bcc60ae0bddc27e0f7202c6073326a13c5390eec/jiter-0.16.0-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "langchain-openai", "version": "0.1.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/27/43f785670a340363fe46e2893a80293fa12448584f19ba4f9e6d03673552/langchain_openai-0.1.7-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "1.109.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1d/2a/7dd3d207ec669cacc1f186fd856a0f61dbc255d24f6fdc1a6715d6051b0f/openai-1.109.1-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/9f/fe6b1aca23331aa5271df5a4bd07bf68a7059254d47faee1b8272592a777/tiktoken-0.14.0-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2b/94/5c8a2b50a496b11dd519f4a24cb5496cf125681dd99e94c604ccdea9419a/frozenlist-1.8.0-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonpointer", "version": "3.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/6a/a83720e953b1682d2d109d3c2dbb0bc9bf28cc1cbc205be4ef4be5da709d/jsonpointer-3.1.1-py3-none-any.whl"}}, {"metadata": {"name": "mypy_extensions", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/7d/49777a3e20b55863d4794384a38acd460c04157b0a00f8602b0d508b8431/propcache-0.5.2-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.7.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/63/4cab4d7f2d384a144d420b763d97674cb70619c878ea6fcd7640d0e62143/regex-2026.7.19-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "aa1fb60a0df2b501cda6dfe6922f3f17"} {"python_version": "3.12", "dependencies": [{"metadata": {"name": "litestar", "version": "2.8.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/e7/3d7ca62d6c48ff4c8162e2f03264c3202d8a76cb6a4987eac67f27af1de5/litestar-2.8.3-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/eb/4fc8d0a7110eb5fc9cc161723a34a8a6c200ce3b4fbf681bc86feee22308/charset_normalizer-3.4.7-cp312-cp312-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/22/adf66990e63584a68dfb50c24f48a125c07b1699899381c8151e63ed458c/cryptography-49.0.0-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "msgspec", "version": "0.21.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6d/81/074612945c0666078f7366f40000013de9f6ba687491d450df699bceebc9/msgspec-0.21.1-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/65/1caac9d4cd32e8433908683446eebc953e82d22b03d10d41a5f0fefe991b/multidict-6.7.1-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "polyfactory", "version": "3.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/34/b6f19941adcdaf415b5e8a8d577499f5b6a76b59cbae37f9b125a9ffe9f2/polyfactory-3.3.0-py3-none-any.whl"}}, {"metadata": {"name": "Faker", "version": "40.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/a6/6111b9f13c1564b0e2f5dbeeb611fd00dc731e6add2336f62b798598c73d/faker-40.28.1-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "rich-click", "version": "1.9.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6d/97/a87901aef6b7e7e4a34c6dd6cc17dca8594a592ef9d9dd765fca2b7facf7/rich_click-1.9.8-py3-none-any.whl"}}], "install_targets_hash": "aad339208686a05fcf6dfa07b8c6ba47"} +{"python_version": "3.12", "dependencies": [{"metadata": {"name": "litestar", "version": "2.8.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/e7/3d7ca62d6c48ff4c8162e2f03264c3202d8a76cb6a4987eac67f27af1de5/litestar-2.8.3-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/eb/4fc8d0a7110eb5fc9cc161723a34a8a6c200ce3b4fbf681bc86feee22308/charset_normalizer-3.4.7-cp312-cp312-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/22/adf66990e63584a68dfb50c24f48a125c07b1699899381c8151e63ed458c/cryptography-49.0.0-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "msgspec", "version": "0.21.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6d/81/074612945c0666078f7366f40000013de9f6ba687491d450df699bceebc9/msgspec-0.21.1-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/65/1caac9d4cd32e8433908683446eebc953e82d22b03d10d41a5f0fefe991b/multidict-6.7.1-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "polyfactory", "version": "3.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/34/b6f19941adcdaf415b5e8a8d577499f5b6a76b59cbae37f9b125a9ffe9f2/polyfactory-3.3.0-py3-none-any.whl"}}, {"metadata": {"name": "Faker", "version": "40.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/a6/6111b9f13c1564b0e2f5dbeeb611fd00dc731e6add2336f62b798598c73d/faker-40.28.1-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "rich-click", "version": "1.9.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6d/97/a87901aef6b7e7e4a34c6dd6cc17dca8594a592ef9d9dd765fca2b7facf7/rich_click-1.9.8-py3-none-any.whl"}}], "install_targets_hash": "aad339208686a05fcf6dfa07b8c6ba47"} +{"python_version": "3.12", "dependencies": [{"metadata": {"name": "litestar", "version": "2.8.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/e7/3d7ca62d6c48ff4c8162e2f03264c3202d8a76cb6a4987eac67f27af1de5/litestar-2.8.3-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/eb/4fc8d0a7110eb5fc9cc161723a34a8a6c200ce3b4fbf681bc86feee22308/charset_normalizer-3.4.7-cp312-cp312-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/22/adf66990e63584a68dfb50c24f48a125c07b1699899381c8151e63ed458c/cryptography-49.0.0-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "msgspec", "version": "0.21.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6d/81/074612945c0666078f7366f40000013de9f6ba687491d450df699bceebc9/msgspec-0.21.1-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/65/1caac9d4cd32e8433908683446eebc953e82d22b03d10d41a5f0fefe991b/multidict-6.7.1-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "polyfactory", "version": "3.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/34/b6f19941adcdaf415b5e8a8d577499f5b6a76b59cbae37f9b125a9ffe9f2/polyfactory-3.3.0-py3-none-any.whl"}}, {"metadata": {"name": "Faker", "version": "40.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/a6/6111b9f13c1564b0e2f5dbeeb611fd00dc731e6add2336f62b798598c73d/faker-40.28.1-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "rich-click", "version": "1.9.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6d/97/a87901aef6b7e7e4a34c6dd6cc17dca8594a592ef9d9dd765fca2b7facf7/rich_click-1.9.8-py3-none-any.whl"}}], "install_targets_hash": "aad339208686a05fcf6dfa07b8c6ba47"} +{"python_version": "3.12", "dependencies": [{"metadata": {"name": "Django", "version": "4.2.30"}, "download_info": {"url": "https://files.pythonhosted.org/packages/39/b7/a7c96f239cf91313a6589233fed55111c7063b26683b226802732c455dbc/django-4.2.30-py3-none-any.whl"}}, {"metadata": {"name": "asgiref", "version": "3.11.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5c/0a/a72d10ed65068e115044937873362e6e32fab1b7dce0046aeb224682c989/asgiref-3.11.1-py3-none-any.whl"}}, {"metadata": {"name": "psycopg2-binary", "version": "2.9.12"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b5/01/3dd14e46ba48c1e1a6ec58ee599fa1b5efa00c246d5046cd903d0eeb1af1/psycopg2_binary-2.9.12-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "djangorestframework", "version": "3.17.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5a/e1/2c516bdc83652b1a60c6119366ac2c0607b479ed05cd6093f916ca8928f8/djangorestframework-3.17.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-django", "version": "4.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/83/a5/41d091f697c09609e7ef1d5d61925494e0454ebf51de7de05f0f0a728f1d/pytest_django-4.12.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/af/9c0bda43e486a3c9bf1e0f876d0f241bc3f229d7d65d09331a0868db9629/pytest_forked-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "channels", "version": "4.3.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/16/34/c32915288b7ef482377b6adc401192f98c6a99b3a145423d3b8aed807898/channels-4.3.2-py3-none-any.whl"}}, {"metadata": {"name": "executing", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "daphne", "version": "4.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/ab/85534d9cbca09f3c10f58fc2093659062280ed5703707c0b41dbca8ec297/daphne-4.2.2-py3-none-any.whl"}}, {"metadata": {"name": "autobahn", "version": "26.6.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/c2/fbb5f752235e8c91167b9071b060981395c6e26d9a6607756e46b7d94e1d/autobahn-26.6.2-cp312-cp312-macosx_15_0_arm64.whl"}}, {"metadata": {"name": "cbor2", "version": "6.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/31/16/cff14259c3d19a7f0ae88b6996fe4c85f6ff1764dad889ac8a39e843e39c/cbor2-6.1.3-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/22/adf66990e63584a68dfb50c24f48a125c07b1699899381c8151e63ed458c/cryptography-49.0.0-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "hyperlink", "version": "21.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/aa/8caf6a0a3e62863cbb9dab27135660acba46903b703e224f14f447e57934/hyperlink-21.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "msgpack", "version": "1.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/2e/ebdb85a8da151397a2790363676b7ed7c125924fe618e4c6d8befb0cc62c/msgpack-1.2.1-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "sqlparse", "version": "0.5.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/4b/359f28a903c13438ef59ebeee215fb25da53066db67b305c125f1c6d2a25/sqlparse-0.5.5-py3-none-any.whl"}}, {"metadata": {"name": "Twisted", "version": "26.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/57/bcf4e2370dd218c9aa68a9140a65d86729c73f1d529f7e94786c2766fc72/twisted-26.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "Automat", "version": "25.4.16"}, "download_info": {"url": "https://files.pythonhosted.org/packages/02/ff/1175b0b7371e46244032d43a56862d0af455823b5280a50c63d99cc50f18/automat-25.4.16-py3-none-any.whl"}}, {"metadata": {"name": "constantly", "version": "23.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b8/40/c199d095151addf69efdb4b9ca3a4f20f70e20508d6222bffb9b76f58573/constantly-23.10.4-py3-none-any.whl"}}, {"metadata": {"name": "Incremental", "version": "24.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1d/55/0f4df2a44053867ea9cbea73fc588b03c55605cd695cee0a3d86f0029cb2/incremental-24.11.0-py3-none-any.whl"}}, {"metadata": {"name": "pyOpenSSL", "version": "26.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/18/1dd71c9b43192ab83f1d531ad6002dc81108ac36c475f79fb7a295abe2f4/pyopenssl-26.3.0-py3-none-any.whl"}}, {"metadata": {"name": "service-identity", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/eb/2433e1af4ff903499144de4846569fb3300b816179ae99a03c2f011b666a/service_identity-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "txaio", "version": "26.6.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/91/68/075bf851e11c9ef65bd6a0426791f0d9a0c7dae0e7f6e0b16ca67334b456/txaio-26.6.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "5.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/88/4f/b03bcc9eaf4621ac9008dec90918d8fb4839d611666cb99eb255696c67fe/ujson-5.13.0-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "zope.interface", "version": "8.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/cbceec44f1b27208a76c1a688c131302685852406a23df5aab68324109cc/zope_interface-8.5-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "py", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "b0d4ec08daf07a9aba63eb1306f8fbf7"} +{"python_version": "3.12", "dependencies": [{"metadata": {"name": "Django", "version": "4.2.30"}, "download_info": {"url": "https://files.pythonhosted.org/packages/39/b7/a7c96f239cf91313a6589233fed55111c7063b26683b226802732c455dbc/django-4.2.30-py3-none-any.whl"}}, {"metadata": {"name": "asgiref", "version": "3.11.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5c/0a/a72d10ed65068e115044937873362e6e32fab1b7dce0046aeb224682c989/asgiref-3.11.1-py3-none-any.whl"}}, {"metadata": {"name": "psycopg2-binary", "version": "2.9.12"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b5/01/3dd14e46ba48c1e1a6ec58ee599fa1b5efa00c246d5046cd903d0eeb1af1/psycopg2_binary-2.9.12-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "djangorestframework", "version": "3.17.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5a/e1/2c516bdc83652b1a60c6119366ac2c0607b479ed05cd6093f916ca8928f8/djangorestframework-3.17.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-django", "version": "4.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/83/a5/41d091f697c09609e7ef1d5d61925494e0454ebf51de7de05f0f0a728f1d/pytest_django-4.12.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/af/9c0bda43e486a3c9bf1e0f876d0f241bc3f229d7d65d09331a0868db9629/pytest_forked-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "channels", "version": "4.3.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/16/34/c32915288b7ef482377b6adc401192f98c6a99b3a145423d3b8aed807898/channels-4.3.2-py3-none-any.whl"}}, {"metadata": {"name": "executing", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "daphne", "version": "4.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/ab/85534d9cbca09f3c10f58fc2093659062280ed5703707c0b41dbca8ec297/daphne-4.2.2-py3-none-any.whl"}}, {"metadata": {"name": "autobahn", "version": "26.6.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/c2/fbb5f752235e8c91167b9071b060981395c6e26d9a6607756e46b7d94e1d/autobahn-26.6.2-cp312-cp312-macosx_15_0_arm64.whl"}}, {"metadata": {"name": "cbor2", "version": "6.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/31/16/cff14259c3d19a7f0ae88b6996fe4c85f6ff1764dad889ac8a39e843e39c/cbor2-6.1.3-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/22/adf66990e63584a68dfb50c24f48a125c07b1699899381c8151e63ed458c/cryptography-49.0.0-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "hyperlink", "version": "21.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/aa/8caf6a0a3e62863cbb9dab27135660acba46903b703e224f14f447e57934/hyperlink-21.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "msgpack", "version": "1.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/2e/ebdb85a8da151397a2790363676b7ed7c125924fe618e4c6d8befb0cc62c/msgpack-1.2.1-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "sqlparse", "version": "0.5.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/4b/359f28a903c13438ef59ebeee215fb25da53066db67b305c125f1c6d2a25/sqlparse-0.5.5-py3-none-any.whl"}}, {"metadata": {"name": "Twisted", "version": "26.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/57/bcf4e2370dd218c9aa68a9140a65d86729c73f1d529f7e94786c2766fc72/twisted-26.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "Automat", "version": "25.4.16"}, "download_info": {"url": "https://files.pythonhosted.org/packages/02/ff/1175b0b7371e46244032d43a56862d0af455823b5280a50c63d99cc50f18/automat-25.4.16-py3-none-any.whl"}}, {"metadata": {"name": "constantly", "version": "23.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b8/40/c199d095151addf69efdb4b9ca3a4f20f70e20508d6222bffb9b76f58573/constantly-23.10.4-py3-none-any.whl"}}, {"metadata": {"name": "Incremental", "version": "24.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1d/55/0f4df2a44053867ea9cbea73fc588b03c55605cd695cee0a3d86f0029cb2/incremental-24.11.0-py3-none-any.whl"}}, {"metadata": {"name": "pyOpenSSL", "version": "26.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/18/1dd71c9b43192ab83f1d531ad6002dc81108ac36c475f79fb7a295abe2f4/pyopenssl-26.3.0-py3-none-any.whl"}}, {"metadata": {"name": "service-identity", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/eb/2433e1af4ff903499144de4846569fb3300b816179ae99a03c2f011b666a/service_identity-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "txaio", "version": "26.6.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/91/68/075bf851e11c9ef65bd6a0426791f0d9a0c7dae0e7f6e0b16ca67334b456/txaio-26.6.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "5.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/88/4f/b03bcc9eaf4621ac9008dec90918d8fb4839d611666cb99eb255696c67fe/ujson-5.13.0-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "zope.interface", "version": "8.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/cbceec44f1b27208a76c1a688c131302685852406a23df5aab68324109cc/zope_interface-8.5-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "py", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "b0d4ec08daf07a9aba63eb1306f8fbf7"} {"python_version": "3.12", "dependencies": [{"metadata": {"name": "Django", "version": "4.2.30"}, "download_info": {"url": "https://files.pythonhosted.org/packages/39/b7/a7c96f239cf91313a6589233fed55111c7063b26683b226802732c455dbc/django-4.2.30-py3-none-any.whl"}}, {"metadata": {"name": "asgiref", "version": "3.11.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5c/0a/a72d10ed65068e115044937873362e6e32fab1b7dce0046aeb224682c989/asgiref-3.11.1-py3-none-any.whl"}}, {"metadata": {"name": "psycopg2-binary", "version": "2.9.12"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b5/01/3dd14e46ba48c1e1a6ec58ee599fa1b5efa00c246d5046cd903d0eeb1af1/psycopg2_binary-2.9.12-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "djangorestframework", "version": "3.17.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5a/e1/2c516bdc83652b1a60c6119366ac2c0607b479ed05cd6093f916ca8928f8/djangorestframework-3.17.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-django", "version": "4.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/83/a5/41d091f697c09609e7ef1d5d61925494e0454ebf51de7de05f0f0a728f1d/pytest_django-4.12.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/af/9c0bda43e486a3c9bf1e0f876d0f241bc3f229d7d65d09331a0868db9629/pytest_forked-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "channels", "version": "4.3.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/16/34/c32915288b7ef482377b6adc401192f98c6a99b3a145423d3b8aed807898/channels-4.3.2-py3-none-any.whl"}}, {"metadata": {"name": "executing", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "daphne", "version": "4.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/ab/85534d9cbca09f3c10f58fc2093659062280ed5703707c0b41dbca8ec297/daphne-4.2.2-py3-none-any.whl"}}, {"metadata": {"name": "autobahn", "version": "26.6.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/c2/fbb5f752235e8c91167b9071b060981395c6e26d9a6607756e46b7d94e1d/autobahn-26.6.2-cp312-cp312-macosx_15_0_arm64.whl"}}, {"metadata": {"name": "cbor2", "version": "6.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/31/16/cff14259c3d19a7f0ae88b6996fe4c85f6ff1764dad889ac8a39e843e39c/cbor2-6.1.3-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/22/adf66990e63584a68dfb50c24f48a125c07b1699899381c8151e63ed458c/cryptography-49.0.0-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "hyperlink", "version": "21.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/aa/8caf6a0a3e62863cbb9dab27135660acba46903b703e224f14f447e57934/hyperlink-21.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "msgpack", "version": "1.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/2e/ebdb85a8da151397a2790363676b7ed7c125924fe618e4c6d8befb0cc62c/msgpack-1.2.1-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "sqlparse", "version": "0.5.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/4b/359f28a903c13438ef59ebeee215fb25da53066db67b305c125f1c6d2a25/sqlparse-0.5.5-py3-none-any.whl"}}, {"metadata": {"name": "Twisted", "version": "26.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/57/bcf4e2370dd218c9aa68a9140a65d86729c73f1d529f7e94786c2766fc72/twisted-26.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "Automat", "version": "25.4.16"}, "download_info": {"url": "https://files.pythonhosted.org/packages/02/ff/1175b0b7371e46244032d43a56862d0af455823b5280a50c63d99cc50f18/automat-25.4.16-py3-none-any.whl"}}, {"metadata": {"name": "constantly", "version": "23.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b8/40/c199d095151addf69efdb4b9ca3a4f20f70e20508d6222bffb9b76f58573/constantly-23.10.4-py3-none-any.whl"}}, {"metadata": {"name": "Incremental", "version": "24.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1d/55/0f4df2a44053867ea9cbea73fc588b03c55605cd695cee0a3d86f0029cb2/incremental-24.11.0-py3-none-any.whl"}}, {"metadata": {"name": "pyOpenSSL", "version": "26.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/18/1dd71c9b43192ab83f1d531ad6002dc81108ac36c475f79fb7a295abe2f4/pyopenssl-26.3.0-py3-none-any.whl"}}, {"metadata": {"name": "service-identity", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/eb/2433e1af4ff903499144de4846569fb3300b816179ae99a03c2f011b666a/service_identity-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "txaio", "version": "26.6.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/91/68/075bf851e11c9ef65bd6a0426791f0d9a0c7dae0e7f6e0b16ca67334b456/txaio-26.6.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "5.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/88/4f/b03bcc9eaf4621ac9008dec90918d8fb4839d611666cb99eb255696c67fe/ujson-5.13.0-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "zope.interface", "version": "8.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/cbceec44f1b27208a76c1a688c131302685852406a23df5aab68324109cc/zope_interface-8.5-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "py", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "b0d4ec08daf07a9aba63eb1306f8fbf7"} {"python_version": "3.12", "dependencies": [{"metadata": {"name": "tornado", "version": "6.5.10"}, "download_info": {"url": "https://files.pythonhosted.org/packages/60/33/df6d7d04854a58619f8349a51e3edb138324130a7562b0bb21f115bb940f/tornado-6.5.10-cp39-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}], "install_targets_hash": "b29e9ff3837ebc143e8b2f14e7600a10"} {"python_version": "3.12", "dependencies": [{"metadata": {"name": "litellm", "version": "1.77.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/86/50/53df2244d4aca2af73d2f2c6ad21c731cf24bd0dbe89d896184a1eaa874f/litellm-1.77.7-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/95/6195171e385007300f0f5574592e467c568becce2d937a0b6804f218bc49/pydantic_core-2.46.4-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anthropic", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/5b/db4a854aebf5d33a5ab714c46af6eb85ee44f390ed29b7b325c00b9f11ed/anthropic-1.0.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/95/411ba65569158e862368917aaf56597f3e5fa3b91b0502919638465a08f3/httpx2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/74/d370e55600d9bcfa0d9794b0166126d49291a3d2b20c268fc98c453a4948/httpcore2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/2e/34957c2c1b661c252ba9bcc60ae0bddc27e0f7202c6073326a13c5390eec/jiter-0.16.0-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "google-genai", "version": "2.19.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/e8/de0accd8cd004cf11252ca53fc5c3dda59bcf1856abfc7609842ceba7363/google_genai-2.19.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.56.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/b3/6117b2f24065cd7e2c4f140e9a193e215f089ca8ba314cf91eb9d0b7fe0a/google_auth-2.56.3-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/27/78873dc8b6a56357517b74b6bb9568b80450e7bb4f6ef7e3fa9d22aa0bd7/charset_normalizer-3.5.1-cp312-cp312-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/73/e3/fe2d498c64dea0095c9a9f9a351af4cd6eef31b618395582bc1f38ba45ff/websockets-16.1.1-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/07/4bbc222cc8dbe31d4c3e8a5baad2286e4d42026ac0c570027b89afce6344/aiohttp-3.14.3-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/65/1caac9d4cd32e8433908683446eebc953e82d22b03d10d41a5f0fefe991b/multidict-6.7.1-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ea/b4/05b4131c407006cd1e410e9c6539f16a0945724677e5364447313c15ea3e/yarl-1.24.5-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/5c/59086b4aac5e879d38ddbcf74e4be7ade89cebc3eb199a55da998c3bb46a/cryptography-50.0.0-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/7d/16e5a096677b5e313ca80cd5e5170efa3ea44624a82bb111925522da64b1/cffi-2.1.1-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "fastuuid", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/ea/682551030f8c4fa9a769d9825570ad28c0c71e30cf34020b85c1f7ee7382/fastuuid-0.14.0-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2b/94/5c8a2b50a496b11dd519f4a24cb5496cf125681dd99e94c604ccdea9419a/frozenlist-1.8.0-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "9.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/38/3d/2d244233ac4f76e38533cfcb2991c9eb4c7bf688ae0a036d30725b8faafe/importlib_metadata-9.0.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "openai", "version": "3.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6a/db/2b7a1b3de659bb82aef979116c74e809982b13e42c057759767552b5155f/openai-3.3.1-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/7d/49777a3e20b55863d4794384a38acd460c04157b0a00f8602b0d508b8431/propcache-0.5.2-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/3b/6163796d69c3977d1e4287bea4a6979161cbbdd170ebb430511e8e1999ce/pyasn1-0.6.4-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a4/73/319dfa745dd668efe89309141ded489126461fcecd2b8f3a3cda185129b6/rpds_py-2026.6.3-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/9f/fe6b1aca23331aa5271df5a4bd07bf68a7059254d47faee1b8272592a777/tiktoken-0.14.0-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "zipp", "version": "4.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.7.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/63/4cab4d7f2d384a144d420b763d97674cb70619c878ea6fcd7640d0e62143/regex-2026.7.19-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tokenizers", "version": "0.23.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e2/6a/068ed9f6e444c9d7e9d55ce134181325700f3d7f30410721bdc8f848d727/tokenizers-0.23.1-cp310-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "huggingface_hub", "version": "1.28.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/0e/eafef18f1a75e125e68395db21131db0cf868a128ecd2fce69b4df6c584b/huggingface_hub-1.28.0-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/69/55b8dcf636142ae660fec1869fcac14c4da2e8412e14d6eee1523be77e9f/hf_xet-1.6.0-cp38-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "filelock", "version": "3.32.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/a4/9b63d595d748e3aff8812b65eacc1a2c4bd90b7c2012e08e72373b4835eb/filelock-3.32.4-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/3c/6a2bf344106328fd04963664a60b9bb6496fc25df8e962fcdc1367285fb9/fsspec-2026.7.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}], "install_targets_hash": "b512ff6d7a8009ab10bb0b7c9175af2f"} {"python_version": "3.12", "dependencies": [{"metadata": {"name": "UnleashClient", "version": "6.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bb/50/af45e97a42056036c4ca7f27ffebcaa01051bd4e9cb07bf4bd40370db316/UnleashClient-6.0.1-py3-none-any.whl"}}, {"metadata": {"name": "APScheduler", "version": "3.11.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/42/c9/8638db32514dbb9157b3d82680c6faea89283523edf9ed2415ea3884f2ae/apscheduler-3.11.3-py3-none-any.whl"}}, {"metadata": {"name": "semver", "version": "3.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/24/4d91e05817e92e3a61c8a21e08fd0f390f5301f1c448b137c57c4bc6e543/semver-3.0.4-py3-none-any.whl"}}, {"metadata": {"name": "tzlocal", "version": "5.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/a4/017a7a6cbe387d961a688ec31364ae60a5c4e22c96ae9921b79a947c855d/tzlocal-5.4.4-py3-none-any.whl"}}, {"metadata": {"name": "fcache", "version": "0.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/84/0c/ababd9fed96d865463f95f897c48a8781bc831f9e08cdc8124b96964f92c/fcache-0.6.0-py3-none-any.whl"}}, {"metadata": {"name": "platformdirs", "version": "3.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/29/3ec311dc18804409ecf0d2b09caa976f3ae6215559306b5b530004e11156/platformdirs-3.11.0-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "9.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/38/3d/2d244233ac4f76e38533cfcb2991c9eb4c7bf688ae0a036d30725b8faafe/importlib_metadata-9.0.0-py3-none-any.whl"}}, {"metadata": {"name": "zipp", "version": "4.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl"}}, {"metadata": {"name": "mmh3", "version": "5.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8b/72/e6d6602ce18adf4ddcd0e48f2e13590cc92a536199e52109f46f259d3c46/mmh3-5.2.1-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/eb/4fc8d0a7110eb5fc9cc161723a34a8a6c200ce3b4fbf681bc86feee22308/charset_normalizer-3.4.7-cp312-cp312-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "yggdrasil-engine", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/5d/952ef9374c364f7e2a14ee56643ff93b4e24ca2607760cffa67e5c16b030/yggdrasil_engine-1.3.1-cp312-abi3-macosx_11_0_arm64.whl"}}], "install_targets_hash": "c2145685d6e6c9355d7ce6f85ea7980a"} {"python_version": "3.12", "dependencies": [{"metadata": {"name": "graphene", "version": "3.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/66/e0/61d8e98007182e6b2aca7cf65904721fb2e4bce0192272ab9cb6f69d8812/graphene-3.4.3-py2.py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/15/b92b4e1d88d02c6eff9733c9eea21846ab435cc4d813d84ccc5d335955df/graphql_core-3.2.11-py3-none-any.whl"}}, {"metadata": {"name": "graphql-relay", "version": "3.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/74/16/a4cf06adbc711bd364a73ce043b0b08d8fa5aae3df11b6ee4248bcdad2e0/graphql_relay-3.2.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "fastapi", "version": "0.139.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/7c/8e3c6ad324ea5cb36604fc3f968554887891c316d9dfde57761611d907ad/fastapi-0.139.0-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/95/6195171e385007300f0f5574592e467c568becce2d937a0b6804f218bc49/pydantic_core-2.46.4-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}], "install_targets_hash": "c463e15a33bbefa7213f58e7f8b31591"} -{"python_version": "3.12", "dependencies": [{"metadata": {"name": "fastmcp", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ac/14/6d950459cc831fa17fe2d1797926b6eb2d2f2af50f830e62d0c098cc1ec8/fastmcp-3.4.7-py3-none-any.whl"}}, {"metadata": {"name": "fastmcp-slim", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b4/97/e0e53642cd029a9a7635ae9c548f9f2cc995af5914e487b3df795664e4be/fastmcp_slim-3.4.7-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "mcp", "version": "1.29.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/c8/248b201f6d753d69fd5d6506011abbb35a946d9142b2ae311a948fd0be3d/mcp-1.29.0-py3-none-any.whl"}}, {"metadata": {"name": "py-key-value-aio", "version": "0.4.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/95/b8ba862968712caa12a19666175334fa979e1f198b896a430adb3bacfe87/py_key_value_aio-0.4.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/95/6195171e385007300f0f5574592e467c568becce2d937a0b6804f218bc49/pydantic_core-2.46.4-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofile", "version": "3.12.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/79/6e45e778c4c3cab39e0937b007b720c15f76c50c6453d153282d0fcc3588/aiofile-3.12.3-py3-none-any.whl"}}, {"metadata": {"name": "caio", "version": "0.12.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/60/bc/b62bf048a6e11870291a24319ed027bdf658df9ba77d1ad762aa138e066b/caio-0.12.2-cp312-cp312-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "Authlib", "version": "1.7.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/95/adcb68e20c34162e9135f370d6e31737719c2b6f94bc953fe7ed1f10fe21/authlib-1.7.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "beartype", "version": "0.22.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/cc/18245721fa7747065ab478316c7fea7c74777d07f37ae60db2e84f8172e8/beartype-0.22.9-py3-none-any.whl"}}, {"metadata": {"name": "cachetools", "version": "7.1.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e4/d8/767faeda872075724b95dd675466a645f1b92aadcdcf2d1429dcfd76c176/cachetools-7.1.7-py3-none-any.whl"}}, {"metadata": {"name": "cyclopts", "version": "4.23.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/35/40/c17d731af4ddbf6dede1f1acb09e6335c2587e8b73b3d4742f3f9c6996d3/cyclopts-4.23.2-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "rich-rst", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/68/1fc93dd759605b5d00fc98b50200739e41ed32bd22d6ba35ca6c3932371b/rich_rst-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "griffelib", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/b6/f65ac785d4ac90dcf7c831ac6256f5dd4a19780f4e1575b2c0d6eeebe319/griffelib-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "joserfc", "version": "1.7.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/bf/249dcd99b3376375910b7fa922383b57792975c8758f50d44612e749226c/joserfc-1.7.4-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/5c/59086b4aac5e879d38ddbcf74e4be7ade89cebc3eb199a55da998c3bb46a/cryptography-50.0.0-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/7d/16e5a096677b5e313ca80cd5e5170efa3ea44624a82bb111925522da64b1/cffi-2.1.1-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "jsonref", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/ec/e1db9922bceb168197a558a2b8c03a7963f1afe93517ddd3cf99f202f996/jsonref-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-path", "version": "0.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/2c/9e69d73c4297508be9e3b64a970ea3971b3eb8db64ffc5802d40bd25981f/jsonschema_path-0.5.0-py3-none-any.whl"}}, {"metadata": {"name": "pathable", "version": "0.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a2/e8/6d75ffd9784bce2e93d1ae4415649427e39a53bb172d4672b2b59c6f0a7b/pathable-0.6.0-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "keyring", "version": "25.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/db/e655086b7f3a705df045bf0933bdd9c2f79bb3c97bfef1384598bb79a217/keyring-25.7.0-py3-none-any.whl"}}, {"metadata": {"name": "openapi-pydantic", "version": "0.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/cf/03675d8bd8ecbf4445504d8071adab19f5f993676795708e36402ab38263/openapi_pydantic-0.5.1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/6f/a04e900f465ff3221ccc395522503e2d10e79fa21f2723c8e177aae1e0d1/opentelemetry_api-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "platformdirs", "version": "4.11.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/a9/c34aebedd3a4c9afe5101b1b8713710b3fec18087c8a36c35d2f909861bd/platformdirs-4.11.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "email-validator", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "dnspython", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "pyperclip", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/80/fc9d01d5ed37ba4c42ca2b55b4339ae6e200b456be3a1aaddf4a9fa99b8c/pyperclip-1.11.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a4/73/319dfa745dd668efe89309141ded489126461fcecd2b8f3a3cda185129b6/rpds_py-2026.6.3-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/3a/764912c58293d95b6dcdf4cc255f9d10de310580ced547b082eb9d72018c/sse_starlette-3.4.8-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uncalled-for", "version": "0.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a2/40/97cec87c077eb3291fc7905e6633e08b7ca593c57d30238444bcb6bb3d53/uncalled_for-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.52.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/79/4a20b54ab0491485ccd8c077db2d39187c7f12b3e15485d38a7be37c81b4/uvicorn-0.52.4-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "watchfiles", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5f/8f/6af2ea19065c91d8b0ea3516fdfc8c0d349f407e8e9fbf4e5a17360de8ad/watchfiles-1.2.0-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "websockets", "version": "17.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d9/82/123660edc759c225626b3b91952c7625f85c77a8362acbc35a4623120f7d/websockets-17.0.1-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.classes", "version": "3.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/66/b15ce62552d84bbfcec9a4873ab79d993a1dd4edb922cbfccae192bd5b5f/jaraco.classes-3.4.0-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.context", "version": "6.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f2/58/bc8954bda5fcda97bd7c19be11b85f91973d67a706ed4a3aec33e7de22db/jaraco_context-6.1.2-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.functools", "version": "4.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/02/36/ecc85bc96c273dc8a11273ed4782272975e6338d4a3e9228621175edf0e3/jaraco_functools-4.6.0-py3-none-any.whl"}}, {"metadata": {"name": "more-itertools", "version": "11.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/3d/1087453384dbde46a8c7f9356eead2c58be8a7bf156bca40243377c85715/more_itertools-11.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "c7af9a5e09a115592eb42861d20f7b29"} {"python_version": "3.12", "dependencies": [{"metadata": {"name": "litestar", "version": "2.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/dc/4d1018577683918cd24a58228c90833f71f792aafcfffb44905c9062f737/litestar-2.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/eb/4fc8d0a7110eb5fc9cc161723a34a8a6c200ce3b4fbf681bc86feee22308/charset_normalizer-3.4.7-cp312-cp312-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/22/adf66990e63584a68dfb50c24f48a125c07b1699899381c8151e63ed458c/cryptography-49.0.0-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "litestar-htmx", "version": "0.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f2/24/8d99982f0aa9c1cd82073c6232b54a0dbe6797c7d63c0583a6c68ee3ddf2/litestar_htmx-0.5.0-py3-none-any.whl"}}, {"metadata": {"name": "msgspec", "version": "0.21.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6d/81/074612945c0666078f7366f40000013de9f6ba687491d450df699bceebc9/msgspec-0.21.1-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/65/1caac9d4cd32e8433908683446eebc953e82d22b03d10d41a5f0fefe991b/multidict-6.7.1-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multipart", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/ed/e1f03200ee1f0bf4a2b9b72709afefbf5319b68df654e0b84b35c65613ee/multipart-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "polyfactory", "version": "3.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/34/b6f19941adcdaf415b5e8a8d577499f5b6a76b59cbae37f9b125a9ffe9f2/polyfactory-3.3.0-py3-none-any.whl"}}, {"metadata": {"name": "Faker", "version": "40.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/a6/6111b9f13c1564b0e2f5dbeeb611fd00dc731e6add2336f62b798598c73d/faker-40.28.1-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "rich-click", "version": "1.9.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6d/97/a87901aef6b7e7e4a34c6dd6cc17dca8594a592ef9d9dd765fca2b7facf7/rich_click-1.9.8-py3-none-any.whl"}}], "install_targets_hash": "c941d62ccc766bdd0c07683673042ea8"} {"python_version": "3.12", "dependencies": [{"metadata": {"name": "langchain", "version": "0.3.30"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/54/c0775c29bf9ae27c8cbf8484ad600edd2e787a0eacf3a374cb6561613de9/langchain-0.3.30-py3-none-any.whl"}}, {"metadata": {"name": "langchain-core", "version": "0.3.86"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/93/ba19ca54701c6118e68f8785949b6c0eab1df3a5cfa5310508cc86877994/langchain_core-0.3.86-py3-none-any.whl"}}, {"metadata": {"name": "jsonpatch", "version": "1.33"}, "download_info": {"url": "https://files.pythonhosted.org/packages/73/07/02e16ed01e04a374e644b575638ec7987ae846d25ad97bcc9945a3ee4b0e/jsonpatch-1.33-py2.py3-none-any.whl"}}, {"metadata": {"name": "langchain-text-splitters", "version": "0.3.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/0d/41a51b40d24ff0384ec4f7ab8dd3dcea8353c05c973836b5e289f1465d4f/langchain_text_splitters-0.3.11-py3-none-any.whl"}}, {"metadata": {"name": "langsmith", "version": "0.11.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/85/0ad6df25588122760b2b40ec182eafc55532c9e66015c83e16675bd34a29/langsmith-0.11.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "25.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/95/6195171e385007300f0f5574592e467c568becce2d937a0b6804f218bc49/pydantic_core-2.46.4-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/27/78873dc8b6a56357517b74b6bb9568b80450e7bb4f6ef7e3fa9d22aa0bd7/charset_normalizer-3.5.1-cp312-cp312-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "SQLAlchemy", "version": "2.0.52"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/d5/1b77a026d161f98a08f11af1a5f6c47b98ee7c7e2648af525a1004826c78/sqlalchemy-2.0.52-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "uuid_utils", "version": "0.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/80/a7e685968e3cec99d6fe2fb25d0f5726310e1bba356da68c13dfd8b7d140/uuid_utils-0.17.0-cp312-cp312-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/2e/34957c2c1b661c252ba9bcc60ae0bddc27e0f7202c6073326a13c5390eec/jiter-0.16.0-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/9f/fe6b1aca23331aa5271df5a4bd07bf68a7059254d47faee1b8272592a777/tiktoken-0.14.0-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "langchain-openai", "version": "0.3.35"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d8/d5/c90c5478215c20ee71d8feaf676f7ffd78d0568f8c98bd83f81ce7562ed7/langchain_openai-0.3.35-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "2.54.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/a8/bb76c7356de8ad57f59d5ff993d434df0607f07f08bcc9c9a5c275e399c0/openai-2.54.0-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "langchain-community", "version": "0.3.31"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e6/0a/b8848db67ad7c8d4652cb6f4cb78d49b5b5e6e8e51d695d62025aa3f7dbc/langchain_community-0.3.31-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/07/4bbc222cc8dbe31d4c3e8a5baad2286e4d42026ac0c570027b89afce6344/aiohttp-3.14.3-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "dataclasses-json", "version": "0.6.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c3/be/d0d44e092656fe7a06b55e6103cbce807cdbdee17884a5367c68c9860853/dataclasses_json-0.6.7-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "marshmallow", "version": "3.26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/be/2f/5108cb3ee4ba6501748c4908b908e55f42a5b66245b4cfe0c99326e1ef6e/marshmallow-3.26.2-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/65/1caac9d4cd32e8433908683446eebc953e82d22b03d10d41a5f0fefe991b/multidict-6.7.1-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspect", "version": "0.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/f3/107a22063bf27bdccf2024833d3445f4eea42b2e598abfbd46f6a63b6cb0/typing_inspect-0.9.0-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ea/b4/05b4131c407006cd1e410e9c6539f16a0945724677e5364447313c15ea3e/yarl-1.24.5-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2b/94/5c8a2b50a496b11dd519f4a24cb5496cf125681dd99e94c604ccdea9419a/frozenlist-1.8.0-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonpointer", "version": "3.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/6a/a83720e953b1682d2d109d3c2dbb0bc9bf28cc1cbc205be4ef4be5da709d/jsonpointer-3.1.1-py3-none-any.whl"}}, {"metadata": {"name": "mypy_extensions", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "numpy", "version": "2.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f3/f4/29e78102a80601cf034d4e9767022cffeca2c3b4c926e1754572ca95593d/numpy-2.5.2-cp312-cp312-macosx_14_0_arm64.whl"}}, {"metadata": {"name": "orjson", "version": "3.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/29/98/758cf90fbeaaafb7f8141bfac75a432099959f3a2f5db93a412e876415d8/orjson-3.12.0-cp312-cp312-macosx_15_0_arm64.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/7d/49777a3e20b55863d4794384a38acd460c04157b0a00f8602b0d508b8431/propcache-0.5.2-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "17.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d9/82/123660edc759c225626b3b91952c7625f85c77a8362acbc35a4623120f7d/websockets-17.0.1-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "xxhash", "version": "4.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/75/c9/cf736f6db8c3273af18925061572db0d4357818a9ce425f4b5fb0021918e/xxhash-4.0.1-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "zstandard", "version": "0.25.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/aa/1c/d920d64b22f8dd028a8b90e2d756e431a5d86194caa78e3819c7bf53b4b3/zstandard-0.25.0-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "regex", "version": "2026.7.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/63/4cab4d7f2d384a144d420b763d97674cb70619c878ea6fcd7640d0e62143/regex-2026.7.19-cp312-cp312-macosx_11_0_arm64.whl"}}], "install_targets_hash": "cf8681468fca1e6ce2b515327a36b948"} {"python_version": "3.12", "dependencies": [{"metadata": {"name": "openai", "version": "1.109.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1d/2a/7dd3d207ec669cacc1f186fd856a0f61dbc255d24f6fdc1a6715d6051b0f/openai-1.109.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/2e/34957c2c1b661c252ba9bcc60ae0bddc27e0f7202c6073326a13c5390eec/jiter-0.16.0-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/95/6195171e385007300f0f5574592e467c568becce2d937a0b6804f218bc49/pydantic_core-2.46.4-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "d84808ce0b2029981b5c45613f25aa8b"} @@ -184,29 +321,52 @@ {"python_version": "3.12", "dependencies": [{"metadata": {"name": "litellm", "version": "1.83.14"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/5c/1b5691575420135e90578543b2bf219497caa33cfd0af64cb38f30288450/litellm-1.83.14-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fa/f9/a5ede193c08f13cc42c0a5b50d1e246ecee9115e4cf6e900d8dbd8fd6acb/aiohttp-3.13.4-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "click", "version": "8.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl"}}, {"metadata": {"name": "fastuuid", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/ea/682551030f8c4fa9a769d9825570ad28c0c71e30cf34020b85c1f7ee7382/fastuuid-0.14.0-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/d9/a1e041c5e7caa9a05c925f4bdbdfb7f006d1f74996af53467bc394c97be7/importlib_metadata-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.23.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/4a/4f9dbeb84e8850557c02365a0eee0649abe5eb1d84af92a25731c6c0f922/jsonschema-4.23.0-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "2.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c9/30/844dc675ee6902579b8eef01ed23917cc9319a1c9c0c14ec6e39340c96d0/openai-2.24.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.12.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.41.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/aa/32/9c2e8ccb57c01111e0fd091f236c7b371c1bccea0fa85247ac55b1e2b6b6/pydantic_core-2.41.5-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4a/42/6573e9129bc55c9bf7300b3a35bef2c6b9117018acca0dc760ac2d93dffe/tiktoken-0.12.0-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tokenizers", "version": "0.22.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2e/47/174dca0502ef88b28f1c9e06b73ce33500eedfac7a7692108aec220464e7/tokenizers-0.22.2-cp39-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "huggingface_hub", "version": "1.16.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/79/621a7dbb80c70974f73a597275351ebe03ce5bc65cb5f8f4acb5859252bc/huggingface_hub-1.16.1-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/69/55b8dcf636142ae660fec1869fcac14c4da2e8412e14d6eee1523be77e9f/hf_xet-1.6.0-cp38-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/2e/34957c2c1b661c252ba9bcc60ae0bddc27e0f7202c6073326a13c5390eec/jiter-0.16.0-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/65/1caac9d4cd32e8433908683446eebc953e82d22b03d10d41a5f0fefe991b/multidict-6.7.1-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ea/b4/05b4131c407006cd1e410e9c6539f16a0945724677e5364447313c15ea3e/yarl-1.24.5-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anthropic", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/5b/db4a854aebf5d33a5ab714c46af6eb85ee44f390ed29b7b325c00b9f11ed/anthropic-1.0.0-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/95/411ba65569158e862368917aaf56597f3e5fa3b91b0502919638465a08f3/httpx2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/74/d370e55600d9bcfa0d9794b0166126d49291a3d2b20c268fc98c453a4948/httpcore2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "google-genai", "version": "2.19.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/e8/de0accd8cd004cf11252ca53fc5c3dda59bcf1856abfc7609842ceba7363/google_genai-2.19.0-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.56.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/b3/6117b2f24065cd7e2c4f140e9a193e215f089ca8ba314cf91eb9d0b7fe0a/google_auth-2.56.3-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/27/78873dc8b6a56357517b74b6bb9568b80450e7bb4f6ef7e3fa9d22aa0bd7/charset_normalizer-3.5.1-cp312-cp312-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/73/e3/fe2d498c64dea0095c9a9f9a351af4cd6eef31b618395582bc1f38ba45ff/websockets-16.1.1-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/5c/59086b4aac5e879d38ddbcf74e4be7ade89cebc3eb199a55da998c3bb46a/cryptography-50.0.0-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/7d/16e5a096677b5e313ca80cd5e5170efa3ea44624a82bb111925522da64b1/cffi-2.1.1-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "filelock", "version": "3.32.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/a4/9b63d595d748e3aff8812b65eacc1a2c4bd90b7c2012e08e72373b4835eb/filelock-3.32.4-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2b/94/5c8a2b50a496b11dd519f4a24cb5496cf125681dd99e94c604ccdea9419a/frozenlist-1.8.0-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/3c/6a2bf344106328fd04963664a60b9bb6496fc25df8e962fcdc1367285fb9/fsspec-2026.7.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/7d/49777a3e20b55863d4794384a38acd460c04157b0a00f8602b0d508b8431/propcache-0.5.2-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/3b/6163796d69c3977d1e4287bea4a6979161cbbdd170ebb430511e8e1999ce/pyasn1-0.6.4-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.7.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/63/4cab4d7f2d384a144d420b763d97674cb70619c878ea6fcd7640d0e62143/regex-2026.7.19-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a4/73/319dfa745dd668efe89309141ded489126461fcecd2b8f3a3cda185129b6/rpds_py-2026.6.3-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typer", "version": "0.27.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/43/89/9518bc0c3929bee36b3a4a8e3daddd6e03f92f9961c66d4983b837160543/typer-0.27.1-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "shellingham", "version": "1.5.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "zipp", "version": "4.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "e4673157ab58986ef4f81da32839974c"} {"python_version": "3.12", "dependencies": [{"metadata": {"name": "langchain", "version": "0.3.30"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/54/c0775c29bf9ae27c8cbf8484ad600edd2e787a0eacf3a374cb6561613de9/langchain-0.3.30-py3-none-any.whl"}}, {"metadata": {"name": "langchain-core", "version": "0.3.86"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/93/ba19ca54701c6118e68f8785949b6c0eab1df3a5cfa5310508cc86877994/langchain_core-0.3.86-py3-none-any.whl"}}, {"metadata": {"name": "jsonpatch", "version": "1.33"}, "download_info": {"url": "https://files.pythonhosted.org/packages/73/07/02e16ed01e04a374e644b575638ec7987ae846d25ad97bcc9945a3ee4b0e/jsonpatch-1.33-py2.py3-none-any.whl"}}, {"metadata": {"name": "langchain-text-splitters", "version": "0.3.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/0d/41a51b40d24ff0384ec4f7ab8dd3dcea8353c05c973836b5e289f1465d4f/langchain_text_splitters-0.3.11-py3-none-any.whl"}}, {"metadata": {"name": "langsmith", "version": "0.11.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/85/0ad6df25588122760b2b40ec182eafc55532c9e66015c83e16675bd34a29/langsmith-0.11.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "25.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/95/6195171e385007300f0f5574592e467c568becce2d937a0b6804f218bc49/pydantic_core-2.46.4-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/27/78873dc8b6a56357517b74b6bb9568b80450e7bb4f6ef7e3fa9d22aa0bd7/charset_normalizer-3.5.1-cp312-cp312-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "SQLAlchemy", "version": "2.0.52"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/d5/1b77a026d161f98a08f11af1a5f6c47b98ee7c7e2648af525a1004826c78/sqlalchemy-2.0.52-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "uuid_utils", "version": "0.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/80/a7e685968e3cec99d6fe2fb25d0f5726310e1bba356da68c13dfd8b7d140/uuid_utils-0.17.0-cp312-cp312-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/2e/34957c2c1b661c252ba9bcc60ae0bddc27e0f7202c6073326a13c5390eec/jiter-0.16.0-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "langchain-openai", "version": "0.3.35"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d8/d5/c90c5478215c20ee71d8feaf676f7ffd78d0568f8c98bd83f81ce7562ed7/langchain_openai-0.3.35-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "2.54.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/a8/bb76c7356de8ad57f59d5ff993d434df0607f07f08bcc9c9a5c275e399c0/openai-2.54.0-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/9f/fe6b1aca23331aa5271df5a4bd07bf68a7059254d47faee1b8272592a777/tiktoken-0.14.0-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "langchain-community", "version": "0.3.31"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e6/0a/b8848db67ad7c8d4652cb6f4cb78d49b5b5e6e8e51d695d62025aa3f7dbc/langchain_community-0.3.31-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/07/4bbc222cc8dbe31d4c3e8a5baad2286e4d42026ac0c570027b89afce6344/aiohttp-3.14.3-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "dataclasses-json", "version": "0.6.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c3/be/d0d44e092656fe7a06b55e6103cbce807cdbdee17884a5367c68c9860853/dataclasses_json-0.6.7-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "marshmallow", "version": "3.26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/be/2f/5108cb3ee4ba6501748c4908b908e55f42a5b66245b4cfe0c99326e1ef6e/marshmallow-3.26.2-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/65/1caac9d4cd32e8433908683446eebc953e82d22b03d10d41a5f0fefe991b/multidict-6.7.1-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspect", "version": "0.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/f3/107a22063bf27bdccf2024833d3445f4eea42b2e598abfbd46f6a63b6cb0/typing_inspect-0.9.0-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ea/b4/05b4131c407006cd1e410e9c6539f16a0945724677e5364447313c15ea3e/yarl-1.24.5-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2b/94/5c8a2b50a496b11dd519f4a24cb5496cf125681dd99e94c604ccdea9419a/frozenlist-1.8.0-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonpointer", "version": "3.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/6a/a83720e953b1682d2d109d3c2dbb0bc9bf28cc1cbc205be4ef4be5da709d/jsonpointer-3.1.1-py3-none-any.whl"}}, {"metadata": {"name": "mypy_extensions", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "numpy", "version": "2.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f3/f4/29e78102a80601cf034d4e9767022cffeca2c3b4c926e1754572ca95593d/numpy-2.5.2-cp312-cp312-macosx_14_0_arm64.whl"}}, {"metadata": {"name": "orjson", "version": "3.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/29/98/758cf90fbeaaafb7f8141bfac75a432099959f3a2f5db93a412e876415d8/orjson-3.12.0-cp312-cp312-macosx_15_0_arm64.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/7d/49777a3e20b55863d4794384a38acd460c04157b0a00f8602b0d508b8431/propcache-0.5.2-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "17.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d9/82/123660edc759c225626b3b91952c7625f85c77a8362acbc35a4623120f7d/websockets-17.0.1-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "xxhash", "version": "4.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/75/c9/cf736f6db8c3273af18925061572db0d4357818a9ce425f4b5fb0021918e/xxhash-4.0.1-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "zstandard", "version": "0.25.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/aa/1c/d920d64b22f8dd028a8b90e2d756e431a5d86194caa78e3819c7bf53b4b3/zstandard-0.25.0-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "regex", "version": "2026.7.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/63/4cab4d7f2d384a144d420b763d97674cb70619c878ea6fcd7640d0e62143/regex-2026.7.19-cp312-cp312-macosx_11_0_arm64.whl"}}], "install_targets_hash": "f4e4bb9460bd93d74ce9abd6823fc735"} {"python_version": "3.12", "dependencies": [{"metadata": {"name": "openai", "version": "1.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/94/99a674bd1dd3a74d5b679bfdd9e1396f08407f933eb15672207e5a8abf1d/openai-1.0.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/95/6195171e385007300f0f5574592e467c568becce2d937a0b6804f218bc49/pydantic_core-2.46.4-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}], "install_targets_hash": "f61ada90175867ade45a2b9f33f30ae0"} -{"python_version": "3.12", "dependencies": [{"metadata": {"name": "mcp", "version": "1.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c9/82/4d0df23d5ff5bb982a59ad597bc7cb9920f2650278ccefb8e0d85c5ce3d4/mcp-1.15.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/95/6195171e385007300f0f5574592e467c568becce2d937a0b6804f218bc49/pydantic_core-2.46.4-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/77/c1/6e422f34e569cf8e18df68d1939c81c099d2b61e4f7d9621c8a77560799c/pydantic_settings-2.14.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a4/73/319dfa745dd668efe89309141ded489126461fcecd2b8f3a3cda185129b6/rpds_py-2026.6.3-cp312-cp312-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/36/e10c1d1b7ca881d2625db2ec28508578499187bb1c389952c398474e1834/sse_starlette-3.4.6-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.51.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/45/ec/dbb7e5a6b91f86bfb9eb7d2988a2730907b6a729875b949c7f022e8b88fa/uvicorn-0.51.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}], "install_targets_hash": "f86dcfa82da844a490c00542989aac98"} {"python_version": "3.12", "dependencies": [{"metadata": {"name": "redis", "version": "6.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/02/89e2ed7e85db6c93dfa9e8f691c5087df4e3551ab39081a4d7c6d1f90e05/redis-6.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "7.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ff/f6e8b8f39e08547faece4bd80f89d5a8de68a38b2d179cc1c4490ffa3286/pytest-7.4.4-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/4d/e6e40f93031adbf654d34e542bd396e9f3bc1c6209b40c920d58c9e1317a/fakeredis-2.36.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.23.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ee/82/62e2d63639ecb0fbe8a7ee59ef0bc69a4669ec50f6d3459f74ad4e4189a2/pytest_asyncio-0.23.8-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}], "install_targets_hash": "f973477f4ba55b7a5455bcb45caae3a9"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "openai-agents", "version": "0.22.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f8/56/f5d32edb2e890a5dea9824cb76d179cef47c6a5ea8269d3559d092936106/openai_agents-0.22.3-py3-none-any.whl"}}, {"metadata": {"name": "griffelib", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/63/e876e789525063c840ccfa8857febdabd6523bcef9ce7eb979b9305ea895/griffelib-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "mcp", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/ff/8e7eade68b8a28f7da0ed1085544341b51f9c935dbf6b95c76b7edfea6a0/mcp-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mcp-types", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8f/d7/6ffba5d8cd5dd9b8a19478875c50e04945314ba5074e84d749283f27f62d/mcp_types-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "3.16.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/17/72/2b1fe3e303db76ab2ba0c2de2b57822869bcb588db82334d4ff3aea8acf2/openai-3.16.2-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/27/17/91420b156315ae22732f5ee1a7b5725a030aab9dc8fd7dcdacfb4aa588d3/jiter-0.17.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d3/f2/9e4de77a6271e07a76d2d58b11c091a979c191ed2939bf80067568b369d2/pydantic_core-2.46.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/af/63240b0c0248c075c2535a1f1bd992821d8251b9f173abc13329661d09e4/charset_normalizer-3.5.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b5/c2/c676c69444d9db448b3f0a55a98dcc534affce0bce961d9d2f0b8499b10a/websockets-16.1.1-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/6f/a04e900f465ff3221ccc395522503e2d10e79fa21f2723c8e177aae1e0d1/opentelemetry_api-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/97/672cb32ce0dfea44b740cb7b4f97038463b9cf7c0ead1aacf595572851d6/pyjwt-2.14.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/85/66/6ccca4722987ddedaa7fc9c3f4708af7431f5535666c174350830888c6b7/cryptography-50.0.1-cp311-abi3-manylinux_2_34_x86_64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/95/86342356ff5953b3fb06f7ef7c5bee212d45e770abc7218d451b9148313c/cffi-2.1.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/d7/fe978efc2ae50abe48eb7464668ea99f53c010c60aeebb7b35ad27f23661/rpds_py-2026.6.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/6a/2ba3ed4a69babf3afdddf7d8314a48d87562c0a442206bbc2a1b50d5efc0/sse_starlette-3.4.11-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.53.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/76/18/0eea75741ee812e9f598b687619ce2454f6c3a1c5cd21ea990ec6bd26f45/uvicorn-0.53.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "00309e9160aac64c6c329f5b3a40b95e"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "pyreqwest", "version": "0.12.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d9/4b/1aaae81ceca5f7375cd2dc13c3cb5c812f013a7fd6e16fba23c6ebd1c67b/pyreqwest-0.12.4-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}], "install_targets_hash": "00e5416511b26b0d583fe31710cc73eb"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "pyreqwest", "version": "0.12.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d9/4b/1aaae81ceca5f7375cd2dc13c3cb5c812f013a7fd6e16fba23c6ebd1c67b/pyreqwest-0.12.4-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}], "install_targets_hash": "00e5416511b26b0d583fe31710cc73eb"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "litestar", "version": "2.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/ce/4697b547790f23d2fcc37a928d48c38140cf86360e4041ca8177e3367c14/litestar-2.24.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/22/adf66990e63584a68dfb50c24f48a125c07b1699899381c8151e63ed458c/cryptography-49.0.0-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/3b/66777e39d3ae1ddc77ee606be4ec6d8cbd4c801f65e5a1b6f2b11b8346dd/charset_normalizer-3.4.7-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "litestar-htmx", "version": "0.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f2/24/8d99982f0aa9c1cd82073c6232b54a0dbe6797c7d63c0583a6c68ee3ddf2/litestar_htmx-0.5.0-py3-none-any.whl"}}, {"metadata": {"name": "msgspec", "version": "0.21.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bb/40/4476c1bd341418a046c4955aff632ec769315d1e3cb94e6acf86d461f9ed/msgspec-0.21.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/76/55cd7186f498ed080a18440c9013011eb548f77ae1b297206d030eb1180a/multidict-6.7.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multipart", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/ed/e1f03200ee1f0bf4a2b9b72709afefbf5319b68df654e0b84b35c65613ee/multipart-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "polyfactory", "version": "3.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/34/b6f19941adcdaf415b5e8a8d577499f5b6a76b59cbae37f9b125a9ffe9f2/polyfactory-3.3.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "rich-click", "version": "1.9.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6d/97/a87901aef6b7e7e4a34c6dd6cc17dca8594a592ef9d9dd765fca2b7facf7/rich_click-1.9.8-py3-none-any.whl"}}, {"metadata": {"name": "Faker", "version": "40.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/a6/6111b9f13c1564b0e2f5dbeeb611fd00dc731e6add2336f62b798598c73d/faker-40.28.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}], "install_targets_hash": "030c889f2cc15fac775b2cc21c8d01e4"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "litestar", "version": "2.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/ce/4697b547790f23d2fcc37a928d48c38140cf86360e4041ca8177e3367c14/litestar-2.24.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/22/adf66990e63584a68dfb50c24f48a125c07b1699899381c8151e63ed458c/cryptography-49.0.0-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/3b/66777e39d3ae1ddc77ee606be4ec6d8cbd4c801f65e5a1b6f2b11b8346dd/charset_normalizer-3.4.7-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "litestar-htmx", "version": "0.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f2/24/8d99982f0aa9c1cd82073c6232b54a0dbe6797c7d63c0583a6c68ee3ddf2/litestar_htmx-0.5.0-py3-none-any.whl"}}, {"metadata": {"name": "msgspec", "version": "0.21.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bb/40/4476c1bd341418a046c4955aff632ec769315d1e3cb94e6acf86d461f9ed/msgspec-0.21.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/76/55cd7186f498ed080a18440c9013011eb548f77ae1b297206d030eb1180a/multidict-6.7.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multipart", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/ed/e1f03200ee1f0bf4a2b9b72709afefbf5319b68df654e0b84b35c65613ee/multipart-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "polyfactory", "version": "3.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/34/b6f19941adcdaf415b5e8a8d577499f5b6a76b59cbae37f9b125a9ffe9f2/polyfactory-3.3.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "rich-click", "version": "1.9.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6d/97/a87901aef6b7e7e4a34c6dd6cc17dca8594a592ef9d9dd765fca2b7facf7/rich_click-1.9.8-py3-none-any.whl"}}, {"metadata": {"name": "Faker", "version": "40.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/a6/6111b9f13c1564b0e2f5dbeeb611fd00dc731e6add2336f62b798598c73d/faker-40.28.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}], "install_targets_hash": "030c889f2cc15fac775b2cc21c8d01e4"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "litestar", "version": "2.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/ce/4697b547790f23d2fcc37a928d48c38140cf86360e4041ca8177e3367c14/litestar-2.24.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/22/adf66990e63584a68dfb50c24f48a125c07b1699899381c8151e63ed458c/cryptography-49.0.0-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/3b/66777e39d3ae1ddc77ee606be4ec6d8cbd4c801f65e5a1b6f2b11b8346dd/charset_normalizer-3.4.7-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "litestar-htmx", "version": "0.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f2/24/8d99982f0aa9c1cd82073c6232b54a0dbe6797c7d63c0583a6c68ee3ddf2/litestar_htmx-0.5.0-py3-none-any.whl"}}, {"metadata": {"name": "msgspec", "version": "0.21.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bb/40/4476c1bd341418a046c4955aff632ec769315d1e3cb94e6acf86d461f9ed/msgspec-0.21.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/76/55cd7186f498ed080a18440c9013011eb548f77ae1b297206d030eb1180a/multidict-6.7.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multipart", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/ed/e1f03200ee1f0bf4a2b9b72709afefbf5319b68df654e0b84b35c65613ee/multipart-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "polyfactory", "version": "3.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/34/b6f19941adcdaf415b5e8a8d577499f5b6a76b59cbae37f9b125a9ffe9f2/polyfactory-3.3.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "rich-click", "version": "1.9.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6d/97/a87901aef6b7e7e4a34c6dd6cc17dca8594a592ef9d9dd765fca2b7facf7/rich_click-1.9.8-py3-none-any.whl"}}, {"metadata": {"name": "Faker", "version": "40.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/a6/6111b9f13c1564b0e2f5dbeeb611fd00dc731e6add2336f62b798598c73d/faker-40.28.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}], "install_targets_hash": "030c889f2cc15fac775b2cc21c8d01e4"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "pyramid", "version": "2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1f/d4/03a8f9b60b8f2a9198c962d08fd9b657c1c0797cbbde3793babbad200845/pyramid-2.1-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "2.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/f3/22afbdb20cc4654b10c98043414a14057cd27fdba9d4ae61cea596000ba2/Werkzeug-2.0.3-py3-none-any.whl"}}, {"metadata": {"name": "hupper", "version": "1.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/86/7d/3888833e4f5ea56af4a9935066ec09a83228e533d7b8877f65889d706ee4/hupper-1.12.1-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "81.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/e3/c164c88b2e5ce7b24d667b9bd83589cf4f3520d97cad01534cd3c4f55fdb/setuptools-81.0.0-py3-none-any.whl"}}, {"metadata": {"name": "translationstring", "version": "1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3b/98/36187601a15e3d37e9bfcf0e0e1055532b39d044353b06861c3a519737a9/translationstring-1.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "venusian", "version": "3.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5a/4b/34d926eba40db81b204066a60b4efdc5d8867a8efcbfe44d69b634b1c907/venusian-3.1.1-py3-none-any.whl"}}, {"metadata": {"name": "WebOb", "version": "1.8.10"}, "download_info": {"url": "https://files.pythonhosted.org/packages/83/21/fce134877fb6fc6ad3c464e4a07ede0ee9219f705d26a981ae58ea36ca13/webob-1.8.10-py2.py3-none-any.whl"}}, {"metadata": {"name": "zope.deprecation", "version": "6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/ed/da7f8b1c73caf989a0ff7096cc73c59e6c36f35a8f967c51104098602e2d/zope_deprecation-6.0-py3-none-any.whl"}}, {"metadata": {"name": "zope.interface", "version": "8.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/2e/4360c54c465db042cc8fbeeec92abac28b4cedbf6ba63c1f092fd08a190f/zope_interface-8.5-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "plaster", "version": "1.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e7/8b/3f98db1448e3b4d2d142716874a7e02f6101685fdaa0f55a8668e9ffa048/plaster-1.1.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "plaster-pastedeploy", "version": "1.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/30/2d4cf89035c22a89bf0e34dbc50fdc07c42c9bdc90fd972d495257ad2b6e/plaster_pastedeploy-1.0.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "legacy-cgi", "version": "2.6.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8c/7e/e7394eeb49a41cc514b3eb49020223666cbf40d86f5721c2f07871e6d84a/legacy_cgi-2.6.4-py3-none-any.whl"}}, {"metadata": {"name": "PasteDeploy", "version": "3.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/85/30/cdddd9a88969683a59222a6d61cd6dce923977f2e9f9ffba38e1324149cd/PasteDeploy-3.1.0-py3-none-any.whl"}}], "install_targets_hash": "060f93eb8052b63b08924e439967bba6"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "pyramid", "version": "2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1f/d4/03a8f9b60b8f2a9198c962d08fd9b657c1c0797cbbde3793babbad200845/pyramid-2.1-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "2.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/f3/22afbdb20cc4654b10c98043414a14057cd27fdba9d4ae61cea596000ba2/Werkzeug-2.0.3-py3-none-any.whl"}}, {"metadata": {"name": "hupper", "version": "1.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/86/7d/3888833e4f5ea56af4a9935066ec09a83228e533d7b8877f65889d706ee4/hupper-1.12.1-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "81.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/e3/c164c88b2e5ce7b24d667b9bd83589cf4f3520d97cad01534cd3c4f55fdb/setuptools-81.0.0-py3-none-any.whl"}}, {"metadata": {"name": "translationstring", "version": "1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3b/98/36187601a15e3d37e9bfcf0e0e1055532b39d044353b06861c3a519737a9/translationstring-1.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "venusian", "version": "3.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5a/4b/34d926eba40db81b204066a60b4efdc5d8867a8efcbfe44d69b634b1c907/venusian-3.1.1-py3-none-any.whl"}}, {"metadata": {"name": "WebOb", "version": "1.8.10"}, "download_info": {"url": "https://files.pythonhosted.org/packages/83/21/fce134877fb6fc6ad3c464e4a07ede0ee9219f705d26a981ae58ea36ca13/webob-1.8.10-py2.py3-none-any.whl"}}, {"metadata": {"name": "zope.deprecation", "version": "6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/ed/da7f8b1c73caf989a0ff7096cc73c59e6c36f35a8f967c51104098602e2d/zope_deprecation-6.0-py3-none-any.whl"}}, {"metadata": {"name": "zope.interface", "version": "8.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/2e/4360c54c465db042cc8fbeeec92abac28b4cedbf6ba63c1f092fd08a190f/zope_interface-8.5-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "plaster", "version": "1.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e7/8b/3f98db1448e3b4d2d142716874a7e02f6101685fdaa0f55a8668e9ffa048/plaster-1.1.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "plaster-pastedeploy", "version": "1.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/30/2d4cf89035c22a89bf0e34dbc50fdc07c42c9bdc90fd972d495257ad2b6e/plaster_pastedeploy-1.0.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "legacy-cgi", "version": "2.6.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8c/7e/e7394eeb49a41cc514b3eb49020223666cbf40d86f5721c2f07871e6d84a/legacy_cgi-2.6.4-py3-none-any.whl"}}, {"metadata": {"name": "PasteDeploy", "version": "3.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/85/30/cdddd9a88969683a59222a6d61cd6dce923977f2e9f9ffba38e1324149cd/PasteDeploy-3.1.0-py3-none-any.whl"}}], "install_targets_hash": "060f93eb8052b63b08924e439967bba6"} -{"python_version": "3.13", "dependencies": [{"metadata": {"name": "fastapi", "version": "0.121.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/b6/4f620d7720fc0a754c8c1b7501d73777f6ba43b57c8ab99671f4d7441eb8/fastapi-0.121.3-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"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"}}, {"metadata": {"name": "starlette", "version": "0.50.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d9/52/1064f510b141bd54025f9b55105e26d1fa970b9be67ad766380a3c9b74b0/starlette-0.50.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ea/f8/72eb13dcabe7257035cea8aefd922caad2f110d252bf9f67c4c2ca763aee/charset_normalizer-3.4.9-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/21/9b05698b46f218fc0e118e1f8168395c65c8a2c750ae2bab54fc4bd4e0e8/markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}], "install_targets_hash": "07dedda23092a79cd219b98e946eb134"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "boto3", "version": "1.43.99"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/6f/37/d59247c882bc078b73cfa6f6bb247ac51bedc7637f6a8800def385dcfbba/boto3-1.43.99-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.99"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/9a/2a62da42bc8bd55d99e5b9599c112260dfe9872bedf335bdc5a10dbb653a/botocore-1.43.99-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "s3transfer", "version": "0.19.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/bc/e7/5c595c75e9f41a44f30e526eda465ea0b4eec93470e074e4a111b253f13a/s3transfer-0.19.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}], "install_targets_hash": "0757b3ed0bd295834a1bf3155319b4f9"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "cohere", "version": "6.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/b4/00c2f9f8387a2e77faf8410210466c46d55dd30a0388de41c54441b148fb/cohere-6.1.0-py3-none-any.whl"}}, {"metadata": {"name": "fastavro", "version": "1.12.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/83/39/f489a441d41cc9c0a8449fb1325d7a9c9eb57a5634e6ab19dfb0a1105324/fastavro-1.12.2-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.12.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.41.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/02/abfa0e0bda67faa65fef1c84971c7e45928e108fe24333c81f3bfe35d5f5/pydantic_core-2.41.5-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "tokenizers", "version": "0.23.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e2/6a/068ed9f6e444c9d7e9d55ce134181325700f3d7f30410721bdc8f848d727/tokenizers-0.23.1-cp310-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "types-requests", "version": "2.33.0.20260518"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1c/bc/b139710a3b6018f7fb2b9508b35c8af564e61bf2bf4fa619d088f3e16f85/types_requests-2.33.0.20260518-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/3b/66777e39d3ae1ddc77ee606be4ec6d8cbd4c801f65e5a1b6f2b11b8346dd/charset_normalizer-3.4.7-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "huggingface_hub", "version": "1.22.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/9c/a1a377265abd8b823a2c661c665028ccb6b9fba1ca9d08e52ff679c20ecd/huggingface_hub-1.22.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "filelock", "version": "3.29.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4a/e3/f1fae3647d170919c2cf2a898e77e7d1a4e5c7cae0aed7bb4bd3f5ebff6f/filelock-3.29.5-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e5/22/4222d7ddf3da30f363edaa98e329c2bce6c65497c9cb2810931c8b2c0fbc/fsspec-2026.6.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/35/94/4b2ecfbad8f8b04701a23aefb62f540b9137d058b7e1dbef16a32676f0e9/hf_xet-1.5.1-cp37-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tqdm", "version": "4.68.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d8/8e/bb97bb0c71802080bfc8952937d174e49cfc50de5c951dd47b2496f0dcdb/tqdm-4.68.3-py3-none-any.whl"}}], "install_targets_hash": "0ad658fae5aa5a77bc7d2271d7f24fcf"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "cohere", "version": "6.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/b4/00c2f9f8387a2e77faf8410210466c46d55dd30a0388de41c54441b148fb/cohere-6.1.0-py3-none-any.whl"}}, {"metadata": {"name": "fastavro", "version": "1.12.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/83/39/f489a441d41cc9c0a8449fb1325d7a9c9eb57a5634e6ab19dfb0a1105324/fastavro-1.12.2-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.12.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.41.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/02/abfa0e0bda67faa65fef1c84971c7e45928e108fe24333c81f3bfe35d5f5/pydantic_core-2.41.5-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "tokenizers", "version": "0.23.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e2/6a/068ed9f6e444c9d7e9d55ce134181325700f3d7f30410721bdc8f848d727/tokenizers-0.23.1-cp310-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "types-requests", "version": "2.33.0.20260518"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1c/bc/b139710a3b6018f7fb2b9508b35c8af564e61bf2bf4fa619d088f3e16f85/types_requests-2.33.0.20260518-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/3b/66777e39d3ae1ddc77ee606be4ec6d8cbd4c801f65e5a1b6f2b11b8346dd/charset_normalizer-3.4.7-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "huggingface_hub", "version": "1.22.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/9c/a1a377265abd8b823a2c661c665028ccb6b9fba1ca9d08e52ff679c20ecd/huggingface_hub-1.22.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "filelock", "version": "3.29.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4a/e3/f1fae3647d170919c2cf2a898e77e7d1a4e5c7cae0aed7bb4bd3f5ebff6f/filelock-3.29.5-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e5/22/4222d7ddf3da30f363edaa98e329c2bce6c65497c9cb2810931c8b2c0fbc/fsspec-2026.6.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/35/94/4b2ecfbad8f8b04701a23aefb62f540b9137d058b7e1dbef16a32676f0e9/hf_xet-1.5.1-cp37-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tqdm", "version": "4.68.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d8/8e/bb97bb0c71802080bfc8952937d174e49cfc50de5c951dd47b2496f0dcdb/tqdm-4.68.3-py3-none-any.whl"}}], "install_targets_hash": "0ad658fae5aa5a77bc7d2271d7f24fcf"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "cohere", "version": "6.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/9e/b4/00c2f9f8387a2e77faf8410210466c46d55dd30a0388de41c54441b148fb/cohere-6.1.0-py3-none-any.whl"}}, {"metadata": {"name": "fastavro", "version": "1.12.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/83/39/f489a441d41cc9c0a8449fb1325d7a9c9eb57a5634e6ab19dfb0a1105324/fastavro-1.12.2-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a4/a0/562247944386f7d4ef94467e84876600cc1e0f1b93239aaa9213d2bc3cbd/charset_normalizer-3.5.1-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "tokenizers", "version": "0.23.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e2/6a/068ed9f6e444c9d7e9d55ce134181325700f3d7f30410721bdc8f848d727/tokenizers-0.23.1-cp310-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "huggingface_hub", "version": "1.29.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/4e/a5/47c2ea9b228ccbcba8467e9a64823146e8ebbad29855e591d8f5eedcc9c7/huggingface_hub-1.29.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/4b/69/55b8dcf636142ae660fec1869fcac14c4da2e8412e14d6eee1523be77e9f/hf_xet-1.6.0-cp38-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "types-requests", "version": "2.33.0.20260712"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/62/e7/010c87f559e216d83f9dc51e939633fd0d0ead3377340181ab0e223cd3b5/types_requests-2.33.0.20260712-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "filelock", "version": "3.32.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/36/d2/b70a31e13d04456d28493f31d2aa087e99eeb2767ef0293b2625727ccb8c/filelock-3.32.5-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.7.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/fd/3c/6a2bf344106328fd04963664a60b9bb6496fc25df8e962fcdc1367285fb9/fsspec-2026.7.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.12.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.41.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/94/02/abfa0e0bda67faa65fef1c84971c7e45928e108fe24333c81f3bfe35d5f5/pydantic_core-2.41.5-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}], "install_targets_hash": "0ad658fae5aa5a77bc7d2271d7f24fcf"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "openai-agents", "version": "0.10.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e2/07/ad27018fb42d6f1e70f471a5ca3f6398a2159575b623edf86e1ddde66ce4/openai_agents-0.10.5-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "2.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ae/f4/561ed79fd94876160018a5e75254cfcb9b0e62d4dded9dcb20072e86d623/openai-2.44.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "griffe", "version": "1.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/83/3b1d03d36f224edded98e9affd0467630fc09d766c0e56fb1498cbb04a9b/griffe-1.15.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/b1/34bfa29599d420423baac6ff7cada6674fe63d5a7a2ccb3900b904678783/jiter-0.17.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "mcp", "version": "1.30.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f5/f4/e58bc33317c92a0203664daaf00bf6f41166cc0149e5d6870a03f7cd004a/mcp-1.30.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/21/43/6323b1f8b217780454c61304bcd2b38ae4762f50754414124603ccc90bb2/pydantic_core-2.46.5-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/03/921a3d3c75785aca9ebfbfcabfbc3a1be12e2ab5265deb026d55a5a3f83e/tqdm-4.70.1-py3-none-any.whl"}}, {"metadata": {"name": "types-requests", "version": "2.33.0.20260906"}, "download_info": {"url": "https://files.pythonhosted.org/packages/60/4c/51ec821d22a45b4162fa3f3e9e94ea4c0f8c49e82363b10955baa5438391/types_requests-2.33.0.20260906-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a4/a0/562247944386f7d4ef94467e84876600cc1e0f1b93239aaa9213d2bc3cbd/charset_normalizer-3.5.1-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "colorama", "version": "0.4.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/97/672cb32ce0dfea44b740cb7b4f97038463b9cf7c0ead1aacf595572851d6/pyjwt-2.14.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/6a/2ba3ed4a69babf3afdddf7d8314a48d87562c0a442206bbc2a1b50d5efc0/sse_starlette-3.4.11-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.52.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/79/4a20b54ab0491485ccd8c077db2d39187c7f12b3e15485d38a7be37c81b4/uvicorn-0.52.4-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/19/797e2aaac9df6a66f1550f49979dc1b1e39ecd2077501c30efa81e8d5d67/cryptography-50.0.1-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f3/6b/686d9dc4359a8f163cfbbf89ee0b4e586431de22fe8248edb63a8cf50d49/rpds_py-2026.6.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/41/4c7042f317b9217502988f0873af87e16ad606dc20f84e546e3e6ce9764c/cffi-2.1.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "0ce5e787d33b4cfe2c733e90e400524e"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "openai", "version": "2.54.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/a8/bb76c7356de8ad57f59d5ff993d434df0607f07f08bcc9c9a5c275e399c0/openai-2.54.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/5f/6448cfe278c3664ba9ec5b5ac08344341f7dc3d42888476e215a14eda2be/tiktoken-0.14.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d0/2b/c3eaf16f5d7c9bad66ea32f40a95bd169b29a91217fcc7f081375157e99c/jiter-0.16.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/81/4fa520eaffa8bd7d1525e644cd6d39e7d60b1592bc5b516693c7340b50f1/pydantic_core-2.46.4-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.7.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/47/2d0564e93d87bc48618360ddca232a2ca612bbdf53ce8465d45ca5ce14ee/regex-2026.7.19-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a4/a0/562247944386f7d4ef94467e84876600cc1e0f1b93239aaa9213d2bc3cbd/charset_normalizer-3.5.1-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}], "install_targets_hash": "0e0a649708de8e981a20111ea63dbf51"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "openai", "version": "2.54.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/a8/bb76c7356de8ad57f59d5ff993d434df0607f07f08bcc9c9a5c275e399c0/openai-2.54.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/5f/6448cfe278c3664ba9ec5b5ac08344341f7dc3d42888476e215a14eda2be/tiktoken-0.14.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d0/2b/c3eaf16f5d7c9bad66ea32f40a95bd169b29a91217fcc7f081375157e99c/jiter-0.16.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/81/4fa520eaffa8bd7d1525e644cd6d39e7d60b1592bc5b516693c7340b50f1/pydantic_core-2.46.4-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.7.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/47/2d0564e93d87bc48618360ddca232a2ca612bbdf53ce8465d45ca5ce14ee/regex-2026.7.19-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a4/a0/562247944386f7d4ef94467e84876600cc1e0f1b93239aaa9213d2bc3cbd/charset_normalizer-3.5.1-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}], "install_targets_hash": "0e0a649708de8e981a20111ea63dbf51"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "langgraph", "version": "0.6.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/94/430f0341c5c2fe3e3b9f5ab2622f35e2bda12c4a7d655c519468e853d1b0/langgraph-0.6.11-py3-none-any.whl"}}, {"metadata": {"name": "langchain-core", "version": "1.4.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/13/d6/bdf6f0481cc57ef300d6b1eb48cf1400c0409be715d6eb3cabadd1142a09/langchain_core-1.4.8-py3-none-any.whl"}}, {"metadata": {"name": "langgraph-checkpoint", "version": "3.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/48/e3/616e3a7ff737d98c1bbb5700dd62278914e2a9ded09a79a1fa93cf24ce12/langgraph_checkpoint-3.0.1-py3-none-any.whl"}}, {"metadata": {"name": "langgraph-prebuilt", "version": "0.6.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8e/d1/e4727f4822943befc3b7046f79049b1086c9493a34b4d44a1adf78577693/langgraph_prebuilt-0.6.5-py3-none-any.whl"}}, {"metadata": {"name": "langgraph-sdk", "version": "0.2.15"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6b/c9/bf2bff18f85bb7973fa5280838580049574bd7649c36e3dd346c49304997/langgraph_sdk-0.2.15-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/81/4fa520eaffa8bd7d1525e644cd6d39e7d60b1592bc5b516693c7340b50f1/pydantic_core-2.46.4-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "xxhash", "version": "3.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/70/80/c053dc51af5c942229689a0e9cb66fdc999bbd840f645e761f5ab73cbb17/xxhash-3.8.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "jsonpatch", "version": "1.33"}, "download_info": {"url": "https://files.pythonhosted.org/packages/73/07/02e16ed01e04a374e644b575638ec7987ae846d25ad97bcc9945a3ee4b0e/jsonpatch-1.33-py2.py3-none-any.whl"}}, {"metadata": {"name": "langchain-protocol", "version": "0.0.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/2e/d82db9eec13ad0f72e7aaad5c4bc730ab111934fdc83c85523206eb9b0a0/langchain_protocol-0.0.18-py3-none-any.whl"}}, {"metadata": {"name": "langsmith", "version": "0.9.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/95/0abb8647123c9ebbb31162bcdba3183f5f3d3bb2f752ef3d777ab715e88c/langsmith-0.9.7-py3-none-any.whl"}}, {"metadata": {"name": "orjson", "version": "3.11.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8f/27/b1e6dadb3c080313c03fdd8067b85e6a0460c7d8d6a1c3984ef77b904e4d/orjson-3.11.9-cp313-cp313-macosx_15_0_arm64.whl"}}, {"metadata": {"name": "ormsgpack", "version": "1.12.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/29/bb0eba3288c0449efbb013e9c6f58aea79cf5cb9ee1921f8865f04c1a9d7/ormsgpack-1.12.2-cp313-cp313-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "uuid_utils", "version": "0.16.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ed/a1/3b48859953ee74fc26628ca5d9e5f848209655a0a8c934032fc596035976/uuid_utils-0.16.2-cp313-cp313-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "jsonpointer", "version": "3.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/6a/a83720e953b1682d2d109d3c2dbb0bc9bf28cc1cbc205be4ef4be5da709d/jsonpointer-3.1.1-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/aa/82/39a5f910cb99ec0b59e482971238c845af9220d3ab9fa76dd9162cda9d62/websockets-16.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "zstandard", "version": "0.25.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/06/9ae96a3e5dcfd119377ba33d4c42a7d89da1efabd5cb3e366b156c45ff4d/zstandard-0.25.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/3b/66777e39d3ae1ddc77ee606be4ec6d8cbd4c801f65e5a1b6f2b11b8346dd/charset_normalizer-3.4.7-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}], "install_targets_hash": "0ee3a52436b4f61e9cdbe5013bf352c3"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "langgraph", "version": "0.6.11"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/df/94/430f0341c5c2fe3e3b9f5ab2622f35e2bda12c4a7d655c519468e853d1b0/langgraph-0.6.11-py3-none-any.whl"}}, {"metadata": {"name": "langgraph-checkpoint", "version": "3.0.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/48/e3/616e3a7ff737d98c1bbb5700dd62278914e2a9ded09a79a1fa93cf24ce12/langgraph_checkpoint-3.0.1-py3-none-any.whl"}}, {"metadata": {"name": "langgraph-prebuilt", "version": "0.6.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/8e/d1/e4727f4822943befc3b7046f79049b1086c9493a34b4d44a1adf78577693/langgraph_prebuilt-0.6.5-py3-none-any.whl"}}, {"metadata": {"name": "langgraph-sdk", "version": "0.2.15"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/6b/c9/bf2bff18f85bb7973fa5280838580049574bd7649c36e3dd346c49304997/langgraph_sdk-0.2.15-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "langchain-core", "version": "1.6.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/8e/25/f50dd65673c819aa33d3c34df58c115dbb6ec627d19f93e6e401dd0fc8d7/langchain_core-1.6.1-py3-none-any.whl"}}, {"metadata": {"name": "jsonpatch", "version": "1.33"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/73/07/02e16ed01e04a374e644b575638ec7987ae846d25ad97bcc9945a3ee4b0e/jsonpatch-1.33-py2.py3-none-any.whl"}}, {"metadata": {"name": "langsmith", "version": "0.11.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/00/d9/cec0c1d24dda8c67a23ad204d0167e50aee202460e9388488661d94513f5/langsmith-0.11.2-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/21/43/6323b1f8b217780454c61304bcd2b38ae4762f50754414124603ccc90bb2/pydantic_core-2.46.5-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "uuid_utils", "version": "0.17.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/d2/dd/614fb9912157ac0128e6050859ccf06d9f13df9a944a803e8f80f6157e38/uuid_utils-0.17.0-cp313-cp313-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "jsonpointer", "version": "3.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/9e/6a/a83720e953b1682d2d109d3c2dbb0bc9bf28cc1cbc205be4ef4be5da709d/jsonpointer-3.1.1-py3-none-any.whl"}}, {"metadata": {"name": "langchain-protocol", "version": "0.0.19"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/80/c9/f6cbf357d48ccbd18bb394433b1fd7ad9be004eed9377ad08bb85777e5e6/langchain_protocol-0.0.19-py3-none-any.whl"}}, {"metadata": {"name": "orjson", "version": "3.12.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/f8/4a/bc87c45e7ec639d35ebefd62618e01939531ac8e171426606a01bda05914/orjson-3.12.0-cp313-cp313-macosx_15_0_arm64.whl"}}, {"metadata": {"name": "ormsgpack", "version": "1.12.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/eb/29/bb0eba3288c0449efbb013e9c6f58aea79cf5cb9ee1921f8865f04c1a9d7/ormsgpack-1.12.2-cp313-cp313-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a4/a0/562247944386f7d4ef94467e84876600cc1e0f1b93239aaa9213d2bc3cbd/charset_normalizer-3.5.1-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "17.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/46/69/66e5b7d01445e0eeb1d4ab419c30315f2c90cf7a8a8cd4ecc47f894dba54/websockets-17.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "xxhash", "version": "4.0.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/da/e0/934af8d99bb5885711006bec30a691f728edd513d2c40f053f887d8e7577/xxhash-4.0.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "zstandard", "version": "0.25.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/3f/06/9ae96a3e5dcfd119377ba33d4c42a7d89da1efabd5cb3e366b156c45ff4d/zstandard-0.25.0-cp313-cp313-macosx_11_0_arm64.whl"}}], "install_targets_hash": "0ee3a52436b4f61e9cdbe5013bf352c3"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "cohere", "version": "5.21.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0a/50/5538f02ec6d10fbb84f29c1b18c68ff2a03d7877926a80275efdf8755a9f/cohere-5.21.1-py3-none-any.whl"}}, {"metadata": {"name": "fastavro", "version": "1.12.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/83/39/f489a441d41cc9c0a8449fb1325d7a9c9eb57a5634e6ab19dfb0a1105324/fastavro-1.12.2-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/81/4fa520eaffa8bd7d1525e644cd6d39e7d60b1592bc5b516693c7340b50f1/pydantic_core-2.46.4-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "tokenizers", "version": "0.23.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e2/6a/068ed9f6e444c9d7e9d55ce134181325700f3d7f30410721bdc8f848d727/tokenizers-0.23.1-cp310-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "types-requests", "version": "2.33.0.20260518"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1c/bc/b139710a3b6018f7fb2b9508b35c8af564e61bf2bf4fa619d088f3e16f85/types_requests-2.33.0.20260518-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/3b/66777e39d3ae1ddc77ee606be4ec6d8cbd4c801f65e5a1b6f2b11b8346dd/charset_normalizer-3.4.7-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "huggingface_hub", "version": "1.22.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/9c/a1a377265abd8b823a2c661c665028ccb6b9fba1ca9d08e52ff679c20ecd/huggingface_hub-1.22.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "filelock", "version": "3.29.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4a/e3/f1fae3647d170919c2cf2a898e77e7d1a4e5c7cae0aed7bb4bd3f5ebff6f/filelock-3.29.5-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e5/22/4222d7ddf3da30f363edaa98e329c2bce6c65497c9cb2810931c8b2c0fbc/fsspec-2026.6.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/35/94/4b2ecfbad8f8b04701a23aefb62f540b9137d058b7e1dbef16a32676f0e9/hf_xet-1.5.1-cp37-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tqdm", "version": "4.68.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d8/8e/bb97bb0c71802080bfc8952937d174e49cfc50de5c951dd47b2496f0dcdb/tqdm-4.68.3-py3-none-any.whl"}}], "install_targets_hash": "1119e874aeb67089151365fd5430145a"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "cohere", "version": "5.21.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0a/50/5538f02ec6d10fbb84f29c1b18c68ff2a03d7877926a80275efdf8755a9f/cohere-5.21.1-py3-none-any.whl"}}, {"metadata": {"name": "fastavro", "version": "1.12.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/83/39/f489a441d41cc9c0a8449fb1325d7a9c9eb57a5634e6ab19dfb0a1105324/fastavro-1.12.2-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a4/a0/562247944386f7d4ef94467e84876600cc1e0f1b93239aaa9213d2bc3cbd/charset_normalizer-3.5.1-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "tokenizers", "version": "0.23.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e2/6a/068ed9f6e444c9d7e9d55ce134181325700f3d7f30410721bdc8f848d727/tokenizers-0.23.1-cp310-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "huggingface_hub", "version": "1.29.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/4e/a5/47c2ea9b228ccbcba8467e9a64823146e8ebbad29855e591d8f5eedcc9c7/huggingface_hub-1.29.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/4b/69/55b8dcf636142ae660fec1869fcac14c4da2e8412e14d6eee1523be77e9f/hf_xet-1.6.0-cp38-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "types-requests", "version": "2.33.0.20260712"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/62/e7/010c87f559e216d83f9dc51e939633fd0d0ead3377340181ab0e223cd3b5/types_requests-2.33.0.20260712-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "filelock", "version": "3.32.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/36/d2/b70a31e13d04456d28493f31d2aa087e99eeb2767ef0293b2625727ccb8c/filelock-3.32.5-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.7.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/fd/3c/6a2bf344106328fd04963664a60b9bb6496fc25df8e962fcdc1367285fb9/fsspec-2026.7.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/21/43/6323b1f8b217780454c61304bcd2b38ae4762f50754414124603ccc90bb2/pydantic_core-2.46.5-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}], "install_targets_hash": "1119e874aeb67089151365fd5430145a"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "openfeature-sdk", "version": "0.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/44/8a4f5225e930ff0d999fd43f5d743a4babeb6c7e76dddc00f0e118878ef3/openfeature_sdk-0.10.0-py3-none-any.whl"}}], "install_targets_hash": "113a6c8b15a3b8283663d37f7b69e71e"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "openfeature-sdk", "version": "0.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/44/8a4f5225e930ff0d999fd43f5d743a4babeb6c7e76dddc00f0e118878ef3/openfeature_sdk-0.10.0-py3-none-any.whl"}}], "install_targets_hash": "113a6c8b15a3b8283663d37f7b69e71e"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "fastapi", "version": "0.123.10"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/f0/7cb92c4a720def85240fd63fbbcf147ce19e7a731c8e1032376bb5a486ac/fastapi-0.123.10-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/81/4fa520eaffa8bd7d1525e644cd6d39e7d60b1592bc5b516693c7340b50f1/pydantic_core-2.46.4-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "starlette", "version": "0.50.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d9/52/1064f510b141bd54025f9b55105e26d1fa970b9be67ad766380a3c9b74b0/starlette-0.50.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b2/06/97ec2aeae780b31d742b6352218b43841a6871e2564578ca522dce4a45c3/charset_normalizer-3.4.9-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}], "install_targets_hash": "11d8ddfacb08ef9d446aa4936e0d4ecd"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "redis", "version": "7.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4a/2e/2677f3f93dae0497e7e33b6637302e7f3744efc553f34231183e32584885/redis-7.4.1-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/4d/e6e40f93031adbf654d34e542bd396e9f3bc1c6209b40c920d58c9e1317a/fakeredis-2.36.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "7.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ff/f6e8b8f39e08547faece4bd80f89d5a8de68a38b2d179cc1c4490ffa3286/pytest-7.4.4-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.23.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ee/82/62e2d63639ecb0fbe8a7ee59ef0bc69a4669ec50f6d3459f74ad4e4189a2/pytest_asyncio-0.23.8-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}], "install_targets_hash": "186c82b63ae560049b87efb5870e7d53"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "redis", "version": "7.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4a/2e/2677f3f93dae0497e7e33b6637302e7f3744efc553f34231183e32584885/redis-7.4.1-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/4d/e6e40f93031adbf654d34e542bd396e9f3bc1c6209b40c920d58c9e1317a/fakeredis-2.36.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "7.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ff/f6e8b8f39e08547faece4bd80f89d5a8de68a38b2d179cc1c4490ffa3286/pytest-7.4.4-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.23.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ee/82/62e2d63639ecb0fbe8a7ee59ef0bc69a4669ec50f6d3459f74ad4e4189a2/pytest_asyncio-0.23.8-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}], "install_targets_hash": "186c82b63ae560049b87efb5870e7d53"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "redis", "version": "7.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4a/2e/2677f3f93dae0497e7e33b6637302e7f3744efc553f34231183e32584885/redis-7.4.1-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/4d/e6e40f93031adbf654d34e542bd396e9f3bc1c6209b40c920d58c9e1317a/fakeredis-2.36.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "7.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ff/f6e8b8f39e08547faece4bd80f89d5a8de68a38b2d179cc1c4490ffa3286/pytest-7.4.4-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.23.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ee/82/62e2d63639ecb0fbe8a7ee59ef0bc69a4669ec50f6d3459f74ad4e4189a2/pytest_asyncio-0.23.8-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}], "install_targets_hash": "186c82b63ae560049b87efb5870e7d53"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "redis", "version": "7.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4a/2e/2677f3f93dae0497e7e33b6637302e7f3744efc553f34231183e32584885/redis-7.4.1-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/4d/e6e40f93031adbf654d34e542bd396e9f3bc1c6209b40c920d58c9e1317a/fakeredis-2.36.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "7.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ff/f6e8b8f39e08547faece4bd80f89d5a8de68a38b2d179cc1c4490ffa3286/pytest-7.4.4-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.23.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ee/82/62e2d63639ecb0fbe8a7ee59ef0bc69a4669ec50f6d3459f74ad4e4189a2/pytest_asyncio-0.23.8-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}], "install_targets_hash": "186c82b63ae560049b87efb5870e7d53"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "Quart", "version": "0.19.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/01/e5d6127f6304c7e596e5c8eec5accdec0f698ec65fe342d8474ad5223717/quart-0.19.9-py3-none-any.whl"}}, {"metadata": {"name": "quart-auth", "version": "0.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/a3/8ca9235569f39e471a9a319ba1665a27cb9cea8c48c688966460db67d48f/quart_auth-0.11.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/af/9c0bda43e486a3c9bf1e0f876d0f241bc3f229d7d65d09331a0868db9629/pytest_forked-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "quart-flask-patch", "version": "0.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/ce/ad2b19e3a26d2c611aa883b8500e8b4eb08f8a2d1595e28c37864e54e99c/quart_flask_patch-0.3.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "Hypercorn", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/35/850277d1b17b206bd10874c8a9a3f52e059452fb49bb0d22cbb908f6038b/hypercorn-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "h2", "version": "4.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/22/e85faf23bd72a92d1921e37d674ca56eb298a3c8be31fdecef0ff2b3aaac/h2-4.4.1-py3-none-any.whl"}}, {"metadata": {"name": "hpack", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/b4/4a9fcfb2aef6ba44d9073ecd301443aa00b3dac95de5619f2a7de7ec8a91/hpack-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "hyperframe", "version": "6.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/48/30/47d0bf6072f7252e6521f3447ccfa40b421b6824517f82854703d0f5a98b/hyperframe-6.1.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "wsproto", "version": "1.3.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a4/f5/10b68b7b1544245097b2a1b8238f66f2fc6dcaeb24ba5d917f52bd2eed4f/wsproto-1.3.2-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "priority", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5e/5f/82c8074f7e84978129347c2c6ec8b6c59f3584ff1a20bc3c940a3e061790/priority-2.0.0-py3-none-any.whl"}}, {"metadata": {"name": "py", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl"}}], "install_targets_hash": "1878488984d6daa9f6c4336c0c223b5b"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "anthropic", "version": "0.125.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2f/1a/b1bd30cda3790557e8791bec5922a6ec8fabb6fa8b008c76a39cf7be6152/anthropic-0.125.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d0/2b/c3eaf16f5d7c9bad66ea32f40a95bd169b29a91217fcc7f081375157e99c/jiter-0.16.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/81/4fa520eaffa8bd7d1525e644cd6d39e7d60b1592bc5b516693c7340b50f1/pydantic_core-2.46.4-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}], "install_targets_hash": "1c358b0efef217a40b276bd14601c7b4"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "langchain", "version": "1.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/85/86/cc13651cfda820d96ca8c612538166334935e8cf4331a31f5dd369d27760/langchain-1.4.2-py3-none-any.whl"}}, {"metadata": {"name": "langchain-core", "version": "1.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e6/18/cf18cfec118b02e003f35300b54d6a1173dc6e4905cffdf5ea49e390a7f9/langchain_core-1.6.3-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "jsonpatch", "version": "1.33"}, "download_info": {"url": "https://files.pythonhosted.org/packages/73/07/02e16ed01e04a374e644b575638ec7987ae846d25ad97bcc9945a3ee4b0e/jsonpatch-1.33-py2.py3-none-any.whl"}}, {"metadata": {"name": "langgraph", "version": "1.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0a/7f/c5c30e4be99ff821029c7ac872a480676bb179c9f3df85ea3f38d13f86d4/langgraph-1.2.11-py3-none-any.whl"}}, {"metadata": {"name": "langgraph-checkpoint", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/71/3b475f09bd57d3a5649792c66353312b4432afd843f301739dfcebd157f0/langgraph_checkpoint-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "langgraph-prebuilt", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/43/3fe1a700b8490ed02679cdbbc8c915eb23a092faf496c9c1118abcd10be3/langgraph_prebuilt-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "langgraph-sdk", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/43/d5/2ad7f3a835c6fcebf58b6669552536ecd52d2dfe4cf49c6c36648fd83572/langgraph_sdk-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "langsmith", "version": "0.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/51/892ff5a2efc8e222ca114dd0e19b56978f78a5ee62d3b33783588dd8e6d4/langsmith-0.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d3/f2/9e4de77a6271e07a76d2d58b11c091a979c191ed2939bf80067568b369d2/pydantic_core-2.46.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "uuid_utils", "version": "0.17.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/96/deded55ce54c5e6a2b7dbb790ab9bf7b5be8c7e8cb22e2355108bd8723cd/uuid_utils-0.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b5/c2/c676c69444d9db448b3f0a55a98dcc534affce0bce961d9d2f0b8499b10a/websockets-16.1.1-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "3.16.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/17/72/2b1fe3e303db76ab2ba0c2de2b57822869bcb588db82334d4ff3aea8acf2/openai-3.16.2-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/27/17/91420b156315ae22732f5ee1a7b5725a030aab9dc8fd7dcdacfb4aa588d3/jiter-0.17.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "langchain-openai", "version": "1.6.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b2/47/b87a3c372e52678eb4408360eadbe04cdd5371e21fe2560b6efd66989624/langchain_openai-1.6.2-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/62/cae690d9783146b0f81f564ada0f8f611de68178c0c9c7e1e969f0516b48/tiktoken-0.14.0-cp313-cp313-manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "langchain-community", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8f/39/5d97e42a3e95dc2a6d71b2f902a3fae71786131e11d01bddb604accb0ebe/langchain_community-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "langchain-classic", "version": "1.0.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/9a/b8f5cb7490fdbf233088031fc69c9c747439d4097f67f196c1eb4869916d/langchain_classic-1.0.8-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/1c/7da8d08e74d56f00070822f9638ff3f1c563f8ad87d1efa996c87bfc8644/aiohttp-3.14.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "langchain-text-splitters", "version": "1.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d3/26/1ef06f56198d631296d646a6223de35bcc6cf9795ceb2442816bc963b84c/langchain_text_splitters-1.1.2-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/fc/19deb0d051c694dbc2d5008ec89b341f7ee42c4412b38630a47a14339115/multidict-6.9.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/af/63240b0c0248c075c2535a1f1bd992821d8251b9f173abc13329661d09e4/charset_normalizer-3.5.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "SQLAlchemy", "version": "2.0.54"}, "download_info": {"url": "https://files.pythonhosted.org/packages/84/26/bd327a1a6be223e438c98ac8faf299307d83797225a81f3b209607a9fd98/sqlalchemy-2.0.54-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "urllib3", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.25.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0e/b7/a82a49bf88340b837ef6972b508a1604ae377b9e6904b46b10cf5f1cf925/yarl-1.25.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "google-genai", "version": "2.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/84/5b/87913fe392ba7b6402577259289ed3740c577956554a674b191a2971d33e/google_genai-2.24.0-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.58.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/59/13/477d90d09591b3938b45c4e11f4d8a51291682112cb5efcac961e815d562/google_auth-2.58.0-py3-none-any.whl"}}, {"metadata": {"name": "langchain-google-genai", "version": "4.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/10/83bb535e78c2cf767a6193c2f3b00b2894c1581a36ef85911ebaa3b9a891/langchain_google_genai-4.4.0-py3-none-any.whl"}}, {"metadata": {"name": "filetype", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/18/79/1b8fa1bb3568781e84c9200f951c735f3f157429f44be0495da55894d620/filetype-1.2.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/85/66/6ccca4722987ddedaa7fc9c3f4708af7431f5535666c174350830888c6b7/cryptography-50.0.1-cp311-abi3-manylinux_2_34_x86_64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/95/86342356ff5953b3fb06f7ef7c5bee212d45e770abc7218d451b9148313c/cffi-2.1.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d5/4e/e4691508f9477ce67da2015d8c00acd751e6287739123113a9fca6f1604e/frozenlist-1.8.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl"}}, {"metadata": {"name": "greenlet", "version": "3.5.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/85/cb/ab0c123c514ed4e94c0dc9ee2e86362633e6b998cfc05de7fc9ac2eb9690/greenlet-3.5.6-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonpointer", "version": "3.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/6a/a83720e953b1682d2d109d3c2dbb0bc9bf28cc1cbc205be4ef4be5da709d/jsonpointer-3.1.1-py3-none-any.whl"}}, {"metadata": {"name": "langchain-protocol", "version": "0.0.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/80/c9/f6cbf357d48ccbd18bb394433b1fd7ad9be004eed9377ad08bb85777e5e6/langchain_protocol-0.0.19-py3-none-any.whl"}}, {"metadata": {"name": "numpy", "version": "2.5.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3a/1b/3b16a9bc514a440a7a0883684111dcb1ef1aee960af2ca95da8fc775f124/numpy-2.5.3-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "orjson", "version": "3.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/74/89bb236deb9565f99434b13052bb40ddfcce4adf3afbfa3132ee7e421468/orjson-3.12.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "ormsgpack", "version": "1.12.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1c/a2/072343e1413d9443e5a252a8eb591c2d5b1bffbe5e7bfc78c069361b92eb/ormsgpack-1.12.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ed/74/08e6c1faf26ee2732023a3828787ba535557122774f4a386b1f715cbd8e0/propcache-0.5.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/3b/6163796d69c3977d1e4287bea4a6979161cbbdd170ebb430511e8e1999ce/pyasn1-0.6.4-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "xxhash", "version": "4.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6f/fb/76580c08e916507859b0f335393cb5fdc59452c4402edbc6bcca6e47e7df/xxhash-4.0.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "zstandard", "version": "0.25.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/4b/e3678b4e776db00f9f7b2fe58e547e8928ef32727d7a1ff01dea010f3f13/zstandard-0.25.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.9.10"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/3b/000c79c3f9c06b7542225a5d3a7f9a85405da7224b3b9af94a491d07abea/regex-2026.9.10-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}], "install_targets_hash": "1f1d7e5fcc21f036dd1fe5ff2434a014"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "fastapi", "version": "0.141.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/03/10388a42375ee7e4ac9b94eb2c5c569c8b5795e377e701c9ac3ad63de890/fastapi-0.141.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b2/06/97ec2aeae780b31d742b6352218b43841a6871e2564578ca522dce4a45c3/charset_normalizer-3.4.9-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/81/4fa520eaffa8bd7d1525e644cd6d39e7d60b1592bc5b516693c7340b50f1/pydantic_core-2.46.4-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}], "install_targets_hash": "20b998148dda6aa7b3fb3474012892c8"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "fastapi", "version": "0.141.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/03/10388a42375ee7e4ac9b94eb2c5c569c8b5795e377e701c9ac3ad63de890/fastapi-0.141.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ea/f8/72eb13dcabe7257035cea8aefd922caad2f110d252bf9f67c4c2ca763aee/charset_normalizer-3.4.9-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/21/9b05698b46f218fc0e118e1f8168395c65c8a2c750ae2bab54fc4bd4e0e8/markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"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"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}], "install_targets_hash": "20b998148dda6aa7b3fb3474012892c8"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "fastapi", "version": "0.141.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/03/10388a42375ee7e4ac9b94eb2c5c569c8b5795e377e701c9ac3ad63de890/fastapi-0.141.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ea/f8/72eb13dcabe7257035cea8aefd922caad2f110d252bf9f67c4c2ca763aee/charset_normalizer-3.4.9-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/21/9b05698b46f218fc0e118e1f8168395c65c8a2c750ae2bab54fc4bd4e0e8/markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"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"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}], "install_targets_hash": "20b998148dda6aa7b3fb3474012892c8"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "fastapi", "version": "0.141.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/03/10388a42375ee7e4ac9b94eb2c5c569c8b5795e377e701c9ac3ad63de890/fastapi-0.141.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ea/f8/72eb13dcabe7257035cea8aefd922caad2f110d252bf9f67c4c2ca763aee/charset_normalizer-3.4.9-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/21/9b05698b46f218fc0e118e1f8168395c65c8a2c750ae2bab54fc4bd4e0e8/markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"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"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}], "install_targets_hash": "20b998148dda6aa7b3fb3474012892c8"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "httpx2", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/29/45/82bc57c3d9c3314f663b67cc057f1c017a6450685dde513f4f8db5cf431f/httpx2-2.4.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2-pytest", "version": "1.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/46/ef/e9b6fb576f1f518f68e9f9cce9776870452ae2b8cfbba53b4127701b9a55/httpx2_pytest-1.0.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/72/4fdf2306143a92a471fad9f3655aa542d43aa9188a7c9534e82c9aecf837/httpcore2-2.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}], "install_targets_hash": "20f77812852d7e4a68656d7028ccce45"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "httpx2", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/29/45/82bc57c3d9c3314f663b67cc057f1c017a6450685dde513f4f8db5cf431f/httpx2-2.4.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2-pytest", "version": "1.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/46/ef/e9b6fb576f1f518f68e9f9cce9776870452ae2b8cfbba53b4127701b9a55/httpx2_pytest-1.0.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/72/4fdf2306143a92a471fad9f3655aa542d43aa9188a7c9534e82c9aecf837/httpcore2-2.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}], "install_targets_hash": "20f77812852d7e4a68656d7028ccce45"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "httpx2", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/29/45/82bc57c3d9c3314f663b67cc057f1c017a6450685dde513f4f8db5cf431f/httpx2-2.4.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2-pytest", "version": "1.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/46/ef/e9b6fb576f1f518f68e9f9cce9776870452ae2b8cfbba53b4127701b9a55/httpx2_pytest-1.0.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/72/4fdf2306143a92a471fad9f3655aa542d43aa9188a7c9534e82c9aecf837/httpcore2-2.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}], "install_targets_hash": "20f77812852d7e4a68656d7028ccce45"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "langgraph", "version": "1.2.12"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/52/27/5a02054c535ed6fcfb2ab1e5c33c51c810cf1e773194ad28c928f0473509/langgraph-1.2.12-py3-none-any.whl"}}, {"metadata": {"name": "langchain-core", "version": "1.6.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c4/f2/41435d9a5448c52a0388f75741edb979fde7415eaa820d6a42878cad7e38/langchain_core-1.6.4-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "jsonpatch", "version": "1.33"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/73/07/02e16ed01e04a374e644b575638ec7987ae846d25ad97bcc9945a3ee4b0e/jsonpatch-1.33-py2.py3-none-any.whl"}}, {"metadata": {"name": "langgraph-checkpoint", "version": "4.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/05/71/3b475f09bd57d3a5649792c66353312b4432afd843f301739dfcebd157f0/langgraph_checkpoint-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "langgraph-prebuilt", "version": "1.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e9/43/3fe1a700b8490ed02679cdbbc8c915eb23a092faf496c9c1118abcd10be3/langgraph_prebuilt-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "langgraph-sdk", "version": "0.4.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/a9/71a6499f3481bc00bf4f42a17cb81caf19a02fce762db356626d7214e2c2/langgraph_sdk-0.4.5-py3-none-any.whl"}}, {"metadata": {"name": "langsmith", "version": "0.14.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/4d/be/d55279f7bfc43763fd479aa526d6f952fa93aaf4d86a40919f78726691cc/langsmith-0.14.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/21/43/6323b1f8b217780454c61304bcd2b38ae4762f50754414124603ccc90bb2/pydantic_core-2.46.5-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "uuid_utils", "version": "0.17.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/03/0d/4c2263a05e95dc11a5c9fad78ab9ac5f76a1f5aaabb545a39c6d34d2a07b/uuid_utils-0.17.1-cp313-cp313-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/3d/86/0a70d3ae2f0f2256bb41302d9804dbca65d4360281e7feb3e1f94102ac46/websockets-16.1.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "jsonpointer", "version": "3.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/9e/6a/a83720e953b1682d2d109d3c2dbb0bc9bf28cc1cbc205be4ef4be5da709d/jsonpointer-3.1.1-py3-none-any.whl"}}, {"metadata": {"name": "langchain-protocol", "version": "0.0.19"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/80/c9/f6cbf357d48ccbd18bb394433b1fd7ad9be004eed9377ad08bb85777e5e6/langchain_protocol-0.0.19-py3-none-any.whl"}}, {"metadata": {"name": "orjson", "version": "3.12.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/f8/4a/bc87c45e7ec639d35ebefd62618e01939531ac8e171426606a01bda05914/orjson-3.12.0-cp313-cp313-macosx_15_0_arm64.whl"}}, {"metadata": {"name": "ormsgpack", "version": "1.12.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/eb/29/bb0eba3288c0449efbb013e9c6f58aea79cf5cb9ee1921f8865f04c1a9d7/ormsgpack-1.12.2-cp313-cp313-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a4/a0/562247944386f7d4ef94467e84876600cc1e0f1b93239aaa9213d2bc3cbd/charset_normalizer-3.5.1-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "urllib3", "version": "2.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "xxhash", "version": "4.0.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/da/e0/934af8d99bb5885711006bec30a691f728edd513d2c40f053f887d8e7577/xxhash-4.0.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "zstandard", "version": "0.25.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/3f/06/9ae96a3e5dcfd119377ba33d4c42a7d89da1efabd5cb3e366b156c45ff4d/zstandard-0.25.0-cp313-cp313-macosx_11_0_arm64.whl"}}], "install_targets_hash": "26d1a3b577a5cb444398332d2ce874d0"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "gql", "version": "4.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ac/94/30bbd09e8d45339fa77a48f5778d74d47e9242c11b3cd1093b3d994770a5/gql-4.0.0-py3-none-any.whl"}}, {"metadata": {"name": "responses", "version": "0.26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/28/693e1d9ebf72baa062ded80d837a035b86ce75eda5a269379e9e2b1008a8/responses-0.26.2-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ab/01/a2d5f96cd4e74424864d30bc0a7e44d0a12dacdcfa91b5b2d1bd3dca6bf3/aiohttp-3.14.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "backoff", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/73/b6e24bd22e6720ca8ee9a85a0c4a2971af8497d8f3193fa05390cbd46e09/backoff-2.2.1-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.40"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/8c/5f7e73fd66b28f0705bc55d7060d41ef72328b656b86ca53e75765b3ba2c/botocore-1.43.40-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/15/b92b4e1d88d02c6eff9733c9eea21846ab435cc4d813d84ccc5d335955df/graphql_core-3.2.11-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "15.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ff/0b/33cef55ff24f2d92924923c99926dcce78e7bd922d649467f0eda8368923/websockets-15.0.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/24/16748d5dab6daec8b0ed81ccec639a1cded0f18dcc62a4f696b4fe366c37/yarl-1.24.2-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/3b/66777e39d3ae1ddc77ee606be4ec6d8cbd4c801f65e5a1b6f2b11b8346dd/charset_normalizer-3.4.7-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/ab/6e5080ee374f875296c4243c381bbdef97a9ac39c6e3ce1d5f7d42cb78d6/frozenlist-1.8.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/76/55cd7186f498ed080a18440c9013011eb548f77ae1b297206d030eb1180a/multidict-6.7.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/12/a6ba6482bb5ea3260c000c9b20881c95fa11c6b30173715668259f844ed7/propcache-0.5.2-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}], "install_targets_hash": "2de3e70bcf4f337f5ecb64d5671c312a"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "gql", "version": "4.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ac/94/30bbd09e8d45339fa77a48f5778d74d47e9242c11b3cd1093b3d994770a5/gql-4.0.0-py3-none-any.whl"}}, {"metadata": {"name": "responses", "version": "0.26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/28/693e1d9ebf72baa062ded80d837a035b86ce75eda5a269379e9e2b1008a8/responses-0.26.2-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ab/01/a2d5f96cd4e74424864d30bc0a7e44d0a12dacdcfa91b5b2d1bd3dca6bf3/aiohttp-3.14.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "backoff", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/73/b6e24bd22e6720ca8ee9a85a0c4a2971af8497d8f3193fa05390cbd46e09/backoff-2.2.1-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.40"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/8c/5f7e73fd66b28f0705bc55d7060d41ef72328b656b86ca53e75765b3ba2c/botocore-1.43.40-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/15/b92b4e1d88d02c6eff9733c9eea21846ab435cc4d813d84ccc5d335955df/graphql_core-3.2.11-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "15.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ff/0b/33cef55ff24f2d92924923c99926dcce78e7bd922d649467f0eda8368923/websockets-15.0.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/24/16748d5dab6daec8b0ed81ccec639a1cded0f18dcc62a4f696b4fe366c37/yarl-1.24.2-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/3b/66777e39d3ae1ddc77ee606be4ec6d8cbd4c801f65e5a1b6f2b11b8346dd/charset_normalizer-3.4.7-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/ab/6e5080ee374f875296c4243c381bbdef97a9ac39c6e3ce1d5f7d42cb78d6/frozenlist-1.8.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/76/55cd7186f498ed080a18440c9013011eb548f77ae1b297206d030eb1180a/multidict-6.7.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/12/a6ba6482bb5ea3260c000c9b20881c95fa11c6b30173715668259f844ed7/propcache-0.5.2-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}], "install_targets_hash": "2de3e70bcf4f337f5ecb64d5671c312a"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "gql", "version": "4.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ac/94/30bbd09e8d45339fa77a48f5778d74d47e9242c11b3cd1093b3d994770a5/gql-4.0.0-py3-none-any.whl"}}, {"metadata": {"name": "responses", "version": "0.26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/28/693e1d9ebf72baa062ded80d837a035b86ce75eda5a269379e9e2b1008a8/responses-0.26.2-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ab/01/a2d5f96cd4e74424864d30bc0a7e44d0a12dacdcfa91b5b2d1bd3dca6bf3/aiohttp-3.14.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "backoff", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/73/b6e24bd22e6720ca8ee9a85a0c4a2971af8497d8f3193fa05390cbd46e09/backoff-2.2.1-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.40"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/8c/5f7e73fd66b28f0705bc55d7060d41ef72328b656b86ca53e75765b3ba2c/botocore-1.43.40-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/15/b92b4e1d88d02c6eff9733c9eea21846ab435cc4d813d84ccc5d335955df/graphql_core-3.2.11-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "15.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ff/0b/33cef55ff24f2d92924923c99926dcce78e7bd922d649467f0eda8368923/websockets-15.0.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/24/16748d5dab6daec8b0ed81ccec639a1cded0f18dcc62a4f696b4fe366c37/yarl-1.24.2-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/3b/66777e39d3ae1ddc77ee606be4ec6d8cbd4c801f65e5a1b6f2b11b8346dd/charset_normalizer-3.4.7-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/ab/6e5080ee374f875296c4243c381bbdef97a9ac39c6e3ce1d5f7d42cb78d6/frozenlist-1.8.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/76/55cd7186f498ed080a18440c9013011eb548f77ae1b297206d030eb1180a/multidict-6.7.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/12/a6ba6482bb5ea3260c000c9b20881c95fa11c6b30173715668259f844ed7/propcache-0.5.2-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}], "install_targets_hash": "2de3e70bcf4f337f5ecb64d5671c312a"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "starlette", "version": "0.52.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/0d/13d1d239a25cbfb19e740db83143e95c772a1fe10202dda4b76792b114dd/starlette-0.52.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/3b/66777e39d3ae1ddc77ee606be4ec6d8cbd4c801f65e5a1b6f2b11b8346dd/charset_normalizer-3.4.7-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "30eeef4352d79f7d31c630da4104816d"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "starlette", "version": "0.52.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/0d/13d1d239a25cbfb19e740db83143e95c772a1fe10202dda4b76792b114dd/starlette-0.52.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/3b/66777e39d3ae1ddc77ee606be4ec6d8cbd4c801f65e5a1b6f2b11b8346dd/charset_normalizer-3.4.7-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "30eeef4352d79f7d31c630da4104816d"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "starlette", "version": "0.52.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/0d/13d1d239a25cbfb19e740db83143e95c772a1fe10202dda4b76792b114dd/starlette-0.52.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/3b/66777e39d3ae1ddc77ee606be4ec6d8cbd4c801f65e5a1b6f2b11b8346dd/charset_normalizer-3.4.7-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "30eeef4352d79f7d31c630da4104816d"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "starlette", "version": "0.52.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/0d/13d1d239a25cbfb19e740db83143e95c772a1fe10202dda4b76792b114dd/starlette-0.52.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/3b/66777e39d3ae1ddc77ee606be4ec6d8cbd4c801f65e5a1b6f2b11b8346dd/charset_normalizer-3.4.7-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "30eeef4352d79f7d31c630da4104816d"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "aiomysql", "version": "0.3.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4c/af/aae0153c3e28712adaf462328f6c7a3c196a1c1c27b491de4377dd3e6b52/aiomysql-0.3.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/22/adf66990e63584a68dfb50c24f48a125c07b1699899381c8151e63ed458c/cryptography-49.0.0-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "PyMySQL", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c4/bd/2534e130295c8cfd4f0a2e31623baab7502278f1e97bcfe61db75656a77f/pymysql-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "3680161bd7dab16c5a7cb3161b3427a9"} -{"python_version": "3.13", "dependencies": [{"metadata": {"name": "aiohttp", "version": "3.10.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/7c/30d161a7e3b208cef1b922eacf2bbb8578b7e5a62266a6a2245a1dd044dc/aiohttp-3.10.11-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-aiohttp", "version": "1.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/a7/6e50ba2c0a27a34859a952162e63362a13142ce3c646e925b76de440e102/pytest_aiohttp-1.0.5-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/ab/6e5080ee374f875296c4243c381bbdef97a9ac39c6e3ce1d5f7d42cb78d6/frozenlist-1.8.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/76/55cd7186f498ed080a18440c9013011eb548f77ae1b297206d030eb1180a/multidict-6.7.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/24/16748d5dab6daec8b0ed81ccec639a1cded0f18dcc62a4f696b4fe366c37/yarl-1.24.2-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/12/a6ba6482bb5ea3260c000c9b20881c95fa11c6b30173715668259f844ed7/propcache-0.5.2-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "38bb936208e4e77b6875b0856d10553a"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "clickhouse-driver", "version": "0.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/66/1b/274ccf06cddbdc3a6ae8eebf0df6b7cefb2ab86292ca4602f92eb778fc04/clickhouse_driver-0.2.11-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytz", "version": "2026.3.post1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0f/7b/39c34ca613b0b198cb866466651b26b045e2009864c5183c979a3b83f383/pytz-2026.3.post1-py2.py3-none-any.whl"}}, {"metadata": {"name": "tzlocal", "version": "5.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/a4/017a7a6cbe387d961a688ec31364ae60a5c4e22c96ae9921b79a947c855d/tzlocal-5.4.4-py3-none-any.whl"}}], "install_targets_hash": "38bca3e47a0c5c6404ea5b79801cb472"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "pyspark", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c3/33/c987434f5d50aa802779a004ca0fd45ee4350caab50554ad7283d5a22b50/pyspark-4.2.0.tar.gz"}}, {"metadata": {"name": "py4j", "version": "0.10.9.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/db/ea0203e495be491c85af87b66e37acfd3bf756fd985f87e46fc5e3bf022c/py4j-0.10.9.9-py2.py3-none-any.whl"}}], "install_targets_hash": "390b2ae4157b0a35d160339447ce08cb"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "rq", "version": "2.12.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a4/c2/995863e88669133a058c2a6a912b62d18a64fa7baaf78eb66aaa4350b48d/rq-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.35.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/6f/27/b8b057a23f7777177e92d3a602fd866751b6b45014964548997e92e048fd/fakeredis-2.35.1-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "redis", "version": "8.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/66/9d/c5731f6e3608663d4d3656fd8d3aecee8b509c3082818f5a13eae925baea/redis-8.1.0-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "croniter", "version": "6.2.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cd/ba/d678e5bd329646ca51d3c92addbc77804e86d21f4b6b6a027218e6abb010/croniter-6.2.4-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}], "install_targets_hash": "39c8ef325254f7a619a821794c33e958"} @@ -215,280 +375,733 @@ {"python_version": "3.13", "dependencies": [{"metadata": {"name": "launchdarkly-server-sdk", "version": "9.8.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/aa/b7/e5eed9ec95341d2fe8f9c78377b951045dd8afc9dcdb4f0c9391be02a030/launchdarkly_server_sdk-9.8.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "expiringdict", "version": "1.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/84/a04c59324445f4bcc98dc05b39a1cd07c242dde643c1a3c21e4f7beaf2f2/expiringdict-1.2.2-py3-none-any.whl"}}, {"metadata": {"name": "launchdarkly-eventsource", "version": "1.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/e5/450c31e70e8f5f8cf6b6f3bab68475677eaab2d56b5dd1f3bfd436defdc9/launchdarkly_eventsource-1.7.1-py3-none-any.whl"}}, {"metadata": {"name": "pyRFC3339", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/34/90/0200184d2124484f918054751ef997ed6409cb05b7e8dcbf5a22da4c4748/pyrfc3339-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "semver", "version": "3.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/24/4d91e05817e92e3a61c8a21e08fd0f390f5301f1c448b137c57c4bc6e543/semver-3.0.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}], "install_targets_hash": "39e38f320060d087837513360056dd40"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "bottle", "version": "0.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/83/f6/b55ec74cfe68c6584163faa311503c20b0da4c09883a41e8e00d6726c954/bottle-0.13.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "2.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/f3/22afbdb20cc4654b10c98043414a14057cd27fdba9d4ae61cea596000ba2/Werkzeug-2.0.3-py3-none-any.whl"}}], "install_targets_hash": "3cb07bf1e9768637334d5ad3e34bfe02"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "bottle", "version": "0.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/83/f6/b55ec74cfe68c6584163faa311503c20b0da4c09883a41e8e00d6726c954/bottle-0.13.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "2.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/f3/22afbdb20cc4654b10c98043414a14057cd27fdba9d4ae61cea596000ba2/Werkzeug-2.0.3-py3-none-any.whl"}}], "install_targets_hash": "3cb07bf1e9768637334d5ad3e34bfe02"} -{"python_version": "3.13", "dependencies": [{"metadata": {"name": "openai", "version": "3.16.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/17/72/2b1fe3e303db76ab2ba0c2de2b57822869bcb588db82334d4ff3aea8acf2/openai-3.16.2-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/27/17/91420b156315ae22732f5ee1a7b5725a030aab9dc8fd7dcdacfb4aa588d3/jiter-0.17.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d3/f2/9e4de77a6271e07a76d2d58b11c091a979c191ed2939bf80067568b369d2/pydantic_core-2.46.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "41aa894704882aa63f37bce872a4e2a2"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "chalice", "version": "1.33.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/ed/c721931d966d135387ab2d5404a026ca0ae205325fbac4b8f9ac91a45186/chalice-1.33.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-chalice", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/0f/3344996a9ca6d1b301f55805bd2aa0daf9055f13317720b4567226e4cb38/pytest-chalice-0.0.5.tar.gz"}}, {"metadata": {"name": "setuptools", "version": "81.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/e3/c164c88b2e5ce7b24d667b9bd83589cf4f3520d97cad01534cd3c4f55fdb/setuptools-81.0.0-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.40"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/8c/5f7e73fd66b28f0705bc55d7060d41ef72328b656b86ca53e75765b3ba2c/botocore-1.43.40-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "inquirer", "version": "3.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f0/fd/7c404169a3e04a908df0644893a331f253a7f221961f2b6c0cf44430ae5a/inquirer-3.4.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pip", "version": "26.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/95/6b5cb3461ea5673ba0995989746db58eb18b91b54dbf331e72f569540946/pip-26.1.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "wheel", "version": "0.47.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/87/1b/9e33c09813d65e248f7f773119148a612516a4bea93e9c6f545f78455b7c/wheel-0.47.0-py3-none-any.whl"}}, {"metadata": {"name": "blessed", "version": "1.46.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/8f/c10d44ba50d5d298699c3c5698ce4e89b397ec72e2139381b9964f87356c/blessed-1.46.0-py3-none-any.whl"}}, {"metadata": {"name": "editor", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/b8/6648cadf38b61045262bf2a534e526f04eb833275ad1fc77a2026e9f7e3a/editor-1.8.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "readchar", "version": "4.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/ca/36133653e00939922dd1416f4c56177361289172a30563fcb9552c9ccde4/readchar-4.2.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "jinxed", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/1d/0a6be99b69bb448448403a45a241aff0dca751832ae54f027ed940d2eb52/jinxed-2.1.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl"}}, {"metadata": {"name": "runs", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/b6/049c75d399ccf6e25abea0652b85bf7e7e101e0300aa9c1d284ad7061c0b/runs-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "xmod", "version": "1.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/e9/c362d47ed2b1928d65d61888c1419fae8ef69417fba2067d2fd3da1d400b/xmod-1.10.0-py3-none-any.whl"}}], "install_targets_hash": "41e4a9a78e14781d2190b51041252959"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "chalice", "version": "1.33.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/ed/c721931d966d135387ab2d5404a026ca0ae205325fbac4b8f9ac91a45186/chalice-1.33.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-chalice", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/0f/3344996a9ca6d1b301f55805bd2aa0daf9055f13317720b4567226e4cb38/pytest-chalice-0.0.5.tar.gz"}}, {"metadata": {"name": "setuptools", "version": "81.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/e3/c164c88b2e5ce7b24d667b9bd83589cf4f3520d97cad01534cd3c4f55fdb/setuptools-81.0.0-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.40"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/8c/5f7e73fd66b28f0705bc55d7060d41ef72328b656b86ca53e75765b3ba2c/botocore-1.43.40-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "inquirer", "version": "3.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f0/fd/7c404169a3e04a908df0644893a331f253a7f221961f2b6c0cf44430ae5a/inquirer-3.4.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pip", "version": "26.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/95/6b5cb3461ea5673ba0995989746db58eb18b91b54dbf331e72f569540946/pip-26.1.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "wheel", "version": "0.47.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/87/1b/9e33c09813d65e248f7f773119148a612516a4bea93e9c6f545f78455b7c/wheel-0.47.0-py3-none-any.whl"}}, {"metadata": {"name": "blessed", "version": "1.46.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/8f/c10d44ba50d5d298699c3c5698ce4e89b397ec72e2139381b9964f87356c/blessed-1.46.0-py3-none-any.whl"}}, {"metadata": {"name": "editor", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/b8/6648cadf38b61045262bf2a534e526f04eb833275ad1fc77a2026e9f7e3a/editor-1.8.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "readchar", "version": "4.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/ca/36133653e00939922dd1416f4c56177361289172a30563fcb9552c9ccde4/readchar-4.2.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "jinxed", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/1d/0a6be99b69bb448448403a45a241aff0dca751832ae54f027ed940d2eb52/jinxed-2.1.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl"}}, {"metadata": {"name": "runs", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/b6/049c75d399ccf6e25abea0652b85bf7e7e101e0300aa9c1d284ad7061c0b/runs-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "xmod", "version": "1.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/e9/c362d47ed2b1928d65d61888c1419fae8ef69417fba2067d2fd3da1d400b/xmod-1.10.0-py3-none-any.whl"}}], "install_targets_hash": "41e4a9a78e14781d2190b51041252959"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "chalice", "version": "1.33.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/ed/c721931d966d135387ab2d5404a026ca0ae205325fbac4b8f9ac91a45186/chalice-1.33.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-chalice", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/0f/3344996a9ca6d1b301f55805bd2aa0daf9055f13317720b4567226e4cb38/pytest-chalice-0.0.5.tar.gz"}}, {"metadata": {"name": "setuptools", "version": "81.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/e3/c164c88b2e5ce7b24d667b9bd83589cf4f3520d97cad01534cd3c4f55fdb/setuptools-81.0.0-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.40"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/8c/5f7e73fd66b28f0705bc55d7060d41ef72328b656b86ca53e75765b3ba2c/botocore-1.43.40-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "inquirer", "version": "3.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f0/fd/7c404169a3e04a908df0644893a331f253a7f221961f2b6c0cf44430ae5a/inquirer-3.4.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pip", "version": "26.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/95/6b5cb3461ea5673ba0995989746db58eb18b91b54dbf331e72f569540946/pip-26.1.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "wheel", "version": "0.47.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/87/1b/9e33c09813d65e248f7f773119148a612516a4bea93e9c6f545f78455b7c/wheel-0.47.0-py3-none-any.whl"}}, {"metadata": {"name": "blessed", "version": "1.46.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/8f/c10d44ba50d5d298699c3c5698ce4e89b397ec72e2139381b9964f87356c/blessed-1.46.0-py3-none-any.whl"}}, {"metadata": {"name": "editor", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/b8/6648cadf38b61045262bf2a534e526f04eb833275ad1fc77a2026e9f7e3a/editor-1.8.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "readchar", "version": "4.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/ca/36133653e00939922dd1416f4c56177361289172a30563fcb9552c9ccde4/readchar-4.2.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "jinxed", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/1d/0a6be99b69bb448448403a45a241aff0dca751832ae54f027ed940d2eb52/jinxed-2.1.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl"}}, {"metadata": {"name": "runs", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/b6/049c75d399ccf6e25abea0652b85bf7e7e101e0300aa9c1d284ad7061c0b/runs-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "xmod", "version": "1.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/e9/c362d47ed2b1928d65d61888c1419fae8ef69417fba2067d2fd3da1d400b/xmod-1.10.0-py3-none-any.whl"}}], "install_targets_hash": "41e4a9a78e14781d2190b51041252959"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "chalice", "version": "1.33.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/ed/c721931d966d135387ab2d5404a026ca0ae205325fbac4b8f9ac91a45186/chalice-1.33.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-chalice", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/0f/3344996a9ca6d1b301f55805bd2aa0daf9055f13317720b4567226e4cb38/pytest-chalice-0.0.5.tar.gz"}}, {"metadata": {"name": "setuptools", "version": "81.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/e3/c164c88b2e5ce7b24d667b9bd83589cf4f3520d97cad01534cd3c4f55fdb/setuptools-81.0.0-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.40"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/8c/5f7e73fd66b28f0705bc55d7060d41ef72328b656b86ca53e75765b3ba2c/botocore-1.43.40-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "inquirer", "version": "3.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f0/fd/7c404169a3e04a908df0644893a331f253a7f221961f2b6c0cf44430ae5a/inquirer-3.4.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pip", "version": "26.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/95/6b5cb3461ea5673ba0995989746db58eb18b91b54dbf331e72f569540946/pip-26.1.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "wheel", "version": "0.47.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/87/1b/9e33c09813d65e248f7f773119148a612516a4bea93e9c6f545f78455b7c/wheel-0.47.0-py3-none-any.whl"}}, {"metadata": {"name": "blessed", "version": "1.46.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/8f/c10d44ba50d5d298699c3c5698ce4e89b397ec72e2139381b9964f87356c/blessed-1.46.0-py3-none-any.whl"}}, {"metadata": {"name": "editor", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/b8/6648cadf38b61045262bf2a534e526f04eb833275ad1fc77a2026e9f7e3a/editor-1.8.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "readchar", "version": "4.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/ca/36133653e00939922dd1416f4c56177361289172a30563fcb9552c9ccde4/readchar-4.2.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "jinxed", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/1d/0a6be99b69bb448448403a45a241aff0dca751832ae54f027ed940d2eb52/jinxed-2.1.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl"}}, {"metadata": {"name": "runs", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/b6/049c75d399ccf6e25abea0652b85bf7e7e101e0300aa9c1d284ad7061c0b/runs-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "xmod", "version": "1.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/e9/c362d47ed2b1928d65d61888c1419fae8ef69417fba2067d2fd3da1d400b/xmod-1.10.0-py3-none-any.whl"}}], "install_targets_hash": "41e4a9a78e14781d2190b51041252959"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "chalice", "version": "1.33.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/ed/c721931d966d135387ab2d5404a026ca0ae205325fbac4b8f9ac91a45186/chalice-1.33.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-chalice", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/0f/3344996a9ca6d1b301f55805bd2aa0daf9055f13317720b4567226e4cb38/pytest-chalice-0.0.5.tar.gz"}}, {"metadata": {"name": "setuptools", "version": "81.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/e3/c164c88b2e5ce7b24d667b9bd83589cf4f3520d97cad01534cd3c4f55fdb/setuptools-81.0.0-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.40"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/8c/5f7e73fd66b28f0705bc55d7060d41ef72328b656b86ca53e75765b3ba2c/botocore-1.43.40-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "inquirer", "version": "3.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f0/fd/7c404169a3e04a908df0644893a331f253a7f221961f2b6c0cf44430ae5a/inquirer-3.4.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pip", "version": "26.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/95/6b5cb3461ea5673ba0995989746db58eb18b91b54dbf331e72f569540946/pip-26.1.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "wheel", "version": "0.47.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/87/1b/9e33c09813d65e248f7f773119148a612516a4bea93e9c6f545f78455b7c/wheel-0.47.0-py3-none-any.whl"}}, {"metadata": {"name": "blessed", "version": "1.46.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/8f/c10d44ba50d5d298699c3c5698ce4e89b397ec72e2139381b9964f87356c/blessed-1.46.0-py3-none-any.whl"}}, {"metadata": {"name": "editor", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/b8/6648cadf38b61045262bf2a534e526f04eb833275ad1fc77a2026e9f7e3a/editor-1.8.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "readchar", "version": "4.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/ca/36133653e00939922dd1416f4c56177361289172a30563fcb9552c9ccde4/readchar-4.2.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "jinxed", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/1d/0a6be99b69bb448448403a45a241aff0dca751832ae54f027ed940d2eb52/jinxed-2.1.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl"}}, {"metadata": {"name": "runs", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/b6/049c75d399ccf6e25abea0652b85bf7e7e101e0300aa9c1d284ad7061c0b/runs-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "xmod", "version": "1.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/e9/c362d47ed2b1928d65d61888c1419fae8ef69417fba2067d2fd3da1d400b/xmod-1.10.0-py3-none-any.whl"}}], "install_targets_hash": "41e4a9a78e14781d2190b51041252959"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "chalice", "version": "1.33.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/ed/c721931d966d135387ab2d5404a026ca0ae205325fbac4b8f9ac91a45186/chalice-1.33.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-chalice", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/0f/3344996a9ca6d1b301f55805bd2aa0daf9055f13317720b4567226e4cb38/pytest-chalice-0.0.5.tar.gz"}}, {"metadata": {"name": "setuptools", "version": "81.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/e3/c164c88b2e5ce7b24d667b9bd83589cf4f3520d97cad01534cd3c4f55fdb/setuptools-81.0.0-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.40"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/8c/5f7e73fd66b28f0705bc55d7060d41ef72328b656b86ca53e75765b3ba2c/botocore-1.43.40-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "inquirer", "version": "3.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f0/fd/7c404169a3e04a908df0644893a331f253a7f221961f2b6c0cf44430ae5a/inquirer-3.4.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pip", "version": "26.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/95/6b5cb3461ea5673ba0995989746db58eb18b91b54dbf331e72f569540946/pip-26.1.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "wheel", "version": "0.47.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/87/1b/9e33c09813d65e248f7f773119148a612516a4bea93e9c6f545f78455b7c/wheel-0.47.0-py3-none-any.whl"}}, {"metadata": {"name": "blessed", "version": "1.46.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/8f/c10d44ba50d5d298699c3c5698ce4e89b397ec72e2139381b9964f87356c/blessed-1.46.0-py3-none-any.whl"}}, {"metadata": {"name": "editor", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/b8/6648cadf38b61045262bf2a534e526f04eb833275ad1fc77a2026e9f7e3a/editor-1.8.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "readchar", "version": "4.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/ca/36133653e00939922dd1416f4c56177361289172a30563fcb9552c9ccde4/readchar-4.2.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "jinxed", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/1d/0a6be99b69bb448448403a45a241aff0dca751832ae54f027ed940d2eb52/jinxed-2.1.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl"}}, {"metadata": {"name": "runs", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/b6/049c75d399ccf6e25abea0652b85bf7e7e101e0300aa9c1d284ad7061c0b/runs-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "xmod", "version": "1.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/e9/c362d47ed2b1928d65d61888c1419fae8ef69417fba2067d2fd3da1d400b/xmod-1.10.0-py3-none-any.whl"}}], "install_targets_hash": "41e4a9a78e14781d2190b51041252959"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "chalice", "version": "1.33.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/ed/c721931d966d135387ab2d5404a026ca0ae205325fbac4b8f9ac91a45186/chalice-1.33.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-chalice", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/0f/3344996a9ca6d1b301f55805bd2aa0daf9055f13317720b4567226e4cb38/pytest-chalice-0.0.5.tar.gz"}}, {"metadata": {"name": "setuptools", "version": "81.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/e3/c164c88b2e5ce7b24d667b9bd83589cf4f3520d97cad01534cd3c4f55fdb/setuptools-81.0.0-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.40"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/8c/5f7e73fd66b28f0705bc55d7060d41ef72328b656b86ca53e75765b3ba2c/botocore-1.43.40-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "inquirer", "version": "3.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f0/fd/7c404169a3e04a908df0644893a331f253a7f221961f2b6c0cf44430ae5a/inquirer-3.4.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pip", "version": "26.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/95/6b5cb3461ea5673ba0995989746db58eb18b91b54dbf331e72f569540946/pip-26.1.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "wheel", "version": "0.47.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/87/1b/9e33c09813d65e248f7f773119148a612516a4bea93e9c6f545f78455b7c/wheel-0.47.0-py3-none-any.whl"}}, {"metadata": {"name": "blessed", "version": "1.46.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/8f/c10d44ba50d5d298699c3c5698ce4e89b397ec72e2139381b9964f87356c/blessed-1.46.0-py3-none-any.whl"}}, {"metadata": {"name": "editor", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/b8/6648cadf38b61045262bf2a534e526f04eb833275ad1fc77a2026e9f7e3a/editor-1.8.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "readchar", "version": "4.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/ca/36133653e00939922dd1416f4c56177361289172a30563fcb9552c9ccde4/readchar-4.2.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "jinxed", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/1d/0a6be99b69bb448448403a45a241aff0dca751832ae54f027ed940d2eb52/jinxed-2.1.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl"}}, {"metadata": {"name": "runs", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/b6/049c75d399ccf6e25abea0652b85bf7e7e101e0300aa9c1d284ad7061c0b/runs-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "xmod", "version": "1.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/e9/c362d47ed2b1928d65d61888c1419fae8ef69417fba2067d2fd3da1d400b/xmod-1.10.0-py3-none-any.whl"}}], "install_targets_hash": "41e4a9a78e14781d2190b51041252959"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "chalice", "version": "1.33.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/ed/c721931d966d135387ab2d5404a026ca0ae205325fbac4b8f9ac91a45186/chalice-1.33.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-chalice", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/0f/3344996a9ca6d1b301f55805bd2aa0daf9055f13317720b4567226e4cb38/pytest-chalice-0.0.5.tar.gz"}}, {"metadata": {"name": "setuptools", "version": "81.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/e3/c164c88b2e5ce7b24d667b9bd83589cf4f3520d97cad01534cd3c4f55fdb/setuptools-81.0.0-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.40"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/8c/5f7e73fd66b28f0705bc55d7060d41ef72328b656b86ca53e75765b3ba2c/botocore-1.43.40-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "inquirer", "version": "3.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f0/fd/7c404169a3e04a908df0644893a331f253a7f221961f2b6c0cf44430ae5a/inquirer-3.4.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pip", "version": "26.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/95/6b5cb3461ea5673ba0995989746db58eb18b91b54dbf331e72f569540946/pip-26.1.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "wheel", "version": "0.47.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/87/1b/9e33c09813d65e248f7f773119148a612516a4bea93e9c6f545f78455b7c/wheel-0.47.0-py3-none-any.whl"}}, {"metadata": {"name": "blessed", "version": "1.46.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/8f/c10d44ba50d5d298699c3c5698ce4e89b397ec72e2139381b9964f87356c/blessed-1.46.0-py3-none-any.whl"}}, {"metadata": {"name": "editor", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/b8/6648cadf38b61045262bf2a534e526f04eb833275ad1fc77a2026e9f7e3a/editor-1.8.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "readchar", "version": "4.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/ca/36133653e00939922dd1416f4c56177361289172a30563fcb9552c9ccde4/readchar-4.2.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "jinxed", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/1d/0a6be99b69bb448448403a45a241aff0dca751832ae54f027ed940d2eb52/jinxed-2.1.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl"}}, {"metadata": {"name": "runs", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/b6/049c75d399ccf6e25abea0652b85bf7e7e101e0300aa9c1d284ad7061c0b/runs-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "xmod", "version": "1.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/e9/c362d47ed2b1928d65d61888c1419fae8ef69417fba2067d2fd3da1d400b/xmod-1.10.0-py3-none-any.whl"}}], "install_targets_hash": "41e4a9a78e14781d2190b51041252959"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "chalice", "version": "1.33.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/ed/c721931d966d135387ab2d5404a026ca0ae205325fbac4b8f9ac91a45186/chalice-1.33.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-chalice", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/0f/3344996a9ca6d1b301f55805bd2aa0daf9055f13317720b4567226e4cb38/pytest-chalice-0.0.5.tar.gz"}}, {"metadata": {"name": "setuptools", "version": "81.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/e3/c164c88b2e5ce7b24d667b9bd83589cf4f3520d97cad01534cd3c4f55fdb/setuptools-81.0.0-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.40"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/8c/5f7e73fd66b28f0705bc55d7060d41ef72328b656b86ca53e75765b3ba2c/botocore-1.43.40-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "inquirer", "version": "3.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f0/fd/7c404169a3e04a908df0644893a331f253a7f221961f2b6c0cf44430ae5a/inquirer-3.4.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pip", "version": "26.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/95/6b5cb3461ea5673ba0995989746db58eb18b91b54dbf331e72f569540946/pip-26.1.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "wheel", "version": "0.47.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/87/1b/9e33c09813d65e248f7f773119148a612516a4bea93e9c6f545f78455b7c/wheel-0.47.0-py3-none-any.whl"}}, {"metadata": {"name": "blessed", "version": "1.46.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/8f/c10d44ba50d5d298699c3c5698ce4e89b397ec72e2139381b9964f87356c/blessed-1.46.0-py3-none-any.whl"}}, {"metadata": {"name": "editor", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/b8/6648cadf38b61045262bf2a534e526f04eb833275ad1fc77a2026e9f7e3a/editor-1.8.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "readchar", "version": "4.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/ca/36133653e00939922dd1416f4c56177361289172a30563fcb9552c9ccde4/readchar-4.2.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "jinxed", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/1d/0a6be99b69bb448448403a45a241aff0dca751832ae54f027ed940d2eb52/jinxed-2.1.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl"}}, {"metadata": {"name": "runs", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/b6/049c75d399ccf6e25abea0652b85bf7e7e101e0300aa9c1d284ad7061c0b/runs-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "xmod", "version": "1.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/e9/c362d47ed2b1928d65d61888c1419fae8ef69417fba2067d2fd3da1d400b/xmod-1.10.0-py3-none-any.whl"}}], "install_targets_hash": "41e4a9a78e14781d2190b51041252959"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "chalice", "version": "1.33.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/ed/c721931d966d135387ab2d5404a026ca0ae205325fbac4b8f9ac91a45186/chalice-1.33.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-chalice", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/0f/3344996a9ca6d1b301f55805bd2aa0daf9055f13317720b4567226e4cb38/pytest-chalice-0.0.5.tar.gz"}}, {"metadata": {"name": "setuptools", "version": "81.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/e3/c164c88b2e5ce7b24d667b9bd83589cf4f3520d97cad01534cd3c4f55fdb/setuptools-81.0.0-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.40"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/8c/5f7e73fd66b28f0705bc55d7060d41ef72328b656b86ca53e75765b3ba2c/botocore-1.43.40-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "inquirer", "version": "3.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f0/fd/7c404169a3e04a908df0644893a331f253a7f221961f2b6c0cf44430ae5a/inquirer-3.4.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pip", "version": "26.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/95/6b5cb3461ea5673ba0995989746db58eb18b91b54dbf331e72f569540946/pip-26.1.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "wheel", "version": "0.47.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/87/1b/9e33c09813d65e248f7f773119148a612516a4bea93e9c6f545f78455b7c/wheel-0.47.0-py3-none-any.whl"}}, {"metadata": {"name": "blessed", "version": "1.46.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/8f/c10d44ba50d5d298699c3c5698ce4e89b397ec72e2139381b9964f87356c/blessed-1.46.0-py3-none-any.whl"}}, {"metadata": {"name": "editor", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/b8/6648cadf38b61045262bf2a534e526f04eb833275ad1fc77a2026e9f7e3a/editor-1.8.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "readchar", "version": "4.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/ca/36133653e00939922dd1416f4c56177361289172a30563fcb9552c9ccde4/readchar-4.2.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "jinxed", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/1d/0a6be99b69bb448448403a45a241aff0dca751832ae54f027ed940d2eb52/jinxed-2.1.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl"}}, {"metadata": {"name": "runs", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/b6/049c75d399ccf6e25abea0652b85bf7e7e101e0300aa9c1d284ad7061c0b/runs-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "xmod", "version": "1.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/e9/c362d47ed2b1928d65d61888c1419fae8ef69417fba2067d2fd3da1d400b/xmod-1.10.0-py3-none-any.whl"}}], "install_targets_hash": "41e4a9a78e14781d2190b51041252959"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "chalice", "version": "1.33.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/ed/c721931d966d135387ab2d5404a026ca0ae205325fbac4b8f9ac91a45186/chalice-1.33.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-chalice", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/0f/3344996a9ca6d1b301f55805bd2aa0daf9055f13317720b4567226e4cb38/pytest-chalice-0.0.5.tar.gz"}}, {"metadata": {"name": "setuptools", "version": "81.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/e3/c164c88b2e5ce7b24d667b9bd83589cf4f3520d97cad01534cd3c4f55fdb/setuptools-81.0.0-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.40"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/8c/5f7e73fd66b28f0705bc55d7060d41ef72328b656b86ca53e75765b3ba2c/botocore-1.43.40-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "inquirer", "version": "3.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f0/fd/7c404169a3e04a908df0644893a331f253a7f221961f2b6c0cf44430ae5a/inquirer-3.4.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pip", "version": "26.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/95/6b5cb3461ea5673ba0995989746db58eb18b91b54dbf331e72f569540946/pip-26.1.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "wheel", "version": "0.47.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/87/1b/9e33c09813d65e248f7f773119148a612516a4bea93e9c6f545f78455b7c/wheel-0.47.0-py3-none-any.whl"}}, {"metadata": {"name": "blessed", "version": "1.46.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/8f/c10d44ba50d5d298699c3c5698ce4e89b397ec72e2139381b9964f87356c/blessed-1.46.0-py3-none-any.whl"}}, {"metadata": {"name": "editor", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/b8/6648cadf38b61045262bf2a534e526f04eb833275ad1fc77a2026e9f7e3a/editor-1.8.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "readchar", "version": "4.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/ca/36133653e00939922dd1416f4c56177361289172a30563fcb9552c9ccde4/readchar-4.2.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "jinxed", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/1d/0a6be99b69bb448448403a45a241aff0dca751832ae54f027ed940d2eb52/jinxed-2.1.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl"}}, {"metadata": {"name": "runs", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/b6/049c75d399ccf6e25abea0652b85bf7e7e101e0300aa9c1d284ad7061c0b/runs-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "xmod", "version": "1.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/e9/c362d47ed2b1928d65d61888c1419fae8ef69417fba2067d2fd3da1d400b/xmod-1.10.0-py3-none-any.whl"}}], "install_targets_hash": "41e4a9a78e14781d2190b51041252959"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "redis", "version": "8.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/66/9d/c5731f6e3608663d4d3656fd8d3aecee8b509c3082818f5a13eae925baea/redis-8.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "7.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ff/f6e8b8f39e08547faece4bd80f89d5a8de68a38b2d179cc1c4490ffa3286/pytest-7.4.4-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/76/e2/964e6ef372770dd7c32f9738b50ff4924f1d3cccd665b568680e4bcb0167/fakeredis-2.37.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.23.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ee/82/62e2d63639ecb0fbe8a7ee59ef0bc69a4669ec50f6d3459f74ad4e4189a2/pytest_asyncio-0.23.8-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}], "install_targets_hash": "42549a00e196f5a73560e967c6bf368f"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "redis", "version": "8.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/66/9d/c5731f6e3608663d4d3656fd8d3aecee8b509c3082818f5a13eae925baea/redis-8.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "7.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ff/f6e8b8f39e08547faece4bd80f89d5a8de68a38b2d179cc1c4490ffa3286/pytest-7.4.4-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/76/e2/964e6ef372770dd7c32f9738b50ff4924f1d3cccd665b568680e4bcb0167/fakeredis-2.37.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.23.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ee/82/62e2d63639ecb0fbe8a7ee59ef0bc69a4669ec50f6d3459f74ad4e4189a2/pytest_asyncio-0.23.8-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}], "install_targets_hash": "42549a00e196f5a73560e967c6bf368f"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "redis", "version": "8.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/66/9d/c5731f6e3608663d4d3656fd8d3aecee8b509c3082818f5a13eae925baea/redis-8.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "7.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ff/f6e8b8f39e08547faece4bd80f89d5a8de68a38b2d179cc1c4490ffa3286/pytest-7.4.4-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/76/e2/964e6ef372770dd7c32f9738b50ff4924f1d3cccd665b568680e4bcb0167/fakeredis-2.37.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.23.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ee/82/62e2d63639ecb0fbe8a7ee59ef0bc69a4669ec50f6d3459f74ad4e4189a2/pytest_asyncio-0.23.8-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}], "install_targets_hash": "42549a00e196f5a73560e967c6bf368f"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "redis", "version": "8.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/66/9d/c5731f6e3608663d4d3656fd8d3aecee8b509c3082818f5a13eae925baea/redis-8.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "7.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ff/f6e8b8f39e08547faece4bd80f89d5a8de68a38b2d179cc1c4490ffa3286/pytest-7.4.4-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/76/e2/964e6ef372770dd7c32f9738b50ff4924f1d3cccd665b568680e4bcb0167/fakeredis-2.37.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.23.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ee/82/62e2d63639ecb0fbe8a7ee59ef0bc69a4669ec50f6d3459f74ad4e4189a2/pytest_asyncio-0.23.8-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}], "install_targets_hash": "42549a00e196f5a73560e967c6bf368f"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "Django", "version": "6.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8d/ca/c1040a4fd15754ede7df15fd72fc2e123045b473b253ab5f5284e11c651e/django-6.1.1-py3-none-any.whl"}}, {"metadata": {"name": "psycopg2-binary", "version": "2.9.13"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b5/63/5a9633f4563a73beba69b20a846ddd14c1c6ac072f5e8aab0da97ffabc2a/psycopg2_binary-2.9.13-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "djangorestframework", "version": "3.18.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/83/5ed615e47339d8e65f62eb1a8133f8f046492eb3a25ad40d90acb9a208b3/djangorestframework-3.18.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-django", "version": "4.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/03/850bffad2b581c440ca51c039d74504d5a422c94bda0bdb8a8ba5068d48b/pytest_django-4.14.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.7.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/18/f1/46d32fe4b9aae09fe397e768ff376d9b6bdbb4f11faaa727f163c3457b43/pytest_forked-1.7.5-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "executing", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "asgiref", "version": "3.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c0/1b/54f4ad77cd8a584fa70746c47df988e002cf1ee1eba43364d46f87803647/asgiref-3.12.1-py3-none-any.whl"}}, {"metadata": {"name": "daphne", "version": "4.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/0c/59e966c167880904f2e6a235c63169760dce58ba8062a7a153a6183539cc/daphne-4.2.3-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "sqlparse", "version": "0.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d9/50/f00935da0ec7cbf325f8dc4f772ae46fbc7b672dd62876e73f0a94adda57/sqlparse-0.6.0-py3-none-any.whl"}}, {"metadata": {"name": "channels", "version": "4.3.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/16/34/c32915288b7ef482377b6adc401192f98c6a99b3a145423d3b8aed807898/channels-4.3.2-py3-none-any.whl"}}, {"metadata": {"name": "autobahn", "version": "26.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/36/92/2f6e57d9f9e6b86b9db362f58aaa6cfeadc2f3a6901ec95aab27ef232b5c/autobahn-26.7.1-cp313-cp313-macosx_15_0_arm64.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "Twisted", "version": "26.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/57/bcf4e2370dd218c9aa68a9140a65d86729c73f1d529f7e94786c2766fc72/twisted-26.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "Automat", "version": "25.4.16"}, "download_info": {"url": "https://files.pythonhosted.org/packages/02/ff/1175b0b7371e46244032d43a56862d0af455823b5280a50c63d99cc50f18/automat-25.4.16-py3-none-any.whl"}}, {"metadata": {"name": "cbor2", "version": "6.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/0b20c88e76942ede86c98cdce138681690f95908c540c264fff847729cd4/cbor2-6.1.4-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/41/4c7042f317b9217502988f0873af87e16ad606dc20f84e546e3e6ce9764c/cffi-2.1.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "constantly", "version": "23.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b8/40/c199d095151addf69efdb4b9ca3a4f20f70e20508d6222bffb9b76f58573/constantly-23.10.4-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/19/797e2aaac9df6a66f1550f49979dc1b1e39ecd2077501c30efa81e8d5d67/cryptography-50.0.1-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "hyperlink", "version": "21.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/aa/8caf6a0a3e62863cbb9dab27135660acba46903b703e224f14f447e57934/hyperlink-21.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "Incremental", "version": "24.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1d/55/0f4df2a44053867ea9cbea73fc588b03c55605cd695cee0a3d86f0029cb2/incremental-24.11.0-py3-none-any.whl"}}, {"metadata": {"name": "msgpack", "version": "1.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/33/54/10c6c16ddba8a5112e3680176b838e3694e4aad7284f9daa6d6d70d98817/msgpack-1.2.2-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pyOpenSSL", "version": "26.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ad/2cf6d3fa2fae5c79e1ed9960c0d42badd0f94d81dd12b50604cdc839e648/pyopenssl-26.4.0-py3-none-any.whl"}}, {"metadata": {"name": "service-identity", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/eb/2433e1af4ff903499144de4846569fb3300b816179ae99a03c2f011b666a/service_identity-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "txaio", "version": "26.6.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/91/68/075bf851e11c9ef65bd6a0426791f0d9a0c7dae0e7f6e0b16ca67334b456/txaio-26.6.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "6.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/a0/e5c7ae933fab41be06f0ff7976e3483519cbbf9e2492a217a5550af95c18/ujson-6.0.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "zope.interface", "version": "8.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/38/09/d4b7c46c020394c830e749c6c4ca6a2ca0b6defed6f4c2eeeb97116c7343/zope_interface-8.6-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "4542a2577ed3296f75e33c4dd3e42bcc"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "Django", "version": "6.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8d/ca/c1040a4fd15754ede7df15fd72fc2e123045b473b253ab5f5284e11c651e/django-6.1.1-py3-none-any.whl"}}, {"metadata": {"name": "psycopg2-binary", "version": "2.9.12"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/9c/eaa74021ac4e4d5c2f83d82fc6615a63f4fe6c94dc4e94c3990427053f67/psycopg2_binary-2.9.12-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "djangorestframework", "version": "3.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/d7/7461738e819b853275b35fd35712a85806c09a327e1fd5f8ff766bdd317e/djangorestframework-3.18.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-django", "version": "4.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/03/850bffad2b581c440ca51c039d74504d5a422c94bda0bdb8a8ba5068d48b/pytest_django-4.14.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.7.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/18/f1/46d32fe4b9aae09fe397e768ff376d9b6bdbb4f11faaa727f163c3457b43/pytest_forked-1.7.5-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "channels", "version": "4.3.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/16/34/c32915288b7ef482377b6adc401192f98c6a99b3a145423d3b8aed807898/channels-4.3.2-py3-none-any.whl"}}, {"metadata": {"name": "asgiref", "version": "3.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c0/1b/54f4ad77cd8a584fa70746c47df988e002cf1ee1eba43364d46f87803647/asgiref-3.12.1-py3-none-any.whl"}}, {"metadata": {"name": "executing", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "daphne", "version": "4.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/0c/59e966c167880904f2e6a235c63169760dce58ba8062a7a153a6183539cc/daphne-4.2.3-py3-none-any.whl"}}, {"metadata": {"name": "autobahn", "version": "26.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/ce/b735fa933e9ba4fa8c3f9aa9ae68b4e2d4aadb0a92b38ade30e37a7d4795/autobahn-26.7.1-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "cbor2", "version": "6.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e3/21/69e4d37f00319b3d37322355aedc83154b4d8b75dc9e9789c06e1fbd8a92/cbor2-6.1.4-cp313-cp313-manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/95/86342356ff5953b3fb06f7ef7c5bee212d45e770abc7218d451b9148313c/cffi-2.1.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/85/66/6ccca4722987ddedaa7fc9c3f4708af7431f5535666c174350830888c6b7/cryptography-50.0.1-cp311-abi3-manylinux_2_34_x86_64.whl"}}, {"metadata": {"name": "hyperlink", "version": "21.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/aa/8caf6a0a3e62863cbb9dab27135660acba46903b703e224f14f447e57934/hyperlink-21.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/21/9b05698b46f218fc0e118e1f8168395c65c8a2c750ae2bab54fc4bd4e0e8/markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "msgpack", "version": "1.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/d3/6592e4064619b04f2dd0054c5fa13e37e3d55eb26044483d871fadb2f46b/msgpack-1.2.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "sqlparse", "version": "0.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d9/50/f00935da0ec7cbf325f8dc4f772ae46fbc7b672dd62876e73f0a94adda57/sqlparse-0.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Twisted", "version": "26.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/57/bcf4e2370dd218c9aa68a9140a65d86729c73f1d529f7e94786c2766fc72/twisted-26.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "Automat", "version": "25.4.16"}, "download_info": {"url": "https://files.pythonhosted.org/packages/02/ff/1175b0b7371e46244032d43a56862d0af455823b5280a50c63d99cc50f18/automat-25.4.16-py3-none-any.whl"}}, {"metadata": {"name": "constantly", "version": "23.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b8/40/c199d095151addf69efdb4b9ca3a4f20f70e20508d6222bffb9b76f58573/constantly-23.10.4-py3-none-any.whl"}}, {"metadata": {"name": "Incremental", "version": "24.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1d/55/0f4df2a44053867ea9cbea73fc588b03c55605cd695cee0a3d86f0029cb2/incremental-24.11.0-py3-none-any.whl"}}, {"metadata": {"name": "pyOpenSSL", "version": "26.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ad/2cf6d3fa2fae5c79e1ed9960c0d42badd0f94d81dd12b50604cdc839e648/pyopenssl-26.4.0-py3-none-any.whl"}}, {"metadata": {"name": "service-identity", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/eb/2433e1af4ff903499144de4846569fb3300b816179ae99a03c2f011b666a/service_identity-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "txaio", "version": "26.6.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/91/68/075bf851e11c9ef65bd6a0426791f0d9a0c7dae0e7f6e0b16ca67334b456/txaio-26.6.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "6.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/45/ad/26f40cdffaebd1158b1083d6c89efd9e056badd706022386a0e9567ae499/ujson-6.0.0-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "zope.interface", "version": "8.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/96/c02befafb8e5d3c92898aa02fffca94d164830013fd0a50c4a652a728712/zope_interface-8.6-cp313-cp313-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "4542a2577ed3296f75e33c4dd3e42bcc"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "anthropic", "version": "1.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c0/dc/74995efda028421917f4caabd24db1373ee0742573a2363fff1a21191441/anthropic-1.7.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/27/17/91420b156315ae22732f5ee1a7b5725a030aab9dc8fd7dcdacfb4aa588d3/jiter-0.17.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d3/f2/9e4de77a6271e07a76d2d58b11c091a979c191ed2939bf80067568b369d2/pydantic_core-2.46.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}], "install_targets_hash": "4727845e3afb2745d5e910cf0c6cbc97"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "trytond", "version": "7.8.16"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d8/05/24ac74eee184cc503c8ab1f39c0b16e17ebd4a5a7622b5517ecbec665db8/trytond-7.8.16-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "lxml", "version": "6.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ac/7d/8bf1fd8bae8247743968bb76d027a1ac5bd2c4b44495fba6a71b30d10706/lxml-6.1.3-cp313-cp313-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/21/9b05698b46f218fc0e118e1f8168395c65c8a2c750ae2bab54fc4bd4e0e8/markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "pwdlib", "version": "0.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6b/2e/51979293b2337f508597d13ee20db1ac1d43e48086b2ed7de6da213ed46b/pwdlib-0.3.1-py3-none-any.whl"}}, {"metadata": {"name": "argon2-cffi", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/d3/a8b22fa575b297cd6e3e3b0155c7e25db170edf1c74783d6a31a2490b8d9/argon2_cffi-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "python-sql", "version": "1.8.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/77/ac/3603bbdde340f7354c975431c94b70ef3e99966c5b170fa121f8e64d269e/python_sql-1.8.1-py3-none-any.whl"}}, {"metadata": {"name": "relatorio", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/74/eb/798c426ebd54f52c27aed6593eaf96ed07dca3ca1d084822cc34f0db5159/relatorio-1.0.0-py3-none-any.whl"}}, {"metadata": {"name": "Genshi", "version": "0.7.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/27/503016bc329720ba2856eb4831d6ba36089cd6f15bc4fe85db69fea5b563/genshi-0.7.11-py3-none-any.whl"}}, {"metadata": {"name": "argon2-cffi-bindings", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6f/86/5363df11b86d02cf3662208e7406496327649cc90eb365bf6f4e8a54a41f/argon2_cffi_bindings-26.1.0-cp310-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/95/86342356ff5953b3fb06f7ef7c5bee212d45e770abc7218d451b9148313c/cffi-2.1.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "defusedxml", "version": "0.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "polib", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6b/99/45bb1f9926efe370c6dbe324741c749658e44cb060124f28dad201202274/polib-1.2.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "puremagic", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/81/314320aeffd88dadeac553ff9eb10f54507ab41deccd0c69f6221d254a0a/puremagic-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "simpleeval", "version": "1.0.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/33/d1ecd9f4f5f272b36ad7b268e307ba0a59c109d8ad134a231cda780baac9/simpleeval-1.0.8-py3-none-any.whl"}}], "install_targets_hash": "4a8515036fcaf8193b6feebd535cc37d"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "arq", "version": "0.28.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/48/32/66b616976c5058d434ca2017979bfffd784888177b16b5038abcec93954a/arq-0.28.0-py3-none-any.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/4d/e6e40f93031adbf654d34e542bd396e9f3bc1c6209b40c920d58c9e1317a/fakeredis-2.36.2-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "redis", "version": "5.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/26/5c5fa0e83c3621db835cfc1f1d789b37e7fa99ed54423b5f519beb931aa7/redis-5.3.1-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "hiredis", "version": "3.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/29/6d/692c50d846a0a36578e9ef0c62c6193ce01a48f353f6961de9de88a30b37/hiredis-3.4.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl"}}], "install_targets_hash": "4bd147206b5343b7421e83fb1f8cf3a4"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "arq", "version": "0.28.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/48/32/66b616976c5058d434ca2017979bfffd784888177b16b5038abcec93954a/arq-0.28.0-py3-none-any.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/4d/e6e40f93031adbf654d34e542bd396e9f3bc1c6209b40c920d58c9e1317a/fakeredis-2.36.2-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "redis", "version": "5.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/26/5c5fa0e83c3621db835cfc1f1d789b37e7fa99ed54423b5f519beb931aa7/redis-5.3.1-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "hiredis", "version": "3.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/29/6d/692c50d846a0a36578e9ef0c62c6193ce01a48f353f6961de9de88a30b37/hiredis-3.4.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl"}}], "install_targets_hash": "4bd147206b5343b7421e83fb1f8cf3a4"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "arq", "version": "0.28.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/48/32/66b616976c5058d434ca2017979bfffd784888177b16b5038abcec93954a/arq-0.28.0-py3-none-any.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/4d/e6e40f93031adbf654d34e542bd396e9f3bc1c6209b40c920d58c9e1317a/fakeredis-2.36.2-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "redis", "version": "5.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/26/5c5fa0e83c3621db835cfc1f1d789b37e7fa99ed54423b5f519beb931aa7/redis-5.3.1-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "hiredis", "version": "3.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/29/6d/692c50d846a0a36578e9ef0c62c6193ce01a48f353f6961de9de88a30b37/hiredis-3.4.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl"}}], "install_targets_hash": "4bd147206b5343b7421e83fb1f8cf3a4"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "arq", "version": "0.28.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/48/32/66b616976c5058d434ca2017979bfffd784888177b16b5038abcec93954a/arq-0.28.0-py3-none-any.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/4d/e6e40f93031adbf654d34e542bd396e9f3bc1c6209b40c920d58c9e1317a/fakeredis-2.36.2-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "redis", "version": "5.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/26/5c5fa0e83c3621db835cfc1f1d789b37e7fa99ed54423b5f519beb931aa7/redis-5.3.1-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "hiredis", "version": "3.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/29/6d/692c50d846a0a36578e9ef0c62c6193ce01a48f353f6961de9de88a30b37/hiredis-3.4.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl"}}], "install_targets_hash": "4bd147206b5343b7421e83fb1f8cf3a4"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "ariadne", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/48/e0bd1918ef56b1a570dfc1882a036286bf4b3f13e5a659a8d9e16d888c69/ariadne-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "fastapi", "version": "0.139.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/7c/8e3c6ad324ea5cb36604fc3f968554887891c316d9dfde57761611d907ad/fastapi-0.139.0-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/15/b92b4e1d88d02c6eff9733c9eea21846ab435cc4d813d84ccc5d335955df/graphql_core-3.2.11-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/81/4fa520eaffa8bd7d1525e644cd6d39e7d60b1592bc5b516693c7340b50f1/pydantic_core-2.46.4-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}], "install_targets_hash": "4be724db1412c7b7718411b02cd97084"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "ariadne", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/48/e0bd1918ef56b1a570dfc1882a036286bf4b3f13e5a659a8d9e16d888c69/ariadne-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "fastapi", "version": "0.139.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/7c/8e3c6ad324ea5cb36604fc3f968554887891c316d9dfde57761611d907ad/fastapi-0.139.0-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/15/b92b4e1d88d02c6eff9733c9eea21846ab435cc4d813d84ccc5d335955df/graphql_core-3.2.11-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/81/4fa520eaffa8bd7d1525e644cd6d39e7d60b1592bc5b516693c7340b50f1/pydantic_core-2.46.4-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}], "install_targets_hash": "4be724db1412c7b7718411b02cd97084"} -{"python_version": "3.13", "dependencies": [{"metadata": {"name": "langgraph", "version": "1.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0a/7f/c5c30e4be99ff821029c7ac872a480676bb179c9f3df85ea3f38d13f86d4/langgraph-1.2.11-py3-none-any.whl"}}, {"metadata": {"name": "langchain-core", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/84/4c/508a90b9d2e3bd7738fd93cb2ac2178ce734662c75e69b3b81c445f1b360/langchain_core-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "langgraph-checkpoint", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/71/3b475f09bd57d3a5649792c66353312b4432afd843f301739dfcebd157f0/langgraph_checkpoint-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "langgraph-prebuilt", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/43/3fe1a700b8490ed02679cdbbc8c915eb23a092faf496c9c1118abcd10be3/langgraph_prebuilt-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "langgraph-sdk", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5a/a0/f3bc44b46ef730588f66fdf9e9ddc54189db78482a9e914ae6a554a2b2e0/langgraph_sdk-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/81/4fa520eaffa8bd7d1525e644cd6d39e7d60b1592bc5b516693c7340b50f1/pydantic_core-2.46.4-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "xxhash", "version": "4.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/e0/934af8d99bb5885711006bec30a691f728edd513d2c40f053f887d8e7577/xxhash-4.0.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "jsonpatch", "version": "1.33"}, "download_info": {"url": "https://files.pythonhosted.org/packages/73/07/02e16ed01e04a374e644b575638ec7987ae846d25ad97bcc9945a3ee4b0e/jsonpatch-1.33-py2.py3-none-any.whl"}}, {"metadata": {"name": "langchain-protocol", "version": "0.0.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/2e/d82db9eec13ad0f72e7aaad5c4bc730ab111934fdc83c85523206eb9b0a0/langchain_protocol-0.0.18-py3-none-any.whl"}}, {"metadata": {"name": "langsmith", "version": "0.11.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/85/0ad6df25588122760b2b40ec182eafc55532c9e66015c83e16675bd34a29/langsmith-0.11.1-py3-none-any.whl"}}, {"metadata": {"name": "orjson", "version": "3.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f8/4a/bc87c45e7ec639d35ebefd62618e01939531ac8e171426606a01bda05914/orjson-3.12.0-cp313-cp313-macosx_15_0_arm64.whl"}}, {"metadata": {"name": "ormsgpack", "version": "1.12.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/29/bb0eba3288c0449efbb013e9c6f58aea79cf5cb9ee1921f8865f04c1a9d7/ormsgpack-1.12.2-cp313-cp313-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uuid_utils", "version": "0.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/dd/614fb9912157ac0128e6050859ccf06d9f13df9a944a803e8f80f6157e38/uuid_utils-0.17.0-cp313-cp313-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/86/0a70d3ae2f0f2256bb41302d9804dbca65d4360281e7feb3e1f94102ac46/websockets-16.1.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "jsonpointer", "version": "3.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/6a/a83720e953b1682d2d109d3c2dbb0bc9bf28cc1cbc205be4ef4be5da709d/jsonpointer-3.1.1-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "zstandard", "version": "0.25.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/06/9ae96a3e5dcfd119377ba33d4c42a7d89da1efabd5cb3e366b156c45ff4d/zstandard-0.25.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a4/a0/562247944386f7d4ef94467e84876600cc1e0f1b93239aaa9213d2bc3cbd/charset_normalizer-3.5.1-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}], "install_targets_hash": "4ded69ebfc3885a149b764fa94a36954"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "ariadne", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/48/e0bd1918ef56b1a570dfc1882a036286bf4b3f13e5a659a8d9e16d888c69/ariadne-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "fastapi", "version": "0.139.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/7c/8e3c6ad324ea5cb36604fc3f968554887891c316d9dfde57761611d907ad/fastapi-0.139.0-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/15/b92b4e1d88d02c6eff9733c9eea21846ab435cc4d813d84ccc5d335955df/graphql_core-3.2.11-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/81/4fa520eaffa8bd7d1525e644cd6d39e7d60b1592bc5b516693c7340b50f1/pydantic_core-2.46.4-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}], "install_targets_hash": "4be724db1412c7b7718411b02cd97084"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "aiohttp", "version": "3.11.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/85/f07718cca55884dad83cc2433746384d267ee970e91f0dcc75c6d5544079/aiohttp-3.11.18-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/76/55cd7186f498ed080a18440c9013011eb548f77ae1b297206d030eb1180a/multidict-6.7.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/15/f0/7688d3f2cfff7590df2af38ec46d969f4281a4dddb08a9ad2eafbcdddf98/yarl-1.24.5-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-aiohttp", "version": "1.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fa/b0/5056ed4c3f68a4db2b4a39fb0ec61b1e4cf1d89ee14effe5261cc587264c/pytest_aiohttp-1.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/ab/6e5080ee374f875296c4243c381bbdef97a9ac39c6e3ce1d5f7d42cb78d6/frozenlist-1.8.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/12/a6ba6482bb5ea3260c000c9b20881c95fa11c6b30173715668259f844ed7/propcache-0.5.2-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "4dcb68c9e098057b61d8630a385f1e96"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "fastmcp", "version": "4.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/c0/1f985175c9eee7725ebef1be5a7c210787ad0c7649f56dab5c5af5185816/fastmcp-4.0.5-py3-none-any.whl"}}, {"metadata": {"name": "fastmcp-slim", "version": "4.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ed/76/8dc551ef1f222bd146537ae100baf7441628aa1050494b567249ece997c2/fastmcp_slim-4.0.5-py3-none-any.whl"}}, {"metadata": {"name": "mcp", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/ff/8e7eade68b8a28f7da0ed1085544341b51f9c935dbf6b95c76b7edfea6a0/mcp-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mcp-types", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8f/d7/6ffba5d8cd5dd9b8a19478875c50e04945314ba5074e84d749283f27f62d/mcp_types-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "py-key-value-aio", "version": "0.4.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/46/12871550fb0613d149144bb9d41f22680d5f46717bc45a76eb5798c20c3f/py_key_value_aio-0.4.6-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "aiofile", "version": "3.12.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/79/6e45e778c4c3cab39e0937b007b720c15f76c50c6453d153282d0fcc3588/aiofile-3.12.3-py3-none-any.whl"}}, {"metadata": {"name": "caio", "version": "0.12.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/64/f33b9aaf7bc9bad988211d8e42b4b85c25a1d5dcc0906798aebe49bd421b/caio-0.12.4-cp313-cp313-manylinux_2_34_x86_64.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "Authlib", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b8/c6/6f124bcfbbfb20fba22c939b4e43a06dccfc0e1ca20e5634ca573cb1e271/authlib-1.8.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "beartype", "version": "0.22.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/cc/18245721fa7747065ab478316c7fea7c74777d07f37ae60db2e84f8172e8/beartype-0.22.9-py3-none-any.whl"}}, {"metadata": {"name": "cachetools", "version": "7.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cc/bb/1c6e7a89b11da19f137e4ef5a5c5fe47a5bb686449ba343944ccf8fb34b2/cachetools-7.2.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/85/66/6ccca4722987ddedaa7fc9c3f4708af7431f5535666c174350830888c6b7/cryptography-50.0.1-cp311-abi3-manylinux_2_34_x86_64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/95/86342356ff5953b3fb06f7ef7c5bee212d45e770abc7218d451b9148313c/cffi-2.1.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "cyclopts", "version": "4.25.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/cc/e879da3d54cf727f90e6d90118e132672c3913338b566740486f8797190d/cyclopts-4.25.3-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "rich-rst", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/68/1fc93dd759605b5d00fc98b50200739e41ed32bd22d6ba35ca6c3932371b/rich_rst-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "griffelib", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/63/e876e789525063c840ccfa8857febdabd6523bcef9ce7eb979b9305ea895/griffelib-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "joserfc", "version": "1.7.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/c5/82addfd375e5ee6520644e0553e4aadde92d668c4fc99cc716d337fe7bb3/joserfc-1.7.5-py3-none-any.whl"}}, {"metadata": {"name": "jsonref", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/ec/e1db9922bceb168197a558a2b8c03a7963f1afe93517ddd3cf99f202f996/jsonref-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-path", "version": "0.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/2c/9e69d73c4297508be9e3b64a970ea3971b3eb8db64ffc5802d40bd25981f/jsonschema_path-0.5.0-py3-none-any.whl"}}, {"metadata": {"name": "pathable", "version": "0.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a2/e8/6d75ffd9784bce2e93d1ae4415649427e39a53bb172d4672b2b59c6f0a7b/pathable-0.6.0-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "keyring", "version": "25.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/db/e655086b7f3a705df045bf0933bdd9c2f79bb3c97bfef1384598bb79a217/keyring-25.7.0-py3-none-any.whl"}}, {"metadata": {"name": "jeepney", "version": "0.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b2/a3/e137168c9c44d18eff0376253da9f1e9234d0239e0ee230d2fee6cea8e55/jeepney-0.9.0-py3-none-any.whl"}}, {"metadata": {"name": "openapi-pydantic", "version": "0.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/cf/03675d8bd8ecbf4445504d8071adab19f5f993676795708e36402ab38263/openapi_pydantic-0.5.1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/6f/a04e900f465ff3221ccc395522503e2d10e79fa21f2723c8e177aae1e0d1/opentelemetry_api-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "platformdirs", "version": "4.11.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/39/be/3ae887e84c38c4dd1c549cd5825adc93f48069a94fe1cb8ac52a9da16f15/platformdirs-4.11.11-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d3/f2/9e4de77a6271e07a76d2d58b11c091a979c191ed2939bf80067568b369d2/pydantic_core-2.46.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "email-validator", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "dnspython", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/97/672cb32ce0dfea44b740cb7b4f97038463b9cf7c0ead1aacf595572851d6/pyjwt-2.14.0-py3-none-any.whl"}}, {"metadata": {"name": "pyperclip", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/80/fc9d01d5ed37ba4c42ca2b55b4339ae6e200b456be3a1aaddf4a9fa99b8c/pyperclip-1.11.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/d7/fe978efc2ae50abe48eb7464668ea99f53c010c60aeebb7b35ad27f23661/rpds_py-2026.6.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "SecretStorage", "version": "3.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/46/f5af3402b579fd5e11573ce652019a67074317e18c1935cc0b4ba9b35552/secretstorage-3.5.0-py3-none-any.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/6a/2ba3ed4a69babf3afdddf7d8314a48d87562c0a442206bbc2a1b50d5efc0/sse_starlette-3.4.11-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uncalled-for", "version": "0.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a2/40/97cec87c077eb3291fc7905e6633e08b7ca593c57d30238444bcb6bb3d53/uncalled_for-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.53.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/76/18/0eea75741ee812e9f598b687619ce2454f6c3a1c5cd21ea990ec6bd26f45/uvicorn-0.53.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "watchfiles", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/6c/89b1a230a78f57c52dd8893adb1f92f94411721b6ec12596c56d98c74356/watchfiles-1.2.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "websockets", "version": "17.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/34/c7/e1c2e8a67f6cc0aa43abe0046fb3b7a020980649e6a843751dc7ce9eb170/websockets-17.1-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.classes", "version": "3.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/66/b15ce62552d84bbfcec9a4873ab79d993a1dd4edb922cbfccae192bd5b5f/jaraco.classes-3.4.0-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.context", "version": "6.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f2/58/bc8954bda5fcda97bd7c19be11b85f91973d67a706ed4a3aec33e7de22db/jaraco_context-6.1.2-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.functools", "version": "4.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/02/36/ecc85bc96c273dc8a11273ed4782272975e6338d4a3e9228621175edf0e3/jaraco_functools-4.6.0-py3-none-any.whl"}}, {"metadata": {"name": "more-itertools", "version": "11.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/3d/1087453384dbde46a8c7f9356eead2c58be8a7bf156bca40243377c85715/more_itertools-11.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "4ea2151a96fd3708d6bee248d6499707"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "Django", "version": "5.2.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/f8/ce120525ca78f12b07daf65786679c5d0b54a75285a8958d3ae55e39da35/django-5.2.17-py3-none-any.whl"}}, {"metadata": {"name": "psycopg2-binary", "version": "2.9.12"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5e/af/48f76af9d50d61cf390f8cd657b503168b089e2e9298e48465d029fcc713/psycopg2_binary-2.9.12-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "djangorestframework", "version": "3.17.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5a/e1/2c516bdc83652b1a60c6119366ac2c0607b479ed05cd6093f916ca8928f8/djangorestframework-3.17.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-django", "version": "4.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/83/a5/41d091f697c09609e7ef1d5d61925494e0454ebf51de7de05f0f0a728f1d/pytest_django-4.12.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/af/9c0bda43e486a3c9bf1e0f876d0f241bc3f229d7d65d09331a0868db9629/pytest_forked-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "channels", "version": "4.3.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/16/34/c32915288b7ef482377b6adc401192f98c6a99b3a145423d3b8aed807898/channels-4.3.2-py3-none-any.whl"}}, {"metadata": {"name": "asgiref", "version": "3.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c0/1b/54f4ad77cd8a584fa70746c47df988e002cf1ee1eba43364d46f87803647/asgiref-3.12.1-py3-none-any.whl"}}, {"metadata": {"name": "executing", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "daphne", "version": "4.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/0c/59e966c167880904f2e6a235c63169760dce58ba8062a7a153a6183539cc/daphne-4.2.3-py3-none-any.whl"}}, {"metadata": {"name": "autobahn", "version": "26.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/36/92/2f6e57d9f9e6b86b9db362f58aaa6cfeadc2f3a6901ec95aab27ef232b5c/autobahn-26.7.1-cp313-cp313-macosx_15_0_arm64.whl"}}, {"metadata": {"name": "cbor2", "version": "6.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/0b20c88e76942ede86c98cdce138681690f95908c540c264fff847729cd4/cbor2-6.1.4-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/41/4c7042f317b9217502988f0873af87e16ad606dc20f84e546e3e6ce9764c/cffi-2.1.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/5c/59086b4aac5e879d38ddbcf74e4be7ade89cebc3eb199a55da998c3bb46a/cryptography-50.0.0-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "hyperlink", "version": "21.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/aa/8caf6a0a3e62863cbb9dab27135660acba46903b703e224f14f447e57934/hyperlink-21.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "msgpack", "version": "1.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/71/fbcfa83a1d6a9c6091942d1cfd070962244664b87427a9a49a6897b1b219/msgpack-1.2.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "sqlparse", "version": "0.5.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/4b/359f28a903c13438ef59ebeee215fb25da53066db67b305c125f1c6d2a25/sqlparse-0.5.5-py3-none-any.whl"}}, {"metadata": {"name": "Twisted", "version": "26.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/57/bcf4e2370dd218c9aa68a9140a65d86729c73f1d529f7e94786c2766fc72/twisted-26.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "Automat", "version": "25.4.16"}, "download_info": {"url": "https://files.pythonhosted.org/packages/02/ff/1175b0b7371e46244032d43a56862d0af455823b5280a50c63d99cc50f18/automat-25.4.16-py3-none-any.whl"}}, {"metadata": {"name": "constantly", "version": "23.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b8/40/c199d095151addf69efdb4b9ca3a4f20f70e20508d6222bffb9b76f58573/constantly-23.10.4-py3-none-any.whl"}}, {"metadata": {"name": "Incremental", "version": "24.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1d/55/0f4df2a44053867ea9cbea73fc588b03c55605cd695cee0a3d86f0029cb2/incremental-24.11.0-py3-none-any.whl"}}, {"metadata": {"name": "pyOpenSSL", "version": "26.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ad/2cf6d3fa2fae5c79e1ed9960c0d42badd0f94d81dd12b50604cdc839e648/pyopenssl-26.4.0-py3-none-any.whl"}}, {"metadata": {"name": "service-identity", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/eb/2433e1af4ff903499144de4846569fb3300b816179ae99a03c2f011b666a/service_identity-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "txaio", "version": "26.6.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/91/68/075bf851e11c9ef65bd6a0426791f0d9a0c7dae0e7f6e0b16ca67334b456/txaio-26.6.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "5.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6a/c0/c7ab82d6471dfa7e4fd68ae6ff2c6a50d077c05d6ecdea0cec8af635b2c4/ujson-5.13.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "zope.interface", "version": "8.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/2e/4360c54c465db042cc8fbeeec92abac28b4cedbf6ba63c1f092fd08a190f/zope_interface-8.5-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "py", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "4ed72e643e6a9d9ab4940427b6f18363"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "Django", "version": "5.2.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/f8/ce120525ca78f12b07daf65786679c5d0b54a75285a8958d3ae55e39da35/django-5.2.17-py3-none-any.whl"}}, {"metadata": {"name": "psycopg2-binary", "version": "2.9.12"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5e/af/48f76af9d50d61cf390f8cd657b503168b089e2e9298e48465d029fcc713/psycopg2_binary-2.9.12-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "djangorestframework", "version": "3.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/d7/7461738e819b853275b35fd35712a85806c09a327e1fd5f8ff766bdd317e/djangorestframework-3.18.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-django", "version": "4.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/27/88/52db7a840fdbd74934f8df11b7450c9919ac00f61c02e88827f3d58180f7/pytest_django-4.13.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.7.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/18/f1/46d32fe4b9aae09fe397e768ff376d9b6bdbb4f11faaa727f163c3457b43/pytest_forked-1.7.5-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "executing", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "asgiref", "version": "3.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c0/1b/54f4ad77cd8a584fa70746c47df988e002cf1ee1eba43364d46f87803647/asgiref-3.12.1-py3-none-any.whl"}}, {"metadata": {"name": "daphne", "version": "4.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/0c/59e966c167880904f2e6a235c63169760dce58ba8062a7a153a6183539cc/daphne-4.2.3-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "sqlparse", "version": "0.5.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/4b/359f28a903c13438ef59ebeee215fb25da53066db67b305c125f1c6d2a25/sqlparse-0.5.5-py3-none-any.whl"}}, {"metadata": {"name": "channels", "version": "4.3.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/16/34/c32915288b7ef482377b6adc401192f98c6a99b3a145423d3b8aed807898/channels-4.3.2-py3-none-any.whl"}}, {"metadata": {"name": "autobahn", "version": "26.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/36/92/2f6e57d9f9e6b86b9db362f58aaa6cfeadc2f3a6901ec95aab27ef232b5c/autobahn-26.7.1-cp313-cp313-macosx_15_0_arm64.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "Twisted", "version": "26.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/57/bcf4e2370dd218c9aa68a9140a65d86729c73f1d529f7e94786c2766fc72/twisted-26.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "Automat", "version": "25.4.16"}, "download_info": {"url": "https://files.pythonhosted.org/packages/02/ff/1175b0b7371e46244032d43a56862d0af455823b5280a50c63d99cc50f18/automat-25.4.16-py3-none-any.whl"}}, {"metadata": {"name": "cbor2", "version": "6.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/0b20c88e76942ede86c98cdce138681690f95908c540c264fff847729cd4/cbor2-6.1.4-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/41/4c7042f317b9217502988f0873af87e16ad606dc20f84e546e3e6ce9764c/cffi-2.1.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "constantly", "version": "23.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b8/40/c199d095151addf69efdb4b9ca3a4f20f70e20508d6222bffb9b76f58573/constantly-23.10.4-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/5c/59086b4aac5e879d38ddbcf74e4be7ade89cebc3eb199a55da998c3bb46a/cryptography-50.0.0-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "hyperlink", "version": "21.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/aa/8caf6a0a3e62863cbb9dab27135660acba46903b703e224f14f447e57934/hyperlink-21.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "Incremental", "version": "24.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1d/55/0f4df2a44053867ea9cbea73fc588b03c55605cd695cee0a3d86f0029cb2/incremental-24.11.0-py3-none-any.whl"}}, {"metadata": {"name": "msgpack", "version": "1.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/71/fbcfa83a1d6a9c6091942d1cfd070962244664b87427a9a49a6897b1b219/msgpack-1.2.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pyOpenSSL", "version": "26.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ad/2cf6d3fa2fae5c79e1ed9960c0d42badd0f94d81dd12b50604cdc839e648/pyopenssl-26.4.0-py3-none-any.whl"}}, {"metadata": {"name": "service-identity", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/eb/2433e1af4ff903499144de4846569fb3300b816179ae99a03c2f011b666a/service_identity-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "txaio", "version": "26.6.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/91/68/075bf851e11c9ef65bd6a0426791f0d9a0c7dae0e7f6e0b16ca67334b456/txaio-26.6.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "5.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6a/c0/c7ab82d6471dfa7e4fd68ae6ff2c6a50d077c05d6ecdea0cec8af635b2c4/ujson-5.13.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "zope.interface", "version": "8.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/2e/4360c54c465db042cc8fbeeec92abac28b4cedbf6ba63c1f092fd08a190f/zope_interface-8.5-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "4ed72e643e6a9d9ab4940427b6f18363"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "Django", "version": "5.2.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/f8/ce120525ca78f12b07daf65786679c5d0b54a75285a8958d3ae55e39da35/django-5.2.17-py3-none-any.whl"}}, {"metadata": {"name": "psycopg2-binary", "version": "2.9.12"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5e/af/48f76af9d50d61cf390f8cd657b503168b089e2e9298e48465d029fcc713/psycopg2_binary-2.9.12-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "djangorestframework", "version": "3.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/d7/7461738e819b853275b35fd35712a85806c09a327e1fd5f8ff766bdd317e/djangorestframework-3.18.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-django", "version": "4.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/27/88/52db7a840fdbd74934f8df11b7450c9919ac00f61c02e88827f3d58180f7/pytest_django-4.13.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.7.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/18/f1/46d32fe4b9aae09fe397e768ff376d9b6bdbb4f11faaa727f163c3457b43/pytest_forked-1.7.5-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "executing", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "asgiref", "version": "3.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c0/1b/54f4ad77cd8a584fa70746c47df988e002cf1ee1eba43364d46f87803647/asgiref-3.12.1-py3-none-any.whl"}}, {"metadata": {"name": "daphne", "version": "4.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/0c/59e966c167880904f2e6a235c63169760dce58ba8062a7a153a6183539cc/daphne-4.2.3-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "sqlparse", "version": "0.5.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/4b/359f28a903c13438ef59ebeee215fb25da53066db67b305c125f1c6d2a25/sqlparse-0.5.5-py3-none-any.whl"}}, {"metadata": {"name": "channels", "version": "4.3.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/16/34/c32915288b7ef482377b6adc401192f98c6a99b3a145423d3b8aed807898/channels-4.3.2-py3-none-any.whl"}}, {"metadata": {"name": "autobahn", "version": "26.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/36/92/2f6e57d9f9e6b86b9db362f58aaa6cfeadc2f3a6901ec95aab27ef232b5c/autobahn-26.7.1-cp313-cp313-macosx_15_0_arm64.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "Twisted", "version": "26.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/57/bcf4e2370dd218c9aa68a9140a65d86729c73f1d529f7e94786c2766fc72/twisted-26.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "Automat", "version": "25.4.16"}, "download_info": {"url": "https://files.pythonhosted.org/packages/02/ff/1175b0b7371e46244032d43a56862d0af455823b5280a50c63d99cc50f18/automat-25.4.16-py3-none-any.whl"}}, {"metadata": {"name": "cbor2", "version": "6.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/0b20c88e76942ede86c98cdce138681690f95908c540c264fff847729cd4/cbor2-6.1.4-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/41/4c7042f317b9217502988f0873af87e16ad606dc20f84e546e3e6ce9764c/cffi-2.1.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "constantly", "version": "23.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b8/40/c199d095151addf69efdb4b9ca3a4f20f70e20508d6222bffb9b76f58573/constantly-23.10.4-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/5c/59086b4aac5e879d38ddbcf74e4be7ade89cebc3eb199a55da998c3bb46a/cryptography-50.0.0-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "hyperlink", "version": "21.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/aa/8caf6a0a3e62863cbb9dab27135660acba46903b703e224f14f447e57934/hyperlink-21.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "Incremental", "version": "24.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1d/55/0f4df2a44053867ea9cbea73fc588b03c55605cd695cee0a3d86f0029cb2/incremental-24.11.0-py3-none-any.whl"}}, {"metadata": {"name": "msgpack", "version": "1.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/71/fbcfa83a1d6a9c6091942d1cfd070962244664b87427a9a49a6897b1b219/msgpack-1.2.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pyOpenSSL", "version": "26.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ad/2cf6d3fa2fae5c79e1ed9960c0d42badd0f94d81dd12b50604cdc839e648/pyopenssl-26.4.0-py3-none-any.whl"}}, {"metadata": {"name": "service-identity", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/eb/2433e1af4ff903499144de4846569fb3300b816179ae99a03c2f011b666a/service_identity-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "txaio", "version": "26.6.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/91/68/075bf851e11c9ef65bd6a0426791f0d9a0c7dae0e7f6e0b16ca67334b456/txaio-26.6.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "5.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6a/c0/c7ab82d6471dfa7e4fd68ae6ff2c6a50d077c05d6ecdea0cec8af635b2c4/ujson-5.13.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "zope.interface", "version": "8.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/2e/4360c54c465db042cc8fbeeec92abac28b4cedbf6ba63c1f092fd08a190f/zope_interface-8.5-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "4ed72e643e6a9d9ab4940427b6f18363"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "Django", "version": "5.2.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/f8/ce120525ca78f12b07daf65786679c5d0b54a75285a8958d3ae55e39da35/django-5.2.17-py3-none-any.whl"}}, {"metadata": {"name": "psycopg2-binary", "version": "2.9.12"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5e/af/48f76af9d50d61cf390f8cd657b503168b089e2e9298e48465d029fcc713/psycopg2_binary-2.9.12-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "djangorestframework", "version": "3.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/d7/7461738e819b853275b35fd35712a85806c09a327e1fd5f8ff766bdd317e/djangorestframework-3.18.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-django", "version": "4.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/27/88/52db7a840fdbd74934f8df11b7450c9919ac00f61c02e88827f3d58180f7/pytest_django-4.13.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.7.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/18/f1/46d32fe4b9aae09fe397e768ff376d9b6bdbb4f11faaa727f163c3457b43/pytest_forked-1.7.5-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "executing", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "asgiref", "version": "3.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c0/1b/54f4ad77cd8a584fa70746c47df988e002cf1ee1eba43364d46f87803647/asgiref-3.12.1-py3-none-any.whl"}}, {"metadata": {"name": "daphne", "version": "4.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/0c/59e966c167880904f2e6a235c63169760dce58ba8062a7a153a6183539cc/daphne-4.2.3-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "sqlparse", "version": "0.5.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/4b/359f28a903c13438ef59ebeee215fb25da53066db67b305c125f1c6d2a25/sqlparse-0.5.5-py3-none-any.whl"}}, {"metadata": {"name": "channels", "version": "4.3.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/16/34/c32915288b7ef482377b6adc401192f98c6a99b3a145423d3b8aed807898/channels-4.3.2-py3-none-any.whl"}}, {"metadata": {"name": "autobahn", "version": "26.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/36/92/2f6e57d9f9e6b86b9db362f58aaa6cfeadc2f3a6901ec95aab27ef232b5c/autobahn-26.7.1-cp313-cp313-macosx_15_0_arm64.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "Twisted", "version": "26.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/57/bcf4e2370dd218c9aa68a9140a65d86729c73f1d529f7e94786c2766fc72/twisted-26.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "Automat", "version": "25.4.16"}, "download_info": {"url": "https://files.pythonhosted.org/packages/02/ff/1175b0b7371e46244032d43a56862d0af455823b5280a50c63d99cc50f18/automat-25.4.16-py3-none-any.whl"}}, {"metadata": {"name": "cbor2", "version": "6.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/0b20c88e76942ede86c98cdce138681690f95908c540c264fff847729cd4/cbor2-6.1.4-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/41/4c7042f317b9217502988f0873af87e16ad606dc20f84e546e3e6ce9764c/cffi-2.1.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "constantly", "version": "23.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b8/40/c199d095151addf69efdb4b9ca3a4f20f70e20508d6222bffb9b76f58573/constantly-23.10.4-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/5c/59086b4aac5e879d38ddbcf74e4be7ade89cebc3eb199a55da998c3bb46a/cryptography-50.0.0-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "hyperlink", "version": "21.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/aa/8caf6a0a3e62863cbb9dab27135660acba46903b703e224f14f447e57934/hyperlink-21.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "Incremental", "version": "24.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1d/55/0f4df2a44053867ea9cbea73fc588b03c55605cd695cee0a3d86f0029cb2/incremental-24.11.0-py3-none-any.whl"}}, {"metadata": {"name": "msgpack", "version": "1.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/71/fbcfa83a1d6a9c6091942d1cfd070962244664b87427a9a49a6897b1b219/msgpack-1.2.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pyOpenSSL", "version": "26.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ad/2cf6d3fa2fae5c79e1ed9960c0d42badd0f94d81dd12b50604cdc839e648/pyopenssl-26.4.0-py3-none-any.whl"}}, {"metadata": {"name": "service-identity", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/eb/2433e1af4ff903499144de4846569fb3300b816179ae99a03c2f011b666a/service_identity-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "txaio", "version": "26.6.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/91/68/075bf851e11c9ef65bd6a0426791f0d9a0c7dae0e7f6e0b16ca67334b456/txaio-26.6.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "5.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6a/c0/c7ab82d6471dfa7e4fd68ae6ff2c6a50d077c05d6ecdea0cec8af635b2c4/ujson-5.13.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "zope.interface", "version": "8.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/2e/4360c54c465db042cc8fbeeec92abac28b4cedbf6ba63c1f092fd08a190f/zope_interface-8.5-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "4ed72e643e6a9d9ab4940427b6f18363"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "Django", "version": "5.2.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/f8/ce120525ca78f12b07daf65786679c5d0b54a75285a8958d3ae55e39da35/django-5.2.17-py3-none-any.whl"}}, {"metadata": {"name": "psycopg2-binary", "version": "2.9.12"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5e/af/48f76af9d50d61cf390f8cd657b503168b089e2e9298e48465d029fcc713/psycopg2_binary-2.9.12-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "djangorestframework", "version": "3.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/d7/7461738e819b853275b35fd35712a85806c09a327e1fd5f8ff766bdd317e/djangorestframework-3.18.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-django", "version": "4.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/27/88/52db7a840fdbd74934f8df11b7450c9919ac00f61c02e88827f3d58180f7/pytest_django-4.13.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.7.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/18/f1/46d32fe4b9aae09fe397e768ff376d9b6bdbb4f11faaa727f163c3457b43/pytest_forked-1.7.5-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "executing", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "asgiref", "version": "3.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c0/1b/54f4ad77cd8a584fa70746c47df988e002cf1ee1eba43364d46f87803647/asgiref-3.12.1-py3-none-any.whl"}}, {"metadata": {"name": "daphne", "version": "4.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/0c/59e966c167880904f2e6a235c63169760dce58ba8062a7a153a6183539cc/daphne-4.2.3-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "sqlparse", "version": "0.5.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/4b/359f28a903c13438ef59ebeee215fb25da53066db67b305c125f1c6d2a25/sqlparse-0.5.5-py3-none-any.whl"}}, {"metadata": {"name": "channels", "version": "4.3.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/16/34/c32915288b7ef482377b6adc401192f98c6a99b3a145423d3b8aed807898/channels-4.3.2-py3-none-any.whl"}}, {"metadata": {"name": "autobahn", "version": "26.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/36/92/2f6e57d9f9e6b86b9db362f58aaa6cfeadc2f3a6901ec95aab27ef232b5c/autobahn-26.7.1-cp313-cp313-macosx_15_0_arm64.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "Twisted", "version": "26.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/57/bcf4e2370dd218c9aa68a9140a65d86729c73f1d529f7e94786c2766fc72/twisted-26.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "Automat", "version": "25.4.16"}, "download_info": {"url": "https://files.pythonhosted.org/packages/02/ff/1175b0b7371e46244032d43a56862d0af455823b5280a50c63d99cc50f18/automat-25.4.16-py3-none-any.whl"}}, {"metadata": {"name": "cbor2", "version": "6.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/0b20c88e76942ede86c98cdce138681690f95908c540c264fff847729cd4/cbor2-6.1.4-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/41/4c7042f317b9217502988f0873af87e16ad606dc20f84e546e3e6ce9764c/cffi-2.1.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "constantly", "version": "23.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b8/40/c199d095151addf69efdb4b9ca3a4f20f70e20508d6222bffb9b76f58573/constantly-23.10.4-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/5c/59086b4aac5e879d38ddbcf74e4be7ade89cebc3eb199a55da998c3bb46a/cryptography-50.0.0-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "hyperlink", "version": "21.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/aa/8caf6a0a3e62863cbb9dab27135660acba46903b703e224f14f447e57934/hyperlink-21.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "Incremental", "version": "24.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1d/55/0f4df2a44053867ea9cbea73fc588b03c55605cd695cee0a3d86f0029cb2/incremental-24.11.0-py3-none-any.whl"}}, {"metadata": {"name": "msgpack", "version": "1.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/71/fbcfa83a1d6a9c6091942d1cfd070962244664b87427a9a49a6897b1b219/msgpack-1.2.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pyOpenSSL", "version": "26.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ad/2cf6d3fa2fae5c79e1ed9960c0d42badd0f94d81dd12b50604cdc839e648/pyopenssl-26.4.0-py3-none-any.whl"}}, {"metadata": {"name": "service-identity", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/eb/2433e1af4ff903499144de4846569fb3300b816179ae99a03c2f011b666a/service_identity-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "txaio", "version": "26.6.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/91/68/075bf851e11c9ef65bd6a0426791f0d9a0c7dae0e7f6e0b16ca67334b456/txaio-26.6.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "5.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6a/c0/c7ab82d6471dfa7e4fd68ae6ff2c6a50d077c05d6ecdea0cec8af635b2c4/ujson-5.13.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "zope.interface", "version": "8.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/2e/4360c54c465db042cc8fbeeec92abac28b4cedbf6ba63c1f092fd08a190f/zope_interface-8.5-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "4ed72e643e6a9d9ab4940427b6f18363"} -{"python_version": "3.13", "dependencies": [{"metadata": {"name": "openai-agents", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a2/92/9cbbdd604f858056d4e4f105a1b99779128bae61b6a3681db0f035ef73b4/openai_agents-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "2.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ae/f4/561ed79fd94876160018a5e75254cfcb9b0e62d4dded9dcb20072e86d623/openai-2.44.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "griffe", "version": "1.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/83/3b1d03d36f224edded98e9affd0467630fc09d766c0e56fb1498cbb04a9b/griffe-1.15.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d0/2b/c3eaf16f5d7c9bad66ea32f40a95bd169b29a91217fcc7f081375157e99c/jiter-0.16.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "mcp", "version": "1.29.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/c8/248b201f6d753d69fd5d6506011abbb35a946d9142b2ae311a948fd0be3d/mcp-1.29.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/81/4fa520eaffa8bd7d1525e644cd6d39e7d60b1592bc5b516693c7340b50f1/pydantic_core-2.46.4-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "types-requests", "version": "2.33.0.20260712"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/e7/010c87f559e216d83f9dc51e939633fd0d0ead3377340181ab0e223cd3b5/types_requests-2.33.0.20260712-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a4/a0/562247944386f7d4ef94467e84876600cc1e0f1b93239aaa9213d2bc3cbd/charset_normalizer-3.5.1-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "colorama", "version": "0.4.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/3a/764912c58293d95b6dcdf4cc255f9d10de310580ced547b082eb9d72018c/sse_starlette-3.4.8-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.52.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/79/4a20b54ab0491485ccd8c077db2d39187c7f12b3e15485d38a7be37c81b4/uvicorn-0.52.4-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/5c/59086b4aac5e879d38ddbcf74e4be7ade89cebc3eb199a55da998c3bb46a/cryptography-50.0.0-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f3/6b/686d9dc4359a8f163cfbbf89ee0b4e586431de22fe8248edb63a8cf50d49/rpds_py-2026.6.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/41/4c7042f317b9217502988f0873af87e16ad606dc20f84e546e3e6ce9764c/cffi-2.1.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "54acb8a9a6cd450523a6e79a8e22ef0c"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "celery", "version": "5.7.0a1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/de/bf/72703e2ac184cc9c4c641ba5abaec725cbdcf48755c7582f006005d38848/celery-5.7.0a1-py3-none-any.whl"}}, {"metadata": {"name": "billiard", "version": "4.3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/60/60/ade6d336983b82fbc330d0d0371f945249b448152852952f643787a3288d/billiard-4.3.0-py3-none-any.whl"}}, {"metadata": {"name": "click-repl", "version": "0.4.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e0/ae/63d94d251d2e1a7bf3794ea47cb1c99fe6de055b732ea79d7bcdabef8ff5/click_repl-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "newrelic", "version": "10.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/d4/71/07c41fd5e8c94e95216b000d00c3cf735f769cb406c0f33c6ff83b7b7418/newrelic-10.16.0.tar.gz"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "vine", "version": "5.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/03/ff/7c0c86c43b3cbb927e0ccc0255cb4057ceba4799cd44ae95174ce8e8b5b2/vine-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "redis", "version": "8.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/66/9d/c5731f6e3608663d4d3656fd8d3aecee8b509c3082818f5a13eae925baea/redis-8.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.7.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/18/f1/46d32fe4b9aae09fe397e768ff376d9b6bdbb4f11faaa727f163c3457b43/pytest_forked-1.7.5-py3-none-any.whl"}}, {"metadata": {"name": "click-didyoumean", "version": "0.3.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/1b/5b/974430b5ffdb7a4f1941d13d83c64a0395114503cc357c6b9ae4ce5047ed/click_didyoumean-0.3.1-py3-none-any.whl"}}, {"metadata": {"name": "click-plugins", "version": "1.1.1.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/3d/9a/2abecb28ae875e39c8cad711eb1186d8d14eab564705325e77e4e6ab9ae5/click_plugins-1.1.1.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "kombu", "version": "5.7.0a1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b6/d9/1b98be4b45c3cb6737663ea5e7847fcc8f6c21de204a0411ae12874fbfc0/kombu-5.7.0a1-py3-none-any.whl"}}, {"metadata": {"name": "amqp", "version": "5.4.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/07/99/6b965aa99a32630c1c61ce57c9dcf81cec6fec354274a87f14525302b7f7/amqp-5.4.0-py3-none-any.whl"}}, {"metadata": {"name": "prompt_toolkit", "version": "3.0.53"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/54/6f/84908cad2d6aa5144abcf7b42709fe4fdb459bc640ec7ac5786e7693dabc/prompt_toolkit-3.0.53-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "tzdata", "version": "2026.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/f9/bc/8737e8d54cf51106118039b83f485a4783112fab49ea9d044b234978a46e/tzdata-2026.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/39/cc/9c0adc5861020de426ec71716b6c1bef8d90694b7d6d0a16202cdb1647f5/wcwidth-0.8.4-py3-none-any.whl"}}, {"metadata": {"name": "tzlocal", "version": "5.4.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/9e/a4/017a7a6cbe387d961a688ec31364ae60a5c4e22c96ae9921b79a947c855d/tzlocal-5.4.4-py3-none-any.whl"}}], "install_targets_hash": "571b466b11beb803cdcf782ce81876e3"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "pydantic-ai", "version": "2.47.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/12/1a/a46dad48b18c004eb686596d360d2310fc9c928b5b9b31341c03c6c813f1/pydantic_ai-2.47.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-ai-slim", "version": "2.47.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/eb/94/5d8a27dbe4a9e27378698c31c5848310d7a7727e22e1334f683dfbe5397d/pydantic_ai_slim-2.47.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-evals", "version": "2.47.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a9/81/34504d9426f420cc3ea05eb5d3f387a17f14d5ea678b6ced18d6f4be9da4/pydantic_evals-2.47.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-graph", "version": "2.47.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/3c/b0/4630a964201fb04dba730cbe54b7941309d97d59c01537465b075c26cae7/pydantic_graph-2.47.0-py3-none-any.whl"}}, {"metadata": {"name": "fastmcp-slim", "version": "4.0.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ed/76/8dc551ef1f222bd146537ae100baf7441628aa1050494b567249ece997c2/fastmcp_slim-4.0.5-py3-none-any.whl"}}, {"metadata": {"name": "mcp", "version": "2.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/1b/ff/8e7eade68b8a28f7da0ed1085544341b51f9c935dbf6b95c76b7edfea6a0/mcp-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mcp-types", "version": "2.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/8f/d7/6ffba5d8cd5dd9b8a19478875c50e04945314ba5074e84d749283f27f62d/mcp_types-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "py-key-value-aio", "version": "0.4.6"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/9a/46/12871550fb0613d149144bb9d41f22680d5f46717bc45a76eb5798c20c3f/py_key_value_aio-0.4.6-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofile", "version": "3.12.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/4e/79/6e45e778c4c3cab39e0937b007b720c15f76c50c6453d153282d0fcc3588/aiofile-3.12.3-py3-none-any.whl"}}, {"metadata": {"name": "caio", "version": "0.12.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/11/ab/12e4896a1e74ff9a65c84894acdfc3b70b8b49e63874a37e0dffcc31f396/caio-0.12.4-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "anthropic", "version": "1.7.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c0/dc/74995efda028421917f4caabd24db1373ee0742573a2363fff1a21191441/anthropic-1.7.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.17.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ca/b1/34bfa29599d420423baac6ff7cada6674fe63d5a7a2ccb3900b904678783/jiter-0.17.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/21/43/6323b1f8b217780454c61304bcd2b38ae4762f50754414124603ccc90bb2/pydantic_core-2.46.5-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "argcomplete", "version": "3.7.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/46/bd/551ee6af426af84ca33e02622be722925c196608e9127d731ef17c47f06e/argcomplete-3.7.2-py3-none-any.whl"}}, {"metadata": {"name": "Authlib", "version": "1.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b8/c6/6f124bcfbbfb20fba22c939b4e43a06dccfc0e1ca20e5634ca573cb1e271/authlib-1.8.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "beartype", "version": "0.22.9"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/cc/18245721fa7747065ab478316c7fea7c74777d07f37ae60db2e84f8172e8/beartype-0.22.9-py3-none-any.whl"}}, {"metadata": {"name": "cachetools", "version": "7.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cc/bb/1c6e7a89b11da19f137e4ef5a5c5fe47a5bb686449ba343944ccf8fb34b2/cachetools-7.2.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ba/19/797e2aaac9df6a66f1550f49979dc1b1e39ecd2077501c30efa81e8d5d67/cryptography-50.0.1-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/55/41/4c7042f317b9217502988f0873af87e16ad606dc20f84e546e3e6ce9764c/cffi-2.1.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "genai-prices", "version": "0.1.7"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/d5/4a/9e04f3dca5ffe74133779ab5e9925ffb6411afbeac55d26fa0e148722599/genai_prices-0.1.7-py3-none-any.whl"}}, {"metadata": {"name": "google-genai", "version": "2.24.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/84/5b/87913fe392ba7b6402577259289ed3740c577956554a674b191a2971d33e/google_genai-2.24.0-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.58.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/59/13/477d90d09591b3938b45c4e11f4d8a51291682112cb5efcac961e815d562/google_auth-2.58.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a4/a0/562247944386f7d4ef94467e84876600cc1e0f1b93239aaa9213d2bc3cbd/charset_normalizer-3.5.1-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/3d/86/0a70d3ae2f0f2256bb41302d9804dbca65d4360281e7feb3e1f94102ac46/websockets-16.1.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "griffelib", "version": "2.3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/41/63/e876e789525063c840ccfa8857febdabd6523bcef9ce7eb979b9305ea895/griffelib-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "joserfc", "version": "1.7.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/67/c5/82addfd375e5ee6520644e0553e4aadde92d668c4fc99cc716d337fe7bb3/joserfc-1.7.5-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "keyring", "version": "25.7.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/81/db/e655086b7f3a705df045bf0933bdd9c2f79bb3c97bfef1384598bb79a217/keyring-25.7.0-py3-none-any.whl"}}, {"metadata": {"name": "logfire", "version": "5.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cd/02/b32c3d5c298e4a9010694d261fb82c2c672747c0bf2b47bffda484aef349/logfire-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-exporter-otlp-proto-http", "version": "1.44.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cd/d0/fdeb1a98d8d3a6205f5f297c51b4a9bfe65126ab60339669bbe3dd54c2e2/opentelemetry_exporter_otlp_proto_http-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-exporter-otlp-proto-common", "version": "1.44.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/5e/71/65fd9d54c10b860f87c045ccee1264cab7011268895d3528818a29c1172a/opentelemetry_exporter_otlp_proto_common-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-proto", "version": "1.44.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/d1/7c/8be563d68e93bbefa5c8affb82ddcff91b3ad858ce49957ba7b16fd3e0ab/opentelemetry_proto-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "googleapis-common-protos", "version": "1.75.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/1a/7a/7d79170c6ce6f12e109df2b3879d6b934010cf4f99aea8de8b7e5408c174/googleapis_common_protos-1.75.3-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.44.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ca/6f/a04e900f465ff3221ccc395522503e2d10e79fa21f2723c8e177aae1e0d1/opentelemetry_api-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-sdk", "version": "1.44.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e7/23/ff077e61886ee020a17ce9c8b6fa11c601c8d8345b09ea24f605445df62a/opentelemetry_sdk-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-semantic-conventions", "version": "0.65b0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a6/0e/49df70d9b81fb5cbae4bbf2a49d865b09bcbcbc4eb53f5851b1027738d78/opentelemetry_semantic_conventions-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "protobuf", "version": "7.36.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/32/72/98342feb672507c8f3a69e34b4fa8961f608edba5c1a48a6f47156d92cb5/protobuf-7.36.2-cp310-abi3-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "executing", "version": "2.2.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "logfire-api", "version": "5.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2d/51/123dab197fb08c0892e3bea1c2266bff159aa2ee82ad43bef93505859705/logfire_api-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "3.17.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/57/bc/5b80a0ca4069a6b5ba6c7d48ae7a4f8176b2c0bde0bebccdb867472ec6f6/openai-3.17.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-instrumentation", "version": "0.65b0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/40/7b/85eab1215f72adf0e68d3dc4a679b9bff993fa679ff34cd8dd378e2659fd/opentelemetry_instrumentation-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "wrapt", "version": "2.4.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/fe/07/dc98150c2f9ee5b5fcbd841765e178ea6cc6c43733ab8d1f5181a4fb9f3d/wrapt-2.4.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "opentelemetry-instrumentation-httpx", "version": "0.65b0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/9d/0f/c6144096b4914bbf44b43ba21c962e8f333ff045770b50a3e79ed8bd455f/opentelemetry_instrumentation_httpx-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-util-http", "version": "0.65b0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/23/3f/ab8d29df207ce5f470a07fa96ebb48af4e95b7fab7e7635311b9a32f2fab/opentelemetry_util_http-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "platformdirs", "version": "4.11.12"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ec/2b/69de6317fbf48865bb12aa56c9cfcfff46b3add0cd45250725d96146dce0/platformdirs-4.11.12-py3-none-any.whl"}}, {"metadata": {"name": "prompt_toolkit", "version": "3.0.53"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/54/6f/84908cad2d6aa5144abcf7b42709fe4fdb459bc640ec7ac5786e7693dabc/prompt_toolkit-3.0.53-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/9a/3b/6163796d69c3977d1e4287bea4a6979161cbbdd170ebb430511e8e1999ce/pyasn1-0.6.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "email-validator", "version": "2.3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "dnspython", "version": "2.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.14.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/9c/97/672cb32ce0dfea44b740cb7b4f97038463b9cf7c0ead1aacf595572851d6/pyjwt-2.14.0-py3-none-any.whl"}}, {"metadata": {"name": "pyperclip", "version": "1.11.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/df/80/fc9d01d5ed37ba4c42ca2b55b4339ae6e200b456be3a1aaddf4a9fa99b8c/pyperclip-1.11.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/f3/6b/686d9dc4359a8f163cfbbf89ee0b4e586431de22fe8248edb63a8cf50d49/rpds_py-2026.6.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.11"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/98/6a/2ba3ed4a69babf3afdddf7d8314a48d87562c0a442206bbc2a1b50d5efc0/sse_starlette-3.4.11-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ad/5f/6448cfe278c3664ba9ec5b5ac08344341f7dc3d42888476e215a14eda2be/tiktoken-0.14.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.53.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/76/18/0eea75741ee812e9f598b687619ce2454f6c3a1c5cd21ea990ec6bd26f45/uvicorn-0.53.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/39/cc/9c0adc5861020de426ec71716b6c1bef8d90694b7d6d0a16202cdb1647f5/wcwidth-0.8.4-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.classes", "version": "3.4.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7f/66/b15ce62552d84bbfcec9a4873ab79d993a1dd4edb922cbfccae192bd5b5f/jaraco.classes-3.4.0-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.context", "version": "6.1.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/f2/58/bc8954bda5fcda97bd7c19be11b85f91973d67a706ed4a3aec33e7de22db/jaraco_context-6.1.2-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.functools", "version": "4.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/02/36/ecc85bc96c273dc8a11273ed4782272975e6338d4a3e9228621175edf0e3/jaraco_functools-4.6.0-py3-none-any.whl"}}, {"metadata": {"name": "more-itertools", "version": "11.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e8/3d/1087453384dbde46a8c7f9356eead2c58be8a7bf156bca40243377c85715/more_itertools-11.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.9.10"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/fa/68/241f88458b17c46ed2f80147a60a03b2ada7fb815c23b6bc76c298abb0a5/regex-2026.9.10-cp313-cp313-macosx_11_0_arm64.whl"}}], "install_targets_hash": "59d07114fce5d52fca16194a659dc9bf"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "openai", "version": "1.109.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1d/2a/7dd3d207ec669cacc1f186fd856a0f61dbc255d24f6fdc1a6715d6051b0f/openai-1.109.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/5f/6448cfe278c3664ba9ec5b5ac08344341f7dc3d42888476e215a14eda2be/tiktoken-0.14.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d0/2b/c3eaf16f5d7c9bad66ea32f40a95bd169b29a91217fcc7f081375157e99c/jiter-0.16.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/81/4fa520eaffa8bd7d1525e644cd6d39e7d60b1592bc5b516693c7340b50f1/pydantic_core-2.46.4-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.7.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/47/2d0564e93d87bc48618360ddca232a2ca612bbdf53ce8465d45ca5ce14ee/regex-2026.7.19-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a4/a0/562247944386f7d4ef94467e84876600cc1e0f1b93239aaa9213d2bc3cbd/charset_normalizer-3.5.1-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}], "install_targets_hash": "5c15f7294f49ccda5d519b89114a1254"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "openai", "version": "1.109.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1d/2a/7dd3d207ec669cacc1f186fd856a0f61dbc255d24f6fdc1a6715d6051b0f/openai-1.109.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/5f/6448cfe278c3664ba9ec5b5ac08344341f7dc3d42888476e215a14eda2be/tiktoken-0.14.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d0/2b/c3eaf16f5d7c9bad66ea32f40a95bd169b29a91217fcc7f081375157e99c/jiter-0.16.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/81/4fa520eaffa8bd7d1525e644cd6d39e7d60b1592bc5b516693c7340b50f1/pydantic_core-2.46.4-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.7.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/47/2d0564e93d87bc48618360ddca232a2ca612bbdf53ce8465d45ca5ce14ee/regex-2026.7.19-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a4/a0/562247944386f7d4ef94467e84876600cc1e0f1b93239aaa9213d2bc3cbd/charset_normalizer-3.5.1-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}], "install_targets_hash": "5c15f7294f49ccda5d519b89114a1254"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "openai", "version": "1.109.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1d/2a/7dd3d207ec669cacc1f186fd856a0f61dbc255d24f6fdc1a6715d6051b0f/openai-1.109.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/5f/6448cfe278c3664ba9ec5b5ac08344341f7dc3d42888476e215a14eda2be/tiktoken-0.14.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d0/2b/c3eaf16f5d7c9bad66ea32f40a95bd169b29a91217fcc7f081375157e99c/jiter-0.16.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/81/4fa520eaffa8bd7d1525e644cd6d39e7d60b1592bc5b516693c7340b50f1/pydantic_core-2.46.4-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.7.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/47/2d0564e93d87bc48618360ddca232a2ca612bbdf53ce8465d45ca5ce14ee/regex-2026.7.19-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a4/a0/562247944386f7d4ef94467e84876600cc1e0f1b93239aaa9213d2bc3cbd/charset_normalizer-3.5.1-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}], "install_targets_hash": "5c15f7294f49ccda5d519b89114a1254"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b2/06/97ec2aeae780b31d742b6352218b43841a6871e2564578ca522dce4a45c3/charset_normalizer-3.4.9-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "623a652072a7d5d73d07fc99e6bd44fb"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "celery", "version": "5.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/c9/6eccdda96e098f7ae843162db2d3c149c6931a24fda69fe4ab84d0027eb5/celery-5.6.3-py3-none-any.whl"}}, {"metadata": {"name": "newrelic", "version": "10.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d4/71/07c41fd5e8c94e95216b000d00c3cf735f769cb406c0f33c6ff83b7b7418/newrelic-10.16.0.tar.gz"}}, {"metadata": {"name": "redis", "version": "8.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/0a/c2345ebf1ebe70840ce3f6c6ee612f8fa749cfbd1b03069c53bf0c62aaad/redis-8.0.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/af/9c0bda43e486a3c9bf1e0f876d0f241bc3f229d7d65d09331a0868db9629/pytest_forked-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "billiard", "version": "4.2.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/87/8bab77b323f16d67be364031220069f79159117dd5e43eeb4be2fef1ac9b/billiard-4.2.4-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "click-didyoumean", "version": "0.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/5b/974430b5ffdb7a4f1941d13d83c64a0395114503cc357c6b9ae4ce5047ed/click_didyoumean-0.3.1-py3-none-any.whl"}}, {"metadata": {"name": "click-plugins", "version": "1.1.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/9a/2abecb28ae875e39c8cad711eb1186d8d14eab564705325e77e4e6ab9ae5/click_plugins-1.1.1.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "click-repl", "version": "0.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/52/40/9d857001228658f0d59e97ebd4c346fe73e138c6de1bce61dc568a57c7f8/click_repl-0.3.0-py3-none-any.whl"}}, {"metadata": {"name": "kombu", "version": "5.6.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/0f/834427d8c03ff1d7e867d3db3d176470c64871753252b21b4f4897d1fa45/kombu-5.6.2-py3-none-any.whl"}}, {"metadata": {"name": "vine", "version": "5.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/ff/7c0c86c43b3cbb927e0ccc0255cb4057ceba4799cd44ae95174ce8e8b5b2/vine-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "py", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tzlocal", "version": "5.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/a4/017a7a6cbe387d961a688ec31364ae60a5c4e22c96ae9921b79a947c855d/tzlocal-5.4.4-py3-none-any.whl"}}, {"metadata": {"name": "amqp", "version": "5.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/26/99/fc813cd978842c26c82534010ea849eee9ab3a13ea2b74e95cb9c99e747b/amqp-5.3.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "prompt_toolkit", "version": "3.0.52"}, "download_info": {"url": "https://files.pythonhosted.org/packages/84/03/0d3ce49e2505ae70cf43bc5bb3033955d2fc9f932163e84dc0779cc47f48/prompt_toolkit-3.0.52-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tzdata", "version": "2026.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ce/e4/dccd7f47c4b64213ac01ef921a1337ee6e30e8c6466046018326977efd95/tzdata-2026.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl"}}], "install_targets_hash": "68a613b2517fdb654276eddecbf135d5"} -{"python_version": "3.13", "dependencies": [{"metadata": {"name": "pymongo", "version": "4.18.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/08/0f/0daf459b604f61253b914b28f0e6dd16cdc8a7aa962cf901e482f5cbba67/pymongo-4.18.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "dnspython", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "mockupdb", "version": "1.8.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2f/c0/bc0c3e82bf91993bf2337b125c4d49c3cadae39f5a4c642baada958f976e/mockupdb-1.8.1-py2.py3-none-any.whl"}}], "install_targets_hash": "69c2fba3fd9077f55ce7488963967c53"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "celery", "version": "5.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/c9/6eccdda96e098f7ae843162db2d3c149c6931a24fda69fe4ab84d0027eb5/celery-5.6.3-py3-none-any.whl"}}, {"metadata": {"name": "newrelic", "version": "10.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d4/71/07c41fd5e8c94e95216b000d00c3cf735f769cb406c0f33c6ff83b7b7418/newrelic-10.16.0.tar.gz"}}, {"metadata": {"name": "redis", "version": "8.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/0a/c2345ebf1ebe70840ce3f6c6ee612f8fa749cfbd1b03069c53bf0c62aaad/redis-8.0.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/af/9c0bda43e486a3c9bf1e0f876d0f241bc3f229d7d65d09331a0868db9629/pytest_forked-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "billiard", "version": "4.2.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/87/8bab77b323f16d67be364031220069f79159117dd5e43eeb4be2fef1ac9b/billiard-4.2.4-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "click-didyoumean", "version": "0.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/5b/974430b5ffdb7a4f1941d13d83c64a0395114503cc357c6b9ae4ce5047ed/click_didyoumean-0.3.1-py3-none-any.whl"}}, {"metadata": {"name": "click-plugins", "version": "1.1.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/9a/2abecb28ae875e39c8cad711eb1186d8d14eab564705325e77e4e6ab9ae5/click_plugins-1.1.1.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "click-repl", "version": "0.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/52/40/9d857001228658f0d59e97ebd4c346fe73e138c6de1bce61dc568a57c7f8/click_repl-0.3.0-py3-none-any.whl"}}, {"metadata": {"name": "kombu", "version": "5.6.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/0f/834427d8c03ff1d7e867d3db3d176470c64871753252b21b4f4897d1fa45/kombu-5.6.2-py3-none-any.whl"}}, {"metadata": {"name": "vine", "version": "5.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/ff/7c0c86c43b3cbb927e0ccc0255cb4057ceba4799cd44ae95174ce8e8b5b2/vine-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "py", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tzlocal", "version": "5.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/a4/017a7a6cbe387d961a688ec31364ae60a5c4e22c96ae9921b79a947c855d/tzlocal-5.4.4-py3-none-any.whl"}}, {"metadata": {"name": "amqp", "version": "5.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/26/99/fc813cd978842c26c82534010ea849eee9ab3a13ea2b74e95cb9c99e747b/amqp-5.3.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "prompt_toolkit", "version": "3.0.52"}, "download_info": {"url": "https://files.pythonhosted.org/packages/84/03/0d3ce49e2505ae70cf43bc5bb3033955d2fc9f932163e84dc0779cc47f48/prompt_toolkit-3.0.52-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tzdata", "version": "2026.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ce/e4/dccd7f47c4b64213ac01ef921a1337ee6e30e8c6466046018326977efd95/tzdata-2026.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl"}}], "install_targets_hash": "68a613b2517fdb654276eddecbf135d5"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "celery", "version": "5.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/c9/6eccdda96e098f7ae843162db2d3c149c6931a24fda69fe4ab84d0027eb5/celery-5.6.3-py3-none-any.whl"}}, {"metadata": {"name": "newrelic", "version": "10.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d4/71/07c41fd5e8c94e95216b000d00c3cf735f769cb406c0f33c6ff83b7b7418/newrelic-10.16.0.tar.gz"}}, {"metadata": {"name": "redis", "version": "8.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/0a/c2345ebf1ebe70840ce3f6c6ee612f8fa749cfbd1b03069c53bf0c62aaad/redis-8.0.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/af/9c0bda43e486a3c9bf1e0f876d0f241bc3f229d7d65d09331a0868db9629/pytest_forked-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "billiard", "version": "4.2.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/87/8bab77b323f16d67be364031220069f79159117dd5e43eeb4be2fef1ac9b/billiard-4.2.4-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "click-didyoumean", "version": "0.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/5b/974430b5ffdb7a4f1941d13d83c64a0395114503cc357c6b9ae4ce5047ed/click_didyoumean-0.3.1-py3-none-any.whl"}}, {"metadata": {"name": "click-plugins", "version": "1.1.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/9a/2abecb28ae875e39c8cad711eb1186d8d14eab564705325e77e4e6ab9ae5/click_plugins-1.1.1.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "click-repl", "version": "0.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/52/40/9d857001228658f0d59e97ebd4c346fe73e138c6de1bce61dc568a57c7f8/click_repl-0.3.0-py3-none-any.whl"}}, {"metadata": {"name": "kombu", "version": "5.6.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/0f/834427d8c03ff1d7e867d3db3d176470c64871753252b21b4f4897d1fa45/kombu-5.6.2-py3-none-any.whl"}}, {"metadata": {"name": "vine", "version": "5.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/ff/7c0c86c43b3cbb927e0ccc0255cb4057ceba4799cd44ae95174ce8e8b5b2/vine-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "py", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tzlocal", "version": "5.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/a4/017a7a6cbe387d961a688ec31364ae60a5c4e22c96ae9921b79a947c855d/tzlocal-5.4.4-py3-none-any.whl"}}, {"metadata": {"name": "amqp", "version": "5.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/26/99/fc813cd978842c26c82534010ea849eee9ab3a13ea2b74e95cb9c99e747b/amqp-5.3.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "prompt_toolkit", "version": "3.0.52"}, "download_info": {"url": "https://files.pythonhosted.org/packages/84/03/0d3ce49e2505ae70cf43bc5bb3033955d2fc9f932163e84dc0779cc47f48/prompt_toolkit-3.0.52-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tzdata", "version": "2026.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ce/e4/dccd7f47c4b64213ac01ef921a1337ee6e30e8c6466046018326977efd95/tzdata-2026.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl"}}], "install_targets_hash": "68a613b2517fdb654276eddecbf135d5"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "celery", "version": "5.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/c9/6eccdda96e098f7ae843162db2d3c149c6931a24fda69fe4ab84d0027eb5/celery-5.6.3-py3-none-any.whl"}}, {"metadata": {"name": "newrelic", "version": "10.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d4/71/07c41fd5e8c94e95216b000d00c3cf735f769cb406c0f33c6ff83b7b7418/newrelic-10.16.0.tar.gz"}}, {"metadata": {"name": "redis", "version": "8.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/0a/c2345ebf1ebe70840ce3f6c6ee612f8fa749cfbd1b03069c53bf0c62aaad/redis-8.0.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/af/9c0bda43e486a3c9bf1e0f876d0f241bc3f229d7d65d09331a0868db9629/pytest_forked-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "billiard", "version": "4.2.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/87/8bab77b323f16d67be364031220069f79159117dd5e43eeb4be2fef1ac9b/billiard-4.2.4-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "click-didyoumean", "version": "0.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/5b/974430b5ffdb7a4f1941d13d83c64a0395114503cc357c6b9ae4ce5047ed/click_didyoumean-0.3.1-py3-none-any.whl"}}, {"metadata": {"name": "click-plugins", "version": "1.1.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/9a/2abecb28ae875e39c8cad711eb1186d8d14eab564705325e77e4e6ab9ae5/click_plugins-1.1.1.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "click-repl", "version": "0.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/52/40/9d857001228658f0d59e97ebd4c346fe73e138c6de1bce61dc568a57c7f8/click_repl-0.3.0-py3-none-any.whl"}}, {"metadata": {"name": "kombu", "version": "5.6.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/0f/834427d8c03ff1d7e867d3db3d176470c64871753252b21b4f4897d1fa45/kombu-5.6.2-py3-none-any.whl"}}, {"metadata": {"name": "vine", "version": "5.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/ff/7c0c86c43b3cbb927e0ccc0255cb4057ceba4799cd44ae95174ce8e8b5b2/vine-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "py", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tzlocal", "version": "5.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/a4/017a7a6cbe387d961a688ec31364ae60a5c4e22c96ae9921b79a947c855d/tzlocal-5.4.4-py3-none-any.whl"}}, {"metadata": {"name": "amqp", "version": "5.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/26/99/fc813cd978842c26c82534010ea849eee9ab3a13ea2b74e95cb9c99e747b/amqp-5.3.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "prompt_toolkit", "version": "3.0.52"}, "download_info": {"url": "https://files.pythonhosted.org/packages/84/03/0d3ce49e2505ae70cf43bc5bb3033955d2fc9f932163e84dc0779cc47f48/prompt_toolkit-3.0.52-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tzdata", "version": "2026.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ce/e4/dccd7f47c4b64213ac01ef921a1337ee6e30e8c6466046018326977efd95/tzdata-2026.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl"}}], "install_targets_hash": "68a613b2517fdb654276eddecbf135d5"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "celery", "version": "5.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/c9/6eccdda96e098f7ae843162db2d3c149c6931a24fda69fe4ab84d0027eb5/celery-5.6.3-py3-none-any.whl"}}, {"metadata": {"name": "newrelic", "version": "10.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d4/71/07c41fd5e8c94e95216b000d00c3cf735f769cb406c0f33c6ff83b7b7418/newrelic-10.16.0.tar.gz"}}, {"metadata": {"name": "redis", "version": "8.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/0a/c2345ebf1ebe70840ce3f6c6ee612f8fa749cfbd1b03069c53bf0c62aaad/redis-8.0.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/af/9c0bda43e486a3c9bf1e0f876d0f241bc3f229d7d65d09331a0868db9629/pytest_forked-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "billiard", "version": "4.2.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/87/8bab77b323f16d67be364031220069f79159117dd5e43eeb4be2fef1ac9b/billiard-4.2.4-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "click-didyoumean", "version": "0.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/5b/974430b5ffdb7a4f1941d13d83c64a0395114503cc357c6b9ae4ce5047ed/click_didyoumean-0.3.1-py3-none-any.whl"}}, {"metadata": {"name": "click-plugins", "version": "1.1.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/9a/2abecb28ae875e39c8cad711eb1186d8d14eab564705325e77e4e6ab9ae5/click_plugins-1.1.1.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "click-repl", "version": "0.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/52/40/9d857001228658f0d59e97ebd4c346fe73e138c6de1bce61dc568a57c7f8/click_repl-0.3.0-py3-none-any.whl"}}, {"metadata": {"name": "kombu", "version": "5.6.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/0f/834427d8c03ff1d7e867d3db3d176470c64871753252b21b4f4897d1fa45/kombu-5.6.2-py3-none-any.whl"}}, {"metadata": {"name": "vine", "version": "5.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/ff/7c0c86c43b3cbb927e0ccc0255cb4057ceba4799cd44ae95174ce8e8b5b2/vine-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "py", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tzlocal", "version": "5.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/a4/017a7a6cbe387d961a688ec31364ae60a5c4e22c96ae9921b79a947c855d/tzlocal-5.4.4-py3-none-any.whl"}}, {"metadata": {"name": "amqp", "version": "5.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/26/99/fc813cd978842c26c82534010ea849eee9ab3a13ea2b74e95cb9c99e747b/amqp-5.3.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "prompt_toolkit", "version": "3.0.52"}, "download_info": {"url": "https://files.pythonhosted.org/packages/84/03/0d3ce49e2505ae70cf43bc5bb3033955d2fc9f932163e84dc0779cc47f48/prompt_toolkit-3.0.52-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tzdata", "version": "2026.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ce/e4/dccd7f47c4b64213ac01ef921a1337ee6e30e8c6466046018326977efd95/tzdata-2026.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl"}}], "install_targets_hash": "68a613b2517fdb654276eddecbf135d5"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "celery", "version": "5.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/c9/6eccdda96e098f7ae843162db2d3c149c6931a24fda69fe4ab84d0027eb5/celery-5.6.3-py3-none-any.whl"}}, {"metadata": {"name": "newrelic", "version": "10.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d4/71/07c41fd5e8c94e95216b000d00c3cf735f769cb406c0f33c6ff83b7b7418/newrelic-10.16.0.tar.gz"}}, {"metadata": {"name": "redis", "version": "8.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/0a/c2345ebf1ebe70840ce3f6c6ee612f8fa749cfbd1b03069c53bf0c62aaad/redis-8.0.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/af/9c0bda43e486a3c9bf1e0f876d0f241bc3f229d7d65d09331a0868db9629/pytest_forked-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "billiard", "version": "4.2.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/87/8bab77b323f16d67be364031220069f79159117dd5e43eeb4be2fef1ac9b/billiard-4.2.4-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "click-didyoumean", "version": "0.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/5b/974430b5ffdb7a4f1941d13d83c64a0395114503cc357c6b9ae4ce5047ed/click_didyoumean-0.3.1-py3-none-any.whl"}}, {"metadata": {"name": "click-plugins", "version": "1.1.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/9a/2abecb28ae875e39c8cad711eb1186d8d14eab564705325e77e4e6ab9ae5/click_plugins-1.1.1.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "click-repl", "version": "0.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/52/40/9d857001228658f0d59e97ebd4c346fe73e138c6de1bce61dc568a57c7f8/click_repl-0.3.0-py3-none-any.whl"}}, {"metadata": {"name": "kombu", "version": "5.6.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/0f/834427d8c03ff1d7e867d3db3d176470c64871753252b21b4f4897d1fa45/kombu-5.6.2-py3-none-any.whl"}}, {"metadata": {"name": "vine", "version": "5.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/ff/7c0c86c43b3cbb927e0ccc0255cb4057ceba4799cd44ae95174ce8e8b5b2/vine-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "py", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tzlocal", "version": "5.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/a4/017a7a6cbe387d961a688ec31364ae60a5c4e22c96ae9921b79a947c855d/tzlocal-5.4.4-py3-none-any.whl"}}, {"metadata": {"name": "amqp", "version": "5.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/26/99/fc813cd978842c26c82534010ea849eee9ab3a13ea2b74e95cb9c99e747b/amqp-5.3.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "prompt_toolkit", "version": "3.0.52"}, "download_info": {"url": "https://files.pythonhosted.org/packages/84/03/0d3ce49e2505ae70cf43bc5bb3033955d2fc9f932163e84dc0779cc47f48/prompt_toolkit-3.0.52-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tzdata", "version": "2026.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ce/e4/dccd7f47c4b64213ac01ef921a1337ee6e30e8c6466046018326977efd95/tzdata-2026.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl"}}], "install_targets_hash": "68a613b2517fdb654276eddecbf135d5"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "pymongo", "version": "4.18.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/11/ee/852cb3c707e6cc53d84e656b4c4f534afa96f0058d88470f49a33770c790/pymongo-4.18.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "mockupdb", "version": "1.8.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2f/c0/bc0c3e82bf91993bf2337b125c4d49c3cadae39f5a4c642baada958f976e/mockupdb-1.8.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "dnspython", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl"}}], "install_targets_hash": "69c2fba3fd9077f55ce7488963967c53"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "litellm", "version": "1.89.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/1a/f087e0555d91ab5f93fb8c740447423aa785468b8edca9987724815b51ec/litellm-1.89.7-py3-none-any.whl"}}, {"metadata": {"name": "anthropic", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/5b/db4a854aebf5d33a5ab714c46af6eb85ee44f390ed29b7b325c00b9f11ed/anthropic-1.0.0-py3-none-any.whl"}}, {"metadata": {"name": "google-genai", "version": "2.19.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/e8/de0accd8cd004cf11252ca53fc5c3dda59bcf1856abfc7609842ceba7363/google_genai-2.19.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/6b/e7f13410d391c6e55b4c007a8de024355389d7d459e3d64c42b2d33617e5/aiohttp-3.14.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "fastuuid", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/6d/64aee0a0f6a58eeabadd582e55d0d7d70258ffdd01d093b30c53d668303b/fastuuid-0.14.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "google-auth", "version": "2.56.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/b3/6117b2f24065cd7e2c4f140e9a193e215f089ca8ba314cf91eb9d0b7fe0a/google_auth-2.56.3-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/95/411ba65569158e862368917aaf56597f3e5fa3b91b0502919638465a08f3/httpx2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/74/d370e55600d9bcfa0d9794b0166126d49291a3d2b20c268fc98c453a4948/httpcore2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7d/f9/97f2ca8bb3ec6e4b1d64f983ebe98b9a192faddff67fac3d6303a537e670/importlib_metadata-8.9.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d0/2b/c3eaf16f5d7c9bad66ea32f40a95bd169b29a91217fcc7f081375157e99c/jiter-0.16.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "2.54.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/a8/bb76c7356de8ad57f59d5ff993d434df0607f07f08bcc9c9a5c275e399c0/openai-2.54.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/81/4fa520eaffa8bd7d1525e644cd6d39e7d60b1592bc5b516693c7340b50f1/pydantic_core-2.46.4-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/5f/6448cfe278c3664ba9ec5b5ac08344341f7dc3d42888476e215a14eda2be/tiktoken-0.14.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tokenizers", "version": "0.23.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e2/6a/068ed9f6e444c9d7e9d55ce134181325700f3d7f30410721bdc8f848d727/tokenizers-0.23.1-cp310-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/86/0a70d3ae2f0f2256bb41302d9804dbca65d4360281e7feb3e1f94102ac46/websockets-16.1.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a4/a0/562247944386f7d4ef94467e84876600cc1e0f1b93239aaa9213d2bc3cbd/charset_normalizer-3.5.1-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/5c/59086b4aac5e879d38ddbcf74e4be7ade89cebc3eb199a55da998c3bb46a/cryptography-50.0.0-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/ab/6e5080ee374f875296c4243c381bbdef97a9ac39c6e3ce1d5f7d42cb78d6/frozenlist-1.8.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "huggingface_hub", "version": "1.28.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/0e/eafef18f1a75e125e68395db21131db0cf868a128ecd2fce69b4df6c584b/huggingface_hub-1.28.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/76/55cd7186f498ed080a18440c9013011eb548f77ae1b297206d030eb1180a/multidict-6.7.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/12/a6ba6482bb5ea3260c000c9b20881c95fa11c6b30173715668259f844ed7/propcache-0.5.2-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f3/6b/686d9dc4359a8f163cfbbf89ee0b4e586431de22fe8248edb63a8cf50d49/rpds_py-2026.6.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/15/f0/7688d3f2cfff7590df2af38ec46d969f4281a4dddb08a9ad2eafbcdddf98/yarl-1.24.5-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "zipp", "version": "4.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.7.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/47/2d0564e93d87bc48618360ddca232a2ca612bbdf53ce8465d45ca5ce14ee/regex-2026.7.19-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/41/4c7042f317b9217502988f0873af87e16ad606dc20f84e546e3e6ce9764c/cffi-2.1.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "filelock", "version": "3.32.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/a4/9b63d595d748e3aff8812b65eacc1a2c4bd90b7c2012e08e72373b4835eb/filelock-3.32.4-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/3c/6a2bf344106328fd04963664a60b9bb6496fc25df8e962fcdc1367285fb9/fsspec-2026.7.0-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/69/55b8dcf636142ae660fec1869fcac14c4da2e8412e14d6eee1523be77e9f/hf_xet-1.6.0-cp38-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/3b/6163796d69c3977d1e4287bea4a6979161cbbdd170ebb430511e8e1999ce/pyasn1-0.6.4-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "6ecbfdc651853ff775d0f1f4b1d21bec"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "pydantic-ai", "version": "1.107.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/64/72ff998a79459c41f0e40f079a06ad45934fb2c095f604b9d44b983620b8/pydantic_ai-1.107.6-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-ai-slim", "version": "1.107.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/41/140a5e2d339e20d50e7685ffdc463977ae708f139a035fc658eced234afb/pydantic_ai_slim-1.107.6-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-evals", "version": "1.107.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/21/bc/299d19d27e237c407a77edb3f72d81a1cac0dd09964ea8cc9beac4e61f96/pydantic_evals-1.107.6-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-graph", "version": "1.107.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/2f/4f94314f952d242de53e6ae0f250d249609710ce500209f0acf46a7133a8/pydantic_graph-1.107.6-py3-none-any.whl"}}, {"metadata": {"name": "anthropic", "version": "0.125.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2f/1a/b1bd30cda3790557e8791bec5922a6ec8fabb6fa8b008c76a39cf7be6152/anthropic-0.125.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "fastmcp", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ac/14/6d950459cc831fa17fe2d1797926b6eb2d2f2af50f830e62d0c098cc1ec8/fastmcp-3.4.7-py3-none-any.whl"}}, {"metadata": {"name": "fastmcp-slim", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b4/97/e0e53642cd029a9a7635ae9c548f9f2cc995af5914e487b3df795664e4be/fastmcp_slim-3.4.7-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/9a/a24b26dc8a65f0ecc0fe5be981a19e61e7ca963b85e062c083f3a9100529/hf_xet-1.4.3-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "huggingface_hub", "version": "1.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/03/40a05316cb6616e5b7efd7773656441ab04b4b022c2199e79bb4622a92a3/huggingface_hub-1.18.0-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/27/17/91420b156315ae22732f5ee1a7b5725a030aab9dc8fd7dcdacfb4aa588d3/jiter-0.17.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "mcp", "version": "1.30.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f5/f4/e58bc33317c92a0203664daaf00bf6f41166cc0149e5d6870a03f7cd004a/mcp-1.30.0-py3-none-any.whl"}}, {"metadata": {"name": "py-key-value-aio", "version": "0.4.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/46/12871550fb0613d149144bb9d41f22680d5f46717bc45a76eb5798c20c3f/py_key_value_aio-0.4.6-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d3/f2/9e4de77a6271e07a76d2d58b11c091a979c191ed2939bf80067568b369d2/pydantic_core-2.46.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typer", "version": "0.25.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/f9/2b3ff4e56e5fa7debfaf9eb135d0da96f3e9a1d5b27222223c7296336e5f/typer-0.25.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "ag-ui-protocol", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/b0/850be4576e6443dc575daa54188d8136ae2b2eca3f19e098e7a088fc9ebc/ag_ui_protocol-1.0.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofile", "version": "3.12.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/79/6e45e778c4c3cab39e0937b007b720c15f76c50c6453d153282d0fcc3588/aiofile-3.12.3-py3-none-any.whl"}}, {"metadata": {"name": "caio", "version": "0.12.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/64/f33b9aaf7bc9bad988211d8e42b4b85c25a1d5dcc0906798aebe49bd421b/caio-0.12.4-cp313-cp313-manylinux_2_34_x86_64.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "argcomplete", "version": "3.7.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/46/bd/551ee6af426af84ca33e02622be722925c196608e9127d731ef17c47f06e/argcomplete-3.7.2-py3-none-any.whl"}}, {"metadata": {"name": "Authlib", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b8/c6/6f124bcfbbfb20fba22c939b4e43a06dccfc0e1ca20e5634ca573cb1e271/authlib-1.8.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "beartype", "version": "0.22.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/cc/18245721fa7747065ab478316c7fea7c74777d07f37ae60db2e84f8172e8/beartype-0.22.9-py3-none-any.whl"}}, {"metadata": {"name": "boto3", "version": "1.43.98"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/46/d29efd46ecac6637065a39418c5fb95500d70ec63e76065b5a72c936172f/boto3-1.43.98-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.98"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/ca/c7617e99c3247f545233ab2181840d142c5f72034e22864172866fb1369a/botocore-1.43.98-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "s3transfer", "version": "0.19.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/e7/5c595c75e9f41a44f30e526eda465ea0b4eec93470e074e4a111b253f13a/s3transfer-0.19.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "cachetools", "version": "7.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cc/bb/1c6e7a89b11da19f137e4ef5a5c5fe47a5bb686449ba343944ccf8fb34b2/cachetools-7.2.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "cohere", "version": "7.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4a/c3/064a44c498bf6ae8621caa14307d3ef5471157f149e33cfd64417c8e9ad3/cohere-7.1.1-py3-none-any.whl"}}, {"metadata": {"name": "fastavro", "version": "1.12.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8c/bc/b7e15fa788f42cbe65827af2ec06c9ad91bb9f72c213110dbef61b53a5b0/fastavro-1.12.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/af/63240b0c0248c075c2535a1f1bd992821d8251b9f173abc13329661d09e4/charset_normalizer-3.5.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "tokenizers", "version": "0.23.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/ca/ca6b93c7820df123b2662a9469e8facc826ccc94e98fdd0d615f6431e73a/tokenizers-0.23.2-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "types-requests", "version": "2.33.0.20260906"}, "download_info": {"url": "https://files.pythonhosted.org/packages/60/4c/51ec821d22a45b4162fa3f3e9e94ea4c0f8c49e82363b10955baa5438391/types_requests-2.33.0.20260906-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/85/66/6ccca4722987ddedaa7fc9c3f4708af7431f5535666c174350830888c6b7/cryptography-50.0.1-cp311-abi3-manylinux_2_34_x86_64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/95/86342356ff5953b3fb06f7ef7c5bee212d45e770abc7218d451b9148313c/cffi-2.1.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "cyclopts", "version": "4.25.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/cc/e879da3d54cf727f90e6d90118e132672c3913338b566740486f8797190d/cyclopts-4.25.3-py3-none-any.whl"}}, {"metadata": {"name": "rich-rst", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/68/1fc93dd759605b5d00fc98b50200739e41ed32bd22d6ba35ca6c3932371b/rich_rst-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "filelock", "version": "4.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/29/33/af0635ab07fe83b1788a1dbe370ff3e226062495a998335cb18a1cac81aa/filelock-4.0.1-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6c/c0/a98505f18594f1bce828bb159cec0fcf9860562f1a2c85913409fc8f3d9e/fsspec-2026.9.0-py3-none-any.whl"}}, {"metadata": {"name": "genai-prices", "version": "0.1.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d5/4a/9e04f3dca5ffe74133779ab5e9925ffb6411afbeac55d26fa0e148722599/genai_prices-0.1.7-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.58.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/59/13/477d90d09591b3938b45c4e11f4d8a51291682112cb5efcac961e815d562/google_auth-2.58.0-py3-none-any.whl"}}, {"metadata": {"name": "google-genai", "version": "2.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/84/5b/87913fe392ba7b6402577259289ed3740c577956554a674b191a2971d33e/google_genai-2.24.0-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b5/c2/c676c69444d9db448b3f0a55a98dcc534affce0bce961d9d2f0b8499b10a/websockets-16.1.1-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl"}}, {"metadata": {"name": "griffelib", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/63/e876e789525063c840ccfa8857febdabd6523bcef9ce7eb979b9305ea895/griffelib-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "groq", "version": "1.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/f6/c3d8ea3194d7d7d8292edd4dbb4b6832d29c2eab04887dda4a742e83902c/groq-1.7.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "joserfc", "version": "1.7.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/c5/82addfd375e5ee6520644e0553e4aadde92d668c4fc99cc716d337fe7bb3/joserfc-1.7.5-py3-none-any.whl"}}, {"metadata": {"name": "jsonref", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/ec/e1db9922bceb168197a558a2b8c03a7963f1afe93517ddd3cf99f202f996/jsonref-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-path", "version": "0.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/2c/9e69d73c4297508be9e3b64a970ea3971b3eb8db64ffc5802d40bd25981f/jsonschema_path-0.5.0-py3-none-any.whl"}}, {"metadata": {"name": "pathable", "version": "0.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a2/e8/6d75ffd9784bce2e93d1ae4415649427e39a53bb172d4672b2b59c6f0a7b/pathable-0.6.0-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "keyring", "version": "25.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/db/e655086b7f3a705df045bf0933bdd9c2f79bb3c97bfef1384598bb79a217/keyring-25.7.0-py3-none-any.whl"}}, {"metadata": {"name": "jeepney", "version": "0.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b2/a3/e137168c9c44d18eff0376253da9f1e9234d0239e0ee230d2fee6cea8e55/jeepney-0.9.0-py3-none-any.whl"}}, {"metadata": {"name": "logfire", "version": "5.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cd/02/b32c3d5c298e4a9010694d261fb82c2c672747c0bf2b47bffda484aef349/logfire-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-exporter-otlp-proto-http", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cd/d0/fdeb1a98d8d3a6205f5f297c51b4a9bfe65126ab60339669bbe3dd54c2e2/opentelemetry_exporter_otlp_proto_http-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-exporter-otlp-proto-common", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5e/71/65fd9d54c10b860f87c045ccee1264cab7011268895d3528818a29c1172a/opentelemetry_exporter_otlp_proto_common-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-proto", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d1/7c/8be563d68e93bbefa5c8affb82ddcff91b3ad858ce49957ba7b16fd3e0ab/opentelemetry_proto-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "googleapis-common-protos", "version": "1.75.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1a/7a/7d79170c6ce6f12e109df2b3879d6b934010cf4f99aea8de8b7e5408c174/googleapis_common_protos-1.75.3-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/6f/a04e900f465ff3221ccc395522503e2d10e79fa21f2723c8e177aae1e0d1/opentelemetry_api-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-sdk", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e7/23/ff077e61886ee020a17ce9c8b6fa11c601c8d8345b09ea24f605445df62a/opentelemetry_sdk-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-semantic-conventions", "version": "0.65b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/0e/49df70d9b81fb5cbae4bbf2a49d865b09bcbcbc4eb53f5851b1027738d78/opentelemetry_semantic_conventions-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "executing", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "logfire-api", "version": "5.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2d/51/123dab197fb08c0892e3bea1c2266bff159aa2ee82ad43bef93505859705/logfire_api-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "mistralai", "version": "2.10.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/98/f64b54166a607ece4e5c8494c843ac1f9c7c0af6f1014272cc420fe1d519/mistralai-2.10.1-py3-none-any.whl"}}, {"metadata": {"name": "eval_type_backport", "version": "0.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/a7/bb99bf5e6f78736ddb53480f2c3ff3702ffe2196a7c5e1661c03081d398e/eval_type_backport-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonpath-python", "version": "1.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/8a/1270a6803bd821cbfcdda387eaa13cb41a7b1f7b9bd145979b3bfb9d6cb7/jsonpath_python-1.1.6-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "3.16.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/17/72/2b1fe3e303db76ab2ba0c2de2b57822869bcb588db82334d4ff3aea8acf2/openai-3.16.2-py3-none-any.whl"}}, {"metadata": {"name": "openapi-pydantic", "version": "0.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/cf/03675d8bd8ecbf4445504d8071adab19f5f993676795708e36402ab38263/openapi_pydantic-0.5.1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-instrumentation", "version": "0.65b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/40/7b/85eab1215f72adf0e68d3dc4a679b9bff993fa679ff34cd8dd378e2659fd/opentelemetry_instrumentation-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "wrapt", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/08/c2/0e772a570e8d75c1b3ec45930a3023492fa68223f8f5e3485af4844c10c3/wrapt-2.4.1-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl"}}, {"metadata": {"name": "opentelemetry-instrumentation-httpx", "version": "0.65b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/0f/c6144096b4914bbf44b43ba21c962e8f333ff045770b50a3e79ed8bd455f/opentelemetry_instrumentation_httpx-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-util-http", "version": "0.65b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/23/3f/ab8d29df207ce5f470a07fa96ebb48af4e95b7fab7e7635311b9a32f2fab/opentelemetry_util_http-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "platformdirs", "version": "4.11.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/39/be/3ae887e84c38c4dd1c549cd5825adc93f48069a94fe1cb8ac52a9da16f15/platformdirs-4.11.11-py3-none-any.whl"}}, {"metadata": {"name": "prompt_toolkit", "version": "3.0.53"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/6f/84908cad2d6aa5144abcf7b42709fe4fdb459bc640ec7ac5786e7693dabc/prompt_toolkit-3.0.53-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/3b/6163796d69c3977d1e4287bea4a6979161cbbdd170ebb430511e8e1999ce/pyasn1-0.6.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-handlebars", "version": "0.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/11/364bc401f1d8fdb3947079fc43ffdfbfc9132d065981a03a95d2e87440c4/pydantic_handlebars-0.2.1-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "email-validator", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "dnspython", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/97/672cb32ce0dfea44b740cb7b4f97038463b9cf7c0ead1aacf595572851d6/pyjwt-2.14.0-py3-none-any.whl"}}, {"metadata": {"name": "pyperclip", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/80/fc9d01d5ed37ba4c42ca2b55b4339ae6e200b456be3a1aaddf4a9fa99b8c/pyperclip-1.11.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/d7/fe978efc2ae50abe48eb7464668ea99f53c010c60aeebb7b35ad27f23661/rpds_py-2026.6.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "SecretStorage", "version": "3.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/46/f5af3402b579fd5e11573ce652019a67074317e18c1935cc0b4ba9b35552/secretstorage-3.5.0-py3-none-any.whl"}}, {"metadata": {"name": "shellingham", "version": "1.5.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/6a/2ba3ed4a69babf3afdddf7d8314a48d87562c0a442206bbc2a1b50d5efc0/sse_starlette-3.4.11-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "temporalio", "version": "1.33.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7a/12/63e13f93b5772f5bd2128990bfeec050f7de9e80ce4d8504d99f7f794b10/temporalio-1.33.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "nexus-rpc", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/11/52/6327a5f4fda01207205038a106a99848a41c83e933cd23ea2cab3d2ebc6c/nexus_rpc-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "types-protobuf", "version": "7.35.1.20260906"}, "download_info": {"url": "https://files.pythonhosted.org/packages/44/4e/f63e826c68f77ef875506d72f225918800346545ee99847bc28f3394f18d/types_protobuf-7.35.1.20260906-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/62/cae690d9783146b0f81f564ada0f8f611de68178c0c9c7e1e969f0516b48/tiktoken-0.14.0-cp313-cp313-manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/03/921a3d3c75785aca9ebfbfcabfbc3a1be12e2ab5265deb026d55a5a3f83e/tqdm-4.70.1-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uncalled-for", "version": "0.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a2/40/97cec87c077eb3291fc7905e6633e08b7ca593c57d30238444bcb6bb3d53/uncalled_for-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.53.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/76/18/0eea75741ee812e9f598b687619ce2454f6c3a1c5cd21ea990ec6bd26f45/uvicorn-0.53.0-py3-none-any.whl"}}, {"metadata": {"name": "watchfiles", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/6c/89b1a230a78f57c52dd8893adb1f92f94411721b6ec12596c56d98c74356/watchfiles-1.2.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/39/cc/9c0adc5861020de426ec71716b6c1bef8d90694b7d6d0a16202cdb1647f5/wcwidth-0.8.4-py3-none-any.whl"}}, {"metadata": {"name": "xai-sdk", "version": "1.19.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/b5/6f6783b97fb3a5498eb852ccaa706e1a2c0de2409480e3c99428e85234fe/xai_sdk-1.19.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/1c/7da8d08e74d56f00070822f9638ff3f1c563f8ad87d1efa996c87bfc8644/aiohttp-3.14.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "grpcio", "version": "1.84.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/56/548a643decb059ca244499c675ae2c13a15f523ba94592c2774bd80a13c1/grpcio-1.84.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "multidict", "version": "6.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/fc/19deb0d051c694dbc2d5008ec89b341f7ee42c4412b38630a47a14339115/multidict-6.9.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "packaging", "version": "25.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl"}}, {"metadata": {"name": "protobuf", "version": "6.33.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/16/92/d1e32e3e0d894fe00b15ce28ad4944ab692713f2e7f0a99787405e43533a/protobuf-6.33.6-cp39-abi3-manylinux2014_x86_64.whl"}}, {"metadata": {"name": "yarl", "version": "1.25.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0e/b7/a82a49bf88340b837ef6972b508a1604ae377b9e6904b46b10cf5f1cf925/yarl-1.25.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d5/4e/e4691508f9477ce67da2015d8c00acd751e6287739123113a9fca6f1604e/frozenlist-1.8.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ed/74/08e6c1faf26ee2732023a3828787ba535557122774f4a386b1f715cbd8e0/propcache-0.5.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "jaraco.classes", "version": "3.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/66/b15ce62552d84bbfcec9a4873ab79d993a1dd4edb922cbfccae192bd5b5f/jaraco.classes-3.4.0-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.context", "version": "6.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f2/58/bc8954bda5fcda97bd7c19be11b85f91973d67a706ed4a3aec33e7de22db/jaraco_context-6.1.2-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.functools", "version": "4.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/02/36/ecc85bc96c273dc8a11273ed4782272975e6338d4a3e9228621175edf0e3/jaraco_functools-4.6.0-py3-none-any.whl"}}, {"metadata": {"name": "more-itertools", "version": "11.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/3d/1087453384dbde46a8c7f9356eead2c58be8a7bf156bca40243377c85715/more_itertools-11.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.9.10"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/3b/000c79c3f9c06b7542225a5d3a7f9a85405da7224b3b9af94a491d07abea/regex-2026.9.10-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}], "install_targets_hash": "6f4f519d18d963ec7cd5445acdc50e5e"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "pyreqwest", "version": "0.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/44/51/48d5c7d034e081e8d495e918b01b6861c3c157e6a439e584ae2ce05bfb3b/pyreqwest-0.13.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}], "install_targets_hash": "6f61e0b03332a8ab3c901a7f00b7fa71"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "pyreqwest", "version": "0.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d9/45/89ccb6ea16d9a2e30c80865b439edf09c8d3680a4980ad5abda3a91ff666/pyreqwest-0.13.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}], "install_targets_hash": "6f61e0b03332a8ab3c901a7f00b7fa71"} -{"python_version": "3.13", "dependencies": [{"metadata": {"name": "boto3", "version": "1.43.98"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/46/d29efd46ecac6637065a39418c5fb95500d70ec63e76065b5a72c936172f/boto3-1.43.98-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.98"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/ca/c7617e99c3247f545233ab2181840d142c5f72034e22864172866fb1369a/botocore-1.43.98-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "s3transfer", "version": "0.19.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/e7/5c595c75e9f41a44f30e526eda465ea0b4eec93470e074e4a111b253f13a/s3transfer-0.19.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}], "install_targets_hash": "732c20a252602bec78b6c7ee26050916"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "openai", "version": "3.17.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/57/bc/5b80a0ca4069a6b5ba6c7d48ae7a4f8176b2c0bde0bebccdb867472ec6f6/openai-3.17.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.17.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ca/b1/34bfa29599d420423baac6ff7cada6674fe63d5a7a2ccb3900b904678783/jiter-0.17.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/21/43/6323b1f8b217780454c61304bcd2b38ae4762f50754414124603ccc90bb2/pydantic_core-2.46.5-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "6fe5caedd83b044975e2a5e20436ed3f"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "openai-agents", "version": "0.18.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/7c/08b9929a15131081898e38c5612d44ee293851d5c80f31ca1153efe82143/openai_agents-0.18.3-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "griffelib", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/63/e876e789525063c840ccfa8857febdabd6523bcef9ce7eb979b9305ea895/griffelib-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "mcp", "version": "1.30.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f5/f4/e58bc33317c92a0203664daaf00bf6f41166cc0149e5d6870a03f7cd004a/mcp-1.30.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "2.54.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/a8/bb76c7356de8ad57f59d5ff993d434df0607f07f08bcc9c9a5c275e399c0/openai-2.54.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/21/43/6323b1f8b217780454c61304bcd2b38ae4762f50754414124603ccc90bb2/pydantic_core-2.46.5-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/86/0a70d3ae2f0f2256bb41302d9804dbca65d4360281e7feb3e1f94102ac46/websockets-16.1.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a4/a0/562247944386f7d4ef94467e84876600cc1e0f1b93239aaa9213d2bc3cbd/charset_normalizer-3.5.1-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/b1/34bfa29599d420423baac6ff7cada6674fe63d5a7a2ccb3900b904678783/jiter-0.17.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/97/672cb32ce0dfea44b740cb7b4f97038463b9cf7c0ead1aacf595572851d6/pyjwt-2.14.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/6a/2ba3ed4a69babf3afdddf7d8314a48d87562c0a442206bbc2a1b50d5efc0/sse_starlette-3.4.11-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/03/921a3d3c75785aca9ebfbfcabfbc3a1be12e2ab5265deb026d55a5a3f83e/tqdm-4.70.1-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.52.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/79/4a20b54ab0491485ccd8c077db2d39187c7f12b3e15485d38a7be37c81b4/uvicorn-0.52.4-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/19/797e2aaac9df6a66f1550f49979dc1b1e39ecd2077501c30efa81e8d5d67/cryptography-50.0.1-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f3/6b/686d9dc4359a8f163cfbbf89ee0b4e586431de22fe8248edb63a8cf50d49/rpds_py-2026.6.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/41/4c7042f317b9217502988f0873af87e16ad606dc20f84e546e3e6ce9764c/cffi-2.1.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "72e451893bc86523078d768ca9965660"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "openai", "version": "2.54.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/a8/bb76c7356de8ad57f59d5ff993d434df0607f07f08bcc9c9a5c275e399c0/openai-2.54.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d0/2b/c3eaf16f5d7c9bad66ea32f40a95bd169b29a91217fcc7f081375157e99c/jiter-0.16.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/81/4fa520eaffa8bd7d1525e644cd6d39e7d60b1592bc5b516693c7340b50f1/pydantic_core-2.46.4-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}], "install_targets_hash": "74376afb5a970b70b12c3903563ea5a0"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "statsig", "version": "0.72.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/76/f6/72e48d6e3b37aaf866d1ca0c59382a28e67d303b1edee446c1fb5ceaf8ba/statsig-0.72.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "brotli", "version": "1.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/6c/d4/4ad5432ac98c73096159d9ce7ffeb82d151c2ac84adcc6168e476bb54674/brotli-1.2.0-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "grpcio", "version": "1.83.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c4/49/0b40bae059c619505c9b751cee6caa208e4904e290aaefa1728c4c2c67a5/grpcio-1.83.1-cp313-cp313-macosx_11_0_universal2.whl"}}, {"metadata": {"name": "ijson", "version": "3.5.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/db/4a/8322c2824c24184880587bbca45531127a21a4b3bfc897f13427fea02424/ijson-3.5.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "ip3country", "version": "0.4.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/d6/b7/48a7f1ab9eee62f1113114207df7e7e6bc29227389d554f42cc11bc98108/ip3country-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "protobuf", "version": "7.36.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/f7/6c/3a54a58f2948b0f485df9ecdd06590f15d0a7abf46a89d50c3de709ff4ff/protobuf-7.36.1-cp310-abi3-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a4/a0/562247944386f7d4ef94467e84876600cc1e0f1b93239aaa9213d2bc3cbd/charset_normalizer-3.5.1-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "ua-parser", "version": "1.0.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a9/7c/6367995ff57aaa2d9e1055adbaec2519cf5a979780a83a93fdf8c6ec37be/ua_parser-1.0.2-py3-none-any.whl"}}, {"metadata": {"name": "ua-parser-builtins", "version": "202606"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/51/a3/f26edd95a2ce2ffbf559da432e5ff544e8dcda3673d1c775f71afffb18b7/ua_parser_builtins-202606-py3-none-any.whl"}}], "install_targets_hash": "763ce761517f8c5492de65d82e642a37"} -{"python_version": "3.13", "dependencies": [{"metadata": {"name": "pydantic-ai", "version": "1.0.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/c3/0237cba693b26fd3d78acdb9c97b07c3cdd7c807c6fadbbba6abede4a7b7/pydantic_ai-1.0.18-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-ai-slim", "version": "1.0.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/18/45/0f6b98ce09d1cdf9403ef228c57d8251c6682713dc1c8870708c6a17378a/pydantic_ai_slim-1.0.18-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-evals", "version": "1.0.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4d/84/1008d2c9e66ab93d132a67f85770f2e58eb9e70d1b76ee2a88f6cefac90a/pydantic_evals-1.0.18-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-graph", "version": "1.0.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/68/8a/b6fa505b12fdd5bfcd846bb52087c30003c925e9820f91dd930a6500e5a9/pydantic_graph-1.0.18-py3-none-any.whl"}}, {"metadata": {"name": "temporalio", "version": "1.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/be/94/24bd903b5594420a4d131bfa3de965313f9a409af77b47e9a9a56d85bb9e/temporalio-1.18.0-cp39-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "nexus-rpc", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bf/2f/9e9d0dcaa4c6ffa22b7aa31069a8a264c753ff8027b36af602cce038c92f/nexus_rpc-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "ag-ui-protocol", "version": "0.1.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4c/0a/bcad8116eb058e4b4a305e3fc37ebd7efc879deeb86b854f1c5b8b6e97dd/ag_ui_protocol-0.1.19-py3-none-any.whl"}}, {"metadata": {"name": "anthropic", "version": "0.116.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c7/dd/2a1e81cf1b163acc340afc4ec74ed1d86f5eed1a809fabdeed3e0997b346/anthropic-0.116.0-py3-none-any.whl"}}, {"metadata": {"name": "argcomplete", "version": "3.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/f6/5b8ec087cd9cfa9449491ec83f76fb6b7006b4dff57d2ba8aaab330fe8e4/argcomplete-3.7.0-py3-none-any.whl"}}, {"metadata": {"name": "boto3", "version": "1.43.40"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/3b/2abcc7f47e955a8cb45a6378ec69cd8ed2dcb3d14ceb67717dea020a794a/boto3-1.43.40-py3-none-any.whl"}}, {"metadata": {"name": "cohere", "version": "7.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e6/eb/64ca464baa34d0fa8144fc09ec7a35c8fcdeea1be878a518e901b0a6032b/cohere-7.0.5-py3-none-any.whl"}}, {"metadata": {"name": "genai-prices", "version": "0.0.69"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/05/6bb176d603210b61d2bf4585c7119dcf5491bbcae195e21254668c5ee07a/genai_prices-0.0.69-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.55.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/1d/f6d3ca1ad0725f2e08a1c6915640748a52de2e66596160a4d53b010cccf0/google_auth-2.55.1-py3-none-any.whl"}}, {"metadata": {"name": "google-genai", "version": "2.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/39/00bcfd94de255d24249401efff4f48d77bf6066b46447e519fa193c0c299/google_genai-2.10.0-py3-none-any.whl"}}, {"metadata": {"name": "griffe", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6b/fb/3c65d392feae6c36dc2b55a14dd8270b7b35a3171c93b71a4d2ee4abf241/griffe-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "griffecli", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/80/2f/513232ec1d5f5da182e4ce45a11427e37dd210844a9e2bca451fc9661fb3/griffecli-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "griffelib", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e4/d3/5268aeabf2ad82658c4e2ff3a060648d0f02f3926cb53247c0e4d0dab49e/griffelib-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "groq", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ce/c3/cac2aee75198c0382a2e6070619a798de2288e01850abb6e999746bb92e3/groq-1.5.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "huggingface_hub", "version": "1.22.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/9c/a1a377265abd8b823a2c661c665028ccb6b9fba1ca9d08e52ff679c20ecd/huggingface_hub-1.22.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "logfire", "version": "4.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7a/08/1805d2f26955671115aae555d78cc4c72a6fe733f332d44d69756bc1737b/logfire-4.37.0-py3-none-any.whl"}}, {"metadata": {"name": "mcp", "version": "1.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e2/5e/d118fce19f87a2e7d8101c35c8ae0ec289098a4df0ff244cec23e415aca0/mcp-1.28.1-py3-none-any.whl"}}, {"metadata": {"name": "mistralai", "version": "2.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/9a/ec5bca319c97859240eef6937bed07853b3b5040475c8756a8ff8caf27a0/mistralai-2.5.1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-instrumentation", "version": "0.60b1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/77/d2/6788e83c5c86a2690101681aeef27eeb2a6bf22df52d3f263a22cee20915/opentelemetry_instrumentation-0.60b1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-semantic-conventions", "version": "0.60b1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7a/5e/5958555e09635d09b75de3c4f8b9cae7335ca545d77392ffe7331534c402/opentelemetry_semantic_conventions-0.60b1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.39.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/df/d3f1ddf4bb4cb50ed9b1139cc7b1c54c34a1e7ce8fd1b9a37c0d1551a6bd/opentelemetry_api-1.39.1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-instrumentation-httpx", "version": "0.60b1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/43/59/b98e84eebf745ffc75397eaad4763795bff8a30cbf2373a50ed4e70646c5/opentelemetry_instrumentation_httpx-0.60b1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-util-http", "version": "0.60b1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/16/5c/d3f1733665f7cd582ef0842fb1d2ed0bc1fba10875160593342d22bba375/opentelemetry_util_http-0.60b1-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "2.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ae/f4/561ed79fd94876160018a5e75254cfcb9b0e62d4dded9dcb20072e86d623/openai-2.44.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "prompt_toolkit", "version": "3.0.52"}, "download_info": {"url": "https://files.pythonhosted.org/packages/84/03/0d3ce49e2505ae70cf43bc5bb3033955d2fc9f932163e84dc0779cc47f48/prompt_toolkit-3.0.52-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/81/4fa520eaffa8bd7d1525e644cd6d39e7d60b1592bc5b516693c7340b50f1/pydantic_core-2.46.4-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "pyperclip", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/80/fc9d01d5ed37ba4c42ca2b55b4339ae6e200b456be3a1aaddf4a9fa99b8c/pyperclip-1.11.0-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.40"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/8c/5f7e73fd66b28f0705bc55d7060d41ef72328b656b86ca53e75765b3ba2c/botocore-1.43.40-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/3b/66777e39d3ae1ddc77ee606be4ec6d8cbd4c801f65e5a1b6f2b11b8346dd/charset_normalizer-3.4.7-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/22/adf66990e63584a68dfb50c24f48a125c07b1699899381c8151e63ed458c/cryptography-49.0.0-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "eval_type_backport", "version": "0.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/a7/bb99bf5e6f78736ddb53480f2c3ff3702ffe2196a7c5e1661c03081d398e/eval_type_backport-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "executing", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "fastavro", "version": "1.12.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/83/39/f489a441d41cc9c0a8449fb1325d7a9c9eb57a5634e6ab19dfb0a1105324/fastavro-1.12.2-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "filelock", "version": "3.29.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4a/e3/f1fae3647d170919c2cf2a898e77e7d1a4e5c7cae0aed7bb4bd3f5ebff6f/filelock-3.29.5-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e5/22/4222d7ddf3da30f363edaa98e329c2bce6c65497c9cb2810931c8b2c0fbc/fsspec-2026.6.0-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/35/94/4b2ecfbad8f8b04701a23aefb62f540b9137d058b7e1dbef16a32676f0e9/hf_xet-1.5.1-cp37-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/31/22/859d8252dad9bc9adee34b52e62cde621ece07b042ccb2ab4da1be46695f/httpx2-2.5.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c9/a1/7564199d1a8728fe737b0a72e5b3f8d92dfe085a74ddf7cdd83bce5f206d/httpcore2-2.5.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fa/5e/f8e9a1d23b9c20a551a8a02ea3637b4642e22c2626e3a13a9a29cdea99eb/importlib_metadata-8.7.1-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d0/2b/c3eaf16f5d7c9bad66ea32f40a95bd169b29a91217fcc7f081375157e99c/jiter-0.16.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonpath-python", "version": "1.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/8a/1270a6803bd821cbfcdda387eaa13cb41a7b1f7b9bd145979b3bfb9d6cb7/jsonpath_python-1.1.6-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "logfire-api", "version": "4.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/2f/23e5b8fa22f75f73965c72e5c29e6fb8715263457394601e254fe26fbe31/logfire_api-4.37.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-exporter-otlp-proto-http", "version": "1.39.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/f1/b27d3e2e003cd9a3592c43d099d2ed8d0a947c15281bf8463a256db0b46c/opentelemetry_exporter_otlp_proto_http-1.39.1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-exporter-otlp-proto-common", "version": "1.39.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8c/02/ffc3e143d89a27ac21fd557365b98bd0653b98de8a101151d5805b5d4c33/opentelemetry_exporter_otlp_proto_common-1.39.1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-proto", "version": "1.39.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/95/b40c96a7b5203005a0b03d8ce8cd212ff23f1793d5ba289c87a097571b18/opentelemetry_proto-1.39.1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-sdk", "version": "1.39.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/98/e91cf858f203d86f4eccdf763dcf01cf03f1dae80c3750f7e635bfa206b6/opentelemetry_sdk-1.39.1-py3-none-any.whl"}}, {"metadata": {"name": "protobuf", "version": "6.33.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5c/01/a3c3ed5cd186f39e7880f8303cc51385a198a81469d53d0fdecf1f64d929/protobuf-6.33.6-cp39-abi3-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/77/c1/6e422f34e569cf8e18df68d1939c81c099d2b61e4f7d9621c8a77560799c/pydantic_settings-2.14.2-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "s3transfer", "version": "0.19.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/46/5f/4c174edad94f82de888ac00a5ddd8d07b35609b6c94f0bdf4d74af57703e/s3transfer-0.19.0-py3-none-any.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/75/c88d3f5dafd59c791da1ce27650d30bf5b70cbf1cbf01cd00e5f9e360915/sse_starlette-3.4.5-py3-none-any.whl"}}, {"metadata": {"name": "tokenizers", "version": "0.23.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e2/6a/068ed9f6e444c9d7e9d55ce134181325700f3d7f30410721bdc8f848d727/tokenizers-0.23.1-cp310-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tqdm", "version": "4.68.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d8/8e/bb97bb0c71802080bfc8952937d174e49cfc50de5c951dd47b2496f0dcdb/tqdm-4.68.3-py3-none-any.whl"}}, {"metadata": {"name": "types-protobuf", "version": "7.34.1.20260518"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/1f/ec5caf72c2e3b688ca3927e0979a04ddad19e1afc4bf1c199bd743e0f419/types_protobuf-7.34.1.20260518-py3-none-any.whl"}}, {"metadata": {"name": "types-requests", "version": "2.33.0.20260518"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1c/bc/b139710a3b6018f7fb2b9508b35c8af564e61bf2bf4fa619d088f3e16f85/types_requests-2.33.0.20260518-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.50.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f2/59/02c7859295b001e77b8079fc9df9f8161b7c872cbf7ea8dab70cf51d61f1/uvicorn-0.50.1-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/aa/82/39a5f910cb99ec0b59e482971238c845af9220d3ab9fa76dd9162cda9d62/websockets-16.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "colorama", "version": "0.4.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl"}}, {"metadata": {"name": "googleapis-common-protos", "version": "1.75.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e7/c8/e2645aa8ed02fd4c7a2f59d68783b65b1f3cbdfe39a6308e156509d1fee8/googleapis_common_protos-1.75.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/a0/7d793dce3fa811fe047d6ae2431c672364b462850c6235ae306c0efd025f/pyasn1-0.6.3-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f3/6b/686d9dc4359a8f163cfbbf89ee0b4e586431de22fe8248edb63a8cf50d49/rpds_py-2026.6.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "wrapt", "version": "1.17.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/45/35/6a08de0f2c96dcdd7fe464d7420ddb9a7655a6561150e5fc4da9356aeaab/wrapt-1.17.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "zipp", "version": "4.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "76bc8d4da920add2d6433f5bd69d9ec8"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "statsig", "version": "0.55.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/17/de62fdea8aab8aa7c4a833378e0e39054b728dfd45ef279e975ed5ef4e86/statsig-0.55.3-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "grpcio", "version": "1.82.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/17/b448f2265e4927188425c0b09fb943c39b50f7f53fbead644b44ccdf834b/grpcio-1.82.0-cp313-cp313-macosx_11_0_universal2.whl"}}, {"metadata": {"name": "ijson", "version": "3.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/16/94/b1438e204d75e01541bebe3e668fe3e68612d210e9931ae1611062dd0a56/ijson-3.5.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "ip3country", "version": "0.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d6/b7/48a7f1ab9eee62f1113114207df7e7e6bc29227389d554f42cc11bc98108/ip3country-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "protobuf", "version": "7.35.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/03/8aeeb7458d22546bf64b5250ca1daeb5ff757d900e8e4a7476c6f0db843e/protobuf-7.35.1-cp310-abi3-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "ua-parser", "version": "1.0.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/7c/6367995ff57aaa2d9e1055adbaec2519cf5a979780a83a93fdf8c6ec37be/ua_parser-1.0.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/3b/66777e39d3ae1ddc77ee606be4ec6d8cbd4c801f65e5a1b6f2b11b8346dd/charset_normalizer-3.4.7-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "ua-parser-builtins", "version": "202606"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/a3/f26edd95a2ce2ffbf559da432e5ff544e8dcda3673d1c775f71afffb18b7/ua_parser_builtins-202606-py3-none-any.whl"}}], "install_targets_hash": "7a12a54efcb27f14786026d8ffbb0792"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "statsig", "version": "0.55.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/17/de62fdea8aab8aa7c4a833378e0e39054b728dfd45ef279e975ed5ef4e86/statsig-0.55.3-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "grpcio", "version": "1.82.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/17/b448f2265e4927188425c0b09fb943c39b50f7f53fbead644b44ccdf834b/grpcio-1.82.0-cp313-cp313-macosx_11_0_universal2.whl"}}, {"metadata": {"name": "ijson", "version": "3.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/16/94/b1438e204d75e01541bebe3e668fe3e68612d210e9931ae1611062dd0a56/ijson-3.5.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "ip3country", "version": "0.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d6/b7/48a7f1ab9eee62f1113114207df7e7e6bc29227389d554f42cc11bc98108/ip3country-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "protobuf", "version": "7.35.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/03/8aeeb7458d22546bf64b5250ca1daeb5ff757d900e8e4a7476c6f0db843e/protobuf-7.35.1-cp310-abi3-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "ua-parser", "version": "1.0.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/7c/6367995ff57aaa2d9e1055adbaec2519cf5a979780a83a93fdf8c6ec37be/ua_parser-1.0.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/3b/66777e39d3ae1ddc77ee606be4ec6d8cbd4c801f65e5a1b6f2b11b8346dd/charset_normalizer-3.4.7-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "ua-parser-builtins", "version": "202606"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/a3/f26edd95a2ce2ffbf559da432e5ff544e8dcda3673d1c775f71afffb18b7/ua_parser_builtins-202606-py3-none-any.whl"}}], "install_targets_hash": "7a12a54efcb27f14786026d8ffbb0792"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "statsig", "version": "0.55.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/9d/17/de62fdea8aab8aa7c4a833378e0e39054b728dfd45ef279e975ed5ef4e86/statsig-0.55.3-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "grpcio", "version": "1.83.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c4/49/0b40bae059c619505c9b751cee6caa208e4904e290aaefa1728c4c2c67a5/grpcio-1.83.1-cp313-cp313-macosx_11_0_universal2.whl"}}, {"metadata": {"name": "ijson", "version": "3.5.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/db/4a/8322c2824c24184880587bbca45531127a21a4b3bfc897f13427fea02424/ijson-3.5.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "ip3country", "version": "0.4.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/d6/b7/48a7f1ab9eee62f1113114207df7e7e6bc29227389d554f42cc11bc98108/ip3country-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "protobuf", "version": "7.36.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/f7/6c/3a54a58f2948b0f485df9ecdd06590f15d0a7abf46a89d50c3de709ff4ff/protobuf-7.36.1-cp310-abi3-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a4/a0/562247944386f7d4ef94467e84876600cc1e0f1b93239aaa9213d2bc3cbd/charset_normalizer-3.5.1-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "ua-parser", "version": "1.0.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a9/7c/6367995ff57aaa2d9e1055adbaec2519cf5a979780a83a93fdf8c6ec37be/ua_parser-1.0.2-py3-none-any.whl"}}, {"metadata": {"name": "ua-parser-builtins", "version": "202606"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/51/a3/f26edd95a2ce2ffbf559da432e5ff544e8dcda3673d1c775f71afffb18b7/ua_parser_builtins-202606-py3-none-any.whl"}}], "install_targets_hash": "7a12a54efcb27f14786026d8ffbb0792"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "statsig", "version": "0.55.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/17/de62fdea8aab8aa7c4a833378e0e39054b728dfd45ef279e975ed5ef4e86/statsig-0.55.3-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "grpcio", "version": "1.82.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/17/b448f2265e4927188425c0b09fb943c39b50f7f53fbead644b44ccdf834b/grpcio-1.82.0-cp313-cp313-macosx_11_0_universal2.whl"}}, {"metadata": {"name": "ijson", "version": "3.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/16/94/b1438e204d75e01541bebe3e668fe3e68612d210e9931ae1611062dd0a56/ijson-3.5.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "ip3country", "version": "0.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d6/b7/48a7f1ab9eee62f1113114207df7e7e6bc29227389d554f42cc11bc98108/ip3country-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "protobuf", "version": "7.35.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/03/8aeeb7458d22546bf64b5250ca1daeb5ff757d900e8e4a7476c6f0db843e/protobuf-7.35.1-cp310-abi3-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "ua-parser", "version": "1.0.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/7c/6367995ff57aaa2d9e1055adbaec2519cf5a979780a83a93fdf8c6ec37be/ua_parser-1.0.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/3b/66777e39d3ae1ddc77ee606be4ec6d8cbd4c801f65e5a1b6f2b11b8346dd/charset_normalizer-3.4.7-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "ua-parser-builtins", "version": "202606"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/a3/f26edd95a2ce2ffbf559da432e5ff544e8dcda3673d1c775f71afffb18b7/ua_parser_builtins-202606-py3-none-any.whl"}}], "install_targets_hash": "7a12a54efcb27f14786026d8ffbb0792"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "gql", "version": "4.4.0b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/97/00105a44b645f2234e4540027d2ae4ea34b6a95d40e45f9f01c020d0f5b0/gql-4.4.0b0-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/6b/e7f13410d391c6e55b4c007a8de024355389d7d459e3d64c42b2d33617e5/aiohttp-3.14.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.57"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/7a/1cfe9c296df0fa6e0143c8622b10f21fa8fb9cce25450e9a8e5cf6523e4b/botocore-1.43.57-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.3.0rc0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8c/89/efd877ac909125f050b9562afc1f4b1bc7c0a90bc2a03ed7b0cb21debca3/graphql_core-3.3.0rc0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/13/b8/cfd91c4ab9134d386d48f0b6ac662ff3d4be6efdee59ee1c67ebc3c0487c/httpx2-2.9.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9f/fb/46c52b781975c335a2bcf1072c7bbc007cbdc8d674217f5ee1daba2c848b/httpcore2-2.9.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/76/55cd7186f498ed080a18440c9013011eb548f77ae1b297206d030eb1180a/multidict-6.7.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b2/06/97ec2aeae780b31d742b6352218b43841a6871e2564578ca522dce4a45c3/charset_normalizer-3.4.9-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "15.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ff/0b/33cef55ff24f2d92924923c99926dcce78e7bd922d649467f0eda8368923/websockets-15.0.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/15/f0/7688d3f2cfff7590df2af38ec46d969f4281a4dddb08a9ad2eafbcdddf98/yarl-1.24.5-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "responses", "version": "0.26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/28/693e1d9ebf72baa062ded80d837a035b86ce75eda5a269379e9e2b1008a8/responses-0.26.2-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/ab/6e5080ee374f875296c4243c381bbdef97a9ac39c6e3ce1d5f7d42cb78d6/frozenlist-1.8.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/12/a6ba6482bb5ea3260c000c9b20881c95fa11c6b30173715668259f844ed7/propcache-0.5.2-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}], "install_targets_hash": "7d9f37badbb06455849b77944a0bd79e"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "gql", "version": "4.4.0b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/97/00105a44b645f2234e4540027d2ae4ea34b6a95d40e45f9f01c020d0f5b0/gql-4.4.0b0-py3-none-any.whl"}}, {"metadata": {"name": "responses", "version": "0.26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/28/693e1d9ebf72baa062ded80d837a035b86ce75eda5a269379e9e2b1008a8/responses-0.26.2-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/6b/e7f13410d391c6e55b4c007a8de024355389d7d459e3d64c42b2d33617e5/aiohttp-3.14.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.57"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/7a/1cfe9c296df0fa6e0143c8622b10f21fa8fb9cce25450e9a8e5cf6523e4b/botocore-1.43.57-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.3.0rc0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8c/89/efd877ac909125f050b9562afc1f4b1bc7c0a90bc2a03ed7b0cb21debca3/graphql_core-3.3.0rc0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/13/b8/cfd91c4ab9134d386d48f0b6ac662ff3d4be6efdee59ee1c67ebc3c0487c/httpx2-2.9.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9f/fb/46c52b781975c335a2bcf1072c7bbc007cbdc8d674217f5ee1daba2c848b/httpcore2-2.9.1-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "15.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ff/0b/33cef55ff24f2d92924923c99926dcce78e7bd922d649467f0eda8368923/websockets-15.0.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/15/f0/7688d3f2cfff7590df2af38ec46d969f4281a4dddb08a9ad2eafbcdddf98/yarl-1.24.5-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b2/06/97ec2aeae780b31d742b6352218b43841a6871e2564578ca522dce4a45c3/charset_normalizer-3.4.9-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/ab/6e5080ee374f875296c4243c381bbdef97a9ac39c6e3ce1d5f7d42cb78d6/frozenlist-1.8.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/76/55cd7186f498ed080a18440c9013011eb548f77ae1b297206d030eb1180a/multidict-6.7.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/12/a6ba6482bb5ea3260c000c9b20881c95fa11c6b30173715668259f844ed7/propcache-0.5.2-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}], "install_targets_hash": "7d9f37badbb06455849b77944a0bd79e"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "gql", "version": "4.4.0b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/97/00105a44b645f2234e4540027d2ae4ea34b6a95d40e45f9f01c020d0f5b0/gql-4.4.0b0-py3-none-any.whl"}}, {"metadata": {"name": "responses", "version": "0.26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/28/693e1d9ebf72baa062ded80d837a035b86ce75eda5a269379e9e2b1008a8/responses-0.26.2-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/6b/e7f13410d391c6e55b4c007a8de024355389d7d459e3d64c42b2d33617e5/aiohttp-3.14.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.57"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/7a/1cfe9c296df0fa6e0143c8622b10f21fa8fb9cce25450e9a8e5cf6523e4b/botocore-1.43.57-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.3.0rc0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8c/89/efd877ac909125f050b9562afc1f4b1bc7c0a90bc2a03ed7b0cb21debca3/graphql_core-3.3.0rc0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/13/b8/cfd91c4ab9134d386d48f0b6ac662ff3d4be6efdee59ee1c67ebc3c0487c/httpx2-2.9.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9f/fb/46c52b781975c335a2bcf1072c7bbc007cbdc8d674217f5ee1daba2c848b/httpcore2-2.9.1-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "15.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ff/0b/33cef55ff24f2d92924923c99926dcce78e7bd922d649467f0eda8368923/websockets-15.0.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/15/f0/7688d3f2cfff7590df2af38ec46d969f4281a4dddb08a9ad2eafbcdddf98/yarl-1.24.5-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b2/06/97ec2aeae780b31d742b6352218b43841a6871e2564578ca522dce4a45c3/charset_normalizer-3.4.9-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/ab/6e5080ee374f875296c4243c381bbdef97a9ac39c6e3ce1d5f7d42cb78d6/frozenlist-1.8.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/76/55cd7186f498ed080a18440c9013011eb548f77ae1b297206d030eb1180a/multidict-6.7.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/12/a6ba6482bb5ea3260c000c9b20881c95fa11c6b30173715668259f844ed7/propcache-0.5.2-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}], "install_targets_hash": "7d9f37badbb06455849b77944a0bd79e"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "UnleashClient", "version": "6.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f3/52/2f9da0f81dba2323409e291dc32975bf20d245d493e22c8295461d8025e3/unleashclient-6.8.0-py3-none-any.whl"}}, {"metadata": {"name": "APScheduler", "version": "3.11.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/42/c9/8638db32514dbb9157b3d82680c6faea89283523edf9ed2415ea3884f2ae/apscheduler-3.11.3-py3-none-any.whl"}}, {"metadata": {"name": "semver", "version": "3.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/24/4d91e05817e92e3a61c8a21e08fd0f390f5301f1c448b137c57c4bc6e543/semver-3.0.4-py3-none-any.whl"}}, {"metadata": {"name": "tzlocal", "version": "5.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/a4/017a7a6cbe387d961a688ec31364ae60a5c4e22c96ae9921b79a947c855d/tzlocal-5.4.4-py3-none-any.whl"}}, {"metadata": {"name": "yggdrasil-engine", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/7f/38b0c1ecb2146362b8f5760e9bf9bad2e56b97ba5515f28796f20dc82821/yggdrasil_engine-1.3.1-cp313-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "fcache", "version": "0.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/84/0c/ababd9fed96d865463f95f897c48a8781bc831f9e08cdc8124b96964f92c/fcache-0.6.0-py3-none-any.whl"}}, {"metadata": {"name": "platformdirs", "version": "3.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/29/3ec311dc18804409ecf0d2b09caa976f3ae6215559306b5b530004e11156/platformdirs-3.11.0-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "9.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/38/3d/2d244233ac4f76e38533cfcb2991c9eb4c7bf688ae0a036d30725b8faafe/importlib_metadata-9.0.0-py3-none-any.whl"}}, {"metadata": {"name": "zipp", "version": "4.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl"}}, {"metadata": {"name": "launchdarkly-eventsource", "version": "1.7.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/49/8592c1d9c156d3c2d3f8c02e1c00260c3e0a7a10bcb50c942bd80c285c62/launchdarkly_eventsource-1.7.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "mmh3", "version": "5.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d4/4c/8e3af1b6d85a299767ec97bd923f12b06267089c1472c27c1696870d1175/mmh3-5.2.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b2/06/97ec2aeae780b31d742b6352218b43841a6871e2564578ca522dce4a45c3/charset_normalizer-3.4.9-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}], "install_targets_hash": "80f0bee8c3b3234399e0317b74ba4c5a"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "UnleashClient", "version": "6.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f3/52/2f9da0f81dba2323409e291dc32975bf20d245d493e22c8295461d8025e3/unleashclient-6.8.0-py3-none-any.whl"}}, {"metadata": {"name": "APScheduler", "version": "3.11.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/42/c9/8638db32514dbb9157b3d82680c6faea89283523edf9ed2415ea3884f2ae/apscheduler-3.11.3-py3-none-any.whl"}}, {"metadata": {"name": "semver", "version": "3.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/24/4d91e05817e92e3a61c8a21e08fd0f390f5301f1c448b137c57c4bc6e543/semver-3.0.4-py3-none-any.whl"}}, {"metadata": {"name": "yggdrasil-engine", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/7f/38b0c1ecb2146362b8f5760e9bf9bad2e56b97ba5515f28796f20dc82821/yggdrasil_engine-1.3.1-cp313-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "fcache", "version": "0.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/84/0c/ababd9fed96d865463f95f897c48a8781bc831f9e08cdc8124b96964f92c/fcache-0.6.0-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "9.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/38/3d/2d244233ac4f76e38533cfcb2991c9eb4c7bf688ae0a036d30725b8faafe/importlib_metadata-9.0.0-py3-none-any.whl"}}, {"metadata": {"name": "launchdarkly-eventsource", "version": "1.7.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/49/8592c1d9c156d3c2d3f8c02e1c00260c3e0a7a10bcb50c942bd80c285c62/launchdarkly_eventsource-1.7.2-py3-none-any.whl"}}, {"metadata": {"name": "mmh3", "version": "5.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d4/4c/8e3af1b6d85a299767ec97bd923f12b06267089c1472c27c1696870d1175/mmh3-5.2.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b2/06/97ec2aeae780b31d742b6352218b43841a6871e2564578ca522dce4a45c3/charset_normalizer-3.4.9-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "platformdirs", "version": "3.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/29/3ec311dc18804409ecf0d2b09caa976f3ae6215559306b5b530004e11156/platformdirs-3.11.0-py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tzlocal", "version": "5.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/a4/017a7a6cbe387d961a688ec31364ae60a5c4e22c96ae9921b79a947c855d/tzlocal-5.4.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "zipp", "version": "4.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl"}}], "install_targets_hash": "80f0bee8c3b3234399e0317b74ba4c5a"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "httpx2", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e6/a7/aea061b450d51cf448c1ccc8e1fc6f04c0d8fdc97c17524c7f835018bb92/httpx2-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2-pytest", "version": "1.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/46/ef/e9b6fb576f1f518f68e9f9cce9776870452ae2b8cfbba53b4127701b9a55/httpx2_pytest-1.0.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b7/76d6baa8c087cf5170f36dbeb92471e77c5c48f8f7ca8e5ba4ad613ea492/httpcore2-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}], "install_targets_hash": "81061e3f7fbd70089dc2dae262e96f28"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "openai", "version": "3.17.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/57/bc/5b80a0ca4069a6b5ba6c7d48ae7a4f8176b2c0bde0bebccdb867472ec6f6/openai-3.17.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.17.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ca/b1/34bfa29599d420423baac6ff7cada6674fe63d5a7a2ccb3900b904678783/jiter-0.17.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/21/43/6323b1f8b217780454c61304bcd2b38ae4762f50754414124603ccc90bb2/pydantic_core-2.46.5-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ad/5f/6448cfe278c3664ba9ec5b5ac08344341f7dc3d42888476e215a14eda2be/tiktoken-0.14.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.9.10"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/fa/68/241f88458b17c46ed2f80147a60a03b2ada7fb815c23b6bc76c298abb0a5/regex-2026.9.10-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a4/a0/562247944386f7d4ef94467e84876600cc1e0f1b93239aaa9213d2bc3cbd/charset_normalizer-3.5.1-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "urllib3", "version": "2.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "828f8978f312e7020633b81adf747d24"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "boto3", "version": "1.35.99"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/77/8bbca82f70b062181cf0ae53fd43f1ac6556f3078884bfef9da2269c06a3/boto3-1.35.99-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.35.99"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fc/dd/d87e2a145fad9e08d0ec6edcf9d71f838ccc7acdd919acc4c0d4a93515f8/botocore-1.35.99-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "s3transfer", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/66/05/7957af15543b8c9799209506df4660cba7afc4cf94bfb60513827e96bed6/s3transfer-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}], "install_targets_hash": "82e93b805ffcefdca457780864f9fb29"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "boto3", "version": "1.35.99"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/77/8bbca82f70b062181cf0ae53fd43f1ac6556f3078884bfef9da2269c06a3/boto3-1.35.99-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.35.99"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fc/dd/d87e2a145fad9e08d0ec6edcf9d71f838ccc7acdd919acc4c0d4a93515f8/botocore-1.35.99-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "s3transfer", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/66/05/7957af15543b8c9799209506df4660cba7afc4cf94bfb60513827e96bed6/s3transfer-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}], "install_targets_hash": "82e93b805ffcefdca457780864f9fb29"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "boto3", "version": "1.35.99"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/77/8bbca82f70b062181cf0ae53fd43f1ac6556f3078884bfef9da2269c06a3/boto3-1.35.99-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.35.99"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fc/dd/d87e2a145fad9e08d0ec6edcf9d71f838ccc7acdd919acc4c0d4a93515f8/botocore-1.35.99-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "s3transfer", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/66/05/7957af15543b8c9799209506df4660cba7afc4cf94bfb60513827e96bed6/s3transfer-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}], "install_targets_hash": "82e93b805ffcefdca457780864f9fb29"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "boto3", "version": "1.35.99"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/77/8bbca82f70b062181cf0ae53fd43f1ac6556f3078884bfef9da2269c06a3/boto3-1.35.99-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.35.99"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fc/dd/d87e2a145fad9e08d0ec6edcf9d71f838ccc7acdd919acc4c0d4a93515f8/botocore-1.35.99-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "s3transfer", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/66/05/7957af15543b8c9799209506df4660cba7afc4cf94bfb60513827e96bed6/s3transfer-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}], "install_targets_hash": "82e93b805ffcefdca457780864f9fb29"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "loguru", "version": "0.7.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/29/0348de65b8cc732daa3e33e67806420b2ae89bdce2b04af740289c5c6c8c/loguru-0.7.3-py3-none-any.whl"}}], "install_targets_hash": "835a301f2aad710918099958aaa42343"} -{"python_version": "3.13", "dependencies": [{"metadata": {"name": "dramatiq", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8c/13/0550ff585ade7b423e2ecaac29c4ab88673a58ae92ef25b6629089a2b92c/dramatiq-2.2.1-py3-none-any.whl"}}], "install_targets_hash": "83dfbbed9bd8bc2ec0e6747a01c98300"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "loguru", "version": "0.7.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/29/0348de65b8cc732daa3e33e67806420b2ae89bdce2b04af740289c5c6c8c/loguru-0.7.3-py3-none-any.whl"}}], "install_targets_hash": "835a301f2aad710918099958aaa42343"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "loguru", "version": "0.7.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/29/0348de65b8cc732daa3e33e67806420b2ae89bdce2b04af740289c5c6c8c/loguru-0.7.3-py3-none-any.whl"}}], "install_targets_hash": "835a301f2aad710918099958aaa42343"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "loguru", "version": "0.7.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/29/0348de65b8cc732daa3e33e67806420b2ae89bdce2b04af740289c5c6c8c/loguru-0.7.3-py3-none-any.whl"}}], "install_targets_hash": "835a301f2aad710918099958aaa42343"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "dramatiq", "version": "2.2.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/8c/13/0550ff585ade7b423e2ecaac29c4ab88673a58ae92ef25b6629089a2b92c/dramatiq-2.2.1-py3-none-any.whl"}}], "install_targets_hash": "83dfbbed9bd8bc2ec0e6747a01c98300"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "Quart", "version": "0.23.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/5c/c1/26dca56249da1a889ebb946000ab272712476209234f714ad3e8013ee005/quart-0.23.1-py3-none-any.whl"}}, {"metadata": {"name": "quart-auth", "version": "0.12.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ce/6b/e902def52a0c1c32bf872d87eb76cf4bf6109d015ac8c9e6768894676c8d/quart_auth-0.12.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.7.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/18/f1/46d32fe4b9aae09fe397e768ff376d9b6bdbb4f11faaa727f163c3457b43/pytest_forked-1.7.5-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "Hypercorn", "version": "0.18.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/93/35/850277d1b17b206bd10874c8a9a3f52e059452fb49bb0d22cbb908f6038b/hypercorn-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "h2", "version": "4.4.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/22/e85faf23bd72a92d1921e37d674ca56eb298a3c8be31fdecef0ff2b3aaac/h2-4.4.1-py3-none-any.whl"}}, {"metadata": {"name": "hpack", "version": "4.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/b4/4a9fcfb2aef6ba44d9073ecd301443aa00b3dac95de5619f2a7de7ec8a91/hpack-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "hyperframe", "version": "6.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/48/30/47d0bf6072f7252e6521f3447ccfa40b421b6824517f82854703d0f5a98b/hyperframe-6.1.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "wsproto", "version": "1.3.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a4/f5/10b68b7b1544245097b2a1b8238f66f2fc6dcaeb24ba5d917f52bd2eed4f/wsproto-1.3.2-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "priority", "version": "2.0.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/5e/5f/82c8074f7e84978129347c2c6ec8b6c59f3584ff1a20bc3c940a3e061790/priority-2.0.0-py3-none-any.whl"}}], "install_targets_hash": "8466032de3e88e282989c969ffd1cb35"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "Quart", "version": "0.23.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/5c/c1/26dca56249da1a889ebb946000ab272712476209234f714ad3e8013ee005/quart-0.23.1-py3-none-any.whl"}}, {"metadata": {"name": "quart-auth", "version": "0.12.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ce/6b/e902def52a0c1c32bf872d87eb76cf4bf6109d015ac8c9e6768894676c8d/quart_auth-0.12.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.7.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/18/f1/46d32fe4b9aae09fe397e768ff376d9b6bdbb4f11faaa727f163c3457b43/pytest_forked-1.7.5-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "Hypercorn", "version": "0.18.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/93/35/850277d1b17b206bd10874c8a9a3f52e059452fb49bb0d22cbb908f6038b/hypercorn-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "h2", "version": "4.4.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/22/e85faf23bd72a92d1921e37d674ca56eb298a3c8be31fdecef0ff2b3aaac/h2-4.4.1-py3-none-any.whl"}}, {"metadata": {"name": "hpack", "version": "4.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/b4/4a9fcfb2aef6ba44d9073ecd301443aa00b3dac95de5619f2a7de7ec8a91/hpack-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "hyperframe", "version": "6.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/48/30/47d0bf6072f7252e6521f3447ccfa40b421b6824517f82854703d0f5a98b/hyperframe-6.1.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "wsproto", "version": "1.3.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a4/f5/10b68b7b1544245097b2a1b8238f66f2fc6dcaeb24ba5d917f52bd2eed4f/wsproto-1.3.2-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "priority", "version": "2.0.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/5e/5f/82c8074f7e84978129347c2c6ec8b6c59f3584ff1a20bc3c940a3e061790/priority-2.0.0-py3-none-any.whl"}}], "install_targets_hash": "8466032de3e88e282989c969ffd1cb35"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "ray", "version": "2.58.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/77/473ba58257ab73fa4bdb182df5ed7f2efcf788d6e8c567109e900f01c37c/ray-2.58.0-cp313-cp313-macosx_12_0_arm64.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "msgpack", "version": "1.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/71/fbcfa83a1d6a9c6091942d1cfd070962244664b87427a9a49a6897b1b219/msgpack-1.2.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "protobuf", "version": "7.36.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8f/ae/58e3ca96cb2e118cc546b677359b3c6659f79a140935c08dec94c7998585/protobuf-7.36.0-cp310-abi3-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "filelock", "version": "3.32.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/a4/9b63d595d748e3aff8812b65eacc1a2c4bd90b7c2012e08e72373b4835eb/filelock-3.32.4-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a4/a0/562247944386f7d4ef94467e84876600cc1e0f1b93239aaa9213d2bc3cbd/charset_normalizer-3.5.1-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f3/6b/686d9dc4359a8f163cfbbf89ee0b4e586431de22fe8248edb63a8cf50d49/rpds_py-2026.6.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}], "install_targets_hash": "8cfb15039ed423e3572da8465f57e8cf"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "ray", "version": "2.58.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/77/473ba58257ab73fa4bdb182df5ed7f2efcf788d6e8c567109e900f01c37c/ray-2.58.0-cp313-cp313-macosx_12_0_arm64.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "msgpack", "version": "1.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/71/fbcfa83a1d6a9c6091942d1cfd070962244664b87427a9a49a6897b1b219/msgpack-1.2.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "protobuf", "version": "7.36.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8f/ae/58e3ca96cb2e118cc546b677359b3c6659f79a140935c08dec94c7998585/protobuf-7.36.0-cp310-abi3-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "filelock", "version": "3.32.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/a4/9b63d595d748e3aff8812b65eacc1a2c4bd90b7c2012e08e72373b4835eb/filelock-3.32.4-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a4/a0/562247944386f7d4ef94467e84876600cc1e0f1b93239aaa9213d2bc3cbd/charset_normalizer-3.5.1-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f3/6b/686d9dc4359a8f163cfbbf89ee0b4e586431de22fe8248edb63a8cf50d49/rpds_py-2026.6.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}], "install_targets_hash": "8cfb15039ed423e3572da8465f57e8cf"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "ray", "version": "2.58.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/77/473ba58257ab73fa4bdb182df5ed7f2efcf788d6e8c567109e900f01c37c/ray-2.58.0-cp313-cp313-macosx_12_0_arm64.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "msgpack", "version": "1.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/71/fbcfa83a1d6a9c6091942d1cfd070962244664b87427a9a49a6897b1b219/msgpack-1.2.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "protobuf", "version": "7.36.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8f/ae/58e3ca96cb2e118cc546b677359b3c6659f79a140935c08dec94c7998585/protobuf-7.36.0-cp310-abi3-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "filelock", "version": "3.32.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/a4/9b63d595d748e3aff8812b65eacc1a2c4bd90b7c2012e08e72373b4835eb/filelock-3.32.4-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a4/a0/562247944386f7d4ef94467e84876600cc1e0f1b93239aaa9213d2bc3cbd/charset_normalizer-3.5.1-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f3/6b/686d9dc4359a8f163cfbbf89ee0b4e586431de22fe8248edb63a8cf50d49/rpds_py-2026.6.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}], "install_targets_hash": "8cfb15039ed423e3572da8465f57e8cf"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "ray", "version": "2.58.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/77/473ba58257ab73fa4bdb182df5ed7f2efcf788d6e8c567109e900f01c37c/ray-2.58.0-cp313-cp313-macosx_12_0_arm64.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "msgpack", "version": "1.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/71/fbcfa83a1d6a9c6091942d1cfd070962244664b87427a9a49a6897b1b219/msgpack-1.2.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "protobuf", "version": "7.36.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8f/ae/58e3ca96cb2e118cc546b677359b3c6659f79a140935c08dec94c7998585/protobuf-7.36.0-cp310-abi3-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "filelock", "version": "3.32.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/a4/9b63d595d748e3aff8812b65eacc1a2c4bd90b7c2012e08e72373b4835eb/filelock-3.32.4-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a4/a0/562247944386f7d4ef94467e84876600cc1e0f1b93239aaa9213d2bc3cbd/charset_normalizer-3.5.1-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f3/6b/686d9dc4359a8f163cfbbf89ee0b4e586431de22fe8248edb63a8cf50d49/rpds_py-2026.6.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}], "install_targets_hash": "8cfb15039ed423e3572da8465f57e8cf"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "huggingface_hub", "version": "1.32.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/cf/d98dd561d6d0d7b7d7a64d1563f8aaaa7c235daee41c1c9bcc3da62420ed/huggingface_hub-1.32.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/4e/a28359bf1c1ecf11eba22123168c138698f7cb576ac678f5a2e16cd5da08/hf_xet-1.6.0-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "responses", "version": "0.26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6d/86/ca7958de70cb0752350575e98229368a3a2f746a2942034b3364e17312bb/responses-0.26.3-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/af/63240b0c0248c075c2535a1f1bd992821d8251b9f173abc13329661d09e4/charset_normalizer-3.5.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-httpx", "version": "0.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/55/1fa65f8e4fceb19dd6daa867c162ad845d547f6058cd92b4b02384a44777/pytest_httpx-0.36.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "filelock", "version": "4.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/29/33/af0635ab07fe83b1788a1dbe370ff3e226062495a998335cb18a1cac81aa/filelock-4.0.1-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6c/c0/a98505f18594f1bce828bb159cec0fcf9860562f1a2c85913409fc8f3d9e/fsspec-2026.9.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/03/921a3d3c75785aca9ebfbfcabfbc3a1be12e2ab5265deb026d55a5a3f83e/tqdm-4.70.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}], "install_targets_hash": "8d3f9781d86e000603a20c010acf0233"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "typer", "version": "0.27.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/dc/bf/205d0004930ede8f542fb58f601526fccf4ae7626075ca1e6c4de5d3d652/typer-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "shellingham", "version": "1.5.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}], "install_targets_hash": "8ea02a85ddecd330a24e7e8daff773d1"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "typer", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/bf/205d0004930ede8f542fb58f601526fccf4ae7626075ca1e6c4de5d3d652/typer-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "shellingham", "version": "1.5.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}], "install_targets_hash": "8ea02a85ddecd330a24e7e8daff773d1"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "typer", "version": "0.27.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/dc/bf/205d0004930ede8f542fb58f601526fccf4ae7626075ca1e6c4de5d3d652/typer-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "shellingham", "version": "1.5.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}], "install_targets_hash": "8ea02a85ddecd330a24e7e8daff773d1"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "typer", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/bf/205d0004930ede8f542fb58f601526fccf4ae7626075ca1e6c4de5d3d652/typer-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "shellingham", "version": "1.5.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}], "install_targets_hash": "8ea02a85ddecd330a24e7e8daff773d1"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "mcp", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/ff/8e7eade68b8a28f7da0ed1085544341b51f9c935dbf6b95c76b7edfea6a0/mcp-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mcp-types", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8f/d7/6ffba5d8cd5dd9b8a19478875c50e04945314ba5074e84d749283f27f62d/mcp_types-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/95/411ba65569158e862368917aaf56597f3e5fa3b91b0502919638465a08f3/httpx2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/74/d370e55600d9bcfa0d9794b0166126d49291a3d2b20c268fc98c453a4948/httpcore2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/6f/a04e900f465ff3221ccc395522503e2d10e79fa21f2723c8e177aae1e0d1/opentelemetry_api-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/21/43/6323b1f8b217780454c61304bcd2b38ae4762f50754414124603ccc90bb2/pydantic_core-2.46.5-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/97/672cb32ce0dfea44b740cb7b4f97038463b9cf7c0ead1aacf595572851d6/pyjwt-2.14.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/6a/2ba3ed4a69babf3afdddf7d8314a48d87562c0a442206bbc2a1b50d5efc0/sse_starlette-3.4.11-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.53.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/76/18/0eea75741ee812e9f598b687619ce2454f6c3a1c5cd21ea990ec6bd26f45/uvicorn-0.53.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/19/797e2aaac9df6a66f1550f49979dc1b1e39ecd2077501c30efa81e8d5d67/cryptography-50.0.1-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f3/6b/686d9dc4359a8f163cfbbf89ee0b4e586431de22fe8248edb63a8cf50d49/rpds_py-2026.6.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/41/4c7042f317b9217502988f0873af87e16ad606dc20f84e546e3e6ce9764c/cffi-2.1.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "92894b9de86e2bb0e11c5c76350def3a"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "mcp", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/ff/8e7eade68b8a28f7da0ed1085544341b51f9c935dbf6b95c76b7edfea6a0/mcp-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mcp-types", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8f/d7/6ffba5d8cd5dd9b8a19478875c50e04945314ba5074e84d749283f27f62d/mcp_types-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/95/411ba65569158e862368917aaf56597f3e5fa3b91b0502919638465a08f3/httpx2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/74/d370e55600d9bcfa0d9794b0166126d49291a3d2b20c268fc98c453a4948/httpcore2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/6f/a04e900f465ff3221ccc395522503e2d10e79fa21f2723c8e177aae1e0d1/opentelemetry_api-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d3/f2/9e4de77a6271e07a76d2d58b11c091a979c191ed2939bf80067568b369d2/pydantic_core-2.46.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/97/672cb32ce0dfea44b740cb7b4f97038463b9cf7c0ead1aacf595572851d6/pyjwt-2.14.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/85/66/6ccca4722987ddedaa7fc9c3f4708af7431f5535666c174350830888c6b7/cryptography-50.0.1-cp311-abi3-manylinux_2_34_x86_64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/95/86342356ff5953b3fb06f7ef7c5bee212d45e770abc7218d451b9148313c/cffi-2.1.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/d7/fe978efc2ae50abe48eb7464668ea99f53c010c60aeebb7b35ad27f23661/rpds_py-2026.6.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/6a/2ba3ed4a69babf3afdddf7d8314a48d87562c0a442206bbc2a1b50d5efc0/sse_starlette-3.4.11-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.52.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/79/4a20b54ab0491485ccd8c077db2d39187c7f12b3e15485d38a7be37c81b4/uvicorn-0.52.4-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "92894b9de86e2bb0e11c5c76350def3a"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "httpx2", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/25/66215a750faeb79b698286c0d0b94894482cfae10371ae4968ef6e165a28/httpx2-2.0.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2-pytest", "version": "1.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/46/ef/e9b6fb576f1f518f68e9f9cce9776870452ae2b8cfbba53b4127701b9a55/httpx2_pytest-1.0.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ae/67/784fd58a5b4dbe8b2aee0cafc6959cb8b53c1b7e9d6e4281f8a4c6935c10/httpcore2-2.0.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}], "install_targets_hash": "9589a3ce6fa0bfc82a7f6fc685f97223"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "grpcio", "version": "1.66.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8b/37/0b57c3769efb3cc9ec97fcaa9f7243046660e7ed58c0faebc4ef315df92c/grpcio-1.66.2-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "protobuf", "version": "7.35.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/03/8aeeb7458d22546bf64b5250ca1daeb5ff757d900e8e4a7476c6f0db843e/protobuf-7.35.1-cp310-abi3-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "mypy-protobuf", "version": "5.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/ec/5ffcf8f5f53757e01afdece10c664e694ac60d2f17c2036811b85b842a5b/mypy_protobuf-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "types-protobuf", "version": "7.34.1.20260518"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/1f/ec5caf72c2e3b688ca3927e0979a04ddad19e1afc4bf1c199bd743e0f419/types_protobuf-7.34.1.20260518-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/af/9c0bda43e486a3c9bf1e0f876d0f241bc3f229d7d65d09331a0868db9629/pytest_forked-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "py", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl"}}], "install_targets_hash": "9664bc6c25b7664cbf0e53ad567cc109"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "grpcio", "version": "1.66.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8b/37/0b57c3769efb3cc9ec97fcaa9f7243046660e7ed58c0faebc4ef315df92c/grpcio-1.66.2-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "protobuf", "version": "7.35.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/03/8aeeb7458d22546bf64b5250ca1daeb5ff757d900e8e4a7476c6f0db843e/protobuf-7.35.1-cp310-abi3-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "mypy-protobuf", "version": "5.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/ec/5ffcf8f5f53757e01afdece10c664e694ac60d2f17c2036811b85b842a5b/mypy_protobuf-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "types-protobuf", "version": "7.34.1.20260518"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/1f/ec5caf72c2e3b688ca3927e0979a04ddad19e1afc4bf1c199bd743e0f419/types_protobuf-7.34.1.20260518-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/af/9c0bda43e486a3c9bf1e0f876d0f241bc3f229d7d65d09331a0868db9629/pytest_forked-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "py", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "9664bc6c25b7664cbf0e53ad567cc109"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "grpcio", "version": "1.66.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8b/37/0b57c3769efb3cc9ec97fcaa9f7243046660e7ed58c0faebc4ef315df92c/grpcio-1.66.2-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "protobuf", "version": "7.35.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/03/8aeeb7458d22546bf64b5250ca1daeb5ff757d900e8e4a7476c6f0db843e/protobuf-7.35.1-cp310-abi3-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "mypy-protobuf", "version": "5.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/ec/5ffcf8f5f53757e01afdece10c664e694ac60d2f17c2036811b85b842a5b/mypy_protobuf-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "types-protobuf", "version": "7.34.1.20260518"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/1f/ec5caf72c2e3b688ca3927e0979a04ddad19e1afc4bf1c199bd743e0f419/types_protobuf-7.34.1.20260518-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/af/9c0bda43e486a3c9bf1e0f876d0f241bc3f229d7d65d09331a0868db9629/pytest_forked-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "py", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "9664bc6c25b7664cbf0e53ad567cc109"} -{"python_version": "3.13", "dependencies": [{"metadata": {"name": "pydantic-ai", "version": "2.46.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/01/20a5fda50b3e30067450d43ecd7ac1ddf41055982540ee6a48626a4e748b/pydantic_ai-2.46.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-ai-slim", "version": "2.46.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8c/fc/6a28534bc4b27026225fec76b4a2cb97274a0bda601a90890676b09c5132/pydantic_ai_slim-2.46.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-evals", "version": "2.46.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/89/83921db264a4d76561c641dd785472e68877525848228876a949565dd6b2/pydantic_evals-2.46.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-graph", "version": "2.46.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8b/7d/711d5e3a1ca9f560a365080779858be76510ff615a5106121ba0430b5f55/pydantic_graph-2.46.0-py3-none-any.whl"}}, {"metadata": {"name": "fastmcp-slim", "version": "4.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ed/76/8dc551ef1f222bd146537ae100baf7441628aa1050494b567249ece997c2/fastmcp_slim-4.0.5-py3-none-any.whl"}}, {"metadata": {"name": "mcp", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/ff/8e7eade68b8a28f7da0ed1085544341b51f9c935dbf6b95c76b7edfea6a0/mcp-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mcp-types", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8f/d7/6ffba5d8cd5dd9b8a19478875c50e04945314ba5074e84d749283f27f62d/mcp_types-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "py-key-value-aio", "version": "0.4.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/46/12871550fb0613d149144bb9d41f22680d5f46717bc45a76eb5798c20c3f/py_key_value_aio-0.4.6-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofile", "version": "3.12.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/79/6e45e778c4c3cab39e0937b007b720c15f76c50c6453d153282d0fcc3588/aiofile-3.12.3-py3-none-any.whl"}}, {"metadata": {"name": "caio", "version": "0.12.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/64/f33b9aaf7bc9bad988211d8e42b4b85c25a1d5dcc0906798aebe49bd421b/caio-0.12.4-cp313-cp313-manylinux_2_34_x86_64.whl"}}, {"metadata": {"name": "anthropic", "version": "1.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c0/dc/74995efda028421917f4caabd24db1373ee0742573a2363fff1a21191441/anthropic-1.7.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/27/17/91420b156315ae22732f5ee1a7b5725a030aab9dc8fd7dcdacfb4aa588d3/jiter-0.17.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d3/f2/9e4de77a6271e07a76d2d58b11c091a979c191ed2939bf80067568b369d2/pydantic_core-2.46.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "argcomplete", "version": "3.7.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/46/bd/551ee6af426af84ca33e02622be722925c196608e9127d731ef17c47f06e/argcomplete-3.7.2-py3-none-any.whl"}}, {"metadata": {"name": "Authlib", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b8/c6/6f124bcfbbfb20fba22c939b4e43a06dccfc0e1ca20e5634ca573cb1e271/authlib-1.8.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "beartype", "version": "0.22.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/cc/18245721fa7747065ab478316c7fea7c74777d07f37ae60db2e84f8172e8/beartype-0.22.9-py3-none-any.whl"}}, {"metadata": {"name": "cachetools", "version": "7.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cc/bb/1c6e7a89b11da19f137e4ef5a5c5fe47a5bb686449ba343944ccf8fb34b2/cachetools-7.2.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/85/66/6ccca4722987ddedaa7fc9c3f4708af7431f5535666c174350830888c6b7/cryptography-50.0.1-cp311-abi3-manylinux_2_34_x86_64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/95/86342356ff5953b3fb06f7ef7c5bee212d45e770abc7218d451b9148313c/cffi-2.1.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "genai-prices", "version": "0.1.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d5/4a/9e04f3dca5ffe74133779ab5e9925ffb6411afbeac55d26fa0e148722599/genai_prices-0.1.7-py3-none-any.whl"}}, {"metadata": {"name": "google-genai", "version": "2.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/84/5b/87913fe392ba7b6402577259289ed3740c577956554a674b191a2971d33e/google_genai-2.24.0-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.58.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/59/13/477d90d09591b3938b45c4e11f4d8a51291682112cb5efcac961e815d562/google_auth-2.58.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/af/63240b0c0248c075c2535a1f1bd992821d8251b9f173abc13329661d09e4/charset_normalizer-3.5.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b5/c2/c676c69444d9db448b3f0a55a98dcc534affce0bce961d9d2f0b8499b10a/websockets-16.1.1-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "griffelib", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/63/e876e789525063c840ccfa8857febdabd6523bcef9ce7eb979b9305ea895/griffelib-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "joserfc", "version": "1.7.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/c5/82addfd375e5ee6520644e0553e4aadde92d668c4fc99cc716d337fe7bb3/joserfc-1.7.5-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "keyring", "version": "25.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/db/e655086b7f3a705df045bf0933bdd9c2f79bb3c97bfef1384598bb79a217/keyring-25.7.0-py3-none-any.whl"}}, {"metadata": {"name": "jeepney", "version": "0.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b2/a3/e137168c9c44d18eff0376253da9f1e9234d0239e0ee230d2fee6cea8e55/jeepney-0.9.0-py3-none-any.whl"}}, {"metadata": {"name": "logfire", "version": "5.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cd/02/b32c3d5c298e4a9010694d261fb82c2c672747c0bf2b47bffda484aef349/logfire-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-exporter-otlp-proto-http", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cd/d0/fdeb1a98d8d3a6205f5f297c51b4a9bfe65126ab60339669bbe3dd54c2e2/opentelemetry_exporter_otlp_proto_http-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-exporter-otlp-proto-common", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5e/71/65fd9d54c10b860f87c045ccee1264cab7011268895d3528818a29c1172a/opentelemetry_exporter_otlp_proto_common-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-proto", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d1/7c/8be563d68e93bbefa5c8affb82ddcff91b3ad858ce49957ba7b16fd3e0ab/opentelemetry_proto-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "googleapis-common-protos", "version": "1.75.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1a/7a/7d79170c6ce6f12e109df2b3879d6b934010cf4f99aea8de8b7e5408c174/googleapis_common_protos-1.75.3-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/6f/a04e900f465ff3221ccc395522503e2d10e79fa21f2723c8e177aae1e0d1/opentelemetry_api-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-sdk", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e7/23/ff077e61886ee020a17ce9c8b6fa11c601c8d8345b09ea24f605445df62a/opentelemetry_sdk-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-semantic-conventions", "version": "0.65b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/0e/49df70d9b81fb5cbae4bbf2a49d865b09bcbcbc4eb53f5851b1027738d78/opentelemetry_semantic_conventions-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "protobuf", "version": "7.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/db/f3/3996583dd2906297a637af12114deddf7658af6e683fedb83be061983fb5/protobuf-7.36.2-cp310-abi3-manylinux2014_x86_64.whl"}}, {"metadata": {"name": "executing", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "logfire-api", "version": "5.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2d/51/123dab197fb08c0892e3bea1c2266bff159aa2ee82ad43bef93505859705/logfire_api-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "3.16.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/17/72/2b1fe3e303db76ab2ba0c2de2b57822869bcb588db82334d4ff3aea8acf2/openai-3.16.2-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-instrumentation", "version": "0.65b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/40/7b/85eab1215f72adf0e68d3dc4a679b9bff993fa679ff34cd8dd378e2659fd/opentelemetry_instrumentation-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "wrapt", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/08/c2/0e772a570e8d75c1b3ec45930a3023492fa68223f8f5e3485af4844c10c3/wrapt-2.4.1-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl"}}, {"metadata": {"name": "opentelemetry-instrumentation-httpx", "version": "0.65b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/0f/c6144096b4914bbf44b43ba21c962e8f333ff045770b50a3e79ed8bd455f/opentelemetry_instrumentation_httpx-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-util-http", "version": "0.65b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/23/3f/ab8d29df207ce5f470a07fa96ebb48af4e95b7fab7e7635311b9a32f2fab/opentelemetry_util_http-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "platformdirs", "version": "4.11.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/39/be/3ae887e84c38c4dd1c549cd5825adc93f48069a94fe1cb8ac52a9da16f15/platformdirs-4.11.11-py3-none-any.whl"}}, {"metadata": {"name": "prompt_toolkit", "version": "3.0.53"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/6f/84908cad2d6aa5144abcf7b42709fe4fdb459bc640ec7ac5786e7693dabc/prompt_toolkit-3.0.53-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/3b/6163796d69c3977d1e4287bea4a6979161cbbdd170ebb430511e8e1999ce/pyasn1-0.6.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "email-validator", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "dnspython", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/97/672cb32ce0dfea44b740cb7b4f97038463b9cf7c0ead1aacf595572851d6/pyjwt-2.14.0-py3-none-any.whl"}}, {"metadata": {"name": "pyperclip", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/80/fc9d01d5ed37ba4c42ca2b55b4339ae6e200b456be3a1aaddf4a9fa99b8c/pyperclip-1.11.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/d7/fe978efc2ae50abe48eb7464668ea99f53c010c60aeebb7b35ad27f23661/rpds_py-2026.6.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "SecretStorage", "version": "3.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/46/f5af3402b579fd5e11573ce652019a67074317e18c1935cc0b4ba9b35552/secretstorage-3.5.0-py3-none-any.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/6a/2ba3ed4a69babf3afdddf7d8314a48d87562c0a442206bbc2a1b50d5efc0/sse_starlette-3.4.11-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/62/cae690d9783146b0f81f564ada0f8f611de68178c0c9c7e1e969f0516b48/tiktoken-0.14.0-cp313-cp313-manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.53.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/76/18/0eea75741ee812e9f598b687619ce2454f6c3a1c5cd21ea990ec6bd26f45/uvicorn-0.53.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/39/cc/9c0adc5861020de426ec71716b6c1bef8d90694b7d6d0a16202cdb1647f5/wcwidth-0.8.4-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.classes", "version": "3.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/66/b15ce62552d84bbfcec9a4873ab79d993a1dd4edb922cbfccae192bd5b5f/jaraco.classes-3.4.0-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.context", "version": "6.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f2/58/bc8954bda5fcda97bd7c19be11b85f91973d67a706ed4a3aec33e7de22db/jaraco_context-6.1.2-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.functools", "version": "4.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/02/36/ecc85bc96c273dc8a11273ed4782272975e6338d4a3e9228621175edf0e3/jaraco_functools-4.6.0-py3-none-any.whl"}}, {"metadata": {"name": "more-itertools", "version": "11.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/3d/1087453384dbde46a8c7f9356eead2c58be8a7bf156bca40243377c85715/more_itertools-11.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.9.10"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/3b/000c79c3f9c06b7542225a5d3a7f9a85405da7224b3b9af94a491d07abea/regex-2026.9.10-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}], "install_targets_hash": "99070e5a015df9ed8efe12e4aa3cf88a"} -{"python_version": "3.13", "dependencies": [{"metadata": {"name": "fastmcp", "version": "2.14.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/f1/56310847b0bdd5b14c2af8f0a39082af078deff60d0dc43efef4e366a83e/fastmcp-2.14.7-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "Authlib", "version": "1.7.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/95/adcb68e20c34162e9135f370d6e31737719c2b6f94bc953fe7ed1f10fe21/authlib-1.7.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "cyclopts", "version": "4.22.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/75/a11bfb5045e58b4ef69337b848985918e829fe9a90572a761d17c1a992f5/cyclopts-4.22.2-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.34.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/b5/82f89307d0d769cd9bf46a54fb9136be08e4e57c5570ae421db4c9a2ba62/fakeredis-2.34.1-py3-none-any.whl"}}, {"metadata": {"name": "jsonref", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/ec/e1db9922bceb168197a558a2b8c03a7963f1afe93517ddd3cf99f202f996/jsonref-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-path", "version": "0.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/2c/9e69d73c4297508be9e3b64a970ea3971b3eb8db64ffc5802d40bd25981f/jsonschema_path-0.5.0-py3-none-any.whl"}}, {"metadata": {"name": "mcp", "version": "1.29.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/c8/248b201f6d753d69fd5d6506011abbb35a946d9142b2ae311a948fd0be3d/mcp-1.29.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "openapi-pydantic", "version": "0.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/cf/03675d8bd8ecbf4445504d8071adab19f5f993676795708e36402ab38263/openapi_pydantic-0.5.1-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "platformdirs", "version": "4.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7d/68/d8d58938dfb1370b266a1a729e6d77a985be23689a0496498ee17b2cbf90/platformdirs-4.11.0-py3-none-any.whl"}}, {"metadata": {"name": "py-key-value-aio", "version": "0.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/10/72f6f213b8f0bce36eff21fda0a13271834e9eeff7f9609b01afdc253c79/py_key_value_aio-0.3.0-py3-none-any.whl"}}, {"metadata": {"name": "py-key-value-shared", "version": "0.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/e4/b8b0a03ece72f47dce2307d36e1c34725b7223d209fc679315ffe6a4e2c3/py_key_value_shared-0.3.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/81/4fa520eaffa8bd7d1525e644cd6d39e7d60b1592bc5b516693c7340b50f1/pydantic_core-2.46.4-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydocket", "version": "0.23.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e6/67/b57ac7cfd2c2f30d58ff2c996591880d200078fc828cbbad8da69d634c0e/pydocket-0.23.1-py3-none-any.whl"}}, {"metadata": {"name": "pyperclip", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/80/fc9d01d5ed37ba4c42ca2b55b4339ae6e200b456be3a1aaddf4a9fa99b8c/pyperclip-1.11.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.52.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/39/e6/b5c0630ace9757232aec07112be8146b812787db52141ff9d50674aa7634/uvicorn-0.52.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/86/0a70d3ae2f0f2256bb41302d9804dbca65d4360281e7feb3e1f94102ac46/websockets-16.1.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "beartype", "version": "0.22.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/cc/18245721fa7747065ab478316c7fea7c74777d07f37ae60db2e84f8172e8/beartype-0.22.9-py3-none-any.whl"}}, {"metadata": {"name": "burner-redis", "version": "0.1.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2f/4e/ce5c91b884ac37fcd380756402536f8810964014097950900517ce8bd30c/burner_redis-0.1.7-cp310-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cachetools", "version": "7.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9f/f2/2086ba18a925a73586c4d4e61d25f4a6058e56fd00d77ce8f1d361ab4c9b/cachetools-7.1.6-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "cloudpickle", "version": "3.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/88/39/799be3f2f0f38cc727ee3b4f1445fe6d5e4133064ec2e4115069418a5bb6/cloudpickle-3.1.2-py3-none-any.whl"}}, {"metadata": {"name": "cronsim", "version": "2.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1a/02f105147f7f2e06ed4f734ff5a6439590bb275a53dd91fc73df6312298a/cronsim-2.7-py3-none-any.whl"}}, {"metadata": {"name": "diskcache", "version": "5.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/27/4570e78fc0bf5ea0ca45eb1de3818a23787af9b390c0b0a0033a1b8236f9/diskcache-5.6.3-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "email-validator", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "joserfc", "version": "1.7.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/bf/249dcd99b3376375910b7fa922383b57792975c8758f50d44612e749226c/joserfc-1.7.4-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/22/adf66990e63584a68dfb50c24f48a125c07b1699899381c8151e63ed458c/cryptography-49.0.0-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "keyring", "version": "25.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/db/e655086b7f3a705df045bf0933bdd9c2f79bb3c97bfef1384598bb79a217/keyring-25.7.0-py3-none-any.whl"}}, {"metadata": {"name": "lupa", "version": "2.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/3f/19f83c3a0c84dc8bea8a58e7416dca6a3ede662c33c8d1ec758e5afc754a/lupa-2.8-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/6f/a04e900f465ff3221ccc395522503e2d10e79fa21f2723c8e177aae1e0d1/opentelemetry_api-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "pathable", "version": "0.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a2/e8/6d75ffd9784bce2e93d1ae4415649427e39a53bb172d4672b2b59c6f0a7b/pathable-0.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pathvalidate", "version": "3.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/70/875f4a23bfc4731703a5835487d0d2fb999031bd415e7d17c0ae615c18b7/pathvalidate-3.3.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "prometheus_client", "version": "0.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/a3/b69efbf4143b5b9859b977770bbbabcc2796b702fa69dc40271e45cd5a56/prometheus_client-0.26.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/77/c1/6e422f34e569cf8e18df68d1939c81c099d2b61e4f7d9621c8a77560799c/pydantic_settings-2.14.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "python-json-logger", "version": "4.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/27/be/0631a861af4d1c875f096c07d34e9a63639560a717130e7a87cbc82b7e3f/python_json_logger-4.1.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "redis", "version": "8.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/0a/c2345ebf1ebe70840ce3f6c6ee612f8fa749cfbd1b03069c53bf0c62aaad/redis-8.0.1-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rich-rst", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/68/1fc93dd759605b5d00fc98b50200739e41ed32bd22d6ba35ca6c3932371b/rich_rst-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/36/e10c1d1b7ca881d2625db2ec28508578499187bb1c389952c398474e1834/sse_starlette-3.4.6-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typer", "version": "0.27.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/40/03/26a383c9e58c213199d1aad1c3d353cfc22d4444ec6d2c0bf8ad02523843/typer-0.27.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "uncalled-for", "version": "0.3.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3b/25/2c87754f3a9e692315f7b811244090e68f362979fc8886b3fbd2985a1d8c/uncalled_for-0.3.2-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/84/4c/82f132cb4418ee6d953d982b19191e87e2a6372c8a4ce36e50b69d6ade4a/cffi-2.1.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "dnspython", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f3/6b/686d9dc4359a8f163cfbbf89ee0b4e586431de22fe8248edb63a8cf50d49/rpds_py-2026.6.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "shellingham", "version": "1.5.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "jaraco.classes", "version": "3.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/66/b15ce62552d84bbfcec9a4873ab79d993a1dd4edb922cbfccae192bd5b5f/jaraco.classes-3.4.0-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.context", "version": "6.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f2/58/bc8954bda5fcda97bd7c19be11b85f91973d67a706ed4a3aec33e7de22db/jaraco_context-6.1.2-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.functools", "version": "4.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/02/36/ecc85bc96c273dc8a11273ed4782272975e6338d4a3e9228621175edf0e3/jaraco_functools-4.6.0-py3-none-any.whl"}}, {"metadata": {"name": "more-itertools", "version": "11.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/3d/1087453384dbde46a8c7f9356eead2c58be8a7bf156bca40243377c85715/more_itertools-11.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "9f62a1568e3800b7daf4b86289b6cb6a"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "google-genai", "version": "1.75.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2d/b6/552d40e96da22921eb1fead7c14b00b5b5473a20e45959488660fab35ee2/google_genai-1.75.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.55.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/1d/f6d3ca1ad0725f2e08a1c6915640748a52de2e66596160a4d53b010cccf0/google_auth-2.55.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/81/4fa520eaffa8bd7d1525e644cd6d39e7d60b1592bc5b516693c7340b50f1/pydantic_core-2.46.4-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/aa/82/39a5f910cb99ec0b59e482971238c845af9220d3ab9fa76dd9162cda9d62/websockets-16.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/3b/66777e39d3ae1ddc77ee606be4ec6d8cbd4c801f65e5a1b6f2b11b8346dd/charset_normalizer-3.4.7-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/22/adf66990e63584a68dfb50c24f48a125c07b1699899381c8151e63ed458c/cryptography-49.0.0-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/a0/7d793dce3fa811fe047d6ae2431c672364b462850c6235ae306c0efd025f/pyasn1-0.6.3-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "a021ecf98104048960d17180bcdfc8fa"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "langchain", "version": "1.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/85/86/cc13651cfda820d96ca8c612538166334935e8cf4331a31f5dd369d27760/langchain-1.4.2-py3-none-any.whl"}}, {"metadata": {"name": "langchain-core", "version": "1.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e6/18/cf18cfec118b02e003f35300b54d6a1173dc6e4905cffdf5ea49e390a7f9/langchain_core-1.6.3-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "jsonpatch", "version": "1.33"}, "download_info": {"url": "https://files.pythonhosted.org/packages/73/07/02e16ed01e04a374e644b575638ec7987ae846d25ad97bcc9945a3ee4b0e/jsonpatch-1.33-py2.py3-none-any.whl"}}, {"metadata": {"name": "langgraph", "version": "1.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0a/7f/c5c30e4be99ff821029c7ac872a480676bb179c9f3df85ea3f38d13f86d4/langgraph-1.2.11-py3-none-any.whl"}}, {"metadata": {"name": "langgraph-checkpoint", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/71/3b475f09bd57d3a5649792c66353312b4432afd843f301739dfcebd157f0/langgraph_checkpoint-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "langgraph-prebuilt", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/43/3fe1a700b8490ed02679cdbbc8c915eb23a092faf496c9c1118abcd10be3/langgraph_prebuilt-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "langgraph-sdk", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/43/d5/2ad7f3a835c6fcebf58b6669552536ecd52d2dfe4cf49c6c36648fd83572/langgraph_sdk-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "langsmith", "version": "0.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/51/892ff5a2efc8e222ca114dd0e19b56978f78a5ee62d3b33783588dd8e6d4/langsmith-0.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d3/f2/9e4de77a6271e07a76d2d58b11c091a979c191ed2939bf80067568b369d2/pydantic_core-2.46.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "uuid_utils", "version": "0.17.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/96/deded55ce54c5e6a2b7dbb790ab9bf7b5be8c7e8cb22e2355108bd8723cd/uuid_utils-0.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b5/c2/c676c69444d9db448b3f0a55a98dcc534affce0bce961d9d2f0b8499b10a/websockets-16.1.1-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "3.16.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/17/72/2b1fe3e303db76ab2ba0c2de2b57822869bcb588db82334d4ff3aea8acf2/openai-3.16.2-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/27/17/91420b156315ae22732f5ee1a7b5725a030aab9dc8fd7dcdacfb4aa588d3/jiter-0.17.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/62/cae690d9783146b0f81f564ada0f8f611de68178c0c9c7e1e969f0516b48/tiktoken-0.14.0-cp313-cp313-manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "langchain-openai", "version": "1.6.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b2/47/b87a3c372e52678eb4408360eadbe04cdd5371e21fe2560b6efd66989624/langchain_openai-1.6.2-py3-none-any.whl"}}, {"metadata": {"name": "langchain-community", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8f/39/5d97e42a3e95dc2a6d71b2f902a3fae71786131e11d01bddb604accb0ebe/langchain_community-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "langchain-classic", "version": "1.0.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/9a/b8f5cb7490fdbf233088031fc69c9c747439d4097f67f196c1eb4869916d/langchain_classic-1.0.8-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/1c/7da8d08e74d56f00070822f9638ff3f1c563f8ad87d1efa996c87bfc8644/aiohttp-3.14.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "langchain-text-splitters", "version": "1.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d3/26/1ef06f56198d631296d646a6223de35bcc6cf9795ceb2442816bc963b84c/langchain_text_splitters-1.1.2-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/fc/19deb0d051c694dbc2d5008ec89b341f7ee42c4412b38630a47a14339115/multidict-6.9.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/af/63240b0c0248c075c2535a1f1bd992821d8251b9f173abc13329661d09e4/charset_normalizer-3.5.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "SQLAlchemy", "version": "2.0.54"}, "download_info": {"url": "https://files.pythonhosted.org/packages/84/26/bd327a1a6be223e438c98ac8faf299307d83797225a81f3b209607a9fd98/sqlalchemy-2.0.54-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "urllib3", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.25.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0e/b7/a82a49bf88340b837ef6972b508a1604ae377b9e6904b46b10cf5f1cf925/yarl-1.25.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "google-genai", "version": "2.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/84/5b/87913fe392ba7b6402577259289ed3740c577956554a674b191a2971d33e/google_genai-2.24.0-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.58.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/59/13/477d90d09591b3938b45c4e11f4d8a51291682112cb5efcac961e815d562/google_auth-2.58.0-py3-none-any.whl"}}, {"metadata": {"name": "langchain-google-genai", "version": "4.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/10/83bb535e78c2cf767a6193c2f3b00b2894c1581a36ef85911ebaa3b9a891/langchain_google_genai-4.4.0-py3-none-any.whl"}}, {"metadata": {"name": "filetype", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/18/79/1b8fa1bb3568781e84c9200f951c735f3f157429f44be0495da55894d620/filetype-1.2.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/85/66/6ccca4722987ddedaa7fc9c3f4708af7431f5535666c174350830888c6b7/cryptography-50.0.1-cp311-abi3-manylinux_2_34_x86_64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/95/86342356ff5953b3fb06f7ef7c5bee212d45e770abc7218d451b9148313c/cffi-2.1.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d5/4e/e4691508f9477ce67da2015d8c00acd751e6287739123113a9fca6f1604e/frozenlist-1.8.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl"}}, {"metadata": {"name": "greenlet", "version": "3.5.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/85/cb/ab0c123c514ed4e94c0dc9ee2e86362633e6b998cfc05de7fc9ac2eb9690/greenlet-3.5.6-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonpointer", "version": "3.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/6a/a83720e953b1682d2d109d3c2dbb0bc9bf28cc1cbc205be4ef4be5da709d/jsonpointer-3.1.1-py3-none-any.whl"}}, {"metadata": {"name": "langchain-protocol", "version": "0.0.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/80/c9/f6cbf357d48ccbd18bb394433b1fd7ad9be004eed9377ad08bb85777e5e6/langchain_protocol-0.0.19-py3-none-any.whl"}}, {"metadata": {"name": "numpy", "version": "2.5.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3a/1b/3b16a9bc514a440a7a0883684111dcb1ef1aee960af2ca95da8fc775f124/numpy-2.5.3-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "orjson", "version": "3.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/74/89bb236deb9565f99434b13052bb40ddfcce4adf3afbfa3132ee7e421468/orjson-3.12.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "ormsgpack", "version": "1.12.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1c/a2/072343e1413d9443e5a252a8eb591c2d5b1bffbe5e7bfc78c069361b92eb/ormsgpack-1.12.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ed/74/08e6c1faf26ee2732023a3828787ba535557122774f4a386b1f715cbd8e0/propcache-0.5.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/3b/6163796d69c3977d1e4287bea4a6979161cbbdd170ebb430511e8e1999ce/pyasn1-0.6.4-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "xxhash", "version": "4.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6f/fb/76580c08e916507859b0f335393cb5fdc59452c4402edbc6bcca6e47e7df/xxhash-4.0.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "zstandard", "version": "0.25.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/4b/e3678b4e776db00f9f7b2fe58e547e8928ef32727d7a1ff01dea010f3f13/zstandard-0.25.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.9.10"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/3b/000c79c3f9c06b7542225a5d3a7f9a85405da7224b3b9af94a491d07abea/regex-2026.9.10-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}], "install_targets_hash": "a282ef4988626dc6ebb6ab9deadd8e4b"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "google-genai", "version": "1.29.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/33/9b22b0b3734f93655d0d28cfcd64496ef46dd68efe8ae19278f3b1297998/google_genai-1.29.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.55.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/1d/f6d3ca1ad0725f2e08a1c6915640748a52de2e66596160a4d53b010cccf0/google_auth-2.55.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/81/4fa520eaffa8bd7d1525e644cd6d39e7d60b1592bc5b516693c7340b50f1/pydantic_core-2.46.4-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "15.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ff/0b/33cef55ff24f2d92924923c99926dcce78e7bd922d649467f0eda8368923/websockets-15.0.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/3b/66777e39d3ae1ddc77ee606be4ec6d8cbd4c801f65e5a1b6f2b11b8346dd/charset_normalizer-3.4.7-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/22/adf66990e63584a68dfb50c24f48a125c07b1699899381c8151e63ed458c/cryptography-49.0.0-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/a0/7d793dce3fa811fe047d6ae2431c672364b462850c6235ae306c0efd025f/pyasn1-0.6.3-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "a43cdff61ea105e2cfc9e159c1a78f1a"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "typer", "version": "0.15.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c9/62/d4ba7afe2096d5659ec3db8b15d8665bdcb92a3c6ff0b95e99895b335a9c/typer-0.15.4-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "shellingham", "version": "1.5.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}], "install_targets_hash": "a84f9aca2b9546e22b929cce508b9110"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "typer", "version": "0.15.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c9/62/d4ba7afe2096d5659ec3db8b15d8665bdcb92a3c6ff0b95e99895b335a9c/typer-0.15.4-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "shellingham", "version": "1.5.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}], "install_targets_hash": "a84f9aca2b9546e22b929cce508b9110"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "typer", "version": "0.15.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c9/62/d4ba7afe2096d5659ec3db8b15d8665bdcb92a3c6ff0b95e99895b335a9c/typer-0.15.4-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "shellingham", "version": "1.5.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}], "install_targets_hash": "a84f9aca2b9546e22b929cce508b9110"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "typer", "version": "0.15.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c9/62/d4ba7afe2096d5659ec3db8b15d8665bdcb92a3c6ff0b95e99895b335a9c/typer-0.15.4-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "shellingham", "version": "1.5.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}], "install_targets_hash": "a84f9aca2b9546e22b929cce508b9110"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "cohere", "version": "7.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/4a/c3/064a44c498bf6ae8621caa14307d3ef5471157f149e33cfd64417c8e9ad3/cohere-7.1.1-py3-none-any.whl"}}, {"metadata": {"name": "fastavro", "version": "1.12.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/83/39/f489a441d41cc9c0a8449fb1325d7a9c9eb57a5634e6ab19dfb0a1105324/fastavro-1.12.2-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a4/a0/562247944386f7d4ef94467e84876600cc1e0f1b93239aaa9213d2bc3cbd/charset_normalizer-3.5.1-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "tokenizers", "version": "0.23.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e2/6a/068ed9f6e444c9d7e9d55ce134181325700f3d7f30410721bdc8f848d727/tokenizers-0.23.1-cp310-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "huggingface_hub", "version": "1.29.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/4e/a5/47c2ea9b228ccbcba8467e9a64823146e8ebbad29855e591d8f5eedcc9c7/huggingface_hub-1.29.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/4b/69/55b8dcf636142ae660fec1869fcac14c4da2e8412e14d6eee1523be77e9f/hf_xet-1.6.0-cp38-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "types-requests", "version": "2.33.0.20260712"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/62/e7/010c87f559e216d83f9dc51e939633fd0d0ead3377340181ab0e223cd3b5/types_requests-2.33.0.20260712-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "filelock", "version": "3.32.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/36/d2/b70a31e13d04456d28493f31d2aa087e99eeb2767ef0293b2625727ccb8c/filelock-3.32.5-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.7.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/fd/3c/6a2bf344106328fd04963664a60b9bb6496fc25df8e962fcdc1367285fb9/fsspec-2026.7.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/21/43/6323b1f8b217780454c61304bcd2b38ae4762f50754414124603ccc90bb2/pydantic_core-2.46.5-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}], "install_targets_hash": "ab733f16537c82282cb23e3e0416c9fc"} -{"python_version": "3.13", "dependencies": [{"metadata": {"name": "openai", "version": "3.16.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/17/72/2b1fe3e303db76ab2ba0c2de2b57822869bcb588db82334d4ff3aea8acf2/openai-3.16.2-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/27/17/91420b156315ae22732f5ee1a7b5725a030aab9dc8fd7dcdacfb4aa588d3/jiter-0.17.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d3/f2/9e4de77a6271e07a76d2d58b11c091a979c191ed2939bf80067568b369d2/pydantic_core-2.46.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/62/cae690d9783146b0f81f564ada0f8f611de68178c0c9c7e1e969f0516b48/tiktoken-0.14.0-cp313-cp313-manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.9.10"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/3b/000c79c3f9c06b7542225a5d3a7f9a85405da7224b3b9af94a491d07abea/regex-2026.9.10-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/af/63240b0c0248c075c2535a1f1bd992821d8251b9f173abc13329661d09e4/charset_normalizer-3.5.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "urllib3", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "ac0b70b42bbda50724e182bcf918e944"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "tornado", "version": "6.5.10"}, "download_info": {"url": "https://files.pythonhosted.org/packages/60/33/df6d7d04854a58619f8349a51e3edb138324130a7562b0bb21f115bb940f/tornado-6.5.10-cp39-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}], "install_targets_hash": "b29e9ff3837ebc143e8b2f14e7600a10"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "apache-beam", "version": "2.77.0rc1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a5/0c/ad2fadfb4faa67862b7a3b561c3a2845a8078fbef02cccd92739bf76dfb8/apache_beam-2.77.0rc1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "betterproto", "version": "2.0.0b6"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/99/6d/007abe4bf14cd02a3c07710c22f0e3252b55b06678de2535ae5f03b7433a/betterproto-2.0.0b6-py3-none-any.whl"}}, {"metadata": {"name": "beartype", "version": "0.22.9"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/cc/18245721fa7747065ab478316c7fea7c74777d07f37ae60db2e84f8172e8/beartype-0.22.9-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ba/19/797e2aaac9df6a66f1550f49979dc1b1e39ecd2077501c30efa81e8d5d67/cryptography-50.0.1-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "fastavro", "version": "1.12.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/83/39/f489a441d41cc9c0a8449fb1325d7a9c9eb57a5634e6ab19dfb0a1105324/fastavro-1.12.2-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "fasteners", "version": "0.20"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/51/ac/e5d886f892666d2d1e5cb8c1a41146e1d79ae8896477b1153a21711d3b44/fasteners-0.20-py3-none-any.whl"}}, {"metadata": {"name": "grpcio", "version": "1.84.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c5/4b/ed8e22a1237e6b2be6ef4f221d074a5b0e0dd8a0da8c944c04aea731f0eb/grpcio-1.84.0-cp313-cp313-macosx_11_0_universal2.whl"}}, {"metadata": {"name": "grpclib", "version": "0.4.9"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/5c/90/b0cbbd9efcc82816c58f31a34963071aa19fb792a212a5d9caf8e0fc3097/grpclib-0.4.9-py3-none-any.whl"}}, {"metadata": {"name": "h2", "version": "4.4.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/22/e85faf23bd72a92d1921e37d674ca56eb298a3c8be31fdecef0ff2b3aaac/h2-4.4.1-py3-none-any.whl"}}, {"metadata": {"name": "hpack", "version": "4.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/b4/4a9fcfb2aef6ba44d9073ecd301443aa00b3dac95de5619f2a7de7ec8a91/hpack-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "httplib2", "version": "0.32.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/33/a0/550eec327e5f5c7b732531c489f5307efec41f047b0d703bd4ca1e5ad2db/httplib2-0.32.0-py3-none-any.whl"}}, {"metadata": {"name": "hyperframe", "version": "6.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/48/30/47d0bf6072f7252e6521f3447ccfa40b421b6824517f82854703d0f5a98b/hyperframe-6.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonpickle", "version": "4.1.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a1/7b/fd3c7a09649aea9da1d3587aea624d8f9b29963dfd84a1bdb2aa93b36dac/jsonpickle-4.1.2-py3-none-any.whl"}}, {"metadata": {"name": "numpy", "version": "2.4.6"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/97/12/70b5d0d7c15e1ebb8a6a84a8caa1d19e181d84fb58bb6d70aca29099dec1/numpy-2.4.6-cp313-cp313-macosx_14_0_arm64.whl"}}, {"metadata": {"name": "objsize", "version": "0.7.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/f3/a7/55f8f3853a4a654d3a6fbf63e646e0b469b52c174703a10db70a1cb06c7e/objsize-0.7.1-py3-none-any.whl"}}, {"metadata": {"name": "pillow", "version": "12.3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/10/76/8803c13605b763d33d156c4678fc77f8443389c0c51c8aef707bb02015f4/pillow-12.3.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "proto-plus", "version": "1.28.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/41/5d/0f04b85dafdc3250ced7f2592efc17dce7f40712e941e9632202481e600d/proto_plus-1.28.4-py3-none-any.whl"}}, {"metadata": {"name": "protobuf", "version": "6.33.6"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/5c/01/a3c3ed5cd186f39e7880f8303cc51385a198a81469d53d0fdecf1f64d929/protobuf-6.33.6-cp39-abi3-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "pyarrow", "version": "25.0.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cc/8d/8f271a7a034c834910ec925d56fa4b29733b1380f5289419f5aaa3b02777/pyarrow-25.0.1-cp313-cp313-macosx_12_0_arm64.whl"}}, {"metadata": {"name": "pymongo", "version": "4.18.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/11/ee/852cb3c707e6cc53d84e656b4c4f534afa96f0058d88470f49a33770c790/pymongo-4.18.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "dnspython", "version": "2.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "pyparsing", "version": "3.3.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/38/bb/d215ee7c73b61497b28a5503f9f53523f294fcc936762b7caf90e0c1c2b5/pyparsing-3.3.3-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a4/a0/562247944386f7d4ef94467e84876600cc1e0f1b93239aaa9213d2bc3cbd/charset_normalizer-3.5.1-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "zstandard", "version": "0.25.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/3f/06/9ae96a3e5dcfd119377ba33d4c42a7d89da1efabd5cb3e366b156c45ff4d/zstandard-0.25.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "dill", "version": "0.4.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/1e/77/dc8c558f7593132cf8fefec57c4f60c83b16941c574ac5f619abb3ae7933/dill-0.4.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/55/41/4c7042f317b9217502988f0873af87e16ad606dc20f84e546e3e6ce9764c/cffi-2.1.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pytz", "version": "2026.3.post1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0f/7b/39c34ca613b0b198cb866466651b26b045e2009864c5183c979a3b83f383/pytz-2026.3.post1-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.9.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/46/46/9b4c1127cece0289fb207d04aae5116382ddfcb2a4dc8e0cb49a33f3c7b3/multidict-6.9.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "b3a715bfab67760cac2023319d4ff7fc"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "litellm", "version": "1.77.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/86/50/53df2244d4aca2af73d2f2c6ad21c731cf24bd0dbe89d896184a1eaa874f/litellm-1.77.7-py3-none-any.whl"}}, {"metadata": {"name": "anthropic", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/5b/db4a854aebf5d33a5ab714c46af6eb85ee44f390ed29b7b325c00b9f11ed/anthropic-1.0.0-py3-none-any.whl"}}, {"metadata": {"name": "google-genai", "version": "2.19.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/e8/de0accd8cd004cf11252ca53fc5c3dda59bcf1856abfc7609842ceba7363/google_genai-2.19.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/6b/e7f13410d391c6e55b4c007a8de024355389d7d459e3d64c42b2d33617e5/aiohttp-3.14.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "fastuuid", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/6d/64aee0a0f6a58eeabadd582e55d0d7d70258ffdd01d093b30c53d668303b/fastuuid-0.14.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "google-auth", "version": "2.56.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/b3/6117b2f24065cd7e2c4f140e9a193e215f089ca8ba314cf91eb9d0b7fe0a/google_auth-2.56.3-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/95/411ba65569158e862368917aaf56597f3e5fa3b91b0502919638465a08f3/httpx2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/74/d370e55600d9bcfa0d9794b0166126d49291a3d2b20c268fc98c453a4948/httpcore2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "9.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/38/3d/2d244233ac4f76e38533cfcb2991c9eb4c7bf688ae0a036d30725b8faafe/importlib_metadata-9.0.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d0/2b/c3eaf16f5d7c9bad66ea32f40a95bd169b29a91217fcc7f081375157e99c/jiter-0.16.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "3.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6a/db/2b7a1b3de659bb82aef979116c74e809982b13e42c057759767552b5155f/openai-3.3.1-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/81/4fa520eaffa8bd7d1525e644cd6d39e7d60b1592bc5b516693c7340b50f1/pydantic_core-2.46.4-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/5f/6448cfe278c3664ba9ec5b5ac08344341f7dc3d42888476e215a14eda2be/tiktoken-0.14.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/86/0a70d3ae2f0f2256bb41302d9804dbca65d4360281e7feb3e1f94102ac46/websockets-16.1.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "tokenizers", "version": "0.23.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e2/6a/068ed9f6e444c9d7e9d55ce134181325700f3d7f30410721bdc8f848d727/tokenizers-0.23.1-cp310-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a4/a0/562247944386f7d4ef94467e84876600cc1e0f1b93239aaa9213d2bc3cbd/charset_normalizer-3.5.1-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/5c/59086b4aac5e879d38ddbcf74e4be7ade89cebc3eb199a55da998c3bb46a/cryptography-50.0.0-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/ab/6e5080ee374f875296c4243c381bbdef97a9ac39c6e3ce1d5f7d42cb78d6/frozenlist-1.8.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "huggingface_hub", "version": "1.28.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/0e/eafef18f1a75e125e68395db21131db0cf868a128ecd2fce69b4df6c584b/huggingface_hub-1.28.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/76/55cd7186f498ed080a18440c9013011eb548f77ae1b297206d030eb1180a/multidict-6.7.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/12/a6ba6482bb5ea3260c000c9b20881c95fa11c6b30173715668259f844ed7/propcache-0.5.2-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f3/6b/686d9dc4359a8f163cfbbf89ee0b4e586431de22fe8248edb63a8cf50d49/rpds_py-2026.6.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/15/f0/7688d3f2cfff7590df2af38ec46d969f4281a4dddb08a9ad2eafbcdddf98/yarl-1.24.5-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "zipp", "version": "4.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.7.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/47/2d0564e93d87bc48618360ddca232a2ca612bbdf53ce8465d45ca5ce14ee/regex-2026.7.19-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/41/4c7042f317b9217502988f0873af87e16ad606dc20f84e546e3e6ce9764c/cffi-2.1.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "filelock", "version": "3.32.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/a4/9b63d595d748e3aff8812b65eacc1a2c4bd90b7c2012e08e72373b4835eb/filelock-3.32.4-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/3c/6a2bf344106328fd04963664a60b9bb6496fc25df8e962fcdc1367285fb9/fsspec-2026.7.0-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/69/55b8dcf636142ae660fec1869fcac14c4da2e8412e14d6eee1523be77e9f/hf_xet-1.6.0-cp38-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/3b/6163796d69c3977d1e4287bea4a6979161cbbdd170ebb430511e8e1999ce/pyasn1-0.6.4-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "b512ff6d7a8009ab10bb0b7c9175af2f"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "litellm", "version": "1.77.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/86/50/53df2244d4aca2af73d2f2c6ad21c731cf24bd0dbe89d896184a1eaa874f/litellm-1.77.7-py3-none-any.whl"}}, {"metadata": {"name": "anthropic", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/5b/db4a854aebf5d33a5ab714c46af6eb85ee44f390ed29b7b325c00b9f11ed/anthropic-1.0.0-py3-none-any.whl"}}, {"metadata": {"name": "google-genai", "version": "2.19.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/e8/de0accd8cd004cf11252ca53fc5c3dda59bcf1856abfc7609842ceba7363/google_genai-2.19.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/6b/e7f13410d391c6e55b4c007a8de024355389d7d459e3d64c42b2d33617e5/aiohttp-3.14.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "fastuuid", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/6d/64aee0a0f6a58eeabadd582e55d0d7d70258ffdd01d093b30c53d668303b/fastuuid-0.14.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "google-auth", "version": "2.56.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/b3/6117b2f24065cd7e2c4f140e9a193e215f089ca8ba314cf91eb9d0b7fe0a/google_auth-2.56.3-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/95/411ba65569158e862368917aaf56597f3e5fa3b91b0502919638465a08f3/httpx2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/74/d370e55600d9bcfa0d9794b0166126d49291a3d2b20c268fc98c453a4948/httpcore2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "9.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/38/3d/2d244233ac4f76e38533cfcb2991c9eb4c7bf688ae0a036d30725b8faafe/importlib_metadata-9.0.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d0/2b/c3eaf16f5d7c9bad66ea32f40a95bd169b29a91217fcc7f081375157e99c/jiter-0.16.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "3.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6a/db/2b7a1b3de659bb82aef979116c74e809982b13e42c057759767552b5155f/openai-3.3.1-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/81/4fa520eaffa8bd7d1525e644cd6d39e7d60b1592bc5b516693c7340b50f1/pydantic_core-2.46.4-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/5f/6448cfe278c3664ba9ec5b5ac08344341f7dc3d42888476e215a14eda2be/tiktoken-0.14.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/86/0a70d3ae2f0f2256bb41302d9804dbca65d4360281e7feb3e1f94102ac46/websockets-16.1.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "tokenizers", "version": "0.23.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e2/6a/068ed9f6e444c9d7e9d55ce134181325700f3d7f30410721bdc8f848d727/tokenizers-0.23.1-cp310-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a4/a0/562247944386f7d4ef94467e84876600cc1e0f1b93239aaa9213d2bc3cbd/charset_normalizer-3.5.1-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/5c/59086b4aac5e879d38ddbcf74e4be7ade89cebc3eb199a55da998c3bb46a/cryptography-50.0.0-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/ab/6e5080ee374f875296c4243c381bbdef97a9ac39c6e3ce1d5f7d42cb78d6/frozenlist-1.8.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "huggingface_hub", "version": "1.28.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/0e/eafef18f1a75e125e68395db21131db0cf868a128ecd2fce69b4df6c584b/huggingface_hub-1.28.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/76/55cd7186f498ed080a18440c9013011eb548f77ae1b297206d030eb1180a/multidict-6.7.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/12/a6ba6482bb5ea3260c000c9b20881c95fa11c6b30173715668259f844ed7/propcache-0.5.2-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f3/6b/686d9dc4359a8f163cfbbf89ee0b4e586431de22fe8248edb63a8cf50d49/rpds_py-2026.6.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/15/f0/7688d3f2cfff7590df2af38ec46d969f4281a4dddb08a9ad2eafbcdddf98/yarl-1.24.5-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "zipp", "version": "4.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.7.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/47/2d0564e93d87bc48618360ddca232a2ca612bbdf53ce8465d45ca5ce14ee/regex-2026.7.19-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/41/4c7042f317b9217502988f0873af87e16ad606dc20f84e546e3e6ce9764c/cffi-2.1.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "filelock", "version": "3.32.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/a4/9b63d595d748e3aff8812b65eacc1a2c4bd90b7c2012e08e72373b4835eb/filelock-3.32.4-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/3c/6a2bf344106328fd04963664a60b9bb6496fc25df8e962fcdc1367285fb9/fsspec-2026.7.0-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/69/55b8dcf636142ae660fec1869fcac14c4da2e8412e14d6eee1523be77e9f/hf_xet-1.6.0-cp38-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/3b/6163796d69c3977d1e4287bea4a6979161cbbdd170ebb430511e8e1999ce/pyasn1-0.6.4-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "b512ff6d7a8009ab10bb0b7c9175af2f"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/6b/e7f13410d391c6e55b4c007a8de024355389d7d459e3d64c42b2d33617e5/aiohttp-3.14.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/76/55cd7186f498ed080a18440c9013011eb548f77ae1b297206d030eb1180a/multidict-6.7.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/15/f0/7688d3f2cfff7590df2af38ec46d969f4281a4dddb08a9ad2eafbcdddf98/yarl-1.24.5-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-aiohttp", "version": "1.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fa/b0/5056ed4c3f68a4db2b4a39fb0ec61b1e4cf1d89ee14effe5261cc587264c/pytest_aiohttp-1.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/ab/6e5080ee374f875296c4243c381bbdef97a9ac39c6e3ce1d5f7d42cb78d6/frozenlist-1.8.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/12/a6ba6482bb5ea3260c000c9b20881c95fa11c6b30173715668259f844ed7/propcache-0.5.2-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "b580cd1bfd98254876a1e968bf8d9af2"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/6b/e7f13410d391c6e55b4c007a8de024355389d7d459e3d64c42b2d33617e5/aiohttp-3.14.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-aiohttp", "version": "1.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fa/b0/5056ed4c3f68a4db2b4a39fb0ec61b1e4cf1d89ee14effe5261cc587264c/pytest_aiohttp-1.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/ab/6e5080ee374f875296c4243c381bbdef97a9ac39c6e3ce1d5f7d42cb78d6/frozenlist-1.8.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/76/55cd7186f498ed080a18440c9013011eb548f77ae1b297206d030eb1180a/multidict-6.7.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/12/a6ba6482bb5ea3260c000c9b20881c95fa11c6b30173715668259f844ed7/propcache-0.5.2-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/15/f0/7688d3f2cfff7590df2af38ec46d969f4281a4dddb08a9ad2eafbcdddf98/yarl-1.24.5-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "b580cd1bfd98254876a1e968bf8d9af2"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/6b/e7f13410d391c6e55b4c007a8de024355389d7d459e3d64c42b2d33617e5/aiohttp-3.14.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-aiohttp", "version": "1.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fa/b0/5056ed4c3f68a4db2b4a39fb0ec61b1e4cf1d89ee14effe5261cc587264c/pytest_aiohttp-1.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/ab/6e5080ee374f875296c4243c381bbdef97a9ac39c6e3ce1d5f7d42cb78d6/frozenlist-1.8.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/76/55cd7186f498ed080a18440c9013011eb548f77ae1b297206d030eb1180a/multidict-6.7.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/12/a6ba6482bb5ea3260c000c9b20881c95fa11c6b30173715668259f844ed7/propcache-0.5.2-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/15/f0/7688d3f2cfff7590df2af38ec46d969f4281a4dddb08a9ad2eafbcdddf98/yarl-1.24.5-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "b580cd1bfd98254876a1e968bf8d9af2"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "sanic", "version": "25.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/91/5ecd9a91374a7b2831cf183357ceeb609fdfc8b390adb5cac90a261fe1f8/sanic-25.12.1-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/85/dc/549a807a53c13fd4a8dac286f117a7a71260defea9ec0c05d6027f2ae273/websockets-10.4.tar.gz"}}, {"metadata": {"name": "aiohttp", "version": "3.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ab/01/a2d5f96cd4e74424864d30bc0a7e44d0a12dacdcfa91b5b2d1bd3dca6bf3/aiohttp-3.14.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-testing", "version": "24.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/93/1d588f1cb9b710b9f22fa78b53d699a8062edc94204d50dd0d78c5f5b495/sanic_testing-24.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/ab/6e5080ee374f875296c4243c381bbdef97a9ac39c6e3ce1d5f7d42cb78d6/frozenlist-1.8.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "html5tagger", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/12/2f5d43ee912ea14a6baba4b3db6d309b02d932e3b7074c3339b4aded98ff/html5tagger-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "httptools", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/0e/0fb14848c19a686c8062ff9067c1a48793e3224b47bc5b201535b6036fce/httptools-0.8.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/76/55cd7186f498ed080a18440c9013011eb548f77ae1b297206d030eb1180a/multidict-6.7.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/12/a6ba6482bb5ea3260c000c9b20881c95fa11c6b30173715668259f844ed7/propcache-0.5.2-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-routing", "version": "23.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/e3/3425c9a8773807ac2c01d6a56c8521733f09b627e5827e733c5cd36b9ac5/sanic_routing-23.12.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "83.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/40/e1e72872c6354b306daef1703549e8e83b4d43cfea356311bf722a043752/setuptools-83.0.0-py3-none-any.whl"}}, {"metadata": {"name": "tracerite", "version": "2.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b6/62/3f385a67ff3cc91209f107d20bbebdecf7a4e4aba55a43f9f71bddc424a9/tracerite-2.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "5.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6a/c0/c7ab82d6471dfa7e4fd68ae6ff2c6a50d077c05d6ecdea0cec8af635b2c4/ujson-5.13.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "uvloop", "version": "0.22.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/8c/182a2a593195bfd39842ea68ebc084e20c850806117213f5a299dfc513d9/uvloop-0.22.1-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/24/16748d5dab6daec8b0ed81ccec639a1cded0f18dcc62a4f696b4fe366c37/yarl-1.24.2-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}], "install_targets_hash": "bdb1f2a8b2b051b4d694fd87001bee9b"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "sanic", "version": "25.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/91/5ecd9a91374a7b2831cf183357ceeb609fdfc8b390adb5cac90a261fe1f8/sanic-25.12.1-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/85/dc/549a807a53c13fd4a8dac286f117a7a71260defea9ec0c05d6027f2ae273/websockets-10.4.tar.gz"}}, {"metadata": {"name": "aiohttp", "version": "3.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ab/01/a2d5f96cd4e74424864d30bc0a7e44d0a12dacdcfa91b5b2d1bd3dca6bf3/aiohttp-3.14.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-testing", "version": "24.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/93/1d588f1cb9b710b9f22fa78b53d699a8062edc94204d50dd0d78c5f5b495/sanic_testing-24.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/ab/6e5080ee374f875296c4243c381bbdef97a9ac39c6e3ce1d5f7d42cb78d6/frozenlist-1.8.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "html5tagger", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/12/2f5d43ee912ea14a6baba4b3db6d309b02d932e3b7074c3339b4aded98ff/html5tagger-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "httptools", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/0e/0fb14848c19a686c8062ff9067c1a48793e3224b47bc5b201535b6036fce/httptools-0.8.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/76/55cd7186f498ed080a18440c9013011eb548f77ae1b297206d030eb1180a/multidict-6.7.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/12/a6ba6482bb5ea3260c000c9b20881c95fa11c6b30173715668259f844ed7/propcache-0.5.2-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-routing", "version": "23.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/e3/3425c9a8773807ac2c01d6a56c8521733f09b627e5827e733c5cd36b9ac5/sanic_routing-23.12.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "83.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/40/e1e72872c6354b306daef1703549e8e83b4d43cfea356311bf722a043752/setuptools-83.0.0-py3-none-any.whl"}}, {"metadata": {"name": "tracerite", "version": "2.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b6/62/3f385a67ff3cc91209f107d20bbebdecf7a4e4aba55a43f9f71bddc424a9/tracerite-2.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "5.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6a/c0/c7ab82d6471dfa7e4fd68ae6ff2c6a50d077c05d6ecdea0cec8af635b2c4/ujson-5.13.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "uvloop", "version": "0.22.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/8c/182a2a593195bfd39842ea68ebc084e20c850806117213f5a299dfc513d9/uvloop-0.22.1-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/24/16748d5dab6daec8b0ed81ccec639a1cded0f18dcc62a4f696b4fe366c37/yarl-1.24.2-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}], "install_targets_hash": "bdb1f2a8b2b051b4d694fd87001bee9b"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "sanic", "version": "25.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/91/5ecd9a91374a7b2831cf183357ceeb609fdfc8b390adb5cac90a261fe1f8/sanic-25.12.1-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/85/dc/549a807a53c13fd4a8dac286f117a7a71260defea9ec0c05d6027f2ae273/websockets-10.4.tar.gz"}}, {"metadata": {"name": "aiohttp", "version": "3.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ab/01/a2d5f96cd4e74424864d30bc0a7e44d0a12dacdcfa91b5b2d1bd3dca6bf3/aiohttp-3.14.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-testing", "version": "24.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/93/1d588f1cb9b710b9f22fa78b53d699a8062edc94204d50dd0d78c5f5b495/sanic_testing-24.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/ab/6e5080ee374f875296c4243c381bbdef97a9ac39c6e3ce1d5f7d42cb78d6/frozenlist-1.8.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "html5tagger", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/12/2f5d43ee912ea14a6baba4b3db6d309b02d932e3b7074c3339b4aded98ff/html5tagger-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "httptools", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/0e/0fb14848c19a686c8062ff9067c1a48793e3224b47bc5b201535b6036fce/httptools-0.8.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/76/55cd7186f498ed080a18440c9013011eb548f77ae1b297206d030eb1180a/multidict-6.7.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/12/a6ba6482bb5ea3260c000c9b20881c95fa11c6b30173715668259f844ed7/propcache-0.5.2-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-routing", "version": "23.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/e3/3425c9a8773807ac2c01d6a56c8521733f09b627e5827e733c5cd36b9ac5/sanic_routing-23.12.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "83.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/40/e1e72872c6354b306daef1703549e8e83b4d43cfea356311bf722a043752/setuptools-83.0.0-py3-none-any.whl"}}, {"metadata": {"name": "tracerite", "version": "2.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b6/62/3f385a67ff3cc91209f107d20bbebdecf7a4e4aba55a43f9f71bddc424a9/tracerite-2.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "5.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6a/c0/c7ab82d6471dfa7e4fd68ae6ff2c6a50d077c05d6ecdea0cec8af635b2c4/ujson-5.13.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "uvloop", "version": "0.22.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/8c/182a2a593195bfd39842ea68ebc084e20c850806117213f5a299dfc513d9/uvloop-0.22.1-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/24/16748d5dab6daec8b0ed81ccec639a1cded0f18dcc62a4f696b4fe366c37/yarl-1.24.2-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}], "install_targets_hash": "bdb1f2a8b2b051b4d694fd87001bee9b"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "UnleashClient", "version": "6.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bb/50/af45e97a42056036c4ca7f27ffebcaa01051bd4e9cb07bf4bd40370db316/UnleashClient-6.0.1-py3-none-any.whl"}}, {"metadata": {"name": "APScheduler", "version": "3.11.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/42/c9/8638db32514dbb9157b3d82680c6faea89283523edf9ed2415ea3884f2ae/apscheduler-3.11.3-py3-none-any.whl"}}, {"metadata": {"name": "semver", "version": "3.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/24/4d91e05817e92e3a61c8a21e08fd0f390f5301f1c448b137c57c4bc6e543/semver-3.0.4-py3-none-any.whl"}}, {"metadata": {"name": "fcache", "version": "0.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/84/0c/ababd9fed96d865463f95f897c48a8781bc831f9e08cdc8124b96964f92c/fcache-0.6.0-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "9.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/38/3d/2d244233ac4f76e38533cfcb2991c9eb4c7bf688ae0a036d30725b8faafe/importlib_metadata-9.0.0-py3-none-any.whl"}}, {"metadata": {"name": "mmh3", "version": "5.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d4/4c/8e3af1b6d85a299767ec97bd923f12b06267089c1472c27c1696870d1175/mmh3-5.2.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "yggdrasil-engine", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/7f/38b0c1ecb2146362b8f5760e9bf9bad2e56b97ba5515f28796f20dc82821/yggdrasil_engine-1.3.1-cp313-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/3b/66777e39d3ae1ddc77ee606be4ec6d8cbd4c801f65e5a1b6f2b11b8346dd/charset_normalizer-3.4.7-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "platformdirs", "version": "3.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/29/3ec311dc18804409ecf0d2b09caa976f3ae6215559306b5b530004e11156/platformdirs-3.11.0-py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tzlocal", "version": "5.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/a4/017a7a6cbe387d961a688ec31364ae60a5c4e22c96ae9921b79a947c855d/tzlocal-5.4.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "zipp", "version": "4.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl"}}], "install_targets_hash": "c2145685d6e6c9355d7ce6f85ea7980a"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "UnleashClient", "version": "6.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bb/50/af45e97a42056036c4ca7f27ffebcaa01051bd4e9cb07bf4bd40370db316/UnleashClient-6.0.1-py3-none-any.whl"}}, {"metadata": {"name": "APScheduler", "version": "3.11.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/42/c9/8638db32514dbb9157b3d82680c6faea89283523edf9ed2415ea3884f2ae/apscheduler-3.11.3-py3-none-any.whl"}}, {"metadata": {"name": "semver", "version": "3.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/24/4d91e05817e92e3a61c8a21e08fd0f390f5301f1c448b137c57c4bc6e543/semver-3.0.4-py3-none-any.whl"}}, {"metadata": {"name": "fcache", "version": "0.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/84/0c/ababd9fed96d865463f95f897c48a8781bc831f9e08cdc8124b96964f92c/fcache-0.6.0-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "9.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/38/3d/2d244233ac4f76e38533cfcb2991c9eb4c7bf688ae0a036d30725b8faafe/importlib_metadata-9.0.0-py3-none-any.whl"}}, {"metadata": {"name": "mmh3", "version": "5.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d4/4c/8e3af1b6d85a299767ec97bd923f12b06267089c1472c27c1696870d1175/mmh3-5.2.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "yggdrasil-engine", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/7f/38b0c1ecb2146362b8f5760e9bf9bad2e56b97ba5515f28796f20dc82821/yggdrasil_engine-1.3.1-cp313-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/3b/66777e39d3ae1ddc77ee606be4ec6d8cbd4c801f65e5a1b6f2b11b8346dd/charset_normalizer-3.4.7-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "platformdirs", "version": "3.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/29/3ec311dc18804409ecf0d2b09caa976f3ae6215559306b5b530004e11156/platformdirs-3.11.0-py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tzlocal", "version": "5.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/a4/017a7a6cbe387d961a688ec31364ae60a5c4e22c96ae9921b79a947c855d/tzlocal-5.4.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "zipp", "version": "4.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl"}}], "install_targets_hash": "c2145685d6e6c9355d7ce6f85ea7980a"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "UnleashClient", "version": "6.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bb/50/af45e97a42056036c4ca7f27ffebcaa01051bd4e9cb07bf4bd40370db316/UnleashClient-6.0.1-py3-none-any.whl"}}, {"metadata": {"name": "APScheduler", "version": "3.11.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/42/c9/8638db32514dbb9157b3d82680c6faea89283523edf9ed2415ea3884f2ae/apscheduler-3.11.3-py3-none-any.whl"}}, {"metadata": {"name": "semver", "version": "3.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/24/4d91e05817e92e3a61c8a21e08fd0f390f5301f1c448b137c57c4bc6e543/semver-3.0.4-py3-none-any.whl"}}, {"metadata": {"name": "fcache", "version": "0.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/84/0c/ababd9fed96d865463f95f897c48a8781bc831f9e08cdc8124b96964f92c/fcache-0.6.0-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "9.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/38/3d/2d244233ac4f76e38533cfcb2991c9eb4c7bf688ae0a036d30725b8faafe/importlib_metadata-9.0.0-py3-none-any.whl"}}, {"metadata": {"name": "mmh3", "version": "5.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d4/4c/8e3af1b6d85a299767ec97bd923f12b06267089c1472c27c1696870d1175/mmh3-5.2.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "yggdrasil-engine", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/7f/38b0c1ecb2146362b8f5760e9bf9bad2e56b97ba5515f28796f20dc82821/yggdrasil_engine-1.3.1-cp313-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/3b/66777e39d3ae1ddc77ee606be4ec6d8cbd4c801f65e5a1b6f2b11b8346dd/charset_normalizer-3.4.7-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "platformdirs", "version": "3.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/29/3ec311dc18804409ecf0d2b09caa976f3ae6215559306b5b530004e11156/platformdirs-3.11.0-py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tzlocal", "version": "5.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/a4/017a7a6cbe387d961a688ec31364ae60a5c4e22c96ae9921b79a947c855d/tzlocal-5.4.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "zipp", "version": "4.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl"}}], "install_targets_hash": "c2145685d6e6c9355d7ce6f85ea7980a"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "UnleashClient", "version": "6.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bb/50/af45e97a42056036c4ca7f27ffebcaa01051bd4e9cb07bf4bd40370db316/UnleashClient-6.0.1-py3-none-any.whl"}}, {"metadata": {"name": "APScheduler", "version": "3.11.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/42/c9/8638db32514dbb9157b3d82680c6faea89283523edf9ed2415ea3884f2ae/apscheduler-3.11.3-py3-none-any.whl"}}, {"metadata": {"name": "semver", "version": "3.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/24/4d91e05817e92e3a61c8a21e08fd0f390f5301f1c448b137c57c4bc6e543/semver-3.0.4-py3-none-any.whl"}}, {"metadata": {"name": "fcache", "version": "0.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/84/0c/ababd9fed96d865463f95f897c48a8781bc831f9e08cdc8124b96964f92c/fcache-0.6.0-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "9.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/38/3d/2d244233ac4f76e38533cfcb2991c9eb4c7bf688ae0a036d30725b8faafe/importlib_metadata-9.0.0-py3-none-any.whl"}}, {"metadata": {"name": "mmh3", "version": "5.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d4/4c/8e3af1b6d85a299767ec97bd923f12b06267089c1472c27c1696870d1175/mmh3-5.2.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "yggdrasil-engine", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/7f/38b0c1ecb2146362b8f5760e9bf9bad2e56b97ba5515f28796f20dc82821/yggdrasil_engine-1.3.1-cp313-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/3b/66777e39d3ae1ddc77ee606be4ec6d8cbd4c801f65e5a1b6f2b11b8346dd/charset_normalizer-3.4.7-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "platformdirs", "version": "3.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/29/3ec311dc18804409ecf0d2b09caa976f3ae6215559306b5b530004e11156/platformdirs-3.11.0-py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tzlocal", "version": "5.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/a4/017a7a6cbe387d961a688ec31364ae60a5c4e22c96ae9921b79a947c855d/tzlocal-5.4.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "zipp", "version": "4.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl"}}], "install_targets_hash": "c2145685d6e6c9355d7ce6f85ea7980a"} -{"python_version": "3.13", "dependencies": [{"metadata": {"name": "mcp", "version": "1.30.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f5/f4/e58bc33317c92a0203664daaf00bf6f41166cc0149e5d6870a03f7cd004a/mcp-1.30.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d3/f2/9e4de77a6271e07a76d2d58b11c091a979c191ed2939bf80067568b369d2/pydantic_core-2.46.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/97/672cb32ce0dfea44b740cb7b4f97038463b9cf7c0ead1aacf595572851d6/pyjwt-2.14.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/85/66/6ccca4722987ddedaa7fc9c3f4708af7431f5535666c174350830888c6b7/cryptography-50.0.1-cp311-abi3-manylinux_2_34_x86_64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/95/86342356ff5953b3fb06f7ef7c5bee212d45e770abc7218d451b9148313c/cffi-2.1.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/d7/fe978efc2ae50abe48eb7464668ea99f53c010c60aeebb7b35ad27f23661/rpds_py-2026.6.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/6a/2ba3ed4a69babf3afdddf7d8314a48d87562c0a442206bbc2a1b50d5efc0/sse_starlette-3.4.11-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.52.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/79/4a20b54ab0491485ccd8c077db2d39187c7f12b3e15485d38a7be37c81b4/uvicorn-0.52.4-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "c22f32eaa2bf5c7f62806b63fcde2d83"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "graphene", "version": "3.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/66/e0/61d8e98007182e6b2aca7cf65904721fb2e4bce0192272ab9cb6f69d8812/graphene-3.4.3-py2.py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/15/b92b4e1d88d02c6eff9733c9eea21846ab435cc4d813d84ccc5d335955df/graphql_core-3.2.11-py3-none-any.whl"}}, {"metadata": {"name": "graphql-relay", "version": "3.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/74/16/a4cf06adbc711bd364a73ce043b0b08d8fa5aae3df11b6ee4248bcdad2e0/graphql_relay-3.2.0-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/81/4fa520eaffa8bd7d1525e644cd6d39e7d60b1592bc5b516693c7340b50f1/pydantic_core-2.46.4-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "fastapi", "version": "0.139.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/7c/8e3c6ad324ea5cb36604fc3f968554887891c316d9dfde57761611d907ad/fastapi-0.139.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}], "install_targets_hash": "c463e15a33bbefa7213f58e7f8b31591"} -{"python_version": "3.13", "dependencies": [{"metadata": {"name": "fastmcp", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ac/14/6d950459cc831fa17fe2d1797926b6eb2d2f2af50f830e62d0c098cc1ec8/fastmcp-3.4.7-py3-none-any.whl"}}, {"metadata": {"name": "fastmcp-slim", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b4/97/e0e53642cd029a9a7635ae9c548f9f2cc995af5914e487b3df795664e4be/fastmcp_slim-3.4.7-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "Authlib", "version": "1.7.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/95/adcb68e20c34162e9135f370d6e31737719c2b6f94bc953fe7ed1f10fe21/authlib-1.7.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "cyclopts", "version": "4.23.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/35/40/c17d731af4ddbf6dede1f1acb09e6335c2587e8b73b3d4742f3f9c6996d3/cyclopts-4.23.2-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "griffelib", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/b6/f65ac785d4ac90dcf7c831ac6256f5dd4a19780f4e1575b2c0d6eeebe319/griffelib-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "joserfc", "version": "1.7.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/bf/249dcd99b3376375910b7fa922383b57792975c8758f50d44612e749226c/joserfc-1.7.4-py3-none-any.whl"}}, {"metadata": {"name": "jsonref", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/ec/e1db9922bceb168197a558a2b8c03a7963f1afe93517ddd3cf99f202f996/jsonref-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-path", "version": "0.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/2c/9e69d73c4297508be9e3b64a970ea3971b3eb8db64ffc5802d40bd25981f/jsonschema_path-0.5.0-py3-none-any.whl"}}, {"metadata": {"name": "mcp", "version": "1.29.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/c8/248b201f6d753d69fd5d6506011abbb35a946d9142b2ae311a948fd0be3d/mcp-1.29.0-py3-none-any.whl"}}, {"metadata": {"name": "openapi-pydantic", "version": "0.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/cf/03675d8bd8ecbf4445504d8071adab19f5f993676795708e36402ab38263/openapi_pydantic-0.5.1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/6f/a04e900f465ff3221ccc395522503e2d10e79fa21f2723c8e177aae1e0d1/opentelemetry_api-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "platformdirs", "version": "4.11.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/a9/c34aebedd3a4c9afe5101b1b8713710b3fec18087c8a36c35d2f909861bd/platformdirs-4.11.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "py-key-value-aio", "version": "0.4.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/95/b8ba862968712caa12a19666175334fa979e1f198b896a430adb3bacfe87/py_key_value_aio-0.4.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/81/4fa520eaffa8bd7d1525e644cd6d39e7d60b1592bc5b516693c7340b50f1/pydantic_core-2.46.4-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "pyperclip", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/80/fc9d01d5ed37ba4c42ca2b55b4339ae6e200b456be3a1aaddf4a9fa99b8c/pyperclip-1.11.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "uncalled-for", "version": "0.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a2/40/97cec87c077eb3291fc7905e6633e08b7ca593c57d30238444bcb6bb3d53/uncalled_for-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.52.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/79/4a20b54ab0491485ccd8c077db2d39187c7f12b3e15485d38a7be37c81b4/uvicorn-0.52.4-py3-none-any.whl"}}, {"metadata": {"name": "watchfiles", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/31/3a/0da302f2307aee316922806ebd5726c542cbd787c938271cf14a074c7daf/watchfiles-1.2.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "websockets", "version": "17.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a2/ef/cc994494bf7d97e41833f6ff55c24f535e4d527a10370b9631737e9c2f00/websockets-17.0.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiofile", "version": "3.12.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/79/6e45e778c4c3cab39e0937b007b720c15f76c50c6453d153282d0fcc3588/aiofile-3.12.3-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "beartype", "version": "0.22.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/cc/18245721fa7747065ab478316c7fea7c74777d07f37ae60db2e84f8172e8/beartype-0.22.9-py3-none-any.whl"}}, {"metadata": {"name": "cachetools", "version": "7.1.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e4/d8/767faeda872075724b95dd675466a645f1b92aadcdcf2d1429dcfd76c176/cachetools-7.1.7-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/5c/59086b4aac5e879d38ddbcf74e4be7ade89cebc3eb199a55da998c3bb46a/cryptography-50.0.0-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "email-validator", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "keyring", "version": "25.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/db/e655086b7f3a705df045bf0933bdd9c2f79bb3c97bfef1384598bb79a217/keyring-25.7.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pathable", "version": "0.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a2/e8/6d75ffd9784bce2e93d1ae4415649427e39a53bb172d4672b2b59c6f0a7b/pathable-0.6.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rich-rst", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/68/1fc93dd759605b5d00fc98b50200739e41ed32bd22d6ba35ca6c3932371b/rich_rst-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/3a/764912c58293d95b6dcdf4cc255f9d10de310580ced547b082eb9d72018c/sse_starlette-3.4.8-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "caio", "version": "0.12.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/9b/31f0b49a2542ffa2f9d6140267e2b568e722a1feeb05cfbffea97666c62b/caio-0.12.2-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/41/4c7042f317b9217502988f0873af87e16ad606dc20f84e546e3e6ce9764c/cffi-2.1.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "dnspython", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f3/6b/686d9dc4359a8f163cfbbf89ee0b4e586431de22fe8248edb63a8cf50d49/rpds_py-2026.6.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "jaraco.classes", "version": "3.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/66/b15ce62552d84bbfcec9a4873ab79d993a1dd4edb922cbfccae192bd5b5f/jaraco.classes-3.4.0-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.context", "version": "6.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f2/58/bc8954bda5fcda97bd7c19be11b85f91973d67a706ed4a3aec33e7de22db/jaraco_context-6.1.2-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.functools", "version": "4.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/02/36/ecc85bc96c273dc8a11273ed4782272975e6338d4a3e9228621175edf0e3/jaraco_functools-4.6.0-py3-none-any.whl"}}, {"metadata": {"name": "more-itertools", "version": "11.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/3d/1087453384dbde46a8c7f9356eead2c58be8a7bf156bca40243377c85715/more_itertools-11.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "c7af9a5e09a115592eb42861d20f7b29"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "graphene", "version": "3.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/66/e0/61d8e98007182e6b2aca7cf65904721fb2e4bce0192272ab9cb6f69d8812/graphene-3.4.3-py2.py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/15/b92b4e1d88d02c6eff9733c9eea21846ab435cc4d813d84ccc5d335955df/graphql_core-3.2.11-py3-none-any.whl"}}, {"metadata": {"name": "graphql-relay", "version": "3.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/74/16/a4cf06adbc711bd364a73ce043b0b08d8fa5aae3df11b6ee4248bcdad2e0/graphql_relay-3.2.0-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/81/4fa520eaffa8bd7d1525e644cd6d39e7d60b1592bc5b516693c7340b50f1/pydantic_core-2.46.4-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "fastapi", "version": "0.139.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/7c/8e3c6ad324ea5cb36604fc3f968554887891c316d9dfde57761611d907ad/fastapi-0.139.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}], "install_targets_hash": "c463e15a33bbefa7213f58e7f8b31591"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "graphene", "version": "3.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/66/e0/61d8e98007182e6b2aca7cf65904721fb2e4bce0192272ab9cb6f69d8812/graphene-3.4.3-py2.py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/15/b92b4e1d88d02c6eff9733c9eea21846ab435cc4d813d84ccc5d335955df/graphql_core-3.2.11-py3-none-any.whl"}}, {"metadata": {"name": "graphql-relay", "version": "3.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/74/16/a4cf06adbc711bd364a73ce043b0b08d8fa5aae3df11b6ee4248bcdad2e0/graphql_relay-3.2.0-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/81/4fa520eaffa8bd7d1525e644cd6d39e7d60b1592bc5b516693c7340b50f1/pydantic_core-2.46.4-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "fastapi", "version": "0.139.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/7c/8e3c6ad324ea5cb36604fc3f968554887891c316d9dfde57761611d907ad/fastapi-0.139.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}], "install_targets_hash": "c463e15a33bbefa7213f58e7f8b31591"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "litellm", "version": "1.96.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ed/1e/76c666f9ba4e0a20d8b3fca8f0af369f97d2e2c2a4874b10b4f344c6bed7/litellm-1.96.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anthropic", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/5b/db4a854aebf5d33a5ab714c46af6eb85ee44f390ed29b7b325c00b9f11ed/anthropic-1.0.0-py3-none-any.whl"}}, {"metadata": {"name": "google-genai", "version": "2.19.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/e8/de0accd8cd004cf11252ca53fc5c3dda59bcf1856abfc7609842ceba7363/google_genai-2.19.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/6b/e7f13410d391c6e55b4c007a8de024355389d7d459e3d64c42b2d33617e5/aiohttp-3.14.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "fastuuid", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/6d/64aee0a0f6a58eeabadd582e55d0d7d70258ffdd01d093b30c53d668303b/fastuuid-0.14.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "google-auth", "version": "2.56.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/b3/6117b2f24065cd7e2c4f140e9a193e215f089ca8ba314cf91eb9d0b7fe0a/google_auth-2.56.3-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/95/411ba65569158e862368917aaf56597f3e5fa3b91b0502919638465a08f3/httpx2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/74/d370e55600d9bcfa0d9794b0166126d49291a3d2b20c268fc98c453a4948/httpcore2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7d/f9/97f2ca8bb3ec6e4b1d64f983ebe98b9a192faddff67fac3d6303a537e670/importlib_metadata-8.9.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d0/2b/c3eaf16f5d7c9bad66ea32f40a95bd169b29a91217fcc7f081375157e99c/jiter-0.16.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "2.54.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/a8/bb76c7356de8ad57f59d5ff993d434df0607f07f08bcc9c9a5c275e399c0/openai-2.54.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/81/4fa520eaffa8bd7d1525e644cd6d39e7d60b1592bc5b516693c7340b50f1/pydantic_core-2.46.4-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/5f/6448cfe278c3664ba9ec5b5ac08344341f7dc3d42888476e215a14eda2be/tiktoken-0.14.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tokenizers", "version": "0.23.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e2/6a/068ed9f6e444c9d7e9d55ce134181325700f3d7f30410721bdc8f848d727/tokenizers-0.23.1-cp310-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/86/0a70d3ae2f0f2256bb41302d9804dbca65d4360281e7feb3e1f94102ac46/websockets-16.1.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a4/a0/562247944386f7d4ef94467e84876600cc1e0f1b93239aaa9213d2bc3cbd/charset_normalizer-3.5.1-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/5c/59086b4aac5e879d38ddbcf74e4be7ade89cebc3eb199a55da998c3bb46a/cryptography-50.0.0-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/ab/6e5080ee374f875296c4243c381bbdef97a9ac39c6e3ce1d5f7d42cb78d6/frozenlist-1.8.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "huggingface_hub", "version": "1.28.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/0e/eafef18f1a75e125e68395db21131db0cf868a128ecd2fce69b4df6c584b/huggingface_hub-1.28.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/76/55cd7186f498ed080a18440c9013011eb548f77ae1b297206d030eb1180a/multidict-6.7.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/12/a6ba6482bb5ea3260c000c9b20881c95fa11c6b30173715668259f844ed7/propcache-0.5.2-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f3/6b/686d9dc4359a8f163cfbbf89ee0b4e586431de22fe8248edb63a8cf50d49/rpds_py-2026.6.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/15/f0/7688d3f2cfff7590df2af38ec46d969f4281a4dddb08a9ad2eafbcdddf98/yarl-1.24.5-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "zipp", "version": "4.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.7.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/47/2d0564e93d87bc48618360ddca232a2ca612bbdf53ce8465d45ca5ce14ee/regex-2026.7.19-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/41/4c7042f317b9217502988f0873af87e16ad606dc20f84e546e3e6ce9764c/cffi-2.1.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "filelock", "version": "3.32.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/a4/9b63d595d748e3aff8812b65eacc1a2c4bd90b7c2012e08e72373b4835eb/filelock-3.32.4-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/3c/6a2bf344106328fd04963664a60b9bb6496fc25df8e962fcdc1367285fb9/fsspec-2026.7.0-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/69/55b8dcf636142ae660fec1869fcac14c4da2e8412e14d6eee1523be77e9f/hf_xet-1.6.0-cp38-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/3b/6163796d69c3977d1e4287bea4a6979161cbbdd170ebb430511e8e1999ce/pyasn1-0.6.4-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "c8297c467689232f577381977852ce9e"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "litellm", "version": "1.96.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ed/1e/76c666f9ba4e0a20d8b3fca8f0af369f97d2e2c2a4874b10b4f344c6bed7/litellm-1.96.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anthropic", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/5b/db4a854aebf5d33a5ab714c46af6eb85ee44f390ed29b7b325c00b9f11ed/anthropic-1.0.0-py3-none-any.whl"}}, {"metadata": {"name": "google-genai", "version": "2.19.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/e8/de0accd8cd004cf11252ca53fc5c3dda59bcf1856abfc7609842ceba7363/google_genai-2.19.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/6b/e7f13410d391c6e55b4c007a8de024355389d7d459e3d64c42b2d33617e5/aiohttp-3.14.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "fastuuid", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/6d/64aee0a0f6a58eeabadd582e55d0d7d70258ffdd01d093b30c53d668303b/fastuuid-0.14.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "google-auth", "version": "2.56.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/b3/6117b2f24065cd7e2c4f140e9a193e215f089ca8ba314cf91eb9d0b7fe0a/google_auth-2.56.3-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/95/411ba65569158e862368917aaf56597f3e5fa3b91b0502919638465a08f3/httpx2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/74/d370e55600d9bcfa0d9794b0166126d49291a3d2b20c268fc98c453a4948/httpcore2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7d/f9/97f2ca8bb3ec6e4b1d64f983ebe98b9a192faddff67fac3d6303a537e670/importlib_metadata-8.9.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d0/2b/c3eaf16f5d7c9bad66ea32f40a95bd169b29a91217fcc7f081375157e99c/jiter-0.16.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "2.54.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/a8/bb76c7356de8ad57f59d5ff993d434df0607f07f08bcc9c9a5c275e399c0/openai-2.54.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/81/4fa520eaffa8bd7d1525e644cd6d39e7d60b1592bc5b516693c7340b50f1/pydantic_core-2.46.4-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/5f/6448cfe278c3664ba9ec5b5ac08344341f7dc3d42888476e215a14eda2be/tiktoken-0.14.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tokenizers", "version": "0.23.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e2/6a/068ed9f6e444c9d7e9d55ce134181325700f3d7f30410721bdc8f848d727/tokenizers-0.23.1-cp310-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/86/0a70d3ae2f0f2256bb41302d9804dbca65d4360281e7feb3e1f94102ac46/websockets-16.1.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a4/a0/562247944386f7d4ef94467e84876600cc1e0f1b93239aaa9213d2bc3cbd/charset_normalizer-3.5.1-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/5c/59086b4aac5e879d38ddbcf74e4be7ade89cebc3eb199a55da998c3bb46a/cryptography-50.0.0-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/ab/6e5080ee374f875296c4243c381bbdef97a9ac39c6e3ce1d5f7d42cb78d6/frozenlist-1.8.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "huggingface_hub", "version": "1.28.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/0e/eafef18f1a75e125e68395db21131db0cf868a128ecd2fce69b4df6c584b/huggingface_hub-1.28.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/76/55cd7186f498ed080a18440c9013011eb548f77ae1b297206d030eb1180a/multidict-6.7.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/12/a6ba6482bb5ea3260c000c9b20881c95fa11c6b30173715668259f844ed7/propcache-0.5.2-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f3/6b/686d9dc4359a8f163cfbbf89ee0b4e586431de22fe8248edb63a8cf50d49/rpds_py-2026.6.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/15/f0/7688d3f2cfff7590df2af38ec46d969f4281a4dddb08a9ad2eafbcdddf98/yarl-1.24.5-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "zipp", "version": "4.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.7.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/47/2d0564e93d87bc48618360ddca232a2ca612bbdf53ce8465d45ca5ce14ee/regex-2026.7.19-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/41/4c7042f317b9217502988f0873af87e16ad606dc20f84e546e3e6ce9764c/cffi-2.1.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "filelock", "version": "3.32.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/a4/9b63d595d748e3aff8812b65eacc1a2c4bd90b7c2012e08e72373b4835eb/filelock-3.32.4-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/3c/6a2bf344106328fd04963664a60b9bb6496fc25df8e962fcdc1367285fb9/fsspec-2026.7.0-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/69/55b8dcf636142ae660fec1869fcac14c4da2e8412e14d6eee1523be77e9f/hf_xet-1.6.0-cp38-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/3b/6163796d69c3977d1e4287bea4a6979161cbbdd170ebb430511e8e1999ce/pyasn1-0.6.4-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "c8297c467689232f577381977852ce9e"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "litestar", "version": "2.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/dc/4d1018577683918cd24a58228c90833f71f792aafcfffb44905c9062f737/litestar-2.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/22/adf66990e63584a68dfb50c24f48a125c07b1699899381c8151e63ed458c/cryptography-49.0.0-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/3b/66777e39d3ae1ddc77ee606be4ec6d8cbd4c801f65e5a1b6f2b11b8346dd/charset_normalizer-3.4.7-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "litestar-htmx", "version": "0.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f2/24/8d99982f0aa9c1cd82073c6232b54a0dbe6797c7d63c0583a6c68ee3ddf2/litestar_htmx-0.5.0-py3-none-any.whl"}}, {"metadata": {"name": "msgspec", "version": "0.21.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bb/40/4476c1bd341418a046c4955aff632ec769315d1e3cb94e6acf86d461f9ed/msgspec-0.21.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/76/55cd7186f498ed080a18440c9013011eb548f77ae1b297206d030eb1180a/multidict-6.7.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multipart", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/ed/e1f03200ee1f0bf4a2b9b72709afefbf5319b68df654e0b84b35c65613ee/multipart-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "polyfactory", "version": "3.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/34/b6f19941adcdaf415b5e8a8d577499f5b6a76b59cbae37f9b125a9ffe9f2/polyfactory-3.3.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "rich-click", "version": "1.9.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6d/97/a87901aef6b7e7e4a34c6dd6cc17dca8594a592ef9d9dd765fca2b7facf7/rich_click-1.9.8-py3-none-any.whl"}}, {"metadata": {"name": "Faker", "version": "40.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/a6/6111b9f13c1564b0e2f5dbeeb611fd00dc731e6add2336f62b798598c73d/faker-40.28.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}], "install_targets_hash": "c941d62ccc766bdd0c07683673042ea8"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "litestar", "version": "2.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/dc/4d1018577683918cd24a58228c90833f71f792aafcfffb44905c9062f737/litestar-2.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/22/adf66990e63584a68dfb50c24f48a125c07b1699899381c8151e63ed458c/cryptography-49.0.0-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/3b/66777e39d3ae1ddc77ee606be4ec6d8cbd4c801f65e5a1b6f2b11b8346dd/charset_normalizer-3.4.7-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "litestar-htmx", "version": "0.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f2/24/8d99982f0aa9c1cd82073c6232b54a0dbe6797c7d63c0583a6c68ee3ddf2/litestar_htmx-0.5.0-py3-none-any.whl"}}, {"metadata": {"name": "msgspec", "version": "0.21.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bb/40/4476c1bd341418a046c4955aff632ec769315d1e3cb94e6acf86d461f9ed/msgspec-0.21.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/76/55cd7186f498ed080a18440c9013011eb548f77ae1b297206d030eb1180a/multidict-6.7.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multipart", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/ed/e1f03200ee1f0bf4a2b9b72709afefbf5319b68df654e0b84b35c65613ee/multipart-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "polyfactory", "version": "3.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/34/b6f19941adcdaf415b5e8a8d577499f5b6a76b59cbae37f9b125a9ffe9f2/polyfactory-3.3.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "rich-click", "version": "1.9.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6d/97/a87901aef6b7e7e4a34c6dd6cc17dca8594a592ef9d9dd765fca2b7facf7/rich_click-1.9.8-py3-none-any.whl"}}, {"metadata": {"name": "Faker", "version": "40.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/a6/6111b9f13c1564b0e2f5dbeeb611fd00dc731e6add2336f62b798598c73d/faker-40.28.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}], "install_targets_hash": "c941d62ccc766bdd0c07683673042ea8"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "litestar", "version": "2.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/dc/4d1018577683918cd24a58228c90833f71f792aafcfffb44905c9062f737/litestar-2.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/22/adf66990e63584a68dfb50c24f48a125c07b1699899381c8151e63ed458c/cryptography-49.0.0-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/3b/66777e39d3ae1ddc77ee606be4ec6d8cbd4c801f65e5a1b6f2b11b8346dd/charset_normalizer-3.4.7-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "litestar-htmx", "version": "0.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f2/24/8d99982f0aa9c1cd82073c6232b54a0dbe6797c7d63c0583a6c68ee3ddf2/litestar_htmx-0.5.0-py3-none-any.whl"}}, {"metadata": {"name": "msgspec", "version": "0.21.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bb/40/4476c1bd341418a046c4955aff632ec769315d1e3cb94e6acf86d461f9ed/msgspec-0.21.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/76/55cd7186f498ed080a18440c9013011eb548f77ae1b297206d030eb1180a/multidict-6.7.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multipart", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/ed/e1f03200ee1f0bf4a2b9b72709afefbf5319b68df654e0b84b35c65613ee/multipart-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "polyfactory", "version": "3.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/34/b6f19941adcdaf415b5e8a8d577499f5b6a76b59cbae37f9b125a9ffe9f2/polyfactory-3.3.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "rich-click", "version": "1.9.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6d/97/a87901aef6b7e7e4a34c6dd6cc17dca8594a592ef9d9dd765fca2b7facf7/rich_click-1.9.8-py3-none-any.whl"}}, {"metadata": {"name": "Faker", "version": "40.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/a6/6111b9f13c1564b0e2f5dbeeb611fd00dc731e6add2336f62b798598c73d/faker-40.28.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}], "install_targets_hash": "c941d62ccc766bdd0c07683673042ea8"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "litestar", "version": "2.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/dc/4d1018577683918cd24a58228c90833f71f792aafcfffb44905c9062f737/litestar-2.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/22/adf66990e63584a68dfb50c24f48a125c07b1699899381c8151e63ed458c/cryptography-49.0.0-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/3b/66777e39d3ae1ddc77ee606be4ec6d8cbd4c801f65e5a1b6f2b11b8346dd/charset_normalizer-3.4.7-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "litestar-htmx", "version": "0.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f2/24/8d99982f0aa9c1cd82073c6232b54a0dbe6797c7d63c0583a6c68ee3ddf2/litestar_htmx-0.5.0-py3-none-any.whl"}}, {"metadata": {"name": "msgspec", "version": "0.21.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bb/40/4476c1bd341418a046c4955aff632ec769315d1e3cb94e6acf86d461f9ed/msgspec-0.21.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/76/55cd7186f498ed080a18440c9013011eb548f77ae1b297206d030eb1180a/multidict-6.7.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multipart", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/ed/e1f03200ee1f0bf4a2b9b72709afefbf5319b68df654e0b84b35c65613ee/multipart-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "polyfactory", "version": "3.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/34/b6f19941adcdaf415b5e8a8d577499f5b6a76b59cbae37f9b125a9ffe9f2/polyfactory-3.3.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "rich-click", "version": "1.9.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6d/97/a87901aef6b7e7e4a34c6dd6cc17dca8594a592ef9d9dd765fca2b7facf7/rich_click-1.9.8-py3-none-any.whl"}}, {"metadata": {"name": "Faker", "version": "40.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/a6/6111b9f13c1564b0e2f5dbeeb611fd00dc731e6add2336f62b798598c73d/faker-40.28.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}], "install_targets_hash": "c941d62ccc766bdd0c07683673042ea8"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "litestar", "version": "2.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/dc/4d1018577683918cd24a58228c90833f71f792aafcfffb44905c9062f737/litestar-2.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/22/adf66990e63584a68dfb50c24f48a125c07b1699899381c8151e63ed458c/cryptography-49.0.0-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/3b/66777e39d3ae1ddc77ee606be4ec6d8cbd4c801f65e5a1b6f2b11b8346dd/charset_normalizer-3.4.7-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "litestar-htmx", "version": "0.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f2/24/8d99982f0aa9c1cd82073c6232b54a0dbe6797c7d63c0583a6c68ee3ddf2/litestar_htmx-0.5.0-py3-none-any.whl"}}, {"metadata": {"name": "msgspec", "version": "0.21.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bb/40/4476c1bd341418a046c4955aff632ec769315d1e3cb94e6acf86d461f9ed/msgspec-0.21.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/76/55cd7186f498ed080a18440c9013011eb548f77ae1b297206d030eb1180a/multidict-6.7.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multipart", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/ed/e1f03200ee1f0bf4a2b9b72709afefbf5319b68df654e0b84b35c65613ee/multipart-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "polyfactory", "version": "3.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/34/b6f19941adcdaf415b5e8a8d577499f5b6a76b59cbae37f9b125a9ffe9f2/polyfactory-3.3.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "rich-click", "version": "1.9.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6d/97/a87901aef6b7e7e4a34c6dd6cc17dca8594a592ef9d9dd765fca2b7facf7/rich_click-1.9.8-py3-none-any.whl"}}, {"metadata": {"name": "Faker", "version": "40.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/a6/6111b9f13c1564b0e2f5dbeeb611fd00dc731e6add2336f62b798598c73d/faker-40.28.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}], "install_targets_hash": "c941d62ccc766bdd0c07683673042ea8"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "mcp", "version": "2.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/75/20/312acf5fd37b90589269349b2c4d5c056b4603c964d181e91f9bf4a79f97/mcp-2.0.1-py3-none-any.whl"}}, {"metadata": {"name": "mcp-types", "version": "2.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b6/49/37a1f580d94ee0f16c1f3d1c6e32bbb264e607f1739a4c0cb9232619dfd9/mcp_types-2.0.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/6f/a04e900f465ff3221ccc395522503e2d10e79fa21f2723c8e177aae1e0d1/opentelemetry_api-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/21/43/6323b1f8b217780454c61304bcd2b38ae4762f50754414124603ccc90bb2/pydantic_core-2.46.5-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/97/672cb32ce0dfea44b740cb7b4f97038463b9cf7c0ead1aacf595572851d6/pyjwt-2.14.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/6a/2ba3ed4a69babf3afdddf7d8314a48d87562c0a442206bbc2a1b50d5efc0/sse_starlette-3.4.11-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.53.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/76/18/0eea75741ee812e9f598b687619ce2454f6c3a1c5cd21ea990ec6bd26f45/uvicorn-0.53.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/19/797e2aaac9df6a66f1550f49979dc1b1e39ecd2077501c30efa81e8d5d67/cryptography-50.0.1-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f3/6b/686d9dc4359a8f163cfbbf89ee0b4e586431de22fe8248edb63a8cf50d49/rpds_py-2026.6.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/41/4c7042f317b9217502988f0873af87e16ad606dc20f84e546e3e6ce9764c/cffi-2.1.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "cce7f3c3feff18eeb00efa85d75073cb"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "langchain", "version": "0.3.30"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/54/c0775c29bf9ae27c8cbf8484ad600edd2e787a0eacf3a374cb6561613de9/langchain-0.3.30-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/5f/6448cfe278c3664ba9ec5b5ac08344341f7dc3d42888476e215a14eda2be/tiktoken-0.14.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "langchain-openai", "version": "0.3.35"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d8/d5/c90c5478215c20ee71d8feaf676f7ffd78d0568f8c98bd83f81ce7562ed7/langchain_openai-0.3.35-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "2.54.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/a8/bb76c7356de8ad57f59d5ff993d434df0607f07f08bcc9c9a5c275e399c0/openai-2.54.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "langchain-community", "version": "0.3.31"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e6/0a/b8848db67ad7c8d4652cb6f4cb78d49b5b5e6e8e51d695d62025aa3f7dbc/langchain_community-0.3.31-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/6b/e7f13410d391c6e55b4c007a8de024355389d7d459e3d64c42b2d33617e5/aiohttp-3.14.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "dataclasses-json", "version": "0.6.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c3/be/d0d44e092656fe7a06b55e6103cbce807cdbdee17884a5367c68c9860853/dataclasses_json-0.6.7-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d0/2b/c3eaf16f5d7c9bad66ea32f40a95bd169b29a91217fcc7f081375157e99c/jiter-0.16.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "langchain-core", "version": "0.3.86"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/93/ba19ca54701c6118e68f8785949b6c0eab1df3a5cfa5310508cc86877994/langchain_core-0.3.86-py3-none-any.whl"}}, {"metadata": {"name": "langchain-text-splitters", "version": "0.3.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/0d/41a51b40d24ff0384ec4f7ab8dd3dcea8353c05c973836b5e289f1465d4f/langchain_text_splitters-0.3.11-py3-none-any.whl"}}, {"metadata": {"name": "langsmith", "version": "0.11.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/85/0ad6df25588122760b2b40ec182eafc55532c9e66015c83e16675bd34a29/langsmith-0.11.1-py3-none-any.whl"}}, {"metadata": {"name": "numpy", "version": "2.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3c/79/81e0bf24f4d020a2b1d5cd297a9f60c3f24eeb116f9bba5870443f7b6a4a/numpy-2.5.2-cp313-cp313-macosx_14_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/81/4fa520eaffa8bd7d1525e644cd6d39e7d60b1592bc5b516693c7340b50f1/pydantic_core-2.46.4-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "SQLAlchemy", "version": "2.0.52"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/18/e30c6fe1eca1bf34a39fbdd6066121cc9974c850faf6f349eac563697a26/sqlalchemy-2.0.52-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.7.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/47/2d0564e93d87bc48618360ddca232a2ca612bbdf53ce8465d45ca5ce14ee/regex-2026.7.19-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a4/a0/562247944386f7d4ef94467e84876600cc1e0f1b93239aaa9213d2bc3cbd/charset_normalizer-3.5.1-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/ab/6e5080ee374f875296c4243c381bbdef97a9ac39c6e3ce1d5f7d42cb78d6/frozenlist-1.8.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonpatch", "version": "1.33"}, "download_info": {"url": "https://files.pythonhosted.org/packages/73/07/02e16ed01e04a374e644b575638ec7987ae846d25ad97bcc9945a3ee4b0e/jsonpatch-1.33-py2.py3-none-any.whl"}}, {"metadata": {"name": "marshmallow", "version": "3.26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/be/2f/5108cb3ee4ba6501748c4908b908e55f42a5b66245b4cfe0c99326e1ef6e/marshmallow-3.26.2-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/76/55cd7186f498ed080a18440c9013011eb548f77ae1b297206d030eb1180a/multidict-6.7.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "orjson", "version": "3.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f8/4a/bc87c45e7ec639d35ebefd62618e01939531ac8e171426606a01bda05914/orjson-3.12.0-cp313-cp313-macosx_15_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "25.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/12/a6ba6482bb5ea3260c000c9b20881c95fa11c6b30173715668259f844ed7/propcache-0.5.2-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing-inspect", "version": "0.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/f3/107a22063bf27bdccf2024833d3445f4eea42b2e598abfbd46f6a63b6cb0/typing_inspect-0.9.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "uuid_utils", "version": "0.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/dd/614fb9912157ac0128e6050859ccf06d9f13df9a944a803e8f80f6157e38/uuid_utils-0.17.0-cp313-cp313-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl"}}, {"metadata": {"name": "websockets", "version": "17.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a2/ef/cc994494bf7d97e41833f6ff55c24f535e4d527a10370b9631737e9c2f00/websockets-17.0.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "xxhash", "version": "4.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/e0/934af8d99bb5885711006bec30a691f728edd513d2c40f053f887d8e7577/xxhash-4.0.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/15/f0/7688d3f2cfff7590df2af38ec46d969f4281a4dddb08a9ad2eafbcdddf98/yarl-1.24.5-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "zstandard", "version": "0.25.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/06/9ae96a3e5dcfd119377ba33d4c42a7d89da1efabd5cb3e366b156c45ff4d/zstandard-0.25.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "jsonpointer", "version": "3.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/6a/a83720e953b1682d2d109d3c2dbb0bc9bf28cc1cbc205be4ef4be5da709d/jsonpointer-3.1.1-py3-none-any.whl"}}, {"metadata": {"name": "mypy_extensions", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl"}}], "install_targets_hash": "cf8681468fca1e6ce2b515327a36b948"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "langchain", "version": "0.3.30"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/54/c0775c29bf9ae27c8cbf8484ad600edd2e787a0eacf3a374cb6561613de9/langchain-0.3.30-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/5f/6448cfe278c3664ba9ec5b5ac08344341f7dc3d42888476e215a14eda2be/tiktoken-0.14.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "langchain-openai", "version": "0.3.35"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d8/d5/c90c5478215c20ee71d8feaf676f7ffd78d0568f8c98bd83f81ce7562ed7/langchain_openai-0.3.35-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "2.54.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/a8/bb76c7356de8ad57f59d5ff993d434df0607f07f08bcc9c9a5c275e399c0/openai-2.54.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "langchain-community", "version": "0.3.31"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e6/0a/b8848db67ad7c8d4652cb6f4cb78d49b5b5e6e8e51d695d62025aa3f7dbc/langchain_community-0.3.31-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/6b/e7f13410d391c6e55b4c007a8de024355389d7d459e3d64c42b2d33617e5/aiohttp-3.14.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "dataclasses-json", "version": "0.6.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c3/be/d0d44e092656fe7a06b55e6103cbce807cdbdee17884a5367c68c9860853/dataclasses_json-0.6.7-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d0/2b/c3eaf16f5d7c9bad66ea32f40a95bd169b29a91217fcc7f081375157e99c/jiter-0.16.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "langchain-core", "version": "0.3.86"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/93/ba19ca54701c6118e68f8785949b6c0eab1df3a5cfa5310508cc86877994/langchain_core-0.3.86-py3-none-any.whl"}}, {"metadata": {"name": "langchain-text-splitters", "version": "0.3.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/0d/41a51b40d24ff0384ec4f7ab8dd3dcea8353c05c973836b5e289f1465d4f/langchain_text_splitters-0.3.11-py3-none-any.whl"}}, {"metadata": {"name": "langsmith", "version": "0.11.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/85/0ad6df25588122760b2b40ec182eafc55532c9e66015c83e16675bd34a29/langsmith-0.11.1-py3-none-any.whl"}}, {"metadata": {"name": "numpy", "version": "2.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3c/79/81e0bf24f4d020a2b1d5cd297a9f60c3f24eeb116f9bba5870443f7b6a4a/numpy-2.5.2-cp313-cp313-macosx_14_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/81/4fa520eaffa8bd7d1525e644cd6d39e7d60b1592bc5b516693c7340b50f1/pydantic_core-2.46.4-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "SQLAlchemy", "version": "2.0.52"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/18/e30c6fe1eca1bf34a39fbdd6066121cc9974c850faf6f349eac563697a26/sqlalchemy-2.0.52-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.7.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/47/2d0564e93d87bc48618360ddca232a2ca612bbdf53ce8465d45ca5ce14ee/regex-2026.7.19-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a4/a0/562247944386f7d4ef94467e84876600cc1e0f1b93239aaa9213d2bc3cbd/charset_normalizer-3.5.1-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/ab/6e5080ee374f875296c4243c381bbdef97a9ac39c6e3ce1d5f7d42cb78d6/frozenlist-1.8.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonpatch", "version": "1.33"}, "download_info": {"url": "https://files.pythonhosted.org/packages/73/07/02e16ed01e04a374e644b575638ec7987ae846d25ad97bcc9945a3ee4b0e/jsonpatch-1.33-py2.py3-none-any.whl"}}, {"metadata": {"name": "marshmallow", "version": "3.26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/be/2f/5108cb3ee4ba6501748c4908b908e55f42a5b66245b4cfe0c99326e1ef6e/marshmallow-3.26.2-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/76/55cd7186f498ed080a18440c9013011eb548f77ae1b297206d030eb1180a/multidict-6.7.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "orjson", "version": "3.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f8/4a/bc87c45e7ec639d35ebefd62618e01939531ac8e171426606a01bda05914/orjson-3.12.0-cp313-cp313-macosx_15_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "25.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/12/a6ba6482bb5ea3260c000c9b20881c95fa11c6b30173715668259f844ed7/propcache-0.5.2-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing-inspect", "version": "0.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/f3/107a22063bf27bdccf2024833d3445f4eea42b2e598abfbd46f6a63b6cb0/typing_inspect-0.9.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "uuid_utils", "version": "0.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/dd/614fb9912157ac0128e6050859ccf06d9f13df9a944a803e8f80f6157e38/uuid_utils-0.17.0-cp313-cp313-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl"}}, {"metadata": {"name": "websockets", "version": "17.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a2/ef/cc994494bf7d97e41833f6ff55c24f535e4d527a10370b9631737e9c2f00/websockets-17.0.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "xxhash", "version": "4.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/e0/934af8d99bb5885711006bec30a691f728edd513d2c40f053f887d8e7577/xxhash-4.0.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/15/f0/7688d3f2cfff7590df2af38ec46d969f4281a4dddb08a9ad2eafbcdddf98/yarl-1.24.5-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "zstandard", "version": "0.25.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/06/9ae96a3e5dcfd119377ba33d4c42a7d89da1efabd5cb3e366b156c45ff4d/zstandard-0.25.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "jsonpointer", "version": "3.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/6a/a83720e953b1682d2d109d3c2dbb0bc9bf28cc1cbc205be4ef4be5da709d/jsonpointer-3.1.1-py3-none-any.whl"}}, {"metadata": {"name": "mypy_extensions", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl"}}], "install_targets_hash": "cf8681468fca1e6ce2b515327a36b948"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "google-genai", "version": "2.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/84/5b/87913fe392ba7b6402577259289ed3740c577956554a674b191a2971d33e/google_genai-2.24.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.58.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/59/13/477d90d09591b3938b45c4e11f4d8a51291682112cb5efcac961e815d562/google_auth-2.58.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d3/f2/9e4de77a6271e07a76d2d58b11c091a979c191ed2939bf80067568b369d2/pydantic_core-2.46.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/af/63240b0c0248c075c2535a1f1bd992821d8251b9f173abc13329661d09e4/charset_normalizer-3.5.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b5/c2/c676c69444d9db448b3f0a55a98dcc534affce0bce961d9d2f0b8499b10a/websockets-16.1.1-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/85/66/6ccca4722987ddedaa7fc9c3f4708af7431f5535666c174350830888c6b7/cryptography-50.0.1-cp311-abi3-manylinux_2_34_x86_64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/95/86342356ff5953b3fb06f7ef7c5bee212d45e770abc7218d451b9148313c/cffi-2.1.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/3b/6163796d69c3977d1e4287bea4a6979161cbbdd170ebb430511e8e1999ce/pyasn1-0.6.4-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "d5f17eff9efc836f1883edb6f7bfdfbc"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "openai", "version": "1.109.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1d/2a/7dd3d207ec669cacc1f186fd856a0f61dbc255d24f6fdc1a6715d6051b0f/openai-1.109.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d0/2b/c3eaf16f5d7c9bad66ea32f40a95bd169b29a91217fcc7f081375157e99c/jiter-0.16.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/81/4fa520eaffa8bd7d1525e644cd6d39e7d60b1592bc5b516693c7340b50f1/pydantic_core-2.46.4-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}], "install_targets_hash": "d84808ce0b2029981b5c45613f25aa8b"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "openai", "version": "1.109.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1d/2a/7dd3d207ec669cacc1f186fd856a0f61dbc255d24f6fdc1a6715d6051b0f/openai-1.109.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d0/2b/c3eaf16f5d7c9bad66ea32f40a95bd169b29a91217fcc7f081375157e99c/jiter-0.16.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/81/4fa520eaffa8bd7d1525e644cd6d39e7d60b1592bc5b516693c7340b50f1/pydantic_core-2.46.4-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}], "install_targets_hash": "d84808ce0b2029981b5c45613f25aa8b"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "pyreqwest", "version": "0.11.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/61/2fb31f5e6ce08da5cc33dfac1427a9a5a17b037bffe7507e779591325bd6/pyreqwest-0.11.8-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "ddbeddd6367dc3ba2a81dfa0d1d7c186"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "pyreqwest", "version": "0.11.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/61/2fb31f5e6ce08da5cc33dfac1427a9a5a17b037bffe7507e779591325bd6/pyreqwest-0.11.8-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "ddbeddd6367dc3ba2a81dfa0d1d7c186"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "pyreqwest", "version": "0.11.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/61/2fb31f5e6ce08da5cc33dfac1427a9a5a17b037bffe7507e779591325bd6/pyreqwest-0.11.8-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "ddbeddd6367dc3ba2a81dfa0d1d7c186"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "apache-beam", "version": "2.76.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/9b/f1/2dcc24a48b41124fca86b925d1571f6288a2b9920d0b17525044a1666494/apache_beam-2.76.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "betterproto", "version": "2.0.0b6"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/99/6d/007abe4bf14cd02a3c07710c22f0e3252b55b06678de2535ae5f03b7433a/betterproto-2.0.0b6-py3-none-any.whl"}}, {"metadata": {"name": "beartype", "version": "0.22.9"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/cc/18245721fa7747065ab478316c7fea7c74777d07f37ae60db2e84f8172e8/beartype-0.22.9-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "48.0.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/1b/bc/ee4137cbbe105652c0ee4252792b78fc8e7afa4b8e61d9d5dc05a7f45731/cryptography-48.0.1-cp311-abi3-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "fastavro", "version": "1.12.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/83/39/f489a441d41cc9c0a8449fb1325d7a9c9eb57a5634e6ab19dfb0a1105324/fastavro-1.12.2-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "fasteners", "version": "0.20"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/51/ac/e5d886f892666d2d1e5cb8c1a41146e1d79ae8896477b1153a21711d3b44/fasteners-0.20-py3-none-any.whl"}}, {"metadata": {"name": "grpcio", "version": "1.83.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c4/49/0b40bae059c619505c9b751cee6caa208e4904e290aaefa1728c4c2c67a5/grpcio-1.83.1-cp313-cp313-macosx_11_0_universal2.whl"}}, {"metadata": {"name": "grpclib", "version": "0.4.9"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/5c/90/b0cbbd9efcc82816c58f31a34963071aa19fb792a212a5d9caf8e0fc3097/grpclib-0.4.9-py3-none-any.whl"}}, {"metadata": {"name": "h2", "version": "4.4.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/22/e85faf23bd72a92d1921e37d674ca56eb298a3c8be31fdecef0ff2b3aaac/h2-4.4.1-py3-none-any.whl"}}, {"metadata": {"name": "hpack", "version": "4.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/b4/4a9fcfb2aef6ba44d9073ecd301443aa00b3dac95de5619f2a7de7ec8a91/hpack-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "httplib2", "version": "0.32.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/33/a0/550eec327e5f5c7b732531c489f5307efec41f047b0d703bd4ca1e5ad2db/httplib2-0.32.0-py3-none-any.whl"}}, {"metadata": {"name": "hyperframe", "version": "6.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/48/30/47d0bf6072f7252e6521f3447ccfa40b421b6824517f82854703d0f5a98b/hyperframe-6.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonpickle", "version": "4.1.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a1/7b/fd3c7a09649aea9da1d3587aea624d8f9b29963dfd84a1bdb2aa93b36dac/jsonpickle-4.1.2-py3-none-any.whl"}}, {"metadata": {"name": "numpy", "version": "2.4.6"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/97/12/70b5d0d7c15e1ebb8a6a84a8caa1d19e181d84fb58bb6d70aca29099dec1/numpy-2.4.6-cp313-cp313-macosx_14_0_arm64.whl"}}, {"metadata": {"name": "objsize", "version": "0.7.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/f3/a7/55f8f3853a4a654d3a6fbf63e646e0b469b52c174703a10db70a1cb06c7e/objsize-0.7.1-py3-none-any.whl"}}, {"metadata": {"name": "pillow", "version": "12.3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/10/76/8803c13605b763d33d156c4678fc77f8443389c0c51c8aef707bb02015f4/pillow-12.3.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "proto-plus", "version": "1.28.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/41/5d/0f04b85dafdc3250ced7f2592efc17dce7f40712e941e9632202481e600d/proto_plus-1.28.4-py3-none-any.whl"}}, {"metadata": {"name": "protobuf", "version": "6.33.6"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/5c/01/a3c3ed5cd186f39e7880f8303cc51385a198a81469d53d0fdecf1f64d929/protobuf-6.33.6-cp39-abi3-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "pyarrow", "version": "25.0.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cc/8d/8f271a7a034c834910ec925d56fa4b29733b1380f5289419f5aaa3b02777/pyarrow-25.0.1-cp313-cp313-macosx_12_0_arm64.whl"}}, {"metadata": {"name": "pymongo", "version": "4.17.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cb/cf/bb044ed85160e5c40f568c7c4f4e8ea16f40764ff5d302e5befbe8f6f814/pymongo-4.17.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "dnspython", "version": "2.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "pyparsing", "version": "3.3.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a4/a0/562247944386f7d4ef94467e84876600cc1e0f1b93239aaa9213d2bc3cbd/charset_normalizer-3.5.1-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "zstandard", "version": "0.25.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/3f/06/9ae96a3e5dcfd119377ba33d4c42a7d89da1efabd5cb3e366b156c45ff4d/zstandard-0.25.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "dill", "version": "0.4.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/1e/77/dc8c558f7593132cf8fefec57c4f60c83b16941c574ac5f619abb3ae7933/dill-0.4.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/55/41/4c7042f317b9217502988f0873af87e16ad606dc20f84e546e3e6ce9764c/cffi-2.1.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pytz", "version": "2026.3.post1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0f/7b/39c34ca613b0b198cb866466651b26b045e2009864c5183c979a3b83f383/pytz-2026.3.post1-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/79/76/55cd7186f498ed080a18440c9013011eb548f77ae1b297206d030eb1180a/multidict-6.7.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "de59b66921db5839d863c7f55d15510f"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "apache-beam", "version": "2.76.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/9b/f1/2dcc24a48b41124fca86b925d1571f6288a2b9920d0b17525044a1666494/apache_beam-2.76.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "betterproto", "version": "2.0.0b6"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/99/6d/007abe4bf14cd02a3c07710c22f0e3252b55b06678de2535ae5f03b7433a/betterproto-2.0.0b6-py3-none-any.whl"}}, {"metadata": {"name": "beartype", "version": "0.22.9"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/cc/18245721fa7747065ab478316c7fea7c74777d07f37ae60db2e84f8172e8/beartype-0.22.9-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "48.0.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/1b/bc/ee4137cbbe105652c0ee4252792b78fc8e7afa4b8e61d9d5dc05a7f45731/cryptography-48.0.1-cp311-abi3-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "fastavro", "version": "1.12.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/83/39/f489a441d41cc9c0a8449fb1325d7a9c9eb57a5634e6ab19dfb0a1105324/fastavro-1.12.2-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "fasteners", "version": "0.20"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/51/ac/e5d886f892666d2d1e5cb8c1a41146e1d79ae8896477b1153a21711d3b44/fasteners-0.20-py3-none-any.whl"}}, {"metadata": {"name": "grpcio", "version": "1.83.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c4/49/0b40bae059c619505c9b751cee6caa208e4904e290aaefa1728c4c2c67a5/grpcio-1.83.1-cp313-cp313-macosx_11_0_universal2.whl"}}, {"metadata": {"name": "grpclib", "version": "0.4.9"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/5c/90/b0cbbd9efcc82816c58f31a34963071aa19fb792a212a5d9caf8e0fc3097/grpclib-0.4.9-py3-none-any.whl"}}, {"metadata": {"name": "h2", "version": "4.4.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/22/e85faf23bd72a92d1921e37d674ca56eb298a3c8be31fdecef0ff2b3aaac/h2-4.4.1-py3-none-any.whl"}}, {"metadata": {"name": "hpack", "version": "4.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/b4/4a9fcfb2aef6ba44d9073ecd301443aa00b3dac95de5619f2a7de7ec8a91/hpack-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "httplib2", "version": "0.32.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/33/a0/550eec327e5f5c7b732531c489f5307efec41f047b0d703bd4ca1e5ad2db/httplib2-0.32.0-py3-none-any.whl"}}, {"metadata": {"name": "hyperframe", "version": "6.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/48/30/47d0bf6072f7252e6521f3447ccfa40b421b6824517f82854703d0f5a98b/hyperframe-6.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonpickle", "version": "4.1.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a1/7b/fd3c7a09649aea9da1d3587aea624d8f9b29963dfd84a1bdb2aa93b36dac/jsonpickle-4.1.2-py3-none-any.whl"}}, {"metadata": {"name": "numpy", "version": "2.4.6"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/97/12/70b5d0d7c15e1ebb8a6a84a8caa1d19e181d84fb58bb6d70aca29099dec1/numpy-2.4.6-cp313-cp313-macosx_14_0_arm64.whl"}}, {"metadata": {"name": "objsize", "version": "0.7.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/f3/a7/55f8f3853a4a654d3a6fbf63e646e0b469b52c174703a10db70a1cb06c7e/objsize-0.7.1-py3-none-any.whl"}}, {"metadata": {"name": "pillow", "version": "12.3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/10/76/8803c13605b763d33d156c4678fc77f8443389c0c51c8aef707bb02015f4/pillow-12.3.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "proto-plus", "version": "1.28.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/41/5d/0f04b85dafdc3250ced7f2592efc17dce7f40712e941e9632202481e600d/proto_plus-1.28.4-py3-none-any.whl"}}, {"metadata": {"name": "protobuf", "version": "6.33.6"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/5c/01/a3c3ed5cd186f39e7880f8303cc51385a198a81469d53d0fdecf1f64d929/protobuf-6.33.6-cp39-abi3-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "pyarrow", "version": "25.0.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cc/8d/8f271a7a034c834910ec925d56fa4b29733b1380f5289419f5aaa3b02777/pyarrow-25.0.1-cp313-cp313-macosx_12_0_arm64.whl"}}, {"metadata": {"name": "pymongo", "version": "4.17.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cb/cf/bb044ed85160e5c40f568c7c4f4e8ea16f40764ff5d302e5befbe8f6f814/pymongo-4.17.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "dnspython", "version": "2.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "pyparsing", "version": "3.3.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a4/a0/562247944386f7d4ef94467e84876600cc1e0f1b93239aaa9213d2bc3cbd/charset_normalizer-3.5.1-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "zstandard", "version": "0.25.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/3f/06/9ae96a3e5dcfd119377ba33d4c42a7d89da1efabd5cb3e366b156c45ff4d/zstandard-0.25.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "dill", "version": "0.4.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/1e/77/dc8c558f7593132cf8fefec57c4f60c83b16941c574ac5f619abb3ae7933/dill-0.4.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/55/41/4c7042f317b9217502988f0873af87e16ad606dc20f84e546e3e6ce9764c/cffi-2.1.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pytz", "version": "2026.3.post1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0f/7b/39c34ca613b0b198cb866466651b26b045e2009864c5183c979a3b83f383/pytz-2026.3.post1-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/79/76/55cd7186f498ed080a18440c9013011eb548f77ae1b297206d030eb1180a/multidict-6.7.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "de59b66921db5839d863c7f55d15510f"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "huggingface_hub", "version": "0.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/af/48ac8483240de756d2438c380746e7130d1c6f75802ef22f3c6d49982787/huggingface_hub-0.36.2-py3-none-any.whl"}}, {"metadata": {"name": "responses", "version": "0.26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/28/693e1d9ebf72baa062ded80d837a035b86ce75eda5a269379e9e2b1008a8/responses-0.26.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest-httpx", "version": "0.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/55/1fa65f8e4fceb19dd6daa867c162ad845d547f6058cd92b4b02384a44777/pytest_httpx-0.36.2-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e5/22/4222d7ddf3da30f363edaa98e329c2bce6c65497c9cb2810931c8b2c0fbc/fsspec-2026.6.0-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/35/94/4b2ecfbad8f8b04701a23aefb62f540b9137d058b7e1dbef16a32676f0e9/hf_xet-1.5.1-cp37-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.68.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d8/8e/bb97bb0c71802080bfc8952937d174e49cfc50de5c951dd47b2496f0dcdb/tqdm-4.68.3-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "filelock", "version": "3.29.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4a/e3/f1fae3647d170919c2cf2a898e77e7d1a4e5c7cae0aed7bb4bd3f5ebff6f/filelock-3.29.5-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/3b/66777e39d3ae1ddc77ee606be4ec6d8cbd4c801f65e5a1b6f2b11b8346dd/charset_normalizer-3.4.7-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}], "install_targets_hash": "dfd10ffb6fbe157d72679f5940ede3a2"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "huggingface_hub", "version": "0.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/af/48ac8483240de756d2438c380746e7130d1c6f75802ef22f3c6d49982787/huggingface_hub-0.36.2-py3-none-any.whl"}}, {"metadata": {"name": "responses", "version": "0.26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/28/693e1d9ebf72baa062ded80d837a035b86ce75eda5a269379e9e2b1008a8/responses-0.26.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest-httpx", "version": "0.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/55/1fa65f8e4fceb19dd6daa867c162ad845d547f6058cd92b4b02384a44777/pytest_httpx-0.36.2-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e5/22/4222d7ddf3da30f363edaa98e329c2bce6c65497c9cb2810931c8b2c0fbc/fsspec-2026.6.0-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/35/94/4b2ecfbad8f8b04701a23aefb62f540b9137d058b7e1dbef16a32676f0e9/hf_xet-1.5.1-cp37-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.68.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d8/8e/bb97bb0c71802080bfc8952937d174e49cfc50de5c951dd47b2496f0dcdb/tqdm-4.68.3-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "filelock", "version": "3.29.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4a/e3/f1fae3647d170919c2cf2a898e77e7d1a4e5c7cae0aed7bb4bd3f5ebff6f/filelock-3.29.5-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/3b/66777e39d3ae1ddc77ee606be4ec6d8cbd4c801f65e5a1b6f2b11b8346dd/charset_normalizer-3.4.7-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}], "install_targets_hash": "dfd10ffb6fbe157d72679f5940ede3a2"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "huggingface_hub", "version": "0.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/af/48ac8483240de756d2438c380746e7130d1c6f75802ef22f3c6d49982787/huggingface_hub-0.36.2-py3-none-any.whl"}}, {"metadata": {"name": "responses", "version": "0.26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/28/693e1d9ebf72baa062ded80d837a035b86ce75eda5a269379e9e2b1008a8/responses-0.26.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest-httpx", "version": "0.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/55/1fa65f8e4fceb19dd6daa867c162ad845d547f6058cd92b4b02384a44777/pytest_httpx-0.36.2-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e5/22/4222d7ddf3da30f363edaa98e329c2bce6c65497c9cb2810931c8b2c0fbc/fsspec-2026.6.0-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/35/94/4b2ecfbad8f8b04701a23aefb62f540b9137d058b7e1dbef16a32676f0e9/hf_xet-1.5.1-cp37-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.68.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d8/8e/bb97bb0c71802080bfc8952937d174e49cfc50de5c951dd47b2496f0dcdb/tqdm-4.68.3-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "filelock", "version": "3.29.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4a/e3/f1fae3647d170919c2cf2a898e77e7d1a4e5c7cae0aed7bb4bd3f5ebff6f/filelock-3.29.5-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/3b/66777e39d3ae1ddc77ee606be4ec6d8cbd4c801f65e5a1b6f2b11b8346dd/charset_normalizer-3.4.7-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}], "install_targets_hash": "dfd10ffb6fbe157d72679f5940ede3a2"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "launchdarkly-server-sdk", "version": "9.17.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c1/58/bcede9c0f11b5c37b492ea993ed0599099e15f803b9fe98452558cfd6e96/launchdarkly_server_sdk-9.17.0-py3-none-any.whl"}}, {"metadata": {"name": "launchdarkly-eventsource", "version": "1.7.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/49/8592c1d9c156d3c2d3f8c02e1c00260c3e0a7a10bcb50c942bd80c285c62/launchdarkly_eventsource-1.7.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "expiringdict", "version": "1.2.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cb/84/a04c59324445f4bcc98dc05b39a1cd07c242dde643c1a3c21e4f7beaf2f2/expiringdict-1.2.2-py3-none-any.whl"}}, {"metadata": {"name": "pyRFC3339", "version": "2.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/34/90/0200184d2124484f918054751ef997ed6409cb05b7e8dcbf5a22da4c4748/pyrfc3339-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "semver", "version": "3.0.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a6/24/4d91e05817e92e3a61c8a21e08fd0f390f5301f1c448b137c57c4bc6e543/semver-3.0.4-py3-none-any.whl"}}], "install_targets_hash": "e039dc9ecf1b28450bdeec6c73e7b68c"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "launchdarkly-server-sdk", "version": "9.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/58/bcede9c0f11b5c37b492ea993ed0599099e15f803b9fe98452558cfd6e96/launchdarkly_server_sdk-9.17.0-py3-none-any.whl"}}, {"metadata": {"name": "launchdarkly-eventsource", "version": "1.7.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/49/8592c1d9c156d3c2d3f8c02e1c00260c3e0a7a10bcb50c942bd80c285c62/launchdarkly_eventsource-1.7.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "expiringdict", "version": "1.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/84/a04c59324445f4bcc98dc05b39a1cd07c242dde643c1a3c21e4f7beaf2f2/expiringdict-1.2.2-py3-none-any.whl"}}, {"metadata": {"name": "pyRFC3339", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/34/90/0200184d2124484f918054751ef997ed6409cb05b7e8dcbf5a22da4c4748/pyrfc3339-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "semver", "version": "3.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/24/4d91e05817e92e3a61c8a21e08fd0f390f5301f1c448b137c57c4bc6e543/semver-3.0.4-py3-none-any.whl"}}], "install_targets_hash": "e039dc9ecf1b28450bdeec6c73e7b68c"} -{"python_version": "3.13", "dependencies": [{"metadata": {"name": "openai-agents", "version": "0.14.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/af/6e/1e9adcedcde7b163579b88a68f765a4915be4ead0713270386d9432cfd2f/openai_agents-0.14.8-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "2.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ae/f4/561ed79fd94876160018a5e75254cfcb9b0e62d4dded9dcb20072e86d623/openai-2.44.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "griffelib", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/b6/f65ac785d4ac90dcf7c831ac6256f5dd4a19780f4e1575b2c0d6eeebe319/griffelib-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d0/2b/c3eaf16f5d7c9bad66ea32f40a95bd169b29a91217fcc7f081375157e99c/jiter-0.16.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "mcp", "version": "1.29.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/c8/248b201f6d753d69fd5d6506011abbb35a946d9142b2ae311a948fd0be3d/mcp-1.29.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/81/4fa520eaffa8bd7d1525e644cd6d39e7d60b1592bc5b516693c7340b50f1/pydantic_core-2.46.4-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "types-requests", "version": "2.33.0.20260712"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/e7/010c87f559e216d83f9dc51e939633fd0d0ead3377340181ab0e223cd3b5/types_requests-2.33.0.20260712-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/86/0a70d3ae2f0f2256bb41302d9804dbca65d4360281e7feb3e1f94102ac46/websockets-16.1.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a4/a0/562247944386f7d4ef94467e84876600cc1e0f1b93239aaa9213d2bc3cbd/charset_normalizer-3.5.1-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/3a/764912c58293d95b6dcdf4cc255f9d10de310580ced547b082eb9d72018c/sse_starlette-3.4.8-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.52.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/79/4a20b54ab0491485ccd8c077db2d39187c7f12b3e15485d38a7be37c81b4/uvicorn-0.52.4-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/5c/59086b4aac5e879d38ddbcf74e4be7ade89cebc3eb199a55da998c3bb46a/cryptography-50.0.0-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f3/6b/686d9dc4359a8f163cfbbf89ee0b4e586431de22fe8248edb63a8cf50d49/rpds_py-2026.6.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/41/4c7042f317b9217502988f0873af87e16ad606dc20f84e546e3e6ce9764c/cffi-2.1.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "e39da8a431d3f40f0c1638f060e9b600"} -{"python_version": "3.13", "dependencies": [{"metadata": {"name": "openai-agents", "version": "0.14.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/af/6e/1e9adcedcde7b163579b88a68f765a4915be4ead0713270386d9432cfd2f/openai_agents-0.14.8-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "2.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ae/f4/561ed79fd94876160018a5e75254cfcb9b0e62d4dded9dcb20072e86d623/openai-2.44.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "griffelib", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/b6/f65ac785d4ac90dcf7c831ac6256f5dd4a19780f4e1575b2c0d6eeebe319/griffelib-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d0/2b/c3eaf16f5d7c9bad66ea32f40a95bd169b29a91217fcc7f081375157e99c/jiter-0.16.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "mcp", "version": "1.29.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/c8/248b201f6d753d69fd5d6506011abbb35a946d9142b2ae311a948fd0be3d/mcp-1.29.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/81/4fa520eaffa8bd7d1525e644cd6d39e7d60b1592bc5b516693c7340b50f1/pydantic_core-2.46.4-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "types-requests", "version": "2.33.0.20260712"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/e7/010c87f559e216d83f9dc51e939633fd0d0ead3377340181ab0e223cd3b5/types_requests-2.33.0.20260712-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/86/0a70d3ae2f0f2256bb41302d9804dbca65d4360281e7feb3e1f94102ac46/websockets-16.1.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a4/a0/562247944386f7d4ef94467e84876600cc1e0f1b93239aaa9213d2bc3cbd/charset_normalizer-3.5.1-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/3a/764912c58293d95b6dcdf4cc255f9d10de310580ced547b082eb9d72018c/sse_starlette-3.4.8-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.52.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/79/4a20b54ab0491485ccd8c077db2d39187c7f12b3e15485d38a7be37c81b4/uvicorn-0.52.4-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/5c/59086b4aac5e879d38ddbcf74e4be7ade89cebc3eb199a55da998c3bb46a/cryptography-50.0.0-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f3/6b/686d9dc4359a8f163cfbbf89ee0b4e586431de22fe8248edb63a8cf50d49/rpds_py-2026.6.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/41/4c7042f317b9217502988f0873af87e16ad606dc20f84e546e3e6ce9764c/cffi-2.1.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "e39da8a431d3f40f0c1638f060e9b600"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "openai-agents", "version": "0.14.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/af/6e/1e9adcedcde7b163579b88a68f765a4915be4ead0713270386d9432cfd2f/openai_agents-0.14.8-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "2.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ae/f4/561ed79fd94876160018a5e75254cfcb9b0e62d4dded9dcb20072e86d623/openai-2.44.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "griffelib", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/63/e876e789525063c840ccfa8857febdabd6523bcef9ce7eb979b9305ea895/griffelib-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/b1/34bfa29599d420423baac6ff7cada6674fe63d5a7a2ccb3900b904678783/jiter-0.17.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "mcp", "version": "1.30.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f5/f4/e58bc33317c92a0203664daaf00bf6f41166cc0149e5d6870a03f7cd004a/mcp-1.30.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/21/43/6323b1f8b217780454c61304bcd2b38ae4762f50754414124603ccc90bb2/pydantic_core-2.46.5-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/03/921a3d3c75785aca9ebfbfcabfbc3a1be12e2ab5265deb026d55a5a3f83e/tqdm-4.70.1-py3-none-any.whl"}}, {"metadata": {"name": "types-requests", "version": "2.33.0.20260906"}, "download_info": {"url": "https://files.pythonhosted.org/packages/60/4c/51ec821d22a45b4162fa3f3e9e94ea4c0f8c49e82363b10955baa5438391/types_requests-2.33.0.20260906-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/86/0a70d3ae2f0f2256bb41302d9804dbca65d4360281e7feb3e1f94102ac46/websockets-16.1.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a4/a0/562247944386f7d4ef94467e84876600cc1e0f1b93239aaa9213d2bc3cbd/charset_normalizer-3.5.1-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/97/672cb32ce0dfea44b740cb7b4f97038463b9cf7c0ead1aacf595572851d6/pyjwt-2.14.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/6a/2ba3ed4a69babf3afdddf7d8314a48d87562c0a442206bbc2a1b50d5efc0/sse_starlette-3.4.11-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.52.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/79/4a20b54ab0491485ccd8c077db2d39187c7f12b3e15485d38a7be37c81b4/uvicorn-0.52.4-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/19/797e2aaac9df6a66f1550f49979dc1b1e39ecd2077501c30efa81e8d5d67/cryptography-50.0.1-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f3/6b/686d9dc4359a8f163cfbbf89ee0b4e586431de22fe8248edb63a8cf50d49/rpds_py-2026.6.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/41/4c7042f317b9217502988f0873af87e16ad606dc20f84e546e3e6ce9764c/cffi-2.1.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "e39da8a431d3f40f0c1638f060e9b600"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "litellm", "version": "1.83.14"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/5c/1b5691575420135e90578543b2bf219497caa33cfd0af64cb38f30288450/litellm-1.83.14-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/42/07e1b543a61250783650df13da8ddcdc0d0a5538b2bd15cef6e042aefc61/aiohttp-3.13.4-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "click", "version": "8.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl"}}, {"metadata": {"name": "fastuuid", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/6d/64aee0a0f6a58eeabadd582e55d0d7d70258ffdd01d093b30c53d668303b/fastuuid-0.14.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/d9/a1e041c5e7caa9a05c925f4bdbdfb7f006d1f74996af53467bc394c97be7/importlib_metadata-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.23.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/4a/4f9dbeb84e8850557c02365a0eee0649abe5eb1d84af92a25731c6c0f922/jsonschema-4.23.0-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "2.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c9/30/844dc675ee6902579b8eef01ed23917cc9319a1c9c0c14ec6e39340c96d0/openai-2.24.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.12.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1f/05/dcf94486d5c5c8d34496abe271ac76c5b785507c8eae71b3708f1ad9b45a/tiktoken-0.12.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tokenizers", "version": "0.22.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2e/47/174dca0502ef88b28f1c9e06b73ce33500eedfac7a7692108aec220464e7/tokenizers-0.22.2-cp39-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.41.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/02/abfa0e0bda67faa65fef1c84971c7e45928e108fe24333c81f3bfe35d5f5/pydantic_core-2.41.5-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anthropic", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/5b/db4a854aebf5d33a5ab714c46af6eb85ee44f390ed29b7b325c00b9f11ed/anthropic-1.0.0-py3-none-any.whl"}}, {"metadata": {"name": "google-genai", "version": "2.19.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/e8/de0accd8cd004cf11252ca53fc5c3dda59bcf1856abfc7609842ceba7363/google_genai-2.19.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.56.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/b3/6117b2f24065cd7e2c4f140e9a193e215f089ca8ba314cf91eb9d0b7fe0a/google_auth-2.56.3-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/95/411ba65569158e862368917aaf56597f3e5fa3b91b0502919638465a08f3/httpx2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/74/d370e55600d9bcfa0d9794b0166126d49291a3d2b20c268fc98c453a4948/httpcore2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d0/2b/c3eaf16f5d7c9bad66ea32f40a95bd169b29a91217fcc7f081375157e99c/jiter-0.16.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/86/0a70d3ae2f0f2256bb41302d9804dbca65d4360281e7feb3e1f94102ac46/websockets-16.1.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a4/a0/562247944386f7d4ef94467e84876600cc1e0f1b93239aaa9213d2bc3cbd/charset_normalizer-3.5.1-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/5c/59086b4aac5e879d38ddbcf74e4be7ade89cebc3eb199a55da998c3bb46a/cryptography-50.0.0-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/ab/6e5080ee374f875296c4243c381bbdef97a9ac39c6e3ce1d5f7d42cb78d6/frozenlist-1.8.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "huggingface_hub", "version": "1.16.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/79/621a7dbb80c70974f73a597275351ebe03ce5bc65cb5f8f4acb5859252bc/huggingface_hub-1.16.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/76/55cd7186f498ed080a18440c9013011eb548f77ae1b297206d030eb1180a/multidict-6.7.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/12/a6ba6482bb5ea3260c000c9b20881c95fa11c6b30173715668259f844ed7/propcache-0.5.2-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.7.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/47/2d0564e93d87bc48618360ddca232a2ca612bbdf53ce8465d45ca5ce14ee/regex-2026.7.19-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f3/6b/686d9dc4359a8f163cfbbf89ee0b4e586431de22fe8248edb63a8cf50d49/rpds_py-2026.6.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/15/f0/7688d3f2cfff7590df2af38ec46d969f4281a4dddb08a9ad2eafbcdddf98/yarl-1.24.5-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "zipp", "version": "4.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/41/4c7042f317b9217502988f0873af87e16ad606dc20f84e546e3e6ce9764c/cffi-2.1.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "filelock", "version": "3.32.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/a4/9b63d595d748e3aff8812b65eacc1a2c4bd90b7c2012e08e72373b4835eb/filelock-3.32.4-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/3c/6a2bf344106328fd04963664a60b9bb6496fc25df8e962fcdc1367285fb9/fsspec-2026.7.0-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/69/55b8dcf636142ae660fec1869fcac14c4da2e8412e14d6eee1523be77e9f/hf_xet-1.6.0-cp38-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/3b/6163796d69c3977d1e4287bea4a6979161cbbdd170ebb430511e8e1999ce/pyasn1-0.6.4-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typer", "version": "0.27.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/43/89/9518bc0c3929bee36b3a4a8e3daddd6e03f92f9961c66d4983b837160543/typer-0.27.1-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "shellingham", "version": "1.5.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}], "install_targets_hash": "e4673157ab58986ef4f81da32839974c"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "litellm", "version": "1.83.14"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/5c/1b5691575420135e90578543b2bf219497caa33cfd0af64cb38f30288450/litellm-1.83.14-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/42/07e1b543a61250783650df13da8ddcdc0d0a5538b2bd15cef6e042aefc61/aiohttp-3.13.4-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "click", "version": "8.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl"}}, {"metadata": {"name": "fastuuid", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/6d/64aee0a0f6a58eeabadd582e55d0d7d70258ffdd01d093b30c53d668303b/fastuuid-0.14.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/d9/a1e041c5e7caa9a05c925f4bdbdfb7f006d1f74996af53467bc394c97be7/importlib_metadata-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.23.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/4a/4f9dbeb84e8850557c02365a0eee0649abe5eb1d84af92a25731c6c0f922/jsonschema-4.23.0-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "2.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c9/30/844dc675ee6902579b8eef01ed23917cc9319a1c9c0c14ec6e39340c96d0/openai-2.24.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.12.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1f/05/dcf94486d5c5c8d34496abe271ac76c5b785507c8eae71b3708f1ad9b45a/tiktoken-0.12.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tokenizers", "version": "0.22.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2e/47/174dca0502ef88b28f1c9e06b73ce33500eedfac7a7692108aec220464e7/tokenizers-0.22.2-cp39-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.41.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/02/abfa0e0bda67faa65fef1c84971c7e45928e108fe24333c81f3bfe35d5f5/pydantic_core-2.41.5-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anthropic", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/5b/db4a854aebf5d33a5ab714c46af6eb85ee44f390ed29b7b325c00b9f11ed/anthropic-1.0.0-py3-none-any.whl"}}, {"metadata": {"name": "google-genai", "version": "2.19.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/e8/de0accd8cd004cf11252ca53fc5c3dda59bcf1856abfc7609842ceba7363/google_genai-2.19.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.56.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/b3/6117b2f24065cd7e2c4f140e9a193e215f089ca8ba314cf91eb9d0b7fe0a/google_auth-2.56.3-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/95/411ba65569158e862368917aaf56597f3e5fa3b91b0502919638465a08f3/httpx2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/74/d370e55600d9bcfa0d9794b0166126d49291a3d2b20c268fc98c453a4948/httpcore2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d0/2b/c3eaf16f5d7c9bad66ea32f40a95bd169b29a91217fcc7f081375157e99c/jiter-0.16.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/86/0a70d3ae2f0f2256bb41302d9804dbca65d4360281e7feb3e1f94102ac46/websockets-16.1.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a4/a0/562247944386f7d4ef94467e84876600cc1e0f1b93239aaa9213d2bc3cbd/charset_normalizer-3.5.1-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/5c/59086b4aac5e879d38ddbcf74e4be7ade89cebc3eb199a55da998c3bb46a/cryptography-50.0.0-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/ab/6e5080ee374f875296c4243c381bbdef97a9ac39c6e3ce1d5f7d42cb78d6/frozenlist-1.8.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "huggingface_hub", "version": "1.16.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/79/621a7dbb80c70974f73a597275351ebe03ce5bc65cb5f8f4acb5859252bc/huggingface_hub-1.16.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/76/55cd7186f498ed080a18440c9013011eb548f77ae1b297206d030eb1180a/multidict-6.7.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/12/a6ba6482bb5ea3260c000c9b20881c95fa11c6b30173715668259f844ed7/propcache-0.5.2-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.7.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/47/2d0564e93d87bc48618360ddca232a2ca612bbdf53ce8465d45ca5ce14ee/regex-2026.7.19-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f3/6b/686d9dc4359a8f163cfbbf89ee0b4e586431de22fe8248edb63a8cf50d49/rpds_py-2026.6.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/15/f0/7688d3f2cfff7590df2af38ec46d969f4281a4dddb08a9ad2eafbcdddf98/yarl-1.24.5-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "zipp", "version": "4.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/41/4c7042f317b9217502988f0873af87e16ad606dc20f84e546e3e6ce9764c/cffi-2.1.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "filelock", "version": "3.32.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/a4/9b63d595d748e3aff8812b65eacc1a2c4bd90b7c2012e08e72373b4835eb/filelock-3.32.4-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/3c/6a2bf344106328fd04963664a60b9bb6496fc25df8e962fcdc1367285fb9/fsspec-2026.7.0-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/69/55b8dcf636142ae660fec1869fcac14c4da2e8412e14d6eee1523be77e9f/hf_xet-1.6.0-cp38-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/3b/6163796d69c3977d1e4287bea4a6979161cbbdd170ebb430511e8e1999ce/pyasn1-0.6.4-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typer", "version": "0.27.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/43/89/9518bc0c3929bee36b3a4a8e3daddd6e03f92f9961c66d4983b837160543/typer-0.27.1-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "shellingham", "version": "1.5.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}], "install_targets_hash": "e4673157ab58986ef4f81da32839974c"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "litellm", "version": "1.83.14"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/5c/1b5691575420135e90578543b2bf219497caa33cfd0af64cb38f30288450/litellm-1.83.14-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/42/07e1b543a61250783650df13da8ddcdc0d0a5538b2bd15cef6e042aefc61/aiohttp-3.13.4-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "click", "version": "8.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl"}}, {"metadata": {"name": "fastuuid", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/6d/64aee0a0f6a58eeabadd582e55d0d7d70258ffdd01d093b30c53d668303b/fastuuid-0.14.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/d9/a1e041c5e7caa9a05c925f4bdbdfb7f006d1f74996af53467bc394c97be7/importlib_metadata-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.23.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/4a/4f9dbeb84e8850557c02365a0eee0649abe5eb1d84af92a25731c6c0f922/jsonschema-4.23.0-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "2.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c9/30/844dc675ee6902579b8eef01ed23917cc9319a1c9c0c14ec6e39340c96d0/openai-2.24.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.12.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1f/05/dcf94486d5c5c8d34496abe271ac76c5b785507c8eae71b3708f1ad9b45a/tiktoken-0.12.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tokenizers", "version": "0.22.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2e/47/174dca0502ef88b28f1c9e06b73ce33500eedfac7a7692108aec220464e7/tokenizers-0.22.2-cp39-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.41.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/02/abfa0e0bda67faa65fef1c84971c7e45928e108fe24333c81f3bfe35d5f5/pydantic_core-2.41.5-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anthropic", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/5b/db4a854aebf5d33a5ab714c46af6eb85ee44f390ed29b7b325c00b9f11ed/anthropic-1.0.0-py3-none-any.whl"}}, {"metadata": {"name": "google-genai", "version": "2.19.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/e8/de0accd8cd004cf11252ca53fc5c3dda59bcf1856abfc7609842ceba7363/google_genai-2.19.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.56.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/b3/6117b2f24065cd7e2c4f140e9a193e215f089ca8ba314cf91eb9d0b7fe0a/google_auth-2.56.3-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/95/411ba65569158e862368917aaf56597f3e5fa3b91b0502919638465a08f3/httpx2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/74/d370e55600d9bcfa0d9794b0166126d49291a3d2b20c268fc98c453a4948/httpcore2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d0/2b/c3eaf16f5d7c9bad66ea32f40a95bd169b29a91217fcc7f081375157e99c/jiter-0.16.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/86/0a70d3ae2f0f2256bb41302d9804dbca65d4360281e7feb3e1f94102ac46/websockets-16.1.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a4/a0/562247944386f7d4ef94467e84876600cc1e0f1b93239aaa9213d2bc3cbd/charset_normalizer-3.5.1-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/5c/59086b4aac5e879d38ddbcf74e4be7ade89cebc3eb199a55da998c3bb46a/cryptography-50.0.0-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/ab/6e5080ee374f875296c4243c381bbdef97a9ac39c6e3ce1d5f7d42cb78d6/frozenlist-1.8.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "huggingface_hub", "version": "1.16.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/79/621a7dbb80c70974f73a597275351ebe03ce5bc65cb5f8f4acb5859252bc/huggingface_hub-1.16.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/76/55cd7186f498ed080a18440c9013011eb548f77ae1b297206d030eb1180a/multidict-6.7.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/12/a6ba6482bb5ea3260c000c9b20881c95fa11c6b30173715668259f844ed7/propcache-0.5.2-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.7.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/47/2d0564e93d87bc48618360ddca232a2ca612bbdf53ce8465d45ca5ce14ee/regex-2026.7.19-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f3/6b/686d9dc4359a8f163cfbbf89ee0b4e586431de22fe8248edb63a8cf50d49/rpds_py-2026.6.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/15/f0/7688d3f2cfff7590df2af38ec46d969f4281a4dddb08a9ad2eafbcdddf98/yarl-1.24.5-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "zipp", "version": "4.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/41/4c7042f317b9217502988f0873af87e16ad606dc20f84e546e3e6ce9764c/cffi-2.1.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "filelock", "version": "3.32.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/a4/9b63d595d748e3aff8812b65eacc1a2c4bd90b7c2012e08e72373b4835eb/filelock-3.32.4-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/3c/6a2bf344106328fd04963664a60b9bb6496fc25df8e962fcdc1367285fb9/fsspec-2026.7.0-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/69/55b8dcf636142ae660fec1869fcac14c4da2e8412e14d6eee1523be77e9f/hf_xet-1.6.0-cp38-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/3b/6163796d69c3977d1e4287bea4a6979161cbbdd170ebb430511e8e1999ce/pyasn1-0.6.4-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typer", "version": "0.27.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/43/89/9518bc0c3929bee36b3a4a8e3daddd6e03f92f9961c66d4983b837160543/typer-0.27.1-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "shellingham", "version": "1.5.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}], "install_targets_hash": "e4673157ab58986ef4f81da32839974c"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "litellm", "version": "1.83.14"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/5c/1b5691575420135e90578543b2bf219497caa33cfd0af64cb38f30288450/litellm-1.83.14-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/42/07e1b543a61250783650df13da8ddcdc0d0a5538b2bd15cef6e042aefc61/aiohttp-3.13.4-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "click", "version": "8.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl"}}, {"metadata": {"name": "fastuuid", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/6d/64aee0a0f6a58eeabadd582e55d0d7d70258ffdd01d093b30c53d668303b/fastuuid-0.14.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/d9/a1e041c5e7caa9a05c925f4bdbdfb7f006d1f74996af53467bc394c97be7/importlib_metadata-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.23.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/4a/4f9dbeb84e8850557c02365a0eee0649abe5eb1d84af92a25731c6c0f922/jsonschema-4.23.0-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "2.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c9/30/844dc675ee6902579b8eef01ed23917cc9319a1c9c0c14ec6e39340c96d0/openai-2.24.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.12.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1f/05/dcf94486d5c5c8d34496abe271ac76c5b785507c8eae71b3708f1ad9b45a/tiktoken-0.12.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tokenizers", "version": "0.22.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2e/47/174dca0502ef88b28f1c9e06b73ce33500eedfac7a7692108aec220464e7/tokenizers-0.22.2-cp39-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.41.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/02/abfa0e0bda67faa65fef1c84971c7e45928e108fe24333c81f3bfe35d5f5/pydantic_core-2.41.5-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anthropic", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/5b/db4a854aebf5d33a5ab714c46af6eb85ee44f390ed29b7b325c00b9f11ed/anthropic-1.0.0-py3-none-any.whl"}}, {"metadata": {"name": "google-genai", "version": "2.19.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/e8/de0accd8cd004cf11252ca53fc5c3dda59bcf1856abfc7609842ceba7363/google_genai-2.19.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.56.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/b3/6117b2f24065cd7e2c4f140e9a193e215f089ca8ba314cf91eb9d0b7fe0a/google_auth-2.56.3-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/95/411ba65569158e862368917aaf56597f3e5fa3b91b0502919638465a08f3/httpx2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/74/d370e55600d9bcfa0d9794b0166126d49291a3d2b20c268fc98c453a4948/httpcore2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d0/2b/c3eaf16f5d7c9bad66ea32f40a95bd169b29a91217fcc7f081375157e99c/jiter-0.16.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/86/0a70d3ae2f0f2256bb41302d9804dbca65d4360281e7feb3e1f94102ac46/websockets-16.1.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a4/a0/562247944386f7d4ef94467e84876600cc1e0f1b93239aaa9213d2bc3cbd/charset_normalizer-3.5.1-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/5c/59086b4aac5e879d38ddbcf74e4be7ade89cebc3eb199a55da998c3bb46a/cryptography-50.0.0-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/ab/6e5080ee374f875296c4243c381bbdef97a9ac39c6e3ce1d5f7d42cb78d6/frozenlist-1.8.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "huggingface_hub", "version": "1.16.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/79/621a7dbb80c70974f73a597275351ebe03ce5bc65cb5f8f4acb5859252bc/huggingface_hub-1.16.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/76/55cd7186f498ed080a18440c9013011eb548f77ae1b297206d030eb1180a/multidict-6.7.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/12/a6ba6482bb5ea3260c000c9b20881c95fa11c6b30173715668259f844ed7/propcache-0.5.2-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.7.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/47/2d0564e93d87bc48618360ddca232a2ca612bbdf53ce8465d45ca5ce14ee/regex-2026.7.19-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f3/6b/686d9dc4359a8f163cfbbf89ee0b4e586431de22fe8248edb63a8cf50d49/rpds_py-2026.6.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/15/f0/7688d3f2cfff7590df2af38ec46d969f4281a4dddb08a9ad2eafbcdddf98/yarl-1.24.5-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "zipp", "version": "4.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/41/4c7042f317b9217502988f0873af87e16ad606dc20f84e546e3e6ce9764c/cffi-2.1.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "filelock", "version": "3.32.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/a4/9b63d595d748e3aff8812b65eacc1a2c4bd90b7c2012e08e72373b4835eb/filelock-3.32.4-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/3c/6a2bf344106328fd04963664a60b9bb6496fc25df8e962fcdc1367285fb9/fsspec-2026.7.0-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/69/55b8dcf636142ae660fec1869fcac14c4da2e8412e14d6eee1523be77e9f/hf_xet-1.6.0-cp38-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/3b/6163796d69c3977d1e4287bea4a6979161cbbdd170ebb430511e8e1999ce/pyasn1-0.6.4-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typer", "version": "0.27.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/43/89/9518bc0c3929bee36b3a4a8e3daddd6e03f92f9961c66d4983b837160543/typer-0.27.1-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "shellingham", "version": "1.5.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}], "install_targets_hash": "e4673157ab58986ef4f81da32839974c"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "litellm", "version": "1.83.14"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/5c/1b5691575420135e90578543b2bf219497caa33cfd0af64cb38f30288450/litellm-1.83.14-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/42/07e1b543a61250783650df13da8ddcdc0d0a5538b2bd15cef6e042aefc61/aiohttp-3.13.4-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "click", "version": "8.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl"}}, {"metadata": {"name": "fastuuid", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/6d/64aee0a0f6a58eeabadd582e55d0d7d70258ffdd01d093b30c53d668303b/fastuuid-0.14.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/d9/a1e041c5e7caa9a05c925f4bdbdfb7f006d1f74996af53467bc394c97be7/importlib_metadata-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.23.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/4a/4f9dbeb84e8850557c02365a0eee0649abe5eb1d84af92a25731c6c0f922/jsonschema-4.23.0-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "2.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c9/30/844dc675ee6902579b8eef01ed23917cc9319a1c9c0c14ec6e39340c96d0/openai-2.24.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.12.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1f/05/dcf94486d5c5c8d34496abe271ac76c5b785507c8eae71b3708f1ad9b45a/tiktoken-0.12.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tokenizers", "version": "0.22.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2e/47/174dca0502ef88b28f1c9e06b73ce33500eedfac7a7692108aec220464e7/tokenizers-0.22.2-cp39-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.41.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/02/abfa0e0bda67faa65fef1c84971c7e45928e108fe24333c81f3bfe35d5f5/pydantic_core-2.41.5-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anthropic", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/5b/db4a854aebf5d33a5ab714c46af6eb85ee44f390ed29b7b325c00b9f11ed/anthropic-1.0.0-py3-none-any.whl"}}, {"metadata": {"name": "google-genai", "version": "2.19.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/e8/de0accd8cd004cf11252ca53fc5c3dda59bcf1856abfc7609842ceba7363/google_genai-2.19.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.56.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/b3/6117b2f24065cd7e2c4f140e9a193e215f089ca8ba314cf91eb9d0b7fe0a/google_auth-2.56.3-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/95/411ba65569158e862368917aaf56597f3e5fa3b91b0502919638465a08f3/httpx2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/74/d370e55600d9bcfa0d9794b0166126d49291a3d2b20c268fc98c453a4948/httpcore2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d0/2b/c3eaf16f5d7c9bad66ea32f40a95bd169b29a91217fcc7f081375157e99c/jiter-0.16.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/86/0a70d3ae2f0f2256bb41302d9804dbca65d4360281e7feb3e1f94102ac46/websockets-16.1.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a4/a0/562247944386f7d4ef94467e84876600cc1e0f1b93239aaa9213d2bc3cbd/charset_normalizer-3.5.1-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/5c/59086b4aac5e879d38ddbcf74e4be7ade89cebc3eb199a55da998c3bb46a/cryptography-50.0.0-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/ab/6e5080ee374f875296c4243c381bbdef97a9ac39c6e3ce1d5f7d42cb78d6/frozenlist-1.8.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "huggingface_hub", "version": "1.16.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/79/621a7dbb80c70974f73a597275351ebe03ce5bc65cb5f8f4acb5859252bc/huggingface_hub-1.16.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/76/55cd7186f498ed080a18440c9013011eb548f77ae1b297206d030eb1180a/multidict-6.7.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/12/a6ba6482bb5ea3260c000c9b20881c95fa11c6b30173715668259f844ed7/propcache-0.5.2-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.7.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/47/2d0564e93d87bc48618360ddca232a2ca612bbdf53ce8465d45ca5ce14ee/regex-2026.7.19-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f3/6b/686d9dc4359a8f163cfbbf89ee0b4e586431de22fe8248edb63a8cf50d49/rpds_py-2026.6.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/15/f0/7688d3f2cfff7590df2af38ec46d969f4281a4dddb08a9ad2eafbcdddf98/yarl-1.24.5-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "zipp", "version": "4.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/41/4c7042f317b9217502988f0873af87e16ad606dc20f84e546e3e6ce9764c/cffi-2.1.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "filelock", "version": "3.32.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/a4/9b63d595d748e3aff8812b65eacc1a2c4bd90b7c2012e08e72373b4835eb/filelock-3.32.4-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/3c/6a2bf344106328fd04963664a60b9bb6496fc25df8e962fcdc1367285fb9/fsspec-2026.7.0-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/69/55b8dcf636142ae660fec1869fcac14c4da2e8412e14d6eee1523be77e9f/hf_xet-1.6.0-cp38-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/3b/6163796d69c3977d1e4287bea4a6979161cbbdd170ebb430511e8e1999ce/pyasn1-0.6.4-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typer", "version": "0.27.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/43/89/9518bc0c3929bee36b3a4a8e3daddd6e03f92f9961c66d4983b837160543/typer-0.27.1-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "shellingham", "version": "1.5.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}], "install_targets_hash": "e4673157ab58986ef4f81da32839974c"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "pydantic-ai", "version": "1.76.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e5/c2/8f762847db3f76cafbfad18aea49305b82f15cd8c67f644d0abfc51fc92c/pydantic_ai-1.76.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-ai-slim", "version": "1.76.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/c6/7801af6853502bd53f00e88560f60270d8a2ab3bd8e19732d5ae8f261503/pydantic_ai_slim-1.76.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-evals", "version": "1.76.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e7/ab/14335e6c988ef2af23d33bb89cde4c737b904f84fb237758acf156bb0748/pydantic_evals-1.76.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-graph", "version": "1.76.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/4f/60b018568a33c907734613fb089ff288168faa6affb634e05e1a53f1f9e8/pydantic_graph-1.76.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "ag-ui-protocol", "version": "0.1.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/be/6c/af3d577e68c9474c99600e65b2c6283772aae187edca6f0f2f5cbd9f565a/ag_ui_protocol-0.1.22-py3-none-any.whl"}}, {"metadata": {"name": "anthropic", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/e3/34a88f0e1e854022a352d67f72ca9baa8b952d4541315088411ba2bfbc2a/anthropic-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "argcomplete", "version": "3.7.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/46/bd/551ee6af426af84ca33e02622be722925c196608e9127d731ef17c47f06e/argcomplete-3.7.2-py3-none-any.whl"}}, {"metadata": {"name": "boto3", "version": "1.43.90"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/c3/1d5c5ea7f599e2b80d122beeb2a9c1a8daff78325ea2391521e5fd5af1fd/boto3-1.43.90-py3-none-any.whl"}}, {"metadata": {"name": "cohere", "version": "7.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4a/c3/064a44c498bf6ae8621caa14307d3ef5471157f149e33cfd64417c8e9ad3/cohere-7.1.1-py3-none-any.whl"}}, {"metadata": {"name": "mcp", "version": "1.30.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f5/f4/e58bc33317c92a0203664daaf00bf6f41166cc0149e5d6870a03f7cd004a/mcp-1.30.0-py3-none-any.whl"}}, {"metadata": {"name": "fastmcp", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ac/14/6d950459cc831fa17fe2d1797926b6eb2d2f2af50f830e62d0c098cc1ec8/fastmcp-3.4.7-py3-none-any.whl"}}, {"metadata": {"name": "fastmcp-slim", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b4/97/e0e53642cd029a9a7635ae9c548f9f2cc995af5914e487b3df795664e4be/fastmcp_slim-3.4.7-py3-none-any.whl"}}, {"metadata": {"name": "genai-prices", "version": "0.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/48/a1/43fa2a4c5557cd977e83eecec265b0b77b726b0c7b9f2f180b46c6fdb458/genai_prices-0.1.6-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.57.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3b/27/0f7247b8002a1404fdb5412aeb15fb0fe70288eb8f88a5873d1c0d8262cf/google_auth-2.57.1-py3-none-any.whl"}}, {"metadata": {"name": "google-genai", "version": "2.22.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/de/96/0120d214958cb54f2b9c48da9f564a0e6eae269e9dd702415fb1d0551cc7/google_genai-2.22.0-py3-none-any.whl"}}, {"metadata": {"name": "griffelib", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/63/e876e789525063c840ccfa8857febdabd6523bcef9ce7eb979b9305ea895/griffelib-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "groq", "version": "1.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/f6/c3d8ea3194d7d7d8292edd4dbb4b6832d29c2eab04887dda4a742e83902c/groq-1.7.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "huggingface_hub", "version": "1.30.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c3/0e/3e45bbe0dd48f4e56b1d46649d342de853cd1c7e815323472ab62687f153/huggingface_hub-1.30.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "logfire", "version": "5.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/a0/f3a6a31587b85283cbb878446b2e55c9152624586d8d7322adab124fbc96/logfire-5.0.0-py3-none-any.whl"}}, {"metadata": {"name": "mistralai", "version": "2.9.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ac/c6/ce6371bd7a56e8c01a8f59baf4bc16d134eed4f3e2c593b5733087012936/mistralai-2.9.4-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "3.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/50/0d796ada2d1222cfe609cf435ce7a688450735cee401b24737882c9b9612/openai-3.10.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/6f/a04e900f465ff3221ccc395522503e2d10e79fa21f2723c8e177aae1e0d1/opentelemetry_api-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "prompt_toolkit", "version": "3.0.53"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/6f/84908cad2d6aa5144abcf7b42709fe4fdb459bc640ec7ac5786e7693dabc/prompt_toolkit-3.0.53-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/21/43/6323b1f8b217780454c61304bcd2b38ae4762f50754414124603ccc90bb2/pydantic_core-2.46.5-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic-handlebars", "version": "0.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/11/364bc401f1d8fdb3947079fc43ffdfbfc9132d065981a03a95d2e87440c4/pydantic_handlebars-0.2.1-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "pyperclip", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/80/fc9d01d5ed37ba4c42ca2b55b4339ae6e200b456be3a1aaddf4a9fa99b8c/pyperclip-1.11.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "temporalio", "version": "1.32.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d0/84/6cc96518a2aff3ce9fb132479811bb29db563fbcdc947c279df8f089721a/temporalio-1.32.0-cp310-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "nexus-rpc", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/11/52/6327a5f4fda01207205038a106a99848a41c83e933cd23ea2cab3d2ebc6c/nexus_rpc-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/5f/6448cfe278c3664ba9ec5b5ac08344341f7dc3d42888476e215a14eda2be/tiktoken-0.14.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "xai-sdk", "version": "1.19.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/b5/6f6783b97fb3a5498eb852ccaa706e1a2c0de2409480e3c99428e85234fe/xai_sdk-1.19.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "25.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/6b/e7f13410d391c6e55b4c007a8de024355389d7d459e3d64c42b2d33617e5/aiohttp-3.14.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.90"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/b8/65cbd0d65553c3e51d27159de4c74308ea008c652b05ed3f830f32667efb/botocore-1.43.90-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a4/a0/562247944386f7d4ef94467e84876600cc1e0f1b93239aaa9213d2bc3cbd/charset_normalizer-3.5.1-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/19/797e2aaac9df6a66f1550f49979dc1b1e39ecd2077501c30efa81e8d5d67/cryptography-50.0.1-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "eval_type_backport", "version": "0.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/a7/bb99bf5e6f78736ddb53480f2c3ff3702ffe2196a7c5e1661c03081d398e/eval_type_backport-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "executing", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "fastavro", "version": "1.12.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/83/39/f489a441d41cc9c0a8449fb1325d7a9c9eb57a5634e6ab19dfb0a1105324/fastavro-1.12.2-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "filelock", "version": "3.32.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cc/06/4f138f618dbea66803291274f228f01daf29f306fe8b96bc30dab765df75/filelock-3.32.6-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/3c/6a2bf344106328fd04963664a60b9bb6496fc25df8e962fcdc1367285fb9/fsspec-2026.7.0-py3-none-any.whl"}}, {"metadata": {"name": "googleapis-common-protos", "version": "1.75.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1a/7a/7d79170c6ce6f12e109df2b3879d6b934010cf4f99aea8de8b7e5408c174/googleapis_common_protos-1.75.3-py3-none-any.whl"}}, {"metadata": {"name": "grpcio", "version": "1.83.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c4/49/0b40bae059c619505c9b751cee6caa208e4904e290aaefa1728c4c2c67a5/grpcio-1.83.1-cp313-cp313-macosx_11_0_universal2.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/69/55b8dcf636142ae660fec1869fcac14c4da2e8412e14d6eee1523be77e9f/hf_xet-1.6.0-cp38-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/95/411ba65569158e862368917aaf56597f3e5fa3b91b0502919638465a08f3/httpx2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/74/d370e55600d9bcfa0d9794b0166126d49291a3d2b20c268fc98c453a4948/httpcore2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d0/2b/c3eaf16f5d7c9bad66ea32f40a95bd169b29a91217fcc7f081375157e99c/jiter-0.16.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonpath-python", "version": "1.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/8a/1270a6803bd821cbfcdda387eaa13cb41a7b1f7b9bd145979b3bfb9d6cb7/jsonpath_python-1.1.6-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "logfire-api", "version": "5.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/36/67/282646935c5af564ca89447f745aa292e2d36b554fac3d1effe5c75495ca/logfire_api-5.0.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-exporter-otlp-proto-http", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cd/d0/fdeb1a98d8d3a6205f5f297c51b4a9bfe65126ab60339669bbe3dd54c2e2/opentelemetry_exporter_otlp_proto_http-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-exporter-otlp-proto-common", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5e/71/65fd9d54c10b860f87c045ccee1264cab7011268895d3528818a29c1172a/opentelemetry_exporter_otlp_proto_common-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-proto", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d1/7c/8be563d68e93bbefa5c8affb82ddcff91b3ad858ce49957ba7b16fd3e0ab/opentelemetry_proto-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-instrumentation", "version": "0.65b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/40/7b/85eab1215f72adf0e68d3dc4a679b9bff993fa679ff34cd8dd378e2659fd/opentelemetry_instrumentation-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-semantic-conventions", "version": "0.65b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/0e/49df70d9b81fb5cbae4bbf2a49d865b09bcbcbc4eb53f5851b1027738d78/opentelemetry_semantic_conventions-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-instrumentation-httpx", "version": "0.65b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/0f/c6144096b4914bbf44b43ba21c962e8f333ff045770b50a3e79ed8bd455f/opentelemetry_instrumentation_httpx-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-util-http", "version": "0.65b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/23/3f/ab8d29df207ce5f470a07fa96ebb48af4e95b7fab7e7635311b9a32f2fab/opentelemetry_util_http-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-sdk", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e7/23/ff077e61886ee020a17ce9c8b6fa11c601c8d8345b09ea24f605445df62a/opentelemetry_sdk-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "protobuf", "version": "6.33.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5c/01/a3c3ed5cd186f39e7880f8303cc51385a198a81469d53d0fdecf1f64d929/protobuf-6.33.6-cp39-abi3-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "s3transfer", "version": "0.19.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/e7/5c595c75e9f41a44f30e526eda465ea0b4eec93470e074e4a111b253f13a/s3transfer-0.19.2-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/6a/2ba3ed4a69babf3afdddf7d8314a48d87562c0a442206bbc2a1b50d5efc0/sse_starlette-3.4.11-py3-none-any.whl"}}, {"metadata": {"name": "tokenizers", "version": "0.23.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/49/22da045a91732384d3a3771816bf188dc5a1f702c32e635afa7c679c0bef/tokenizers-0.23.2-cp310-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "types-protobuf", "version": "7.35.1.20260906"}, "download_info": {"url": "https://files.pythonhosted.org/packages/44/4e/f63e826c68f77ef875506d72f225918800346545ee99847bc28f3394f18d/types_protobuf-7.35.1.20260906-py3-none-any.whl"}}, {"metadata": {"name": "types-requests", "version": "2.33.0.20260906"}, "download_info": {"url": "https://files.pythonhosted.org/packages/60/4c/51ec821d22a45b4162fa3f3e9e94ea4c0f8c49e82363b10955baa5438391/types_requests-2.33.0.20260906-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.52.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/79/4a20b54ab0491485ccd8c077db2d39187c7f12b3e15485d38a7be37c81b4/uvicorn-0.52.4-py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c4/0e/57f6bb3024a597b2e8ec4aee710ffe62ddc95af2e2bb1ee7a7abdc22c68c/wcwidth-0.8.3-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/86/0a70d3ae2f0f2256bb41302d9804dbca65d4360281e7feb3e1f94102ac46/websockets-16.1.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "regex", "version": "2026.9.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e6/eb/5750ebabdb010ffb0d31fceae68c7a8f3876c06140c3bd6a7feff6240d6d/regex-2026.9.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "Authlib", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b8/c6/6f124bcfbbfb20fba22c939b4e43a06dccfc0e1ca20e5634ca573cb1e271/authlib-1.8.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/41/4c7042f317b9217502988f0873af87e16ad606dc20f84e546e3e6ce9764c/cffi-2.1.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cyclopts", "version": "4.25.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/0e/eadf712ca776fd96982c09348dd8f141ae6f96746a4eabc3e3fb54dea738/cyclopts-4.25.2-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/ab/6e5080ee374f875296c4243c381bbdef97a9ac39c6e3ce1d5f7d42cb78d6/frozenlist-1.8.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "joserfc", "version": "1.7.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/c5/82addfd375e5ee6520644e0553e4aadde92d668c4fc99cc716d337fe7bb3/joserfc-1.7.5-py3-none-any.whl"}}, {"metadata": {"name": "jsonref", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/ec/e1db9922bceb168197a558a2b8c03a7963f1afe93517ddd3cf99f202f996/jsonref-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-path", "version": "0.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/2c/9e69d73c4297508be9e3b64a970ea3971b3eb8db64ffc5802d40bd25981f/jsonschema_path-0.5.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/76/55cd7186f498ed080a18440c9013011eb548f77ae1b297206d030eb1180a/multidict-6.7.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "openapi-pydantic", "version": "0.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/cf/03675d8bd8ecbf4445504d8071adab19f5f993676795708e36402ab38263/openapi_pydantic-0.5.1-py3-none-any.whl"}}, {"metadata": {"name": "platformdirs", "version": "4.11.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/e1/5b7b8bbb55084d1425bcb9bc823ff519e1b2be05f6ebb0089e2eacc38413/platformdirs-4.11.8-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/12/a6ba6482bb5ea3260c000c9b20881c95fa11c6b30173715668259f844ed7/propcache-0.5.2-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "py-key-value-aio", "version": "0.4.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/95/b8ba862968712caa12a19666175334fa979e1f198b896a430adb3bacfe87/py_key_value_aio-0.4.5-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/3b/6163796d69c3977d1e4287bea4a6979161cbbdd170ebb430511e8e1999ce/pyasn1-0.6.4-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f3/6b/686d9dc4359a8f163cfbbf89ee0b4e586431de22fe8248edb63a8cf50d49/rpds_py-2026.6.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "uncalled-for", "version": "0.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a2/40/97cec87c077eb3291fc7905e6633e08b7ca593c57d30238444bcb6bb3d53/uncalled_for-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "watchfiles", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/31/3a/0da302f2307aee316922806ebd5726c542cbd787c938271cf14a074c7daf/watchfiles-1.2.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "wrapt", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c3/ab/1dbf50802bea3b46192fd0dc39bb0eb2e77a064c813b2bbd88d2888ad49f/wrapt-2.4.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/15/f0/7688d3f2cfff7590df2af38ec46d969f4281a4dddb08a9ad2eafbcdddf98/yarl-1.24.5-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiofile", "version": "3.12.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/79/6e45e778c4c3cab39e0937b007b720c15f76c50c6453d153282d0fcc3588/aiofile-3.12.3-py3-none-any.whl"}}, {"metadata": {"name": "beartype", "version": "0.22.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/cc/18245721fa7747065ab478316c7fea7c74777d07f37ae60db2e84f8172e8/beartype-0.22.9-py3-none-any.whl"}}, {"metadata": {"name": "cachetools", "version": "7.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/3d/9487690d0e937854db587205c66bab3c3cf88d9f00ed380b74cb88cc94ee/cachetools-7.1.8-py3-none-any.whl"}}, {"metadata": {"name": "email-validator", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "keyring", "version": "25.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/db/e655086b7f3a705df045bf0933bdd9c2f79bb3c97bfef1384598bb79a217/keyring-25.7.0-py3-none-any.whl"}}, {"metadata": {"name": "pathable", "version": "0.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a2/e8/6d75ffd9784bce2e93d1ae4415649427e39a53bb172d4672b2b59c6f0a7b/pathable-0.6.0-py3-none-any.whl"}}, {"metadata": {"name": "rich-rst", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/68/1fc93dd759605b5d00fc98b50200739e41ed32bd22d6ba35ca6c3932371b/rich_rst-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "caio", "version": "0.12.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/11/ab/12e4896a1e74ff9a65c84894acdfc3b70b8b49e63874a37e0dffcc31f396/caio-0.12.4-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "dnspython", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.classes", "version": "3.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/66/b15ce62552d84bbfcec9a4873ab79d993a1dd4edb922cbfccae192bd5b5f/jaraco.classes-3.4.0-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.context", "version": "6.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f2/58/bc8954bda5fcda97bd7c19be11b85f91973d67a706ed4a3aec33e7de22db/jaraco_context-6.1.2-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.functools", "version": "4.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/02/36/ecc85bc96c273dc8a11273ed4782272975e6338d4a3e9228621175edf0e3/jaraco_functools-4.6.0-py3-none-any.whl"}}, {"metadata": {"name": "more-itertools", "version": "11.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/3d/1087453384dbde46a8c7f9356eead2c58be8a7bf156bca40243377c85715/more_itertools-11.1.0-py3-none-any.whl"}}], "install_targets_hash": "e7b1126e413bef21402b41f19a1e7222"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "mcp", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/af/8644cc5fa26a59afd2df2e98eeb19e72926887fa4b7441aba4ff661140db/mcp-2.1.1-py3-none-any.whl"}}, {"metadata": {"name": "mcp-types", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/d0/242e63c510f4a17381f55b1549a3f94f5687a0595984febd2b6f87a687a0/mcp_types-2.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/6f/a04e900f465ff3221ccc395522503e2d10e79fa21f2723c8e177aae1e0d1/opentelemetry_api-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/21/43/6323b1f8b217780454c61304bcd2b38ae4762f50754414124603ccc90bb2/pydantic_core-2.46.5-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/97/672cb32ce0dfea44b740cb7b4f97038463b9cf7c0ead1aacf595572851d6/pyjwt-2.14.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/6a/2ba3ed4a69babf3afdddf7d8314a48d87562c0a442206bbc2a1b50d5efc0/sse_starlette-3.4.11-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.53.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/76/18/0eea75741ee812e9f598b687619ce2454f6c3a1c5cd21ea990ec6bd26f45/uvicorn-0.53.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/19/797e2aaac9df6a66f1550f49979dc1b1e39ecd2077501c30efa81e8d5d67/cryptography-50.0.1-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f3/6b/686d9dc4359a8f163cfbbf89ee0b4e586431de22fe8248edb63a8cf50d49/rpds_py-2026.6.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/41/4c7042f317b9217502988f0873af87e16ad606dc20f84e546e3e6ce9764c/cffi-2.1.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "f0d2472e8e45f37ecbb75fd658385dd5"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "langchain", "version": "0.3.30"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/54/c0775c29bf9ae27c8cbf8484ad600edd2e787a0eacf3a374cb6561613de9/langchain-0.3.30-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "langchain-openai", "version": "0.3.35"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d8/d5/c90c5478215c20ee71d8feaf676f7ffd78d0568f8c98bd83f81ce7562ed7/langchain_openai-0.3.35-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "2.54.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/a8/bb76c7356de8ad57f59d5ff993d434df0607f07f08bcc9c9a5c275e399c0/openai-2.54.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "langchain-community", "version": "0.3.31"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e6/0a/b8848db67ad7c8d4652cb6f4cb78d49b5b5e6e8e51d695d62025aa3f7dbc/langchain_community-0.3.31-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/6b/e7f13410d391c6e55b4c007a8de024355389d7d459e3d64c42b2d33617e5/aiohttp-3.14.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "dataclasses-json", "version": "0.6.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c3/be/d0d44e092656fe7a06b55e6103cbce807cdbdee17884a5367c68c9860853/dataclasses_json-0.6.7-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d0/2b/c3eaf16f5d7c9bad66ea32f40a95bd169b29a91217fcc7f081375157e99c/jiter-0.16.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "langchain-core", "version": "0.3.86"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/93/ba19ca54701c6118e68f8785949b6c0eab1df3a5cfa5310508cc86877994/langchain_core-0.3.86-py3-none-any.whl"}}, {"metadata": {"name": "langchain-text-splitters", "version": "0.3.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/0d/41a51b40d24ff0384ec4f7ab8dd3dcea8353c05c973836b5e289f1465d4f/langchain_text_splitters-0.3.11-py3-none-any.whl"}}, {"metadata": {"name": "langsmith", "version": "0.11.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/85/0ad6df25588122760b2b40ec182eafc55532c9e66015c83e16675bd34a29/langsmith-0.11.1-py3-none-any.whl"}}, {"metadata": {"name": "numpy", "version": "2.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3c/79/81e0bf24f4d020a2b1d5cd297a9f60c3f24eeb116f9bba5870443f7b6a4a/numpy-2.5.2-cp313-cp313-macosx_14_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/81/4fa520eaffa8bd7d1525e644cd6d39e7d60b1592bc5b516693c7340b50f1/pydantic_core-2.46.4-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "SQLAlchemy", "version": "2.0.52"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/18/e30c6fe1eca1bf34a39fbdd6066121cc9974c850faf6f349eac563697a26/sqlalchemy-2.0.52-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/5f/6448cfe278c3664ba9ec5b5ac08344341f7dc3d42888476e215a14eda2be/tiktoken-0.14.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a4/a0/562247944386f7d4ef94467e84876600cc1e0f1b93239aaa9213d2bc3cbd/charset_normalizer-3.5.1-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/ab/6e5080ee374f875296c4243c381bbdef97a9ac39c6e3ce1d5f7d42cb78d6/frozenlist-1.8.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonpatch", "version": "1.33"}, "download_info": {"url": "https://files.pythonhosted.org/packages/73/07/02e16ed01e04a374e644b575638ec7987ae846d25ad97bcc9945a3ee4b0e/jsonpatch-1.33-py2.py3-none-any.whl"}}, {"metadata": {"name": "marshmallow", "version": "3.26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/be/2f/5108cb3ee4ba6501748c4908b908e55f42a5b66245b4cfe0c99326e1ef6e/marshmallow-3.26.2-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/76/55cd7186f498ed080a18440c9013011eb548f77ae1b297206d030eb1180a/multidict-6.7.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "orjson", "version": "3.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f8/4a/bc87c45e7ec639d35ebefd62618e01939531ac8e171426606a01bda05914/orjson-3.12.0-cp313-cp313-macosx_15_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "25.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/12/a6ba6482bb5ea3260c000c9b20881c95fa11c6b30173715668259f844ed7/propcache-0.5.2-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing-inspect", "version": "0.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/f3/107a22063bf27bdccf2024833d3445f4eea42b2e598abfbd46f6a63b6cb0/typing_inspect-0.9.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "uuid_utils", "version": "0.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/dd/614fb9912157ac0128e6050859ccf06d9f13df9a944a803e8f80f6157e38/uuid_utils-0.17.0-cp313-cp313-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl"}}, {"metadata": {"name": "websockets", "version": "17.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a2/ef/cc994494bf7d97e41833f6ff55c24f535e4d527a10370b9631737e9c2f00/websockets-17.0.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "xxhash", "version": "4.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/e0/934af8d99bb5885711006bec30a691f728edd513d2c40f053f887d8e7577/xxhash-4.0.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/15/f0/7688d3f2cfff7590df2af38ec46d969f4281a4dddb08a9ad2eafbcdddf98/yarl-1.24.5-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "zstandard", "version": "0.25.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/06/9ae96a3e5dcfd119377ba33d4c42a7d89da1efabd5cb3e366b156c45ff4d/zstandard-0.25.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "regex", "version": "2026.7.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/47/2d0564e93d87bc48618360ddca232a2ca612bbdf53ce8465d45ca5ce14ee/regex-2026.7.19-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "jsonpointer", "version": "3.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/6a/a83720e953b1682d2d109d3c2dbb0bc9bf28cc1cbc205be4ef4be5da709d/jsonpointer-3.1.1-py3-none-any.whl"}}, {"metadata": {"name": "mypy_extensions", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl"}}], "install_targets_hash": "f4e4bb9460bd93d74ce9abd6823fc735"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "langchain", "version": "0.3.30"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/54/c0775c29bf9ae27c8cbf8484ad600edd2e787a0eacf3a374cb6561613de9/langchain-0.3.30-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "langchain-openai", "version": "0.3.35"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d8/d5/c90c5478215c20ee71d8feaf676f7ffd78d0568f8c98bd83f81ce7562ed7/langchain_openai-0.3.35-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "2.54.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/a8/bb76c7356de8ad57f59d5ff993d434df0607f07f08bcc9c9a5c275e399c0/openai-2.54.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "langchain-community", "version": "0.3.31"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e6/0a/b8848db67ad7c8d4652cb6f4cb78d49b5b5e6e8e51d695d62025aa3f7dbc/langchain_community-0.3.31-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/6b/e7f13410d391c6e55b4c007a8de024355389d7d459e3d64c42b2d33617e5/aiohttp-3.14.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "dataclasses-json", "version": "0.6.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c3/be/d0d44e092656fe7a06b55e6103cbce807cdbdee17884a5367c68c9860853/dataclasses_json-0.6.7-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d0/2b/c3eaf16f5d7c9bad66ea32f40a95bd169b29a91217fcc7f081375157e99c/jiter-0.16.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "langchain-core", "version": "0.3.86"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/93/ba19ca54701c6118e68f8785949b6c0eab1df3a5cfa5310508cc86877994/langchain_core-0.3.86-py3-none-any.whl"}}, {"metadata": {"name": "langchain-text-splitters", "version": "0.3.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/0d/41a51b40d24ff0384ec4f7ab8dd3dcea8353c05c973836b5e289f1465d4f/langchain_text_splitters-0.3.11-py3-none-any.whl"}}, {"metadata": {"name": "langsmith", "version": "0.11.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/85/0ad6df25588122760b2b40ec182eafc55532c9e66015c83e16675bd34a29/langsmith-0.11.1-py3-none-any.whl"}}, {"metadata": {"name": "numpy", "version": "2.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3c/79/81e0bf24f4d020a2b1d5cd297a9f60c3f24eeb116f9bba5870443f7b6a4a/numpy-2.5.2-cp313-cp313-macosx_14_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/81/4fa520eaffa8bd7d1525e644cd6d39e7d60b1592bc5b516693c7340b50f1/pydantic_core-2.46.4-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "SQLAlchemy", "version": "2.0.52"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/18/e30c6fe1eca1bf34a39fbdd6066121cc9974c850faf6f349eac563697a26/sqlalchemy-2.0.52-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/5f/6448cfe278c3664ba9ec5b5ac08344341f7dc3d42888476e215a14eda2be/tiktoken-0.14.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a4/a0/562247944386f7d4ef94467e84876600cc1e0f1b93239aaa9213d2bc3cbd/charset_normalizer-3.5.1-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/ab/6e5080ee374f875296c4243c381bbdef97a9ac39c6e3ce1d5f7d42cb78d6/frozenlist-1.8.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonpatch", "version": "1.33"}, "download_info": {"url": "https://files.pythonhosted.org/packages/73/07/02e16ed01e04a374e644b575638ec7987ae846d25ad97bcc9945a3ee4b0e/jsonpatch-1.33-py2.py3-none-any.whl"}}, {"metadata": {"name": "marshmallow", "version": "3.26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/be/2f/5108cb3ee4ba6501748c4908b908e55f42a5b66245b4cfe0c99326e1ef6e/marshmallow-3.26.2-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/76/55cd7186f498ed080a18440c9013011eb548f77ae1b297206d030eb1180a/multidict-6.7.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "orjson", "version": "3.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f8/4a/bc87c45e7ec639d35ebefd62618e01939531ac8e171426606a01bda05914/orjson-3.12.0-cp313-cp313-macosx_15_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "25.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/12/a6ba6482bb5ea3260c000c9b20881c95fa11c6b30173715668259f844ed7/propcache-0.5.2-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing-inspect", "version": "0.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/f3/107a22063bf27bdccf2024833d3445f4eea42b2e598abfbd46f6a63b6cb0/typing_inspect-0.9.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "uuid_utils", "version": "0.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/dd/614fb9912157ac0128e6050859ccf06d9f13df9a944a803e8f80f6157e38/uuid_utils-0.17.0-cp313-cp313-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl"}}, {"metadata": {"name": "websockets", "version": "17.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a2/ef/cc994494bf7d97e41833f6ff55c24f535e4d527a10370b9631737e9c2f00/websockets-17.0.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "xxhash", "version": "4.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/e0/934af8d99bb5885711006bec30a691f728edd513d2c40f053f887d8e7577/xxhash-4.0.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/15/f0/7688d3f2cfff7590df2af38ec46d969f4281a4dddb08a9ad2eafbcdddf98/yarl-1.24.5-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "zstandard", "version": "0.25.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/06/9ae96a3e5dcfd119377ba33d4c42a7d89da1efabd5cb3e366b156c45ff4d/zstandard-0.25.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "regex", "version": "2026.7.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/47/2d0564e93d87bc48618360ddca232a2ca612bbdf53ce8465d45ca5ce14ee/regex-2026.7.19-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "jsonpointer", "version": "3.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/6a/a83720e953b1682d2d109d3c2dbb0bc9bf28cc1cbc205be4ef4be5da709d/jsonpointer-3.1.1-py3-none-any.whl"}}, {"metadata": {"name": "mypy_extensions", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl"}}], "install_targets_hash": "f4e4bb9460bd93d74ce9abd6823fc735"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "langchain", "version": "0.3.30"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/54/c0775c29bf9ae27c8cbf8484ad600edd2e787a0eacf3a374cb6561613de9/langchain-0.3.30-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "langchain-openai", "version": "0.3.35"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d8/d5/c90c5478215c20ee71d8feaf676f7ffd78d0568f8c98bd83f81ce7562ed7/langchain_openai-0.3.35-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "2.54.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/a8/bb76c7356de8ad57f59d5ff993d434df0607f07f08bcc9c9a5c275e399c0/openai-2.54.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "langchain-community", "version": "0.3.31"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e6/0a/b8848db67ad7c8d4652cb6f4cb78d49b5b5e6e8e51d695d62025aa3f7dbc/langchain_community-0.3.31-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/6b/e7f13410d391c6e55b4c007a8de024355389d7d459e3d64c42b2d33617e5/aiohttp-3.14.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "dataclasses-json", "version": "0.6.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c3/be/d0d44e092656fe7a06b55e6103cbce807cdbdee17884a5367c68c9860853/dataclasses_json-0.6.7-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d0/2b/c3eaf16f5d7c9bad66ea32f40a95bd169b29a91217fcc7f081375157e99c/jiter-0.16.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "langchain-core", "version": "0.3.86"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/93/ba19ca54701c6118e68f8785949b6c0eab1df3a5cfa5310508cc86877994/langchain_core-0.3.86-py3-none-any.whl"}}, {"metadata": {"name": "langchain-text-splitters", "version": "0.3.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/0d/41a51b40d24ff0384ec4f7ab8dd3dcea8353c05c973836b5e289f1465d4f/langchain_text_splitters-0.3.11-py3-none-any.whl"}}, {"metadata": {"name": "langsmith", "version": "0.11.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/85/0ad6df25588122760b2b40ec182eafc55532c9e66015c83e16675bd34a29/langsmith-0.11.1-py3-none-any.whl"}}, {"metadata": {"name": "numpy", "version": "2.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3c/79/81e0bf24f4d020a2b1d5cd297a9f60c3f24eeb116f9bba5870443f7b6a4a/numpy-2.5.2-cp313-cp313-macosx_14_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/81/4fa520eaffa8bd7d1525e644cd6d39e7d60b1592bc5b516693c7340b50f1/pydantic_core-2.46.4-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "SQLAlchemy", "version": "2.0.52"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/18/e30c6fe1eca1bf34a39fbdd6066121cc9974c850faf6f349eac563697a26/sqlalchemy-2.0.52-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/5f/6448cfe278c3664ba9ec5b5ac08344341f7dc3d42888476e215a14eda2be/tiktoken-0.14.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a4/a0/562247944386f7d4ef94467e84876600cc1e0f1b93239aaa9213d2bc3cbd/charset_normalizer-3.5.1-cp313-cp313-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/ab/6e5080ee374f875296c4243c381bbdef97a9ac39c6e3ce1d5f7d42cb78d6/frozenlist-1.8.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonpatch", "version": "1.33"}, "download_info": {"url": "https://files.pythonhosted.org/packages/73/07/02e16ed01e04a374e644b575638ec7987ae846d25ad97bcc9945a3ee4b0e/jsonpatch-1.33-py2.py3-none-any.whl"}}, {"metadata": {"name": "marshmallow", "version": "3.26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/be/2f/5108cb3ee4ba6501748c4908b908e55f42a5b66245b4cfe0c99326e1ef6e/marshmallow-3.26.2-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/76/55cd7186f498ed080a18440c9013011eb548f77ae1b297206d030eb1180a/multidict-6.7.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "orjson", "version": "3.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f8/4a/bc87c45e7ec639d35ebefd62618e01939531ac8e171426606a01bda05914/orjson-3.12.0-cp313-cp313-macosx_15_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "25.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/12/a6ba6482bb5ea3260c000c9b20881c95fa11c6b30173715668259f844ed7/propcache-0.5.2-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing-inspect", "version": "0.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/f3/107a22063bf27bdccf2024833d3445f4eea42b2e598abfbd46f6a63b6cb0/typing_inspect-0.9.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "uuid_utils", "version": "0.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/dd/614fb9912157ac0128e6050859ccf06d9f13df9a944a803e8f80f6157e38/uuid_utils-0.17.0-cp313-cp313-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl"}}, {"metadata": {"name": "websockets", "version": "17.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a2/ef/cc994494bf7d97e41833f6ff55c24f535e4d527a10370b9631737e9c2f00/websockets-17.0.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "xxhash", "version": "4.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/e0/934af8d99bb5885711006bec30a691f728edd513d2c40f053f887d8e7577/xxhash-4.0.1-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/15/f0/7688d3f2cfff7590df2af38ec46d969f4281a4dddb08a9ad2eafbcdddf98/yarl-1.24.5-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "zstandard", "version": "0.25.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/06/9ae96a3e5dcfd119377ba33d4c42a7d89da1efabd5cb3e366b156c45ff4d/zstandard-0.25.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "regex", "version": "2026.7.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/47/2d0564e93d87bc48618360ddca232a2ca612bbdf53ce8465d45ca5ce14ee/regex-2026.7.19-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "jsonpointer", "version": "3.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/6a/a83720e953b1682d2d109d3c2dbb0bc9bf28cc1cbc205be4ef4be5da709d/jsonpointer-3.1.1-py3-none-any.whl"}}, {"metadata": {"name": "mypy_extensions", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl"}}], "install_targets_hash": "f4e4bb9460bd93d74ce9abd6823fc735"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "asyncpg", "version": "0.31.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/71/157d611c791a5e2d0423f09f027bd499935f0906e0c2a416ce712ba51ef3/asyncpg-0.31.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "f737563b075b37dba35f4a4e7631e9cd"} -{"python_version": "3.13", "dependencies": [{"metadata": {"name": "mcp", "version": "1.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c9/82/4d0df23d5ff5bb982a59ad597bc7cb9920f2650278ccefb8e0d85c5ce3d4/mcp-1.15.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/81/4fa520eaffa8bd7d1525e644cd6d39e7d60b1592bc5b516693c7340b50f1/pydantic_core-2.46.4-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/77/c1/6e422f34e569cf8e18df68d1939c81c099d2b61e4f7d9621c8a77560799c/pydantic_settings-2.14.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/36/e10c1d1b7ca881d2625db2ec28508578499187bb1c389952c398474e1834/sse_starlette-3.4.6-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.51.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/45/ec/dbb7e5a6b91f86bfb9eb7d2988a2730907b6a729875b949c7f022e8b88fa/uvicorn-0.51.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f3/6b/686d9dc4359a8f163cfbbf89ee0b4e586431de22fe8248edb63a8cf50d49/rpds_py-2026.6.3-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}], "install_targets_hash": "f86dcfa82da844a490c00542989aac98"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "asyncpg", "version": "0.31.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/71/157d611c791a5e2d0423f09f027bd499935f0906e0c2a416ce712ba51ef3/asyncpg-0.31.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "f737563b075b37dba35f4a4e7631e9cd"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "asyncpg", "version": "0.31.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/71/157d611c791a5e2d0423f09f027bd499935f0906e0c2a416ce712ba51ef3/asyncpg-0.31.0-cp313-cp313-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "f737563b075b37dba35f4a4e7631e9cd"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "redis", "version": "6.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/02/89e2ed7e85db6c93dfa9e8f691c5087df4e3551ab39081a4d7c6d1f90e05/redis-6.4.0-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/4d/e6e40f93031adbf654d34e542bd396e9f3bc1c6209b40c920d58c9e1317a/fakeredis-2.36.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "7.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ff/f6e8b8f39e08547faece4bd80f89d5a8de68a38b2d179cc1c4490ffa3286/pytest-7.4.4-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.23.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ee/82/62e2d63639ecb0fbe8a7ee59ef0bc69a4669ec50f6d3459f74ad4e4189a2/pytest_asyncio-0.23.8-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}], "install_targets_hash": "f973477f4ba55b7a5455bcb45caae3a9"} +{"python_version": "3.13", "dependencies": [{"metadata": {"name": "redis", "version": "6.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/02/89e2ed7e85db6c93dfa9e8f691c5087df4e3551ab39081a4d7c6d1f90e05/redis-6.4.0-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/4d/e6e40f93031adbf654d34e542bd396e9f3bc1c6209b40c920d58c9e1317a/fakeredis-2.36.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "7.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ff/f6e8b8f39e08547faece4bd80f89d5a8de68a38b2d179cc1c4490ffa3286/pytest-7.4.4-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.23.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ee/82/62e2d63639ecb0fbe8a7ee59ef0bc69a4669ec50f6d3459f74ad4e4189a2/pytest_asyncio-0.23.8-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}], "install_targets_hash": "f973477f4ba55b7a5455bcb45caae3a9"} {"python_version": "3.13", "dependencies": [{"metadata": {"name": "redis", "version": "6.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/02/89e2ed7e85db6c93dfa9e8f691c5087df4e3551ab39081a4d7c6d1f90e05/redis-6.4.0-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/4d/e6e40f93031adbf654d34e542bd396e9f3bc1c6209b40c920d58c9e1317a/fakeredis-2.36.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "7.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ff/f6e8b8f39e08547faece4bd80f89d5a8de68a38b2d179cc1c4490ffa3286/pytest-7.4.4-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.23.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ee/82/62e2d63639ecb0fbe8a7ee59ef0bc69a4669ec50f6d3459f74ad4e4189a2/pytest_asyncio-0.23.8-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}], "install_targets_hash": "f973477f4ba55b7a5455bcb45caae3a9"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "openai-agents", "version": "0.22.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f8/56/f5d32edb2e890a5dea9824cb76d179cef47c6a5ea8269d3559d092936106/openai_agents-0.22.3-py3-none-any.whl"}}, {"metadata": {"name": "griffelib", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/63/e876e789525063c840ccfa8857febdabd6523bcef9ce7eb979b9305ea895/griffelib-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "mcp", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/ff/8e7eade68b8a28f7da0ed1085544341b51f9c935dbf6b95c76b7edfea6a0/mcp-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mcp-types", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8f/d7/6ffba5d8cd5dd9b8a19478875c50e04945314ba5074e84d749283f27f62d/mcp_types-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "3.16.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/17/72/2b1fe3e303db76ab2ba0c2de2b57822869bcb588db82334d4ff3aea8acf2/openai-3.16.2-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/96/c1813dcca15c5a370145a448aaea7d1f83f6f0228a5f1130e79340ee385f/jiter-0.17.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/64/a4e536cb16d7f61a7fd3120b46c577fc7fa7325992f69c4f52bc786d77d8/pydantic_core-2.46.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/ee/e4e10a94d51cd1ee638aa7e00b65399e6b2a4e8376ab6d2eac9f95586671/charset_normalizer-3.5.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b2/39/26762f734113e22da2b942c3aca85798e0c0405d64c256549540ff31e5a1/websockets-16.1.1-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/6f/a04e900f465ff3221ccc395522503e2d10e79fa21f2723c8e177aae1e0d1/opentelemetry_api-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/97/672cb32ce0dfea44b740cb7b4f97038463b9cf7c0ead1aacf595572851d6/pyjwt-2.14.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1a/01/0127d11a762b31a9ee0221894f540318761783f3fdc4bc5d057698caebd5/cryptography-50.0.1-cp314-cp314t-manylinux_2_34_x86_64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/95/eff5f0cee78d2eabc7eebffec40d3fc1876b5f3c95582e018bb4b99601f2/cffi-2.1.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8e/f4/b7ac49f30013aba8f7b9566b1dd07e81de95e708c1374b7bacc5b9bc5c9c/rpds_py-2026.6.3-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/6a/2ba3ed4a69babf3afdddf7d8314a48d87562c0a442206bbc2a1b50d5efc0/sse_starlette-3.4.11-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.53.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/76/18/0eea75741ee812e9f598b687619ce2454f6c3a1c5cd21ea990ec6bd26f45/uvicorn-0.53.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "00309e9160aac64c6c329f5b3a40b95e"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "pyreqwest", "version": "0.12.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/db/12/2f32c605dcdc6bca0d01fb12205aaef1b19c29e8f8333fdfdf7ee2f7123c/pyreqwest-0.12.4.tar.gz"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}], "install_targets_hash": "00e5416511b26b0d583fe31710cc73eb"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "pyreqwest", "version": "0.12.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/db/12/2f32c605dcdc6bca0d01fb12205aaef1b19c29e8f8333fdfdf7ee2f7123c/pyreqwest-0.12.4.tar.gz"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}], "install_targets_hash": "00e5416511b26b0d583fe31710cc73eb"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "pyreqwest", "version": "0.12.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/db/12/2f32c605dcdc6bca0d01fb12205aaef1b19c29e8f8333fdfdf7ee2f7123c/pyreqwest-0.12.4.tar.gz"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}], "install_targets_hash": "00e5416511b26b0d583fe31710cc73eb"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "litestar", "version": "2.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/ce/4697b547790f23d2fcc37a928d48c38140cf86360e4041ca8177e3367c14/litestar-2.24.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/9e/db72b3ae7fc9cfad53e630e56c6ae83b9b6ff0bf3718ffb8012d20b3aabf/cryptography-49.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "litestar-htmx", "version": "0.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f2/24/8d99982f0aa9c1cd82073c6232b54a0dbe6797c7d63c0583a6c68ee3ddf2/litestar_htmx-0.5.0-py3-none-any.whl"}}, {"metadata": {"name": "msgspec", "version": "0.21.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/70/9b/ce0cca6d2d87fcd4b6ff97600790494e64f26a2c55d61507cd2755c16193/msgspec-0.21.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multipart", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/ed/e1f03200ee1f0bf4a2b9b72709afefbf5319b68df654e0b84b35c65613ee/multipart-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "polyfactory", "version": "3.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/34/b6f19941adcdaf415b5e8a8d577499f5b6a76b59cbae37f9b125a9ffe9f2/polyfactory-3.3.0-py3-none-any.whl"}}, {"metadata": {"name": "Faker", "version": "40.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/a6/6111b9f13c1564b0e2f5dbeeb611fd00dc731e6add2336f62b798598c73d/faker-40.28.1-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "rich-click", "version": "1.9.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6d/97/a87901aef6b7e7e4a34c6dd6cc17dca8594a592ef9d9dd765fca2b7facf7/rich_click-1.9.8-py3-none-any.whl"}}], "install_targets_hash": "030c889f2cc15fac775b2cc21c8d01e4"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "litestar", "version": "2.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/ce/4697b547790f23d2fcc37a928d48c38140cf86360e4041ca8177e3367c14/litestar-2.24.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/9e/db72b3ae7fc9cfad53e630e56c6ae83b9b6ff0bf3718ffb8012d20b3aabf/cryptography-49.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "litestar-htmx", "version": "0.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f2/24/8d99982f0aa9c1cd82073c6232b54a0dbe6797c7d63c0583a6c68ee3ddf2/litestar_htmx-0.5.0-py3-none-any.whl"}}, {"metadata": {"name": "msgspec", "version": "0.21.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/70/9b/ce0cca6d2d87fcd4b6ff97600790494e64f26a2c55d61507cd2755c16193/msgspec-0.21.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multipart", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/ed/e1f03200ee1f0bf4a2b9b72709afefbf5319b68df654e0b84b35c65613ee/multipart-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "polyfactory", "version": "3.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/34/b6f19941adcdaf415b5e8a8d577499f5b6a76b59cbae37f9b125a9ffe9f2/polyfactory-3.3.0-py3-none-any.whl"}}, {"metadata": {"name": "Faker", "version": "40.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/a6/6111b9f13c1564b0e2f5dbeeb611fd00dc731e6add2336f62b798598c73d/faker-40.28.1-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "rich-click", "version": "1.9.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6d/97/a87901aef6b7e7e4a34c6dd6cc17dca8594a592ef9d9dd765fca2b7facf7/rich_click-1.9.8-py3-none-any.whl"}}], "install_targets_hash": "030c889f2cc15fac775b2cc21c8d01e4"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "litestar", "version": "2.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/ce/4697b547790f23d2fcc37a928d48c38140cf86360e4041ca8177e3367c14/litestar-2.24.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/9e/db72b3ae7fc9cfad53e630e56c6ae83b9b6ff0bf3718ffb8012d20b3aabf/cryptography-49.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "litestar-htmx", "version": "0.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f2/24/8d99982f0aa9c1cd82073c6232b54a0dbe6797c7d63c0583a6c68ee3ddf2/litestar_htmx-0.5.0-py3-none-any.whl"}}, {"metadata": {"name": "msgspec", "version": "0.21.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/70/9b/ce0cca6d2d87fcd4b6ff97600790494e64f26a2c55d61507cd2755c16193/msgspec-0.21.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multipart", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/ed/e1f03200ee1f0bf4a2b9b72709afefbf5319b68df654e0b84b35c65613ee/multipart-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "polyfactory", "version": "3.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/34/b6f19941adcdaf415b5e8a8d577499f5b6a76b59cbae37f9b125a9ffe9f2/polyfactory-3.3.0-py3-none-any.whl"}}, {"metadata": {"name": "Faker", "version": "40.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/a6/6111b9f13c1564b0e2f5dbeeb611fd00dc731e6add2336f62b798598c73d/faker-40.28.1-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "rich-click", "version": "1.9.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6d/97/a87901aef6b7e7e4a34c6dd6cc17dca8594a592ef9d9dd765fca2b7facf7/rich_click-1.9.8-py3-none-any.whl"}}], "install_targets_hash": "030c889f2cc15fac775b2cc21c8d01e4"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "pyramid", "version": "2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1f/d4/03a8f9b60b8f2a9198c962d08fd9b657c1c0797cbbde3793babbad200845/pyramid-2.1-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "2.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/f3/22afbdb20cc4654b10c98043414a14057cd27fdba9d4ae61cea596000ba2/Werkzeug-2.0.3-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "81.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/e3/c164c88b2e5ce7b24d667b9bd83589cf4f3520d97cad01534cd3c4f55fdb/setuptools-81.0.0-py3-none-any.whl"}}, {"metadata": {"name": "hupper", "version": "1.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/86/7d/3888833e4f5ea56af4a9935066ec09a83228e533d7b8877f65889d706ee4/hupper-1.12.1-py3-none-any.whl"}}, {"metadata": {"name": "translationstring", "version": "1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3b/98/36187601a15e3d37e9bfcf0e0e1055532b39d044353b06861c3a519737a9/translationstring-1.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "venusian", "version": "3.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5a/4b/34d926eba40db81b204066a60b4efdc5d8867a8efcbfe44d69b634b1c907/venusian-3.1.1-py3-none-any.whl"}}, {"metadata": {"name": "WebOb", "version": "1.8.10"}, "download_info": {"url": "https://files.pythonhosted.org/packages/83/21/fce134877fb6fc6ad3c464e4a07ede0ee9219f705d26a981ae58ea36ca13/webob-1.8.10-py2.py3-none-any.whl"}}, {"metadata": {"name": "legacy-cgi", "version": "2.6.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8c/7e/e7394eeb49a41cc514b3eb49020223666cbf40d86f5721c2f07871e6d84a/legacy_cgi-2.6.4-py3-none-any.whl"}}, {"metadata": {"name": "zope.deprecation", "version": "6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/ed/da7f8b1c73caf989a0ff7096cc73c59e6c36f35a8f967c51104098602e2d/zope_deprecation-6.0-py3-none-any.whl"}}, {"metadata": {"name": "zope.interface", "version": "8.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f3/55/de0c3459ff717fce3342f9a29464c281fdeb0d36c3171ee88d119d5f0650/zope_interface-8.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "plaster", "version": "1.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e7/8b/3f98db1448e3b4d2d142716874a7e02f6101685fdaa0f55a8668e9ffa048/plaster-1.1.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "plaster-pastedeploy", "version": "1.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/30/2d4cf89035c22a89bf0e34dbc50fdc07c42c9bdc90fd972d495257ad2b6e/plaster_pastedeploy-1.0.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "PasteDeploy", "version": "3.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/85/30/cdddd9a88969683a59222a6d61cd6dce923977f2e9f9ffba38e1324149cd/PasteDeploy-3.1.0-py3-none-any.whl"}}], "install_targets_hash": "060f93eb8052b63b08924e439967bba6"} -{"python_version": "3.14", "dependencies": [{"metadata": {"name": "fastapi", "version": "0.121.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/b6/4f620d7720fc0a754c8c1b7501d73777f6ba43b57c8ab99671f4d7441eb8/fastapi-0.121.3-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"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"}}, {"metadata": {"name": "starlette", "version": "0.50.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d9/52/1064f510b141bd54025f9b55105e26d1fa970b9be67ad766380a3c9b74b0/starlette-0.50.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d4/ce/9af95f7876194bd7a14e3dfe4a4de2e0bff02666a3910d72beafd06cc297/charset_normalizer-3.4.9-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/09/c419f6f5a92e5fadde27efd190eca90f05e1261b10dbd8cbcb39cd8ea1dc/markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}], "install_targets_hash": "07dedda23092a79cd219b98e946eb134"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "boto3", "version": "1.43.99"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/6f/37/d59247c882bc078b73cfa6f6bb247ac51bedc7637f6a8800def385dcfbba/boto3-1.43.99-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.99"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/9a/2a62da42bc8bd55d99e5b9599c112260dfe9872bedf335bdc5a10dbb653a/botocore-1.43.99-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "s3transfer", "version": "0.19.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/bc/e7/5c595c75e9f41a44f30e526eda465ea0b4eec93470e074e4a111b253f13a/s3transfer-0.19.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}], "install_targets_hash": "0757b3ed0bd295834a1bf3155319b4f9"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "cohere", "version": "6.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/b4/00c2f9f8387a2e77faf8410210466c46d55dd30a0388de41c54441b148fb/cohere-6.1.0-py3-none-any.whl"}}, {"metadata": {"name": "fastavro", "version": "1.12.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/8f/18f60329b627d2118a4a2b19e8741fbd807d60bf0470554e1bbfb7f1bca3/fastavro-1.12.2-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "tokenizers", "version": "0.23.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/60/21f715d9faba5f5407ff759472ade058ec4a507ad62bcea47cb847239a73/tokenizers-0.23.1.tar.gz"}}, {"metadata": {"name": "huggingface_hub", "version": "1.22.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/9c/a1a377265abd8b823a2c661c665028ccb6b9fba1ca9d08e52ff679c20ecd/huggingface_hub-1.22.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/17/261ba565b6a4d960fb478f61fdf919c0be5824645aaf1c319eca660c1611/hf_xet-1.5.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "types-requests", "version": "2.33.0.20260518"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1c/bc/b139710a3b6018f7fb2b9508b35c8af564e61bf2bf4fa619d088f3e16f85/types_requests-2.33.0.20260518-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "filelock", "version": "3.29.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4a/e3/f1fae3647d170919c2cf2a898e77e7d1a4e5c7cae0aed7bb4bd3f5ebff6f/filelock-3.29.5-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e5/22/4222d7ddf3da30f363edaa98e329c2bce6c65497c9cb2810931c8b2c0fbc/fsspec-2026.6.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.12.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.41.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bb/3d/6913dde84d5be21e284439676168b28d8bbba5600d838b9dca99de0fad71/pydantic_core-2.41.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tqdm", "version": "4.68.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d8/8e/bb97bb0c71802080bfc8952937d174e49cfc50de5c951dd47b2496f0dcdb/tqdm-4.68.3-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}], "install_targets_hash": "0ad658fae5aa5a77bc7d2271d7f24fcf"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "cohere", "version": "6.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/b4/00c2f9f8387a2e77faf8410210466c46d55dd30a0388de41c54441b148fb/cohere-6.1.0-py3-none-any.whl"}}, {"metadata": {"name": "fastavro", "version": "1.12.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/8f/18f60329b627d2118a4a2b19e8741fbd807d60bf0470554e1bbfb7f1bca3/fastavro-1.12.2-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "tokenizers", "version": "0.23.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/60/21f715d9faba5f5407ff759472ade058ec4a507ad62bcea47cb847239a73/tokenizers-0.23.1.tar.gz"}}, {"metadata": {"name": "huggingface_hub", "version": "1.22.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/9c/a1a377265abd8b823a2c661c665028ccb6b9fba1ca9d08e52ff679c20ecd/huggingface_hub-1.22.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/17/261ba565b6a4d960fb478f61fdf919c0be5824645aaf1c319eca660c1611/hf_xet-1.5.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "types-requests", "version": "2.33.0.20260518"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1c/bc/b139710a3b6018f7fb2b9508b35c8af564e61bf2bf4fa619d088f3e16f85/types_requests-2.33.0.20260518-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "filelock", "version": "3.29.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4a/e3/f1fae3647d170919c2cf2a898e77e7d1a4e5c7cae0aed7bb4bd3f5ebff6f/filelock-3.29.5-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e5/22/4222d7ddf3da30f363edaa98e329c2bce6c65497c9cb2810931c8b2c0fbc/fsspec-2026.6.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.12.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.41.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bb/3d/6913dde84d5be21e284439676168b28d8bbba5600d838b9dca99de0fad71/pydantic_core-2.41.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tqdm", "version": "4.68.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d8/8e/bb97bb0c71802080bfc8952937d174e49cfc50de5c951dd47b2496f0dcdb/tqdm-4.68.3-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}], "install_targets_hash": "0ad658fae5aa5a77bc7d2271d7f24fcf"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "openai-agents", "version": "0.10.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e2/07/ad27018fb42d6f1e70f471a5ca3f6398a2159575b623edf86e1ddde66ce4/openai_agents-0.10.5-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "2.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ae/f4/561ed79fd94876160018a5e75254cfcb9b0e62d4dded9dcb20072e86d623/openai-2.44.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "griffe", "version": "1.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/83/3b1d03d36f224edded98e9affd0467630fc09d766c0e56fb1498cbb04a9b/griffe-1.15.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ac/4a/84a5ec271d09f7590b6073af5ee4abb44eab4ccace453b7e2c5ce45234ca/jiter-0.17.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "mcp", "version": "1.30.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f5/f4/e58bc33317c92a0203664daaf00bf6f41166cc0149e5d6870a03f7cd004a/mcp-1.30.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/02/bc19b47a96c2d3109760711acf22369e56bd7e405ca52f7ade164d2ead57/pydantic_core-2.46.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1c/6c/c73fa9d5a85f6ab05395de61c5f6984e0a9ff40bb5ff888d46dff02526c6/charset_normalizer-3.5.1-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "types-requests", "version": "2.33.0.20260906"}, "download_info": {"url": "https://files.pythonhosted.org/packages/60/4c/51ec821d22a45b4162fa3f3e9e94ea4c0f8c49e82363b10955baa5438391/types_requests-2.33.0.20260906-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "colorama", "version": "0.4.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/97/672cb32ce0dfea44b740cb7b4f97038463b9cf7c0ead1aacf595572851d6/pyjwt-2.14.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/f0/424cb557d99aa86ac55da5e2add02e2882e44047b6264f93ade1b975a993/cryptography-50.0.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7d/47/5ecf1023850036e674c77ec4de86182d309ae344e39e7cba984b7df5d647/cffi-2.1.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/77bcb1168b33704908295533d27f10eb811e9e3e193e8993dc99572211d3/rpds_py-2026.6.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/6a/2ba3ed4a69babf3afdddf7d8314a48d87562c0a442206bbc2a1b50d5efc0/sse_starlette-3.4.11-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/03/921a3d3c75785aca9ebfbfcabfbc3a1be12e2ab5265deb026d55a5a3f83e/tqdm-4.70.1-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.52.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/79/4a20b54ab0491485ccd8c077db2d39187c7f12b3e15485d38a7be37c81b4/uvicorn-0.52.4-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "0ce5e787d33b4cfe2c733e90e400524e"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "openai", "version": "2.54.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/a8/bb76c7356de8ad57f59d5ff993d434df0607f07f08bcc9c9a5c275e399c0/openai-2.54.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/6b/59127338b86d9fe4d99418f5a15118bea778103ee0fe9d9dd7e0af174e95/jiter-0.16.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/29/46ad8061f57bd9f8b2ea0aa82bf574e0f2aa040b0857a1582adba9957899/tiktoken-0.14.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.7.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cd/d6/0dd1a321afaab95eb7ff44aa0f637301786f1dc71c6b797b9ed236ed8890/regex-2026.7.19-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1c/6c/c73fa9d5a85f6ab05395de61c5f6984e0a9ff40bb5ff888d46dff02526c6/charset_normalizer-3.5.1-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "0e0a649708de8e981a20111ea63dbf51"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "langgraph", "version": "0.6.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/94/430f0341c5c2fe3e3b9f5ab2622f35e2bda12c4a7d655c519468e853d1b0/langgraph-0.6.11-py3-none-any.whl"}}, {"metadata": {"name": "langgraph-checkpoint", "version": "3.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/48/e3/616e3a7ff737d98c1bbb5700dd62278914e2a9ded09a79a1fa93cf24ce12/langgraph_checkpoint-3.0.1-py3-none-any.whl"}}, {"metadata": {"name": "langgraph-prebuilt", "version": "0.6.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8e/d1/e4727f4822943befc3b7046f79049b1086c9493a34b4d44a1adf78577693/langgraph_prebuilt-0.6.5-py3-none-any.whl"}}, {"metadata": {"name": "langgraph-sdk", "version": "0.2.15"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6b/c9/bf2bff18f85bb7973fa5280838580049574bd7649c36e3dd346c49304997/langgraph_sdk-0.2.15-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "langchain-core", "version": "1.4.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/13/d6/bdf6f0481cc57ef300d6b1eb48cf1400c0409be715d6eb3cabadd1142a09/langchain_core-1.4.8-py3-none-any.whl"}}, {"metadata": {"name": "jsonpatch", "version": "1.33"}, "download_info": {"url": "https://files.pythonhosted.org/packages/73/07/02e16ed01e04a374e644b575638ec7987ae846d25ad97bcc9945a3ee4b0e/jsonpatch-1.33-py2.py3-none-any.whl"}}, {"metadata": {"name": "langsmith", "version": "0.9.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/95/0abb8647123c9ebbb31162bcdba3183f5f3d3bb2f752ef3d777ab715e88c/langsmith-0.9.7-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "uuid_utils", "version": "0.16.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/43/401acf6fc0e0665dd11a095a28f6d22708c6f8f148c326cfc5b0b1ae9882/uuid_utils-0.16.2-cp314-cp314t-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "jsonpointer", "version": "3.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/6a/a83720e953b1682d2d109d3c2dbb0bc9bf28cc1cbc205be4ef4be5da709d/jsonpointer-3.1.1-py3-none-any.whl"}}, {"metadata": {"name": "langchain-protocol", "version": "0.0.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/2e/d82db9eec13ad0f72e7aaad5c4bc730ab111934fdc83c85523206eb9b0a0/langchain_protocol-0.0.18-py3-none-any.whl"}}, {"metadata": {"name": "orjson", "version": "3.11.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/0c/964746fcafbd16f8ff53219ad9f6b412b34f345c75f384ad434ceaadb538/orjson-3.11.9.tar.gz"}}, {"metadata": {"name": "ormsgpack", "version": "1.12.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/c2/6feb972dc87285ad381749d3882d8aecbde9f6ecf908dd717d33d66df095/ormsgpack-1.12.2-cp314-cp314t-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/74/9b/6158d4e459b984f949dcbbb0c5d270154c7618e11c01029b9bbd1bb4c4f9/websockets-16.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "xxhash", "version": "3.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/14/175c573ae4fac48bf21a82e5b9ceec75d64c520c51ca08de3105de539438/xxhash-3.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "zstandard", "version": "0.25.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/aa/3e0508d5a5dd96529cdc5a97011299056e14c6505b678fd58938792794b1/zstandard-0.25.0.tar.gz"}}], "install_targets_hash": "0ee3a52436b4f61e9cdbe5013bf352c3"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "openfeature_sdk", "version": "0.7.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/20/cb043f54b11505d993e4dd84652cfc44c1260dc94b7f41aa35489af58277/openfeature_sdk-0.7.5-py3-none-any.whl"}}], "install_targets_hash": "1014994e190575f0710da79951d7f561"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "cohere", "version": "5.21.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0a/50/5538f02ec6d10fbb84f29c1b18c68ff2a03d7877926a80275efdf8755a9f/cohere-5.21.1-py3-none-any.whl"}}, {"metadata": {"name": "fastavro", "version": "1.12.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/8f/18f60329b627d2118a4a2b19e8741fbd807d60bf0470554e1bbfb7f1bca3/fastavro-1.12.2-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "tokenizers", "version": "0.23.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/60/21f715d9faba5f5407ff759472ade058ec4a507ad62bcea47cb847239a73/tokenizers-0.23.1.tar.gz"}}, {"metadata": {"name": "huggingface_hub", "version": "1.22.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/9c/a1a377265abd8b823a2c661c665028ccb6b9fba1ca9d08e52ff679c20ecd/huggingface_hub-1.22.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/17/261ba565b6a4d960fb478f61fdf919c0be5824645aaf1c319eca660c1611/hf_xet-1.5.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "types-requests", "version": "2.33.0.20260518"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1c/bc/b139710a3b6018f7fb2b9508b35c8af564e61bf2bf4fa619d088f3e16f85/types_requests-2.33.0.20260518-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "filelock", "version": "3.29.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4a/e3/f1fae3647d170919c2cf2a898e77e7d1a4e5c7cae0aed7bb4bd3f5ebff6f/filelock-3.29.5-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e5/22/4222d7ddf3da30f363edaa98e329c2bce6c65497c9cb2810931c8b2c0fbc/fsspec-2026.6.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tqdm", "version": "4.68.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d8/8e/bb97bb0c71802080bfc8952937d174e49cfc50de5c951dd47b2496f0dcdb/tqdm-4.68.3-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}], "install_targets_hash": "1119e874aeb67089151365fd5430145a"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "openfeature-sdk", "version": "0.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/44/8a4f5225e930ff0d999fd43f5d743a4babeb6c7e76dddc00f0e118878ef3/openfeature_sdk-0.10.0-py3-none-any.whl"}}], "install_targets_hash": "113a6c8b15a3b8283663d37f7b69e71e"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "fastapi", "version": "0.123.10"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/f0/7cb92c4a720def85240fd63fbbcf147ce19e7a731c8e1032376bb5a486ac/fastapi-0.123.10-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "starlette", "version": "0.50.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d9/52/1064f510b141bd54025f9b55105e26d1fa970b9be67ad766380a3c9b74b0/starlette-0.50.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/5e/17398df3a139985ba9d11ed072531986f408c8fca952835ef1ab1820c02b/charset_normalizer-3.4.9-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}], "install_targets_hash": "11d8ddfacb08ef9d446aa4936e0d4ecd"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "redis", "version": "7.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4a/2e/2677f3f93dae0497e7e33b6637302e7f3744efc553f34231183e32584885/redis-7.4.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "7.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ff/f6e8b8f39e08547faece4bd80f89d5a8de68a38b2d179cc1c4490ffa3286/pytest-7.4.4-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/76/e2/964e6ef372770dd7c32f9738b50ff4924f1d3cccd665b568680e4bcb0167/fakeredis-2.37.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.23.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ee/82/62e2d63639ecb0fbe8a7ee59ef0bc69a4669ec50f6d3459f74ad4e4189a2/pytest_asyncio-0.23.8-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}], "install_targets_hash": "186c82b63ae560049b87efb5870e7d53"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "redis", "version": "7.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4a/2e/2677f3f93dae0497e7e33b6637302e7f3744efc553f34231183e32584885/redis-7.4.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "7.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ff/f6e8b8f39e08547faece4bd80f89d5a8de68a38b2d179cc1c4490ffa3286/pytest-7.4.4-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/76/e2/964e6ef372770dd7c32f9738b50ff4924f1d3cccd665b568680e4bcb0167/fakeredis-2.37.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.23.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ee/82/62e2d63639ecb0fbe8a7ee59ef0bc69a4669ec50f6d3459f74ad4e4189a2/pytest_asyncio-0.23.8-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}], "install_targets_hash": "186c82b63ae560049b87efb5870e7d53"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "anthropic", "version": "0.125.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2f/1a/b1bd30cda3790557e8791bec5922a6ec8fabb6fa8b008c76a39cf7be6152/anthropic-0.125.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/6b/59127338b86d9fe4d99418f5a15118bea778103ee0fe9d9dd7e0af174e95/jiter-0.16.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}], "install_targets_hash": "1c358b0efef217a40b276bd14601c7b4"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "anthropic", "version": "0.125.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2f/1a/b1bd30cda3790557e8791bec5922a6ec8fabb6fa8b008c76a39cf7be6152/anthropic-0.125.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/6b/59127338b86d9fe4d99418f5a15118bea778103ee0fe9d9dd7e0af174e95/jiter-0.16.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}], "install_targets_hash": "1c358b0efef217a40b276bd14601c7b4"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "langchain", "version": "1.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/85/86/cc13651cfda820d96ca8c612538166334935e8cf4331a31f5dd369d27760/langchain-1.4.2-py3-none-any.whl"}}, {"metadata": {"name": "langchain-core", "version": "1.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e6/18/cf18cfec118b02e003f35300b54d6a1173dc6e4905cffdf5ea49e390a7f9/langchain_core-1.6.3-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "jsonpatch", "version": "1.33"}, "download_info": {"url": "https://files.pythonhosted.org/packages/73/07/02e16ed01e04a374e644b575638ec7987ae846d25ad97bcc9945a3ee4b0e/jsonpatch-1.33-py2.py3-none-any.whl"}}, {"metadata": {"name": "langgraph", "version": "1.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0a/7f/c5c30e4be99ff821029c7ac872a480676bb179c9f3df85ea3f38d13f86d4/langgraph-1.2.11-py3-none-any.whl"}}, {"metadata": {"name": "langgraph-checkpoint", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/71/3b475f09bd57d3a5649792c66353312b4432afd843f301739dfcebd157f0/langgraph_checkpoint-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "langgraph-prebuilt", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/43/3fe1a700b8490ed02679cdbbc8c915eb23a092faf496c9c1118abcd10be3/langgraph_prebuilt-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "langgraph-sdk", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/43/d5/2ad7f3a835c6fcebf58b6669552536ecd52d2dfe4cf49c6c36648fd83572/langgraph_sdk-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "langsmith", "version": "0.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/51/892ff5a2efc8e222ca114dd0e19b56978f78a5ee62d3b33783588dd8e6d4/langsmith-0.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/64/a4e536cb16d7f61a7fd3120b46c577fc7fa7325992f69c4f52bc786d77d8/pydantic_core-2.46.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "uuid_utils", "version": "0.17.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/33/11/a2ef25dc4a3dcae5ddf8a7c2debc0d10719a991e327e43913605fd3b9c90/uuid_utils-0.17.1-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b2/39/26762f734113e22da2b942c3aca85798e0c0405d64c256549540ff31e5a1/websockets-16.1.1-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "3.16.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/17/72/2b1fe3e303db76ab2ba0c2de2b57822869bcb588db82334d4ff3aea8acf2/openai-3.16.2-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/96/c1813dcca15c5a370145a448aaea7d1f83f6f0228a5f1130e79340ee385f/jiter-0.17.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "langchain-openai", "version": "1.6.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b2/47/b87a3c372e52678eb4408360eadbe04cdd5371e21fe2560b6efd66989624/langchain_openai-1.6.2-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/e8/46de4400d5bf859f640feee85bd7e32235f68ddf25db53c63be78e581e3a/tiktoken-0.14.0-cp314-cp314t-manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "langchain-community", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8f/39/5d97e42a3e95dc2a6d71b2f902a3fae71786131e11d01bddb604accb0ebe/langchain_community-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "langchain-classic", "version": "1.0.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/9a/b8f5cb7490fdbf233088031fc69c9c747439d4097f67f196c1eb4869916d/langchain_classic-1.0.8-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bb/6b/62cbd6577758699525f5c712d1ddef57d9875fbab0ae8d5f5a202fd598f8/aiohttp-3.14.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "langchain-text-splitters", "version": "1.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d3/26/1ef06f56198d631296d646a6223de35bcc6cf9795ceb2442816bc963b84c/langchain_text_splitters-1.1.2-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/b0/8ee78b0fbe5fe153e9566055e1107c9bae0011b1ae903e30c7ab2ba3e07f/multidict-6.9.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/ee/e4e10a94d51cd1ee638aa7e00b65399e6b2a4e8376ab6d2eac9f95586671/charset_normalizer-3.5.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "SQLAlchemy", "version": "2.0.54"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/25/15dfe6814847eeda773bd58ab6cf42a94b0176e5cf25a578fc1165777160/sqlalchemy-2.0.54-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "urllib3", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.25.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d1/38/97d79b81c342b78246cfedb74809e68841f3198d21653e10d3232bd9c622/yarl-1.25.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "google-genai", "version": "2.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/84/5b/87913fe392ba7b6402577259289ed3740c577956554a674b191a2971d33e/google_genai-2.24.0-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.58.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/59/13/477d90d09591b3938b45c4e11f4d8a51291682112cb5efcac961e815d562/google_auth-2.58.0-py3-none-any.whl"}}, {"metadata": {"name": "langchain-google-genai", "version": "4.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/10/83bb535e78c2cf767a6193c2f3b00b2894c1581a36ef85911ebaa3b9a891/langchain_google_genai-4.4.0-py3-none-any.whl"}}, {"metadata": {"name": "filetype", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/18/79/1b8fa1bb3568781e84c9200f951c735f3f157429f44be0495da55894d620/filetype-1.2.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1a/01/0127d11a762b31a9ee0221894f540318761783f3fdc4bc5d057698caebd5/cryptography-50.0.1-cp314-cp314t-manylinux_2_34_x86_64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/95/eff5f0cee78d2eabc7eebffec40d3fc1876b5f3c95582e018bb4b99601f2/cffi-2.1.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/1c/3d8622e60d0b767a5510d1d3cf21065b9db874696a51ea6d7a43180a259c/frozenlist-1.8.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl"}}, {"metadata": {"name": "greenlet", "version": "3.5.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/c5/2b6c721ba8b8963da42d5a0f57f25b8aaeb1fe9bdd156875e57f3be648a2/greenlet-3.5.6-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonpointer", "version": "3.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/6a/a83720e953b1682d2d109d3c2dbb0bc9bf28cc1cbc205be4ef4be5da709d/jsonpointer-3.1.1-py3-none-any.whl"}}, {"metadata": {"name": "langchain-protocol", "version": "0.0.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/80/c9/f6cbf357d48ccbd18bb394433b1fd7ad9be004eed9377ad08bb85777e5e6/langchain_protocol-0.0.19-py3-none-any.whl"}}, {"metadata": {"name": "numpy", "version": "2.5.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/59/08/9df04103947b95e3b6b1f2ed1a70521f325647a31b82da6a2aae3a485508/numpy-2.5.3-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "orjson", "version": "3.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0f/f3/742fb1f62b825f2c010697eaf4e828004bc2a81e7e806666989c132c7c42/orjson-3.12.0.tar.gz"}}, {"metadata": {"name": "ormsgpack", "version": "1.12.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/87/4c/27a95466354606b256f24fad464d7c97ab62bce6cc529dd4673e1179b8fb/ormsgpack-1.12.2-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fc/57/527910c455b5ec62f6871bef45d4f79fea16cb8c966ba0d4a07f0339ddc4/propcache-0.5.4-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/3b/6163796d69c3977d1e4287bea4a6979161cbbdd170ebb430511e8e1999ce/pyasn1-0.6.4-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "xxhash", "version": "4.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/0c/16b5e419f24e59507ee05626d2bb0deafdb03f9f27783bc0785a9849602e/xxhash-4.0.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "zstandard", "version": "0.25.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/aa/3e0508d5a5dd96529cdc5a97011299056e14c6505b678fd58938792794b1/zstandard-0.25.0.tar.gz"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.9.10"}, "download_info": {"url": "https://files.pythonhosted.org/packages/86/38/49f8d6fd34fc1a9c75b5b96364ebdde702a8144e5ed63d2213c58d454c27/regex-2026.9.10-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}], "install_targets_hash": "1f1d7e5fcc21f036dd1fe5ff2434a014"} -{"python_version": "3.14", "dependencies": [{"metadata": {"name": "fastmcp", "version": "1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/bf/0a77688242f30f81e3633d3765289966d9c7e408f9dcb4928a85852b9fde/fastmcp-1.0-py3-none-any.whl"}}, {"metadata": {"name": "mcp", "version": "1.29.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/c8/248b201f6d753d69fd5d6506011abbb35a946d9142b2ae311a948fd0be3d/mcp-1.29.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/77/c1/6e422f34e569cf8e18df68d1939c81c099d2b61e4f7d9621c8a77560799c/pydantic_settings-2.14.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/9e/db72b3ae7fc9cfad53e630e56c6ae83b9b6ff0bf3718ffb8012d20b3aabf/cryptography-49.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/d8/3b86aba791cb610d24e8a3e1b2cd529e71fa15096b04e4d4e360049d4a4c/cffi-2.1.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/77bcb1168b33704908295533d27f10eb811e9e3e193e8993dc99572211d3/rpds_py-2026.6.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/36/e10c1d1b7ca881d2625db2ec28508578499187bb1c389952c398474e1834/sse_starlette-3.4.6-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typer", "version": "0.27.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/40/03/26a383c9e58c213199d1aad1c3d353cfc22d4444ec6d2c0bf8ad02523843/typer-0.27.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "shellingham", "version": "1.5.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.52.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/39/e6/b5c0630ace9757232aec07112be8146b812787db52141ff9d50674aa7634/uvicorn-0.52.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "20723503fc47693dca3f6601f6cab1ee"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "fastapi", "version": "0.141.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/03/10388a42375ee7e4ac9b94eb2c5c569c8b5795e377e701c9ac3ad63de890/fastapi-0.141.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/5e/17398df3a139985ba9d11ed072531986f408c8fca952835ef1ab1820c02b/charset_normalizer-3.4.9-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}], "install_targets_hash": "20b998148dda6aa7b3fb3474012892c8"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "fastapi", "version": "0.141.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/03/10388a42375ee7e4ac9b94eb2c5c569c8b5795e377e701c9ac3ad63de890/fastapi-0.141.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/5e/17398df3a139985ba9d11ed072531986f408c8fca952835ef1ab1820c02b/charset_normalizer-3.4.9-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}], "install_targets_hash": "20b998148dda6aa7b3fb3474012892c8"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "fastapi", "version": "0.141.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/03/10388a42375ee7e4ac9b94eb2c5c569c8b5795e377e701c9ac3ad63de890/fastapi-0.141.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/5e/17398df3a139985ba9d11ed072531986f408c8fca952835ef1ab1820c02b/charset_normalizer-3.4.9-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}], "install_targets_hash": "20b998148dda6aa7b3fb3474012892c8"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "fastapi", "version": "0.141.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/03/10388a42375ee7e4ac9b94eb2c5c569c8b5795e377e701c9ac3ad63de890/fastapi-0.141.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/5e/17398df3a139985ba9d11ed072531986f408c8fca952835ef1ab1820c02b/charset_normalizer-3.4.9-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}], "install_targets_hash": "20b998148dda6aa7b3fb3474012892c8"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "fastapi", "version": "0.141.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/03/10388a42375ee7e4ac9b94eb2c5c569c8b5795e377e701c9ac3ad63de890/fastapi-0.141.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/5e/17398df3a139985ba9d11ed072531986f408c8fca952835ef1ab1820c02b/charset_normalizer-3.4.9-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}], "install_targets_hash": "20b998148dda6aa7b3fb3474012892c8"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "fastapi", "version": "0.141.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/03/10388a42375ee7e4ac9b94eb2c5c569c8b5795e377e701c9ac3ad63de890/fastapi-0.141.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d4/ce/9af95f7876194bd7a14e3dfe4a4de2e0bff02666a3910d72beafd06cc297/charset_normalizer-3.4.9-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/09/c419f6f5a92e5fadde27efd190eca90f05e1261b10dbd8cbcb39cd8ea1dc/markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"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"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}], "install_targets_hash": "20b998148dda6aa7b3fb3474012892c8"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "fastapi", "version": "0.141.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/03/10388a42375ee7e4ac9b94eb2c5c569c8b5795e377e701c9ac3ad63de890/fastapi-0.141.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d4/ce/9af95f7876194bd7a14e3dfe4a4de2e0bff02666a3910d72beafd06cc297/charset_normalizer-3.4.9-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/09/c419f6f5a92e5fadde27efd190eca90f05e1261b10dbd8cbcb39cd8ea1dc/markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"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"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}], "install_targets_hash": "20b998148dda6aa7b3fb3474012892c8"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "httpx2", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/29/45/82bc57c3d9c3314f663b67cc057f1c017a6450685dde513f4f8db5cf431f/httpx2-2.4.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2-pytest", "version": "1.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/46/ef/e9b6fb576f1f518f68e9f9cce9776870452ae2b8cfbba53b4127701b9a55/httpx2_pytest-1.0.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/72/4fdf2306143a92a471fad9f3655aa542d43aa9188a7c9534e82c9aecf837/httpcore2-2.4.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}], "install_targets_hash": "20f77812852d7e4a68656d7028ccce45"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "httpx2", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/29/45/82bc57c3d9c3314f663b67cc057f1c017a6450685dde513f4f8db5cf431f/httpx2-2.4.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2-pytest", "version": "1.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/46/ef/e9b6fb576f1f518f68e9f9cce9776870452ae2b8cfbba53b4127701b9a55/httpx2_pytest-1.0.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/72/4fdf2306143a92a471fad9f3655aa542d43aa9188a7c9534e82c9aecf837/httpcore2-2.4.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}], "install_targets_hash": "20f77812852d7e4a68656d7028ccce45"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "mistralai", "version": "2.3.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/83/e0/9f246d18f8fe6e815f7cae88c437c986b342d3ff568607c8e0d53f4710d0/mistralai-2.3.2-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-semantic-conventions", "version": "0.60b1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7a/5e/5958555e09635d09b75de3c4f8b9cae7335ca545d77392ffe7331534c402/opentelemetry_semantic_conventions-0.60b1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.39.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/df/d3f1ddf4bb4cb50ed9b1139cc7b1c54c34a1e7ce8fd1b9a37c0d1551a6bd/opentelemetry_api-1.39.1-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fa/5e/f8e9a1d23b9c20a551a8a02ea3637b4642e22c2626e3a13a9a29cdea99eb/importlib_metadata-8.7.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "eval_type_backport", "version": "0.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/a7/bb99bf5e6f78736ddb53480f2c3ff3702ffe2196a7c5e1661c03081d398e/eval_type_backport-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonpath-python", "version": "1.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/8a/1270a6803bd821cbfcdda387eaa13cb41a7b1f7b9bd145979b3bfb9d6cb7/jsonpath_python-1.1.6-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/02/bc19b47a96c2d3109760711acf22369e56bd7e405ca52f7ade164d2ead57/pydantic_core-2.46.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "zipp", "version": "4.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}], "install_targets_hash": "220b48fa30e6d4e6ee437946e03f7dfd"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "Flask", "version": "2.3.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/56/26f0be8adc2b4257df20c1c4260ddd0aa396cf8e75d90ab2f7ff99bc34f9/flask-2.3.3-py3-none-any.whl"}}, {"metadata": {"name": "Flask-Login", "version": "0.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/59/f5/67e9cc5c2036f58115f9fe0f00d203cf6780c3ff8ae0e705e7a9d9e8ff9e/Flask_Login-0.6.3-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}], "install_targets_hash": "26b4bd6a717ed504426367c6af492c2d"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "Flask", "version": "2.3.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/56/26f0be8adc2b4257df20c1c4260ddd0aa396cf8e75d90ab2f7ff99bc34f9/flask-2.3.3-py3-none-any.whl"}}, {"metadata": {"name": "Flask-Login", "version": "0.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/59/f5/67e9cc5c2036f58115f9fe0f00d203cf6780c3ff8ae0e705e7a9d9e8ff9e/Flask_Login-0.6.3-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}], "install_targets_hash": "26b4bd6a717ed504426367c6af492c2d"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "starlette", "version": "0.52.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/0d/13d1d239a25cbfb19e740db83143e95c772a1fe10202dda4b76792b114dd/starlette-0.52.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "30eeef4352d79f7d31c630da4104816d"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "starlette", "version": "0.52.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/0d/13d1d239a25cbfb19e740db83143e95c772a1fe10202dda4b76792b114dd/starlette-0.52.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "30eeef4352d79f7d31c630da4104816d"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "clickhouse-driver", "version": "0.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/75/42c6c0f1e0b84213ff096f913ac0ff82037da6f06754bff28685b2d1e23a/clickhouse_driver-0.2.11.tar.gz"}}, {"metadata": {"name": "pytz", "version": "2026.3.post1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0f/7b/39c34ca613b0b198cb866466651b26b045e2009864c5183c979a3b83f383/pytz-2026.3.post1-py2.py3-none-any.whl"}}, {"metadata": {"name": "tzlocal", "version": "5.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/a4/017a7a6cbe387d961a688ec31364ae60a5c4e22c96ae9921b79a947c855d/tzlocal-5.4.4-py3-none-any.whl"}}], "install_targets_hash": "38bca3e47a0c5c6404ea5b79801cb472"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "clickhouse-driver", "version": "0.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/75/42c6c0f1e0b84213ff096f913ac0ff82037da6f06754bff28685b2d1e23a/clickhouse_driver-0.2.11.tar.gz"}}, {"metadata": {"name": "pytz", "version": "2026.3.post1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0f/7b/39c34ca613b0b198cb866466651b26b045e2009864c5183c979a3b83f383/pytz-2026.3.post1-py2.py3-none-any.whl"}}, {"metadata": {"name": "tzlocal", "version": "5.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/a4/017a7a6cbe387d961a688ec31364ae60a5c4e22c96ae9921b79a947c855d/tzlocal-5.4.4-py3-none-any.whl"}}], "install_targets_hash": "38bca3e47a0c5c6404ea5b79801cb472"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "clickhouse-driver", "version": "0.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/75/42c6c0f1e0b84213ff096f913ac0ff82037da6f06754bff28685b2d1e23a/clickhouse_driver-0.2.11.tar.gz"}}, {"metadata": {"name": "pytz", "version": "2026.3.post1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0f/7b/39c34ca613b0b198cb866466651b26b045e2009864c5183c979a3b83f383/pytz-2026.3.post1-py2.py3-none-any.whl"}}, {"metadata": {"name": "tzlocal", "version": "5.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/a4/017a7a6cbe387d961a688ec31364ae60a5c4e22c96ae9921b79a947c855d/tzlocal-5.4.4-py3-none-any.whl"}}], "install_targets_hash": "38bca3e47a0c5c6404ea5b79801cb472"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "clickhouse-driver", "version": "0.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/75/42c6c0f1e0b84213ff096f913ac0ff82037da6f06754bff28685b2d1e23a/clickhouse_driver-0.2.11.tar.gz"}}, {"metadata": {"name": "pytz", "version": "2026.3.post1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0f/7b/39c34ca613b0b198cb866466651b26b045e2009864c5183c979a3b83f383/pytz-2026.3.post1-py2.py3-none-any.whl"}}, {"metadata": {"name": "tzlocal", "version": "5.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/a4/017a7a6cbe387d961a688ec31364ae60a5c4e22c96ae9921b79a947c855d/tzlocal-5.4.4-py3-none-any.whl"}}], "install_targets_hash": "38bca3e47a0c5c6404ea5b79801cb472"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "pyspark", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c3/33/c987434f5d50aa802779a004ca0fd45ee4350caab50554ad7283d5a22b50/pyspark-4.2.0.tar.gz"}}, {"metadata": {"name": "py4j", "version": "0.10.9.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/db/ea0203e495be491c85af87b66e37acfd3bf756fd985f87e46fc5e3bf022c/py4j-0.10.9.9-py2.py3-none-any.whl"}}], "install_targets_hash": "390b2ae4157b0a35d160339447ce08cb"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "pyspark", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c3/33/c987434f5d50aa802779a004ca0fd45ee4350caab50554ad7283d5a22b50/pyspark-4.2.0.tar.gz"}}, {"metadata": {"name": "py4j", "version": "0.10.9.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/db/ea0203e495be491c85af87b66e37acfd3bf756fd985f87e46fc5e3bf022c/py4j-0.10.9.9-py2.py3-none-any.whl"}}], "install_targets_hash": "390b2ae4157b0a35d160339447ce08cb"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "pyspark", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c3/33/c987434f5d50aa802779a004ca0fd45ee4350caab50554ad7283d5a22b50/pyspark-4.2.0.tar.gz"}}, {"metadata": {"name": "py4j", "version": "0.10.9.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/db/ea0203e495be491c85af87b66e37acfd3bf756fd985f87e46fc5e3bf022c/py4j-0.10.9.9-py2.py3-none-any.whl"}}], "install_targets_hash": "390b2ae4157b0a35d160339447ce08cb"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "pyspark", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c3/33/c987434f5d50aa802779a004ca0fd45ee4350caab50554ad7283d5a22b50/pyspark-4.2.0.tar.gz"}}, {"metadata": {"name": "py4j", "version": "0.10.9.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/db/ea0203e495be491c85af87b66e37acfd3bf756fd985f87e46fc5e3bf022c/py4j-0.10.9.9-py2.py3-none-any.whl"}}], "install_targets_hash": "390b2ae4157b0a35d160339447ce08cb"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "pyspark", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c3/33/c987434f5d50aa802779a004ca0fd45ee4350caab50554ad7283d5a22b50/pyspark-4.2.0.tar.gz"}}, {"metadata": {"name": "py4j", "version": "0.10.9.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/db/ea0203e495be491c85af87b66e37acfd3bf756fd985f87e46fc5e3bf022c/py4j-0.10.9.9-py2.py3-none-any.whl"}}], "install_targets_hash": "390b2ae4157b0a35d160339447ce08cb"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "pyspark", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c3/33/c987434f5d50aa802779a004ca0fd45ee4350caab50554ad7283d5a22b50/pyspark-4.2.0.tar.gz"}}, {"metadata": {"name": "py4j", "version": "0.10.9.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/db/ea0203e495be491c85af87b66e37acfd3bf756fd985f87e46fc5e3bf022c/py4j-0.10.9.9-py2.py3-none-any.whl"}}], "install_targets_hash": "390b2ae4157b0a35d160339447ce08cb"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "pyspark", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c3/33/c987434f5d50aa802779a004ca0fd45ee4350caab50554ad7283d5a22b50/pyspark-4.2.0.tar.gz"}}, {"metadata": {"name": "py4j", "version": "0.10.9.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/db/ea0203e495be491c85af87b66e37acfd3bf756fd985f87e46fc5e3bf022c/py4j-0.10.9.9-py2.py3-none-any.whl"}}], "install_targets_hash": "390b2ae4157b0a35d160339447ce08cb"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "pyspark", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c3/33/c987434f5d50aa802779a004ca0fd45ee4350caab50554ad7283d5a22b50/pyspark-4.2.0.tar.gz"}}, {"metadata": {"name": "py4j", "version": "0.10.9.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/db/ea0203e495be491c85af87b66e37acfd3bf756fd985f87e46fc5e3bf022c/py4j-0.10.9.9-py2.py3-none-any.whl"}}], "install_targets_hash": "390b2ae4157b0a35d160339447ce08cb"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "pyspark", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c3/33/c987434f5d50aa802779a004ca0fd45ee4350caab50554ad7283d5a22b50/pyspark-4.2.0.tar.gz"}}, {"metadata": {"name": "py4j", "version": "0.10.9.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/db/ea0203e495be491c85af87b66e37acfd3bf756fd985f87e46fc5e3bf022c/py4j-0.10.9.9-py2.py3-none-any.whl"}}], "install_targets_hash": "390b2ae4157b0a35d160339447ce08cb"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "pyspark", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c3/33/c987434f5d50aa802779a004ca0fd45ee4350caab50554ad7283d5a22b50/pyspark-4.2.0.tar.gz"}}, {"metadata": {"name": "py4j", "version": "0.10.9.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/db/ea0203e495be491c85af87b66e37acfd3bf756fd985f87e46fc5e3bf022c/py4j-0.10.9.9-py2.py3-none-any.whl"}}], "install_targets_hash": "390b2ae4157b0a35d160339447ce08cb"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "rq", "version": "2.12.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a4/c2/995863e88669133a058c2a6a912b62d18a64fa7baaf78eb66aaa4350b48d/rq-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.35.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/6f/27/b8b057a23f7777177e92d3a602fd866751b6b45014964548997e92e048fd/fakeredis-2.35.1-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "redis", "version": "8.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/66/9d/c5731f6e3608663d4d3656fd8d3aecee8b509c3082818f5a13eae925baea/redis-8.1.0-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "croniter", "version": "6.2.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cd/ba/d678e5bd329646ca51d3c92addbc77804e86d21f4b6b6a027218e6abb010/croniter-6.2.4-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}], "install_targets_hash": "39c8ef325254f7a619a821794c33e958"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "rq", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a4/c2/995863e88669133a058c2a6a912b62d18a64fa7baaf78eb66aaa4350b48d/rq-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.35.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6f/27/b8b057a23f7777177e92d3a602fd866751b6b45014964548997e92e048fd/fakeredis-2.35.1-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "redis", "version": "8.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/66/9d/c5731f6e3608663d4d3656fd8d3aecee8b509c3082818f5a13eae925baea/redis-8.1.0-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "croniter", "version": "6.2.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cd/ba/d678e5bd329646ca51d3c92addbc77804e86d21f4b6b6a027218e6abb010/croniter-6.2.4-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}], "install_targets_hash": "39c8ef325254f7a619a821794c33e958"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "SQLAlchemy", "version": "2.1.0rc2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/53/eb/6c84feb95fbbccb0a4646552261d4f4c53fb36de4fb874ad227f0f55c862/sqlalchemy-2.1.0rc2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}], "install_targets_hash": "3f216279dfc7a16b8b146f00ed33cb9a"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "SQLAlchemy", "version": "2.1.0rc2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5c/a6/6adfceca59aae2a0b7147425796bdf3016932de46c601043cfe8770e415f/sqlalchemy-2.1.0rc2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}], "install_targets_hash": "3f216279dfc7a16b8b146f00ed33cb9a"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "huey", "version": "3.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/31/cee585bd4d1e39947a426a6736f4e17d22b454952370fb9cf48eb3103085/huey-3.4.0-py3-none-any.whl"}}], "install_targets_hash": "40f9e0b7b0afb09fe34d19285f3f89c9"} -{"python_version": "3.14", "dependencies": [{"metadata": {"name": "openai", "version": "3.16.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/17/72/2b1fe3e303db76ab2ba0c2de2b57822869bcb588db82334d4ff3aea8acf2/openai-3.16.2-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/96/c1813dcca15c5a370145a448aaea7d1f83f6f0228a5f1130e79340ee385f/jiter-0.17.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/64/a4e536cb16d7f61a7fd3120b46c577fc7fa7325992f69c4f52bc786d77d8/pydantic_core-2.46.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "41aa894704882aa63f37bce872a4e2a2"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "chalice", "version": "1.33.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/ed/c721931d966d135387ab2d5404a026ca0ae205325fbac4b8f9ac91a45186/chalice-1.33.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "81.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/e3/c164c88b2e5ce7b24d667b9bd83589cf4f3520d97cad01534cd3c4f55fdb/setuptools-81.0.0-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.40"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/8c/5f7e73fd66b28f0705bc55d7060d41ef72328b656b86ca53e75765b3ba2c/botocore-1.43.40-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "inquirer", "version": "3.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f0/fd/7c404169a3e04a908df0644893a331f253a7f221961f2b6c0cf44430ae5a/inquirer-3.4.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pip", "version": "26.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/95/6b5cb3461ea5673ba0995989746db58eb18b91b54dbf331e72f569540946/pip-26.1.2-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-chalice", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/0f/3344996a9ca6d1b301f55805bd2aa0daf9055f13317720b4567226e4cb38/pytest-chalice-0.0.5.tar.gz"}}, {"metadata": {"name": "blessed", "version": "1.46.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/8f/c10d44ba50d5d298699c3c5698ce4e89b397ec72e2139381b9964f87356c/blessed-1.46.0-py3-none-any.whl"}}, {"metadata": {"name": "jinxed", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/1d/0a6be99b69bb448448403a45a241aff0dca751832ae54f027ed940d2eb52/jinxed-2.1.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "editor", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/b8/6648cadf38b61045262bf2a534e526f04eb833275ad1fc77a2026e9f7e3a/editor-1.8.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "readchar", "version": "4.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/ca/36133653e00939922dd1416f4c56177361289172a30563fcb9552c9ccde4/readchar-4.2.2-py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl"}}, {"metadata": {"name": "runs", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/b6/049c75d399ccf6e25abea0652b85bf7e7e101e0300aa9c1d284ad7061c0b/runs-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "wheel", "version": "0.47.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/87/1b/9e33c09813d65e248f7f773119148a612516a4bea93e9c6f545f78455b7c/wheel-0.47.0-py3-none-any.whl"}}, {"metadata": {"name": "xmod", "version": "1.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/e9/c362d47ed2b1928d65d61888c1419fae8ef69417fba2067d2fd3da1d400b/xmod-1.10.0-py3-none-any.whl"}}], "install_targets_hash": "41e4a9a78e14781d2190b51041252959"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "chalice", "version": "1.33.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/ed/c721931d966d135387ab2d5404a026ca0ae205325fbac4b8f9ac91a45186/chalice-1.33.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "81.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/e3/c164c88b2e5ce7b24d667b9bd83589cf4f3520d97cad01534cd3c4f55fdb/setuptools-81.0.0-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.40"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/8c/5f7e73fd66b28f0705bc55d7060d41ef72328b656b86ca53e75765b3ba2c/botocore-1.43.40-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "inquirer", "version": "3.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f0/fd/7c404169a3e04a908df0644893a331f253a7f221961f2b6c0cf44430ae5a/inquirer-3.4.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pip", "version": "26.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/95/6b5cb3461ea5673ba0995989746db58eb18b91b54dbf331e72f569540946/pip-26.1.2-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-chalice", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/0f/3344996a9ca6d1b301f55805bd2aa0daf9055f13317720b4567226e4cb38/pytest-chalice-0.0.5.tar.gz"}}, {"metadata": {"name": "blessed", "version": "1.46.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/8f/c10d44ba50d5d298699c3c5698ce4e89b397ec72e2139381b9964f87356c/blessed-1.46.0-py3-none-any.whl"}}, {"metadata": {"name": "jinxed", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/1d/0a6be99b69bb448448403a45a241aff0dca751832ae54f027ed940d2eb52/jinxed-2.1.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "editor", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/b8/6648cadf38b61045262bf2a534e526f04eb833275ad1fc77a2026e9f7e3a/editor-1.8.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "readchar", "version": "4.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/ca/36133653e00939922dd1416f4c56177361289172a30563fcb9552c9ccde4/readchar-4.2.2-py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl"}}, {"metadata": {"name": "runs", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/b6/049c75d399ccf6e25abea0652b85bf7e7e101e0300aa9c1d284ad7061c0b/runs-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "wheel", "version": "0.47.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/87/1b/9e33c09813d65e248f7f773119148a612516a4bea93e9c6f545f78455b7c/wheel-0.47.0-py3-none-any.whl"}}, {"metadata": {"name": "xmod", "version": "1.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/e9/c362d47ed2b1928d65d61888c1419fae8ef69417fba2067d2fd3da1d400b/xmod-1.10.0-py3-none-any.whl"}}], "install_targets_hash": "41e4a9a78e14781d2190b51041252959"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "chalice", "version": "1.33.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/ed/c721931d966d135387ab2d5404a026ca0ae205325fbac4b8f9ac91a45186/chalice-1.33.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "81.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/e3/c164c88b2e5ce7b24d667b9bd83589cf4f3520d97cad01534cd3c4f55fdb/setuptools-81.0.0-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.40"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/8c/5f7e73fd66b28f0705bc55d7060d41ef72328b656b86ca53e75765b3ba2c/botocore-1.43.40-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "inquirer", "version": "3.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f0/fd/7c404169a3e04a908df0644893a331f253a7f221961f2b6c0cf44430ae5a/inquirer-3.4.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pip", "version": "26.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/95/6b5cb3461ea5673ba0995989746db58eb18b91b54dbf331e72f569540946/pip-26.1.2-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-chalice", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/0f/3344996a9ca6d1b301f55805bd2aa0daf9055f13317720b4567226e4cb38/pytest-chalice-0.0.5.tar.gz"}}, {"metadata": {"name": "blessed", "version": "1.46.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/8f/c10d44ba50d5d298699c3c5698ce4e89b397ec72e2139381b9964f87356c/blessed-1.46.0-py3-none-any.whl"}}, {"metadata": {"name": "jinxed", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/1d/0a6be99b69bb448448403a45a241aff0dca751832ae54f027ed940d2eb52/jinxed-2.1.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "editor", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/b8/6648cadf38b61045262bf2a534e526f04eb833275ad1fc77a2026e9f7e3a/editor-1.8.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "readchar", "version": "4.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/ca/36133653e00939922dd1416f4c56177361289172a30563fcb9552c9ccde4/readchar-4.2.2-py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl"}}, {"metadata": {"name": "runs", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/b6/049c75d399ccf6e25abea0652b85bf7e7e101e0300aa9c1d284ad7061c0b/runs-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "wheel", "version": "0.47.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/87/1b/9e33c09813d65e248f7f773119148a612516a4bea93e9c6f545f78455b7c/wheel-0.47.0-py3-none-any.whl"}}, {"metadata": {"name": "xmod", "version": "1.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/e9/c362d47ed2b1928d65d61888c1419fae8ef69417fba2067d2fd3da1d400b/xmod-1.10.0-py3-none-any.whl"}}], "install_targets_hash": "41e4a9a78e14781d2190b51041252959"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "chalice", "version": "1.33.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/ed/c721931d966d135387ab2d5404a026ca0ae205325fbac4b8f9ac91a45186/chalice-1.33.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "81.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/e3/c164c88b2e5ce7b24d667b9bd83589cf4f3520d97cad01534cd3c4f55fdb/setuptools-81.0.0-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.40"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/8c/5f7e73fd66b28f0705bc55d7060d41ef72328b656b86ca53e75765b3ba2c/botocore-1.43.40-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "inquirer", "version": "3.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f0/fd/7c404169a3e04a908df0644893a331f253a7f221961f2b6c0cf44430ae5a/inquirer-3.4.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pip", "version": "26.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/95/6b5cb3461ea5673ba0995989746db58eb18b91b54dbf331e72f569540946/pip-26.1.2-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-chalice", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/0f/3344996a9ca6d1b301f55805bd2aa0daf9055f13317720b4567226e4cb38/pytest-chalice-0.0.5.tar.gz"}}, {"metadata": {"name": "blessed", "version": "1.46.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/8f/c10d44ba50d5d298699c3c5698ce4e89b397ec72e2139381b9964f87356c/blessed-1.46.0-py3-none-any.whl"}}, {"metadata": {"name": "jinxed", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/1d/0a6be99b69bb448448403a45a241aff0dca751832ae54f027ed940d2eb52/jinxed-2.1.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "editor", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/b8/6648cadf38b61045262bf2a534e526f04eb833275ad1fc77a2026e9f7e3a/editor-1.8.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "readchar", "version": "4.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/ca/36133653e00939922dd1416f4c56177361289172a30563fcb9552c9ccde4/readchar-4.2.2-py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl"}}, {"metadata": {"name": "runs", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/b6/049c75d399ccf6e25abea0652b85bf7e7e101e0300aa9c1d284ad7061c0b/runs-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "wheel", "version": "0.47.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/87/1b/9e33c09813d65e248f7f773119148a612516a4bea93e9c6f545f78455b7c/wheel-0.47.0-py3-none-any.whl"}}, {"metadata": {"name": "xmod", "version": "1.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/e9/c362d47ed2b1928d65d61888c1419fae8ef69417fba2067d2fd3da1d400b/xmod-1.10.0-py3-none-any.whl"}}], "install_targets_hash": "41e4a9a78e14781d2190b51041252959"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "chalice", "version": "1.33.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/ed/c721931d966d135387ab2d5404a026ca0ae205325fbac4b8f9ac91a45186/chalice-1.33.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "81.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/e3/c164c88b2e5ce7b24d667b9bd83589cf4f3520d97cad01534cd3c4f55fdb/setuptools-81.0.0-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.40"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/8c/5f7e73fd66b28f0705bc55d7060d41ef72328b656b86ca53e75765b3ba2c/botocore-1.43.40-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "inquirer", "version": "3.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f0/fd/7c404169a3e04a908df0644893a331f253a7f221961f2b6c0cf44430ae5a/inquirer-3.4.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pip", "version": "26.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/95/6b5cb3461ea5673ba0995989746db58eb18b91b54dbf331e72f569540946/pip-26.1.2-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-chalice", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/0f/3344996a9ca6d1b301f55805bd2aa0daf9055f13317720b4567226e4cb38/pytest-chalice-0.0.5.tar.gz"}}, {"metadata": {"name": "blessed", "version": "1.46.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/8f/c10d44ba50d5d298699c3c5698ce4e89b397ec72e2139381b9964f87356c/blessed-1.46.0-py3-none-any.whl"}}, {"metadata": {"name": "jinxed", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/1d/0a6be99b69bb448448403a45a241aff0dca751832ae54f027ed940d2eb52/jinxed-2.1.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "editor", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/b8/6648cadf38b61045262bf2a534e526f04eb833275ad1fc77a2026e9f7e3a/editor-1.8.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "readchar", "version": "4.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/ca/36133653e00939922dd1416f4c56177361289172a30563fcb9552c9ccde4/readchar-4.2.2-py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl"}}, {"metadata": {"name": "runs", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/b6/049c75d399ccf6e25abea0652b85bf7e7e101e0300aa9c1d284ad7061c0b/runs-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "wheel", "version": "0.47.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/87/1b/9e33c09813d65e248f7f773119148a612516a4bea93e9c6f545f78455b7c/wheel-0.47.0-py3-none-any.whl"}}, {"metadata": {"name": "xmod", "version": "1.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/e9/c362d47ed2b1928d65d61888c1419fae8ef69417fba2067d2fd3da1d400b/xmod-1.10.0-py3-none-any.whl"}}], "install_targets_hash": "41e4a9a78e14781d2190b51041252959"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "chalice", "version": "1.33.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/ed/c721931d966d135387ab2d5404a026ca0ae205325fbac4b8f9ac91a45186/chalice-1.33.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "81.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/e3/c164c88b2e5ce7b24d667b9bd83589cf4f3520d97cad01534cd3c4f55fdb/setuptools-81.0.0-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.40"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/8c/5f7e73fd66b28f0705bc55d7060d41ef72328b656b86ca53e75765b3ba2c/botocore-1.43.40-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "inquirer", "version": "3.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f0/fd/7c404169a3e04a908df0644893a331f253a7f221961f2b6c0cf44430ae5a/inquirer-3.4.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pip", "version": "26.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/95/6b5cb3461ea5673ba0995989746db58eb18b91b54dbf331e72f569540946/pip-26.1.2-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-chalice", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/0f/3344996a9ca6d1b301f55805bd2aa0daf9055f13317720b4567226e4cb38/pytest-chalice-0.0.5.tar.gz"}}, {"metadata": {"name": "blessed", "version": "1.46.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/8f/c10d44ba50d5d298699c3c5698ce4e89b397ec72e2139381b9964f87356c/blessed-1.46.0-py3-none-any.whl"}}, {"metadata": {"name": "jinxed", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/1d/0a6be99b69bb448448403a45a241aff0dca751832ae54f027ed940d2eb52/jinxed-2.1.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "editor", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/b8/6648cadf38b61045262bf2a534e526f04eb833275ad1fc77a2026e9f7e3a/editor-1.8.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "readchar", "version": "4.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/ca/36133653e00939922dd1416f4c56177361289172a30563fcb9552c9ccde4/readchar-4.2.2-py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl"}}, {"metadata": {"name": "runs", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/b6/049c75d399ccf6e25abea0652b85bf7e7e101e0300aa9c1d284ad7061c0b/runs-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "wheel", "version": "0.47.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/87/1b/9e33c09813d65e248f7f773119148a612516a4bea93e9c6f545f78455b7c/wheel-0.47.0-py3-none-any.whl"}}, {"metadata": {"name": "xmod", "version": "1.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/e9/c362d47ed2b1928d65d61888c1419fae8ef69417fba2067d2fd3da1d400b/xmod-1.10.0-py3-none-any.whl"}}], "install_targets_hash": "41e4a9a78e14781d2190b51041252959"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "chalice", "version": "1.33.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/ed/c721931d966d135387ab2d5404a026ca0ae205325fbac4b8f9ac91a45186/chalice-1.33.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "81.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/e3/c164c88b2e5ce7b24d667b9bd83589cf4f3520d97cad01534cd3c4f55fdb/setuptools-81.0.0-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.40"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/8c/5f7e73fd66b28f0705bc55d7060d41ef72328b656b86ca53e75765b3ba2c/botocore-1.43.40-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "inquirer", "version": "3.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f0/fd/7c404169a3e04a908df0644893a331f253a7f221961f2b6c0cf44430ae5a/inquirer-3.4.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pip", "version": "26.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/95/6b5cb3461ea5673ba0995989746db58eb18b91b54dbf331e72f569540946/pip-26.1.2-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-chalice", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/0f/3344996a9ca6d1b301f55805bd2aa0daf9055f13317720b4567226e4cb38/pytest-chalice-0.0.5.tar.gz"}}, {"metadata": {"name": "blessed", "version": "1.46.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/8f/c10d44ba50d5d298699c3c5698ce4e89b397ec72e2139381b9964f87356c/blessed-1.46.0-py3-none-any.whl"}}, {"metadata": {"name": "jinxed", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/1d/0a6be99b69bb448448403a45a241aff0dca751832ae54f027ed940d2eb52/jinxed-2.1.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "editor", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/b8/6648cadf38b61045262bf2a534e526f04eb833275ad1fc77a2026e9f7e3a/editor-1.8.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "readchar", "version": "4.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/ca/36133653e00939922dd1416f4c56177361289172a30563fcb9552c9ccde4/readchar-4.2.2-py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl"}}, {"metadata": {"name": "runs", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/b6/049c75d399ccf6e25abea0652b85bf7e7e101e0300aa9c1d284ad7061c0b/runs-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "wheel", "version": "0.47.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/87/1b/9e33c09813d65e248f7f773119148a612516a4bea93e9c6f545f78455b7c/wheel-0.47.0-py3-none-any.whl"}}, {"metadata": {"name": "xmod", "version": "1.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/e9/c362d47ed2b1928d65d61888c1419fae8ef69417fba2067d2fd3da1d400b/xmod-1.10.0-py3-none-any.whl"}}], "install_targets_hash": "41e4a9a78e14781d2190b51041252959"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "chalice", "version": "1.33.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/ed/c721931d966d135387ab2d5404a026ca0ae205325fbac4b8f9ac91a45186/chalice-1.33.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "81.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/e3/c164c88b2e5ce7b24d667b9bd83589cf4f3520d97cad01534cd3c4f55fdb/setuptools-81.0.0-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.40"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/8c/5f7e73fd66b28f0705bc55d7060d41ef72328b656b86ca53e75765b3ba2c/botocore-1.43.40-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "inquirer", "version": "3.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f0/fd/7c404169a3e04a908df0644893a331f253a7f221961f2b6c0cf44430ae5a/inquirer-3.4.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pip", "version": "26.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/95/6b5cb3461ea5673ba0995989746db58eb18b91b54dbf331e72f569540946/pip-26.1.2-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-chalice", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/0f/3344996a9ca6d1b301f55805bd2aa0daf9055f13317720b4567226e4cb38/pytest-chalice-0.0.5.tar.gz"}}, {"metadata": {"name": "blessed", "version": "1.46.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/8f/c10d44ba50d5d298699c3c5698ce4e89b397ec72e2139381b9964f87356c/blessed-1.46.0-py3-none-any.whl"}}, {"metadata": {"name": "jinxed", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/1d/0a6be99b69bb448448403a45a241aff0dca751832ae54f027ed940d2eb52/jinxed-2.1.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "editor", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/b8/6648cadf38b61045262bf2a534e526f04eb833275ad1fc77a2026e9f7e3a/editor-1.8.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "readchar", "version": "4.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/ca/36133653e00939922dd1416f4c56177361289172a30563fcb9552c9ccde4/readchar-4.2.2-py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl"}}, {"metadata": {"name": "runs", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/b6/049c75d399ccf6e25abea0652b85bf7e7e101e0300aa9c1d284ad7061c0b/runs-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "wheel", "version": "0.47.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/87/1b/9e33c09813d65e248f7f773119148a612516a4bea93e9c6f545f78455b7c/wheel-0.47.0-py3-none-any.whl"}}, {"metadata": {"name": "xmod", "version": "1.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/e9/c362d47ed2b1928d65d61888c1419fae8ef69417fba2067d2fd3da1d400b/xmod-1.10.0-py3-none-any.whl"}}], "install_targets_hash": "41e4a9a78e14781d2190b51041252959"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "chalice", "version": "1.33.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/ed/c721931d966d135387ab2d5404a026ca0ae205325fbac4b8f9ac91a45186/chalice-1.33.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "81.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/e3/c164c88b2e5ce7b24d667b9bd83589cf4f3520d97cad01534cd3c4f55fdb/setuptools-81.0.0-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.40"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/8c/5f7e73fd66b28f0705bc55d7060d41ef72328b656b86ca53e75765b3ba2c/botocore-1.43.40-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "inquirer", "version": "3.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f0/fd/7c404169a3e04a908df0644893a331f253a7f221961f2b6c0cf44430ae5a/inquirer-3.4.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pip", "version": "26.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/95/6b5cb3461ea5673ba0995989746db58eb18b91b54dbf331e72f569540946/pip-26.1.2-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-chalice", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/0f/3344996a9ca6d1b301f55805bd2aa0daf9055f13317720b4567226e4cb38/pytest-chalice-0.0.5.tar.gz"}}, {"metadata": {"name": "blessed", "version": "1.46.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/8f/c10d44ba50d5d298699c3c5698ce4e89b397ec72e2139381b9964f87356c/blessed-1.46.0-py3-none-any.whl"}}, {"metadata": {"name": "jinxed", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/1d/0a6be99b69bb448448403a45a241aff0dca751832ae54f027ed940d2eb52/jinxed-2.1.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "editor", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/b8/6648cadf38b61045262bf2a534e526f04eb833275ad1fc77a2026e9f7e3a/editor-1.8.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "readchar", "version": "4.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/ca/36133653e00939922dd1416f4c56177361289172a30563fcb9552c9ccde4/readchar-4.2.2-py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl"}}, {"metadata": {"name": "runs", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/b6/049c75d399ccf6e25abea0652b85bf7e7e101e0300aa9c1d284ad7061c0b/runs-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "wheel", "version": "0.47.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/87/1b/9e33c09813d65e248f7f773119148a612516a4bea93e9c6f545f78455b7c/wheel-0.47.0-py3-none-any.whl"}}, {"metadata": {"name": "xmod", "version": "1.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/e9/c362d47ed2b1928d65d61888c1419fae8ef69417fba2067d2fd3da1d400b/xmod-1.10.0-py3-none-any.whl"}}], "install_targets_hash": "41e4a9a78e14781d2190b51041252959"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "chalice", "version": "1.33.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/ed/c721931d966d135387ab2d5404a026ca0ae205325fbac4b8f9ac91a45186/chalice-1.33.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "81.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/e3/c164c88b2e5ce7b24d667b9bd83589cf4f3520d97cad01534cd3c4f55fdb/setuptools-81.0.0-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.40"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/8c/5f7e73fd66b28f0705bc55d7060d41ef72328b656b86ca53e75765b3ba2c/botocore-1.43.40-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "inquirer", "version": "3.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f0/fd/7c404169a3e04a908df0644893a331f253a7f221961f2b6c0cf44430ae5a/inquirer-3.4.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pip", "version": "26.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/95/6b5cb3461ea5673ba0995989746db58eb18b91b54dbf331e72f569540946/pip-26.1.2-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-chalice", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/0f/3344996a9ca6d1b301f55805bd2aa0daf9055f13317720b4567226e4cb38/pytest-chalice-0.0.5.tar.gz"}}, {"metadata": {"name": "blessed", "version": "1.46.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/8f/c10d44ba50d5d298699c3c5698ce4e89b397ec72e2139381b9964f87356c/blessed-1.46.0-py3-none-any.whl"}}, {"metadata": {"name": "jinxed", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/1d/0a6be99b69bb448448403a45a241aff0dca751832ae54f027ed940d2eb52/jinxed-2.1.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "editor", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/b8/6648cadf38b61045262bf2a534e526f04eb833275ad1fc77a2026e9f7e3a/editor-1.8.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "readchar", "version": "4.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/ca/36133653e00939922dd1416f4c56177361289172a30563fcb9552c9ccde4/readchar-4.2.2-py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl"}}, {"metadata": {"name": "runs", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/b6/049c75d399ccf6e25abea0652b85bf7e7e101e0300aa9c1d284ad7061c0b/runs-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "wheel", "version": "0.47.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/87/1b/9e33c09813d65e248f7f773119148a612516a4bea93e9c6f545f78455b7c/wheel-0.47.0-py3-none-any.whl"}}, {"metadata": {"name": "xmod", "version": "1.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/e9/c362d47ed2b1928d65d61888c1419fae8ef69417fba2067d2fd3da1d400b/xmod-1.10.0-py3-none-any.whl"}}], "install_targets_hash": "41e4a9a78e14781d2190b51041252959"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "chalice", "version": "1.33.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/ed/c721931d966d135387ab2d5404a026ca0ae205325fbac4b8f9ac91a45186/chalice-1.33.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "81.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/e3/c164c88b2e5ce7b24d667b9bd83589cf4f3520d97cad01534cd3c4f55fdb/setuptools-81.0.0-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.40"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/8c/5f7e73fd66b28f0705bc55d7060d41ef72328b656b86ca53e75765b3ba2c/botocore-1.43.40-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "inquirer", "version": "3.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f0/fd/7c404169a3e04a908df0644893a331f253a7f221961f2b6c0cf44430ae5a/inquirer-3.4.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pip", "version": "26.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/95/6b5cb3461ea5673ba0995989746db58eb18b91b54dbf331e72f569540946/pip-26.1.2-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-chalice", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/0f/3344996a9ca6d1b301f55805bd2aa0daf9055f13317720b4567226e4cb38/pytest-chalice-0.0.5.tar.gz"}}, {"metadata": {"name": "blessed", "version": "1.46.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/8f/c10d44ba50d5d298699c3c5698ce4e89b397ec72e2139381b9964f87356c/blessed-1.46.0-py3-none-any.whl"}}, {"metadata": {"name": "jinxed", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/1d/0a6be99b69bb448448403a45a241aff0dca751832ae54f027ed940d2eb52/jinxed-2.1.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "editor", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/b8/6648cadf38b61045262bf2a534e526f04eb833275ad1fc77a2026e9f7e3a/editor-1.8.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "readchar", "version": "4.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/ca/36133653e00939922dd1416f4c56177361289172a30563fcb9552c9ccde4/readchar-4.2.2-py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl"}}, {"metadata": {"name": "runs", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/b6/049c75d399ccf6e25abea0652b85bf7e7e101e0300aa9c1d284ad7061c0b/runs-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "wheel", "version": "0.47.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/87/1b/9e33c09813d65e248f7f773119148a612516a4bea93e9c6f545f78455b7c/wheel-0.47.0-py3-none-any.whl"}}, {"metadata": {"name": "xmod", "version": "1.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/e9/c362d47ed2b1928d65d61888c1419fae8ef69417fba2067d2fd3da1d400b/xmod-1.10.0-py3-none-any.whl"}}], "install_targets_hash": "41e4a9a78e14781d2190b51041252959"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "chalice", "version": "1.33.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/ed/c721931d966d135387ab2d5404a026ca0ae205325fbac4b8f9ac91a45186/chalice-1.33.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "81.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/e3/c164c88b2e5ce7b24d667b9bd83589cf4f3520d97cad01534cd3c4f55fdb/setuptools-81.0.0-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.40"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/8c/5f7e73fd66b28f0705bc55d7060d41ef72328b656b86ca53e75765b3ba2c/botocore-1.43.40-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "inquirer", "version": "3.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f0/fd/7c404169a3e04a908df0644893a331f253a7f221961f2b6c0cf44430ae5a/inquirer-3.4.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pip", "version": "26.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/95/6b5cb3461ea5673ba0995989746db58eb18b91b54dbf331e72f569540946/pip-26.1.2-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-chalice", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/0f/3344996a9ca6d1b301f55805bd2aa0daf9055f13317720b4567226e4cb38/pytest-chalice-0.0.5.tar.gz"}}, {"metadata": {"name": "blessed", "version": "1.46.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/8f/c10d44ba50d5d298699c3c5698ce4e89b397ec72e2139381b9964f87356c/blessed-1.46.0-py3-none-any.whl"}}, {"metadata": {"name": "jinxed", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/1d/0a6be99b69bb448448403a45a241aff0dca751832ae54f027ed940d2eb52/jinxed-2.1.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "editor", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/b8/6648cadf38b61045262bf2a534e526f04eb833275ad1fc77a2026e9f7e3a/editor-1.8.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "readchar", "version": "4.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/ca/36133653e00939922dd1416f4c56177361289172a30563fcb9552c9ccde4/readchar-4.2.2-py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl"}}, {"metadata": {"name": "runs", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/b6/049c75d399ccf6e25abea0652b85bf7e7e101e0300aa9c1d284ad7061c0b/runs-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "wheel", "version": "0.47.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/87/1b/9e33c09813d65e248f7f773119148a612516a4bea93e9c6f545f78455b7c/wheel-0.47.0-py3-none-any.whl"}}, {"metadata": {"name": "xmod", "version": "1.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/e9/c362d47ed2b1928d65d61888c1419fae8ef69417fba2067d2fd3da1d400b/xmod-1.10.0-py3-none-any.whl"}}], "install_targets_hash": "41e4a9a78e14781d2190b51041252959"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "redis", "version": "8.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/66/9d/c5731f6e3608663d4d3656fd8d3aecee8b509c3082818f5a13eae925baea/redis-8.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "7.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ff/f6e8b8f39e08547faece4bd80f89d5a8de68a38b2d179cc1c4490ffa3286/pytest-7.4.4-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/76/e2/964e6ef372770dd7c32f9738b50ff4924f1d3cccd665b568680e4bcb0167/fakeredis-2.37.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.23.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ee/82/62e2d63639ecb0fbe8a7ee59ef0bc69a4669ec50f6d3459f74ad4e4189a2/pytest_asyncio-0.23.8-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}], "install_targets_hash": "42549a00e196f5a73560e967c6bf368f"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "redis", "version": "8.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/66/9d/c5731f6e3608663d4d3656fd8d3aecee8b509c3082818f5a13eae925baea/redis-8.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "7.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ff/f6e8b8f39e08547faece4bd80f89d5a8de68a38b2d179cc1c4490ffa3286/pytest-7.4.4-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/76/e2/964e6ef372770dd7c32f9738b50ff4924f1d3cccd665b568680e4bcb0167/fakeredis-2.37.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.23.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ee/82/62e2d63639ecb0fbe8a7ee59ef0bc69a4669ec50f6d3459f74ad4e4189a2/pytest_asyncio-0.23.8-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}], "install_targets_hash": "42549a00e196f5a73560e967c6bf368f"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "redis", "version": "8.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/66/9d/c5731f6e3608663d4d3656fd8d3aecee8b509c3082818f5a13eae925baea/redis-8.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "7.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ff/f6e8b8f39e08547faece4bd80f89d5a8de68a38b2d179cc1c4490ffa3286/pytest-7.4.4-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/76/e2/964e6ef372770dd7c32f9738b50ff4924f1d3cccd665b568680e4bcb0167/fakeredis-2.37.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.23.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ee/82/62e2d63639ecb0fbe8a7ee59ef0bc69a4669ec50f6d3459f74ad4e4189a2/pytest_asyncio-0.23.8-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}], "install_targets_hash": "42549a00e196f5a73560e967c6bf368f"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "anthropic", "version": "1.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c0/dc/74995efda028421917f4caabd24db1373ee0742573a2363fff1a21191441/anthropic-1.7.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/96/c1813dcca15c5a370145a448aaea7d1f83f6f0228a5f1130e79340ee385f/jiter-0.17.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/64/a4e536cb16d7f61a7fd3120b46c577fc7fa7325992f69c4f52bc786d77d8/pydantic_core-2.46.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}], "install_targets_hash": "4727845e3afb2745d5e910cf0c6cbc97"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "arq", "version": "0.28.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/48/32/66b616976c5058d434ca2017979bfffd784888177b16b5038abcec93954a/arq-0.28.0-py3-none-any.whl"}}, {"metadata": {"name": "redis", "version": "5.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/26/5c5fa0e83c3621db835cfc1f1d789b37e7fa99ed54423b5f519beb931aa7/redis-5.3.1-py3-none-any.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/4d/e6e40f93031adbf654d34e542bd396e9f3bc1c6209b40c920d58c9e1317a/fakeredis-2.36.2-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "hiredis", "version": "3.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9f/09/ee568562f36f481395d5cea3ab75fd9350cd77d98d55ee5f9b395f3fc358/hiredis-3.4.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}], "install_targets_hash": "4bd147206b5343b7421e83fb1f8cf3a4"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "arq", "version": "0.28.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/48/32/66b616976c5058d434ca2017979bfffd784888177b16b5038abcec93954a/arq-0.28.0-py3-none-any.whl"}}, {"metadata": {"name": "redis", "version": "5.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/26/5c5fa0e83c3621db835cfc1f1d789b37e7fa99ed54423b5f519beb931aa7/redis-5.3.1-py3-none-any.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/4d/e6e40f93031adbf654d34e542bd396e9f3bc1c6209b40c920d58c9e1317a/fakeredis-2.36.2-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "hiredis", "version": "3.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9f/09/ee568562f36f481395d5cea3ab75fd9350cd77d98d55ee5f9b395f3fc358/hiredis-3.4.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}], "install_targets_hash": "4bd147206b5343b7421e83fb1f8cf3a4"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "arq", "version": "0.28.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/48/32/66b616976c5058d434ca2017979bfffd784888177b16b5038abcec93954a/arq-0.28.0-py3-none-any.whl"}}, {"metadata": {"name": "redis", "version": "5.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/26/5c5fa0e83c3621db835cfc1f1d789b37e7fa99ed54423b5f519beb931aa7/redis-5.3.1-py3-none-any.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/4d/e6e40f93031adbf654d34e542bd396e9f3bc1c6209b40c920d58c9e1317a/fakeredis-2.36.2-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "hiredis", "version": "3.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9f/09/ee568562f36f481395d5cea3ab75fd9350cd77d98d55ee5f9b395f3fc358/hiredis-3.4.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}], "install_targets_hash": "4bd147206b5343b7421e83fb1f8cf3a4"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "arq", "version": "0.28.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/48/32/66b616976c5058d434ca2017979bfffd784888177b16b5038abcec93954a/arq-0.28.0-py3-none-any.whl"}}, {"metadata": {"name": "redis", "version": "5.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/26/5c5fa0e83c3621db835cfc1f1d789b37e7fa99ed54423b5f519beb931aa7/redis-5.3.1-py3-none-any.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/4d/e6e40f93031adbf654d34e542bd396e9f3bc1c6209b40c920d58c9e1317a/fakeredis-2.36.2-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "hiredis", "version": "3.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9f/09/ee568562f36f481395d5cea3ab75fd9350cd77d98d55ee5f9b395f3fc358/hiredis-3.4.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}], "install_targets_hash": "4bd147206b5343b7421e83fb1f8cf3a4"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "arq", "version": "0.28.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/48/32/66b616976c5058d434ca2017979bfffd784888177b16b5038abcec93954a/arq-0.28.0-py3-none-any.whl"}}, {"metadata": {"name": "redis", "version": "5.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/26/5c5fa0e83c3621db835cfc1f1d789b37e7fa99ed54423b5f519beb931aa7/redis-5.3.1-py3-none-any.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/4d/e6e40f93031adbf654d34e542bd396e9f3bc1c6209b40c920d58c9e1317a/fakeredis-2.36.2-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "hiredis", "version": "3.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9f/09/ee568562f36f481395d5cea3ab75fd9350cd77d98d55ee5f9b395f3fc358/hiredis-3.4.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}], "install_targets_hash": "4bd147206b5343b7421e83fb1f8cf3a4"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "arq", "version": "0.28.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/48/32/66b616976c5058d434ca2017979bfffd784888177b16b5038abcec93954a/arq-0.28.0-py3-none-any.whl"}}, {"metadata": {"name": "redis", "version": "5.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/26/5c5fa0e83c3621db835cfc1f1d789b37e7fa99ed54423b5f519beb931aa7/redis-5.3.1-py3-none-any.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/4d/e6e40f93031adbf654d34e542bd396e9f3bc1c6209b40c920d58c9e1317a/fakeredis-2.36.2-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "hiredis", "version": "3.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9f/09/ee568562f36f481395d5cea3ab75fd9350cd77d98d55ee5f9b395f3fc358/hiredis-3.4.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}], "install_targets_hash": "4bd147206b5343b7421e83fb1f8cf3a4"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "arq", "version": "0.28.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/48/32/66b616976c5058d434ca2017979bfffd784888177b16b5038abcec93954a/arq-0.28.0-py3-none-any.whl"}}, {"metadata": {"name": "redis", "version": "5.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/26/5c5fa0e83c3621db835cfc1f1d789b37e7fa99ed54423b5f519beb931aa7/redis-5.3.1-py3-none-any.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/4d/e6e40f93031adbf654d34e542bd396e9f3bc1c6209b40c920d58c9e1317a/fakeredis-2.36.2-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "hiredis", "version": "3.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9f/09/ee568562f36f481395d5cea3ab75fd9350cd77d98d55ee5f9b395f3fc358/hiredis-3.4.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}], "install_targets_hash": "4bd147206b5343b7421e83fb1f8cf3a4"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "ariadne", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/48/e0bd1918ef56b1a570dfc1882a036286bf4b3f13e5a659a8d9e16d888c69/ariadne-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "fastapi", "version": "0.139.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/7c/8e3c6ad324ea5cb36604fc3f968554887891c316d9dfde57761611d907ad/fastapi-0.139.0-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/15/b92b4e1d88d02c6eff9733c9eea21846ab435cc4d813d84ccc5d335955df/graphql_core-3.2.11-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "4be724db1412c7b7718411b02cd97084"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "ariadne", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/48/e0bd1918ef56b1a570dfc1882a036286bf4b3f13e5a659a8d9e16d888c69/ariadne-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "fastapi", "version": "0.139.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/7c/8e3c6ad324ea5cb36604fc3f968554887891c316d9dfde57761611d907ad/fastapi-0.139.0-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/15/b92b4e1d88d02c6eff9733c9eea21846ab435cc4d813d84ccc5d335955df/graphql_core-3.2.11-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "4be724db1412c7b7718411b02cd97084"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "ariadne", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/48/e0bd1918ef56b1a570dfc1882a036286bf4b3f13e5a659a8d9e16d888c69/ariadne-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "fastapi", "version": "0.139.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/7c/8e3c6ad324ea5cb36604fc3f968554887891c316d9dfde57761611d907ad/fastapi-0.139.0-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/15/b92b4e1d88d02c6eff9733c9eea21846ab435cc4d813d84ccc5d335955df/graphql_core-3.2.11-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "4be724db1412c7b7718411b02cd97084"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "ariadne", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/48/e0bd1918ef56b1a570dfc1882a036286bf4b3f13e5a659a8d9e16d888c69/ariadne-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "fastapi", "version": "0.139.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/7c/8e3c6ad324ea5cb36604fc3f968554887891c316d9dfde57761611d907ad/fastapi-0.139.0-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/15/b92b4e1d88d02c6eff9733c9eea21846ab435cc4d813d84ccc5d335955df/graphql_core-3.2.11-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "4be724db1412c7b7718411b02cd97084"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "ariadne", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/48/e0bd1918ef56b1a570dfc1882a036286bf4b3f13e5a659a8d9e16d888c69/ariadne-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "fastapi", "version": "0.139.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/7c/8e3c6ad324ea5cb36604fc3f968554887891c316d9dfde57761611d907ad/fastapi-0.139.0-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/15/b92b4e1d88d02c6eff9733c9eea21846ab435cc4d813d84ccc5d335955df/graphql_core-3.2.11-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "4be724db1412c7b7718411b02cd97084"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "ariadne", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/48/e0bd1918ef56b1a570dfc1882a036286bf4b3f13e5a659a8d9e16d888c69/ariadne-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "fastapi", "version": "0.139.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/7c/8e3c6ad324ea5cb36604fc3f968554887891c316d9dfde57761611d907ad/fastapi-0.139.0-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/15/b92b4e1d88d02c6eff9733c9eea21846ab435cc4d813d84ccc5d335955df/graphql_core-3.2.11-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "4be724db1412c7b7718411b02cd97084"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "ariadne", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/48/e0bd1918ef56b1a570dfc1882a036286bf4b3f13e5a659a8d9e16d888c69/ariadne-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "fastapi", "version": "0.139.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/7c/8e3c6ad324ea5cb36604fc3f968554887891c316d9dfde57761611d907ad/fastapi-0.139.0-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/15/b92b4e1d88d02c6eff9733c9eea21846ab435cc4d813d84ccc5d335955df/graphql_core-3.2.11-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "4be724db1412c7b7718411b02cd97084"} -{"python_version": "3.14", "dependencies": [{"metadata": {"name": "fastmcp", "version": "0.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f5/07/bc69e65b45d638822190bce0defb497a50d240291b8467cb79078d0064b7/fastmcp-0.1.0-py3-none-any.whl"}}, {"metadata": {"name": "mcp", "version": "1.29.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/c8/248b201f6d753d69fd5d6506011abbb35a946d9142b2ae311a948fd0be3d/mcp-1.29.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/77/c1/6e422f34e569cf8e18df68d1939c81c099d2b61e4f7d9621c8a77560799c/pydantic_settings-2.14.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/9e/db72b3ae7fc9cfad53e630e56c6ae83b9b6ff0bf3718ffb8012d20b3aabf/cryptography-49.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/d8/3b86aba791cb610d24e8a3e1b2cd529e71fa15096b04e4d4e360049d4a4c/cffi-2.1.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/77bcb1168b33704908295533d27f10eb811e9e3e193e8993dc99572211d3/rpds_py-2026.6.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/36/e10c1d1b7ca881d2625db2ec28508578499187bb1c389952c398474e1834/sse_starlette-3.4.6-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typer", "version": "0.27.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/40/03/26a383c9e58c213199d1aad1c3d353cfc22d4444ec6d2c0bf8ad02523843/typer-0.27.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "shellingham", "version": "1.5.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.52.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/39/e6/b5c0630ace9757232aec07112be8146b812787db52141ff9d50674aa7634/uvicorn-0.52.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "4ef5d5161db3a01ccf52260b7895e529"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "mistralai", "version": "2.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e3/d5/6b9c08ab9b5b890970e8949bf00a9f8f82653826de5cc5ad506fe1c1fb73/mistralai-2.6.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-semantic-conventions", "version": "0.60b1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7a/5e/5958555e09635d09b75de3c4f8b9cae7335ca545d77392ffe7331534c402/opentelemetry_semantic_conventions-0.60b1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.39.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/df/d3f1ddf4bb4cb50ed9b1139cc7b1c54c34a1e7ce8fd1b9a37c0d1551a6bd/opentelemetry_api-1.39.1-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fa/5e/f8e9a1d23b9c20a551a8a02ea3637b4642e22c2626e3a13a9a29cdea99eb/importlib_metadata-8.7.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "eval_type_backport", "version": "0.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/a7/bb99bf5e6f78736ddb53480f2c3ff3702ffe2196a7c5e1661c03081d398e/eval_type_backport-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonpath-python", "version": "1.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/8a/1270a6803bd821cbfcdda387eaa13cb41a7b1f7b9bd145979b3bfb9d6cb7/jsonpath_python-1.1.6-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/02/bc19b47a96c2d3109760711acf22369e56bd7e405ca52f7ade164d2ead57/pydantic_core-2.46.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "zipp", "version": "4.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}], "install_targets_hash": "4f94c708225730a84d6fdb55c929ba1b"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "Django", "version": "6.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8d/ca/c1040a4fd15754ede7df15fd72fc2e123045b473b253ab5f5284e11c651e/django-6.1.1-py3-none-any.whl"}}, {"metadata": {"name": "coverage", "version": "7.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/d1/7f645fc2eccd318369a8a9948acc447bb7c1ade2911e31d3c5620544c22b/coverage-7.11.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "psycopg2-binary", "version": "2.9.13"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ed/76/7b4383014be0fcc6c1c0e24292845a14e1672cf17fca62ca0a2bd5f4563d/psycopg2_binary-2.9.13.tar.gz"}}, {"metadata": {"name": "djangorestframework", "version": "3.18.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/83/5ed615e47339d8e65f62eb1a8133f8f046492eb3a25ad40d90acb9a208b3/djangorestframework-3.18.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-django", "version": "4.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/03/850bffad2b581c440ca51c039d74504d5a422c94bda0bdb8a8ba5068d48b/pytest_django-4.14.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.7.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/18/f1/46d32fe4b9aae09fe397e768ff376d9b6bdbb4f11faaa727f163c3457b43/pytest_forked-1.7.5-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "channels", "version": "4.3.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/16/34/c32915288b7ef482377b6adc401192f98c6a99b3a145423d3b8aed807898/channels-4.3.2-py3-none-any.whl"}}, {"metadata": {"name": "asgiref", "version": "3.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c0/1b/54f4ad77cd8a584fa70746c47df988e002cf1ee1eba43364d46f87803647/asgiref-3.12.1-py3-none-any.whl"}}, {"metadata": {"name": "executing", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "daphne", "version": "4.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/0c/59e966c167880904f2e6a235c63169760dce58ba8062a7a153a6183539cc/daphne-4.2.3-py3-none-any.whl"}}, {"metadata": {"name": "autobahn", "version": "26.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/de/73/f109f563c27e048e45d135d81af19e6ca391e24905550b06bd1c9d674c57/autobahn-26.7.1.tar.gz"}}, {"metadata": {"name": "cbor2", "version": "6.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/41/3b28184154f6cbf7e47c1b7fb4a7a291c54f27a6f3a0a2f64b078c6a13e1/cbor2-6.1.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7d/47/5ecf1023850036e674c77ec4de86182d309ae344e39e7cba984b7df5d647/cffi-2.1.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/f0/424cb557d99aa86ac55da5e2add02e2882e44047b6264f93ade1b975a993/cryptography-50.0.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "hyperlink", "version": "21.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/aa/8caf6a0a3e62863cbb9dab27135660acba46903b703e224f14f447e57934/hyperlink-21.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "msgpack", "version": "1.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ae/f0/250f5985b6ee533e60d357571a808aaae03c54118294dc3db7158e27feb1/msgpack-1.2.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "sqlparse", "version": "0.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d9/50/f00935da0ec7cbf325f8dc4f772ae46fbc7b672dd62876e73f0a94adda57/sqlparse-0.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Twisted", "version": "26.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/57/bcf4e2370dd218c9aa68a9140a65d86729c73f1d529f7e94786c2766fc72/twisted-26.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "Automat", "version": "25.4.16"}, "download_info": {"url": "https://files.pythonhosted.org/packages/02/ff/1175b0b7371e46244032d43a56862d0af455823b5280a50c63d99cc50f18/automat-25.4.16-py3-none-any.whl"}}, {"metadata": {"name": "constantly", "version": "23.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b8/40/c199d095151addf69efdb4b9ca3a4f20f70e20508d6222bffb9b76f58573/constantly-23.10.4-py3-none-any.whl"}}, {"metadata": {"name": "Incremental", "version": "24.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1d/55/0f4df2a44053867ea9cbea73fc588b03c55605cd695cee0a3d86f0029cb2/incremental-24.11.0-py3-none-any.whl"}}, {"metadata": {"name": "pyOpenSSL", "version": "26.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ad/2cf6d3fa2fae5c79e1ed9960c0d42badd0f94d81dd12b50604cdc839e648/pyopenssl-26.4.0-py3-none-any.whl"}}, {"metadata": {"name": "service-identity", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/eb/2433e1af4ff903499144de4846569fb3300b816179ae99a03c2f011b666a/service_identity-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "txaio", "version": "26.6.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/91/68/075bf851e11c9ef65bd6a0426791f0d9a0c7dae0e7f6e0b16ca67334b456/txaio-26.6.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "6.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/29/33891cfee86cc13e00a1de6fa326378a637dad786078aaf56ab6336c60cf/ujson-6.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "zope.interface", "version": "8.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/c1/889dc114e9a9e8d59fec53facb71dd26345f60c504ad20fd17121af0449c/zope_interface-8.6-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "51cd9fff1aee44191ca961c35fd304e6"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "Django", "version": "6.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8d/ca/c1040a4fd15754ede7df15fd72fc2e123045b473b253ab5f5284e11c651e/django-6.1.1-py3-none-any.whl"}}, {"metadata": {"name": "coverage", "version": "7.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6c/3f/6f5922f80dc6f2d8b2c6f974835c43f53eb4257a7797727e6ca5b7b2ec1f/coverage-7.11.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl"}}, {"metadata": {"name": "psycopg2-binary", "version": "2.9.12"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/60/a3624f79acea344c16fbef3a94d28b89a8042ddfb8f3e4ca83f538671409/psycopg2_binary-2.9.12.tar.gz"}}, {"metadata": {"name": "djangorestframework", "version": "3.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/d7/7461738e819b853275b35fd35712a85806c09a327e1fd5f8ff766bdd317e/djangorestframework-3.18.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-django", "version": "4.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/03/850bffad2b581c440ca51c039d74504d5a422c94bda0bdb8a8ba5068d48b/pytest_django-4.14.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.7.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/18/f1/46d32fe4b9aae09fe397e768ff376d9b6bdbb4f11faaa727f163c3457b43/pytest_forked-1.7.5-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "channels", "version": "4.3.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/16/34/c32915288b7ef482377b6adc401192f98c6a99b3a145423d3b8aed807898/channels-4.3.2-py3-none-any.whl"}}, {"metadata": {"name": "asgiref", "version": "3.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c0/1b/54f4ad77cd8a584fa70746c47df988e002cf1ee1eba43364d46f87803647/asgiref-3.12.1-py3-none-any.whl"}}, {"metadata": {"name": "executing", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "daphne", "version": "4.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/0c/59e966c167880904f2e6a235c63169760dce58ba8062a7a153a6183539cc/daphne-4.2.3-py3-none-any.whl"}}, {"metadata": {"name": "autobahn", "version": "26.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/de/73/f109f563c27e048e45d135d81af19e6ca391e24905550b06bd1c9d674c57/autobahn-26.7.1.tar.gz"}}, {"metadata": {"name": "cbor2", "version": "6.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/60/39/07dd0ea957c1f48673d3947f97ee36826efd4a824053dd0ec4df2f0c89d6/cbor2-6.1.4-cp314-cp314t-manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/95/eff5f0cee78d2eabc7eebffec40d3fc1876b5f3c95582e018bb4b99601f2/cffi-2.1.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1a/01/0127d11a762b31a9ee0221894f540318761783f3fdc4bc5d057698caebd5/cryptography-50.0.1-cp314-cp314t-manylinux_2_34_x86_64.whl"}}, {"metadata": {"name": "hyperlink", "version": "21.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/aa/8caf6a0a3e62863cbb9dab27135660acba46903b703e224f14f447e57934/hyperlink-21.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/09/c419f6f5a92e5fadde27efd190eca90f05e1261b10dbd8cbcb39cd8ea1dc/markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "msgpack", "version": "1.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/21/d2d81d50aaedb14147d01f22094185794db3ad8a8791b60afacba0627c89/msgpack-1.2.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "sqlparse", "version": "0.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d9/50/f00935da0ec7cbf325f8dc4f772ae46fbc7b672dd62876e73f0a94adda57/sqlparse-0.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Twisted", "version": "26.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/57/bcf4e2370dd218c9aa68a9140a65d86729c73f1d529f7e94786c2766fc72/twisted-26.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "Automat", "version": "25.4.16"}, "download_info": {"url": "https://files.pythonhosted.org/packages/02/ff/1175b0b7371e46244032d43a56862d0af455823b5280a50c63d99cc50f18/automat-25.4.16-py3-none-any.whl"}}, {"metadata": {"name": "constantly", "version": "23.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b8/40/c199d095151addf69efdb4b9ca3a4f20f70e20508d6222bffb9b76f58573/constantly-23.10.4-py3-none-any.whl"}}, {"metadata": {"name": "Incremental", "version": "24.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1d/55/0f4df2a44053867ea9cbea73fc588b03c55605cd695cee0a3d86f0029cb2/incremental-24.11.0-py3-none-any.whl"}}, {"metadata": {"name": "pyOpenSSL", "version": "26.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ad/2cf6d3fa2fae5c79e1ed9960c0d42badd0f94d81dd12b50604cdc839e648/pyopenssl-26.4.0-py3-none-any.whl"}}, {"metadata": {"name": "service-identity", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/eb/2433e1af4ff903499144de4846569fb3300b816179ae99a03c2f011b666a/service_identity-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "txaio", "version": "26.6.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/91/68/075bf851e11c9ef65bd6a0426791f0d9a0c7dae0e7f6e0b16ca67334b456/txaio-26.6.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "6.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/c9/9ab8d5ab9ca362381d0fcc8c6e6a831e96385a908792b2378db6282a374e/ujson-6.0.0-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "zope.interface", "version": "8.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a2/54/4df4bb0b1aace2298386375ab2fb752378683b558d2db713e25c40a3e96a/zope_interface-8.6-cp314-cp314t-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "51cd9fff1aee44191ca961c35fd304e6"} -{"python_version": "3.14", "dependencies": [{"metadata": {"name": "openai-agents", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a2/92/9cbbdd604f858056d4e4f105a1b99779128bae61b6a3681db0f035ef73b4/openai_agents-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "2.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ae/f4/561ed79fd94876160018a5e75254cfcb9b0e62d4dded9dcb20072e86d623/openai-2.44.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "griffe", "version": "1.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/83/3b1d03d36f224edded98e9affd0467630fc09d766c0e56fb1498cbb04a9b/griffe-1.15.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/6b/59127338b86d9fe4d99418f5a15118bea778103ee0fe9d9dd7e0af174e95/jiter-0.16.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "mcp", "version": "1.29.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/c8/248b201f6d753d69fd5d6506011abbb35a946d9142b2ae311a948fd0be3d/mcp-1.29.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1c/6c/c73fa9d5a85f6ab05395de61c5f6984e0a9ff40bb5ff888d46dff02526c6/charset_normalizer-3.5.1-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "types-requests", "version": "2.33.0.20260712"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/e7/010c87f559e216d83f9dc51e939633fd0d0ead3377340181ab0e223cd3b5/types_requests-2.33.0.20260712-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "colorama", "version": "0.4.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c3/fb/951032a3bf22a5697c83183fb6294a4843772947a70e616c57b3ff5f522e/cryptography-50.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7d/47/5ecf1023850036e674c77ec4de86182d309ae344e39e7cba984b7df5d647/cffi-2.1.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/77bcb1168b33704908295533d27f10eb811e9e3e193e8993dc99572211d3/rpds_py-2026.6.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/3a/764912c58293d95b6dcdf4cc255f9d10de310580ced547b082eb9d72018c/sse_starlette-3.4.8-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.52.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/79/4a20b54ab0491485ccd8c077db2d39187c7f12b3e15485d38a7be37c81b4/uvicorn-0.52.4-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "54acb8a9a6cd450523a6e79a8e22ef0c"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "celery", "version": "5.7.0a1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/de/bf/72703e2ac184cc9c4c641ba5abaec725cbdcf48755c7582f006005d38848/celery-5.7.0a1-py3-none-any.whl"}}, {"metadata": {"name": "billiard", "version": "4.3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/60/60/ade6d336983b82fbc330d0d0371f945249b448152852952f643787a3288d/billiard-4.3.0-py3-none-any.whl"}}, {"metadata": {"name": "click-repl", "version": "0.4.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e0/ae/63d94d251d2e1a7bf3794ea47cb1c99fe6de055b732ea79d7bcdabef8ff5/click_repl-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "newrelic", "version": "10.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/d4/71/07c41fd5e8c94e95216b000d00c3cf735f769cb406c0f33c6ff83b7b7418/newrelic-10.16.0.tar.gz"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "vine", "version": "5.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/03/ff/7c0c86c43b3cbb927e0ccc0255cb4057ceba4799cd44ae95174ce8e8b5b2/vine-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "redis", "version": "8.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/66/9d/c5731f6e3608663d4d3656fd8d3aecee8b509c3082818f5a13eae925baea/redis-8.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.7.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/18/f1/46d32fe4b9aae09fe397e768ff376d9b6bdbb4f11faaa727f163c3457b43/pytest_forked-1.7.5-py3-none-any.whl"}}, {"metadata": {"name": "click-didyoumean", "version": "0.3.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/1b/5b/974430b5ffdb7a4f1941d13d83c64a0395114503cc357c6b9ae4ce5047ed/click_didyoumean-0.3.1-py3-none-any.whl"}}, {"metadata": {"name": "click-plugins", "version": "1.1.1.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/3d/9a/2abecb28ae875e39c8cad711eb1186d8d14eab564705325e77e4e6ab9ae5/click_plugins-1.1.1.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "kombu", "version": "5.7.0a1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b6/d9/1b98be4b45c3cb6737663ea5e7847fcc8f6c21de204a0411ae12874fbfc0/kombu-5.7.0a1-py3-none-any.whl"}}, {"metadata": {"name": "amqp", "version": "5.4.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/07/99/6b965aa99a32630c1c61ce57c9dcf81cec6fec354274a87f14525302b7f7/amqp-5.4.0-py3-none-any.whl"}}, {"metadata": {"name": "prompt_toolkit", "version": "3.0.53"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/54/6f/84908cad2d6aa5144abcf7b42709fe4fdb459bc640ec7ac5786e7693dabc/prompt_toolkit-3.0.53-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "tzdata", "version": "2026.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/f9/bc/8737e8d54cf51106118039b83f485a4783112fab49ea9d044b234978a46e/tzdata-2026.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/39/cc/9c0adc5861020de426ec71716b6c1bef8d90694b7d6d0a16202cdb1647f5/wcwidth-0.8.4-py3-none-any.whl"}}, {"metadata": {"name": "tzlocal", "version": "5.4.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/9e/a4/017a7a6cbe387d961a688ec31364ae60a5c4e22c96ae9921b79a947c855d/tzlocal-5.4.4-py3-none-any.whl"}}], "install_targets_hash": "571b466b11beb803cdcf782ce81876e3"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "pydantic-ai", "version": "2.47.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/12/1a/a46dad48b18c004eb686596d360d2310fc9c928b5b9b31341c03c6c813f1/pydantic_ai-2.47.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-ai-slim", "version": "2.47.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/eb/94/5d8a27dbe4a9e27378698c31c5848310d7a7727e22e1334f683dfbe5397d/pydantic_ai_slim-2.47.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-evals", "version": "2.47.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a9/81/34504d9426f420cc3ea05eb5d3f387a17f14d5ea678b6ced18d6f4be9da4/pydantic_evals-2.47.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-graph", "version": "2.47.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/3c/b0/4630a964201fb04dba730cbe54b7941309d97d59c01537465b075c26cae7/pydantic_graph-2.47.0-py3-none-any.whl"}}, {"metadata": {"name": "fastmcp-slim", "version": "4.0.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ed/76/8dc551ef1f222bd146537ae100baf7441628aa1050494b567249ece997c2/fastmcp_slim-4.0.5-py3-none-any.whl"}}, {"metadata": {"name": "mcp", "version": "2.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/1b/ff/8e7eade68b8a28f7da0ed1085544341b51f9c935dbf6b95c76b7edfea6a0/mcp-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mcp-types", "version": "2.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/8f/d7/6ffba5d8cd5dd9b8a19478875c50e04945314ba5074e84d749283f27f62d/mcp_types-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "py-key-value-aio", "version": "0.4.6"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/9a/46/12871550fb0613d149144bb9d41f22680d5f46717bc45a76eb5798c20c3f/py_key_value_aio-0.4.6-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofile", "version": "3.12.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/4e/79/6e45e778c4c3cab39e0937b007b720c15f76c50c6453d153282d0fcc3588/aiofile-3.12.3-py3-none-any.whl"}}, {"metadata": {"name": "caio", "version": "0.12.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/d3/f4/c39ed874d420bb2719d52932d763953c28371c536d6bf264de1febeb27d5/caio-0.12.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anthropic", "version": "1.7.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c0/dc/74995efda028421917f4caabd24db1373ee0742573a2363fff1a21191441/anthropic-1.7.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.17.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ac/4a/84a5ec271d09f7590b6073af5ee4abb44eab4ccace453b7e2c5ce45234ca/jiter-0.17.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c5/02/bc19b47a96c2d3109760711acf22369e56bd7e405ca52f7ade164d2ead57/pydantic_core-2.46.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "argcomplete", "version": "3.7.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/46/bd/551ee6af426af84ca33e02622be722925c196608e9127d731ef17c47f06e/argcomplete-3.7.2-py3-none-any.whl"}}, {"metadata": {"name": "Authlib", "version": "1.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b8/c6/6f124bcfbbfb20fba22c939b4e43a06dccfc0e1ca20e5634ca573cb1e271/authlib-1.8.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "beartype", "version": "0.22.9"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/cc/18245721fa7747065ab478316c7fea7c74777d07f37ae60db2e84f8172e8/beartype-0.22.9-py3-none-any.whl"}}, {"metadata": {"name": "cachetools", "version": "7.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cc/bb/1c6e7a89b11da19f137e4ef5a5c5fe47a5bb686449ba343944ccf8fb34b2/cachetools-7.2.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/5b/f0/424cb557d99aa86ac55da5e2add02e2882e44047b6264f93ade1b975a993/cryptography-50.0.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7d/47/5ecf1023850036e674c77ec4de86182d309ae344e39e7cba984b7df5d647/cffi-2.1.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "genai-prices", "version": "0.1.7"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/d5/4a/9e04f3dca5ffe74133779ab5e9925ffb6411afbeac55d26fa0e148722599/genai_prices-0.1.7-py3-none-any.whl"}}, {"metadata": {"name": "google-genai", "version": "2.24.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/84/5b/87913fe392ba7b6402577259289ed3740c577956554a674b191a2971d33e/google_genai-2.24.0-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.58.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/59/13/477d90d09591b3938b45c4e11f4d8a51291682112cb5efcac961e815d562/google_auth-2.58.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/1c/6c/c73fa9d5a85f6ab05395de61c5f6984e0a9ff40bb5ff888d46dff02526c6/charset_normalizer-3.5.1-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0c/e8/f7dac2e980bacc92bdc26cebae4ae4d50cae5380732c50980598fc0bbae4/websockets-16.1.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "griffelib", "version": "2.3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/41/63/e876e789525063c840ccfa8857febdabd6523bcef9ce7eb979b9305ea895/griffelib-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "joserfc", "version": "1.7.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/67/c5/82addfd375e5ee6520644e0553e4aadde92d668c4fc99cc716d337fe7bb3/joserfc-1.7.5-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "keyring", "version": "25.7.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/81/db/e655086b7f3a705df045bf0933bdd9c2f79bb3c97bfef1384598bb79a217/keyring-25.7.0-py3-none-any.whl"}}, {"metadata": {"name": "logfire", "version": "5.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cd/02/b32c3d5c298e4a9010694d261fb82c2c672747c0bf2b47bffda484aef349/logfire-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-exporter-otlp-proto-http", "version": "1.44.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cd/d0/fdeb1a98d8d3a6205f5f297c51b4a9bfe65126ab60339669bbe3dd54c2e2/opentelemetry_exporter_otlp_proto_http-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-exporter-otlp-proto-common", "version": "1.44.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/5e/71/65fd9d54c10b860f87c045ccee1264cab7011268895d3528818a29c1172a/opentelemetry_exporter_otlp_proto_common-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-proto", "version": "1.44.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/d1/7c/8be563d68e93bbefa5c8affb82ddcff91b3ad858ce49957ba7b16fd3e0ab/opentelemetry_proto-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "googleapis-common-protos", "version": "1.75.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/1a/7a/7d79170c6ce6f12e109df2b3879d6b934010cf4f99aea8de8b7e5408c174/googleapis_common_protos-1.75.3-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.44.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ca/6f/a04e900f465ff3221ccc395522503e2d10e79fa21f2723c8e177aae1e0d1/opentelemetry_api-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-sdk", "version": "1.44.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e7/23/ff077e61886ee020a17ce9c8b6fa11c601c8d8345b09ea24f605445df62a/opentelemetry_sdk-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-semantic-conventions", "version": "0.65b0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a6/0e/49df70d9b81fb5cbae4bbf2a49d865b09bcbcbc4eb53f5851b1027738d78/opentelemetry_semantic_conventions-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "protobuf", "version": "7.36.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e4/04/d52c7016b04b6c5108f26691f9d33ec82a9b65d041f1a9c771137693d618/protobuf-7.36.2-py3-none-any.whl"}}, {"metadata": {"name": "executing", "version": "2.2.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "logfire-api", "version": "5.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2d/51/123dab197fb08c0892e3bea1c2266bff159aa2ee82ad43bef93505859705/logfire_api-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "3.17.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/57/bc/5b80a0ca4069a6b5ba6c7d48ae7a4f8176b2c0bde0bebccdb867472ec6f6/openai-3.17.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-instrumentation", "version": "0.65b0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/40/7b/85eab1215f72adf0e68d3dc4a679b9bff993fa679ff34cd8dd378e2659fd/opentelemetry_instrumentation-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "wrapt", "version": "2.4.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/72/26/7435de516099b528e2232770b459d6706002736f41d8f092bbb11ea01575/wrapt-2.4.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "opentelemetry-instrumentation-httpx", "version": "0.65b0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/9d/0f/c6144096b4914bbf44b43ba21c962e8f333ff045770b50a3e79ed8bd455f/opentelemetry_instrumentation_httpx-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-util-http", "version": "0.65b0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/23/3f/ab8d29df207ce5f470a07fa96ebb48af4e95b7fab7e7635311b9a32f2fab/opentelemetry_util_http-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "platformdirs", "version": "4.11.12"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ec/2b/69de6317fbf48865bb12aa56c9cfcfff46b3add0cd45250725d96146dce0/platformdirs-4.11.12-py3-none-any.whl"}}, {"metadata": {"name": "prompt_toolkit", "version": "3.0.53"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/54/6f/84908cad2d6aa5144abcf7b42709fe4fdb459bc640ec7ac5786e7693dabc/prompt_toolkit-3.0.53-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/9a/3b/6163796d69c3977d1e4287bea4a6979161cbbdd170ebb430511e8e1999ce/pyasn1-0.6.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "email-validator", "version": "2.3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "dnspython", "version": "2.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.14.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/9c/97/672cb32ce0dfea44b740cb7b4f97038463b9cf7c0ead1aacf595572851d6/pyjwt-2.14.0-py3-none-any.whl"}}, {"metadata": {"name": "pyperclip", "version": "1.11.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/df/80/fc9d01d5ed37ba4c42ca2b55b4339ae6e200b456be3a1aaddf4a9fa99b8c/pyperclip-1.11.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e9/44/77bcb1168b33704908295533d27f10eb811e9e3e193e8993dc99572211d3/rpds_py-2026.6.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.11"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/98/6a/2ba3ed4a69babf3afdddf7d8314a48d87562c0a442206bbc2a1b50d5efc0/sse_starlette-3.4.11-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/79/29/46ad8061f57bd9f8b2ea0aa82bf574e0f2aa040b0857a1582adba9957899/tiktoken-0.14.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.53.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/76/18/0eea75741ee812e9f598b687619ce2454f6c3a1c5cd21ea990ec6bd26f45/uvicorn-0.53.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/39/cc/9c0adc5861020de426ec71716b6c1bef8d90694b7d6d0a16202cdb1647f5/wcwidth-0.8.4-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.classes", "version": "3.4.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7f/66/b15ce62552d84bbfcec9a4873ab79d993a1dd4edb922cbfccae192bd5b5f/jaraco.classes-3.4.0-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.context", "version": "6.1.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/f2/58/bc8954bda5fcda97bd7c19be11b85f91973d67a706ed4a3aec33e7de22db/jaraco_context-6.1.2-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.functools", "version": "4.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/02/36/ecc85bc96c273dc8a11273ed4782272975e6338d4a3e9228621175edf0e3/jaraco_functools-4.6.0-py3-none-any.whl"}}, {"metadata": {"name": "more-itertools", "version": "11.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e8/3d/1087453384dbde46a8c7f9356eead2c58be8a7bf156bca40243377c85715/more_itertools-11.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.9.10"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2b/d1/ee7662561735f90475443c3ca1977e5cecaeaa8f29620dec75580aebc839/regex-2026.9.10-cp314-cp314t-macosx_11_0_arm64.whl"}}], "install_targets_hash": "59d07114fce5d52fca16194a659dc9bf"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "SQLAlchemy", "version": "2.0.54"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/25/15dfe6814847eeda773bd58ab6cf42a94b0176e5cf25a578fc1165777160/sqlalchemy-2.0.54-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "greenlet", "version": "3.5.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/c5/2b6c721ba8b8963da42d5a0f57f25b8aaeb1fe9bdd156875e57f3be648a2/greenlet-3.5.6-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}], "install_targets_hash": "5f2fe90c79dc2d3da3f52a628b506ec0"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/5e/17398df3a139985ba9d11ed072531986f408c8fca952835ef1ab1820c02b/charset_normalizer-3.4.9-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "623a652072a7d5d73d07fc99e6bd44fb"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/5e/17398df3a139985ba9d11ed072531986f408c8fca952835ef1ab1820c02b/charset_normalizer-3.4.9-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "623a652072a7d5d73d07fc99e6bd44fb"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/5e/17398df3a139985ba9d11ed072531986f408c8fca952835ef1ab1820c02b/charset_normalizer-3.4.9-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "623a652072a7d5d73d07fc99e6bd44fb"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "pymongo", "version": "4.18.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9f/cf/41c06f9cce2035bf061248d1576439bc60701852f75118fd2b5a3408abd0/pymongo-4.18.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "dnspython", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "mockupdb", "version": "1.8.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2f/c0/bc0c3e82bf91993bf2337b125c4d49c3cadae39f5a4c642baada958f976e/mockupdb-1.8.1-py2.py3-none-any.whl"}}], "install_targets_hash": "69c2fba3fd9077f55ce7488963967c53"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "pymongo", "version": "4.18.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c4/42/aa057e91930209d731ec3fed03edf32cf6aa59838f7766227ee219142574/pymongo-4.18.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "dnspython", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "mockupdb", "version": "1.8.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2f/c0/bc0c3e82bf91993bf2337b125c4d49c3cadae39f5a4c642baada958f976e/mockupdb-1.8.1-py2.py3-none-any.whl"}}], "install_targets_hash": "69c2fba3fd9077f55ce7488963967c53"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "pydantic-ai", "version": "1.107.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/64/72ff998a79459c41f0e40f079a06ad45934fb2c095f604b9d44b983620b8/pydantic_ai-1.107.6-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-ai-slim", "version": "1.107.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/41/140a5e2d339e20d50e7685ffdc463977ae708f139a035fc658eced234afb/pydantic_ai_slim-1.107.6-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-evals", "version": "1.107.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/21/bc/299d19d27e237c407a77edb3f72d81a1cac0dd09964ea8cc9beac4e61f96/pydantic_evals-1.107.6-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-graph", "version": "1.107.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/2f/4f94314f952d242de53e6ae0f250d249609710ce500209f0acf46a7133a8/pydantic_graph-1.107.6-py3-none-any.whl"}}, {"metadata": {"name": "anthropic", "version": "0.125.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2f/1a/b1bd30cda3790557e8791bec5922a6ec8fabb6fa8b008c76a39cf7be6152/anthropic-0.125.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "fastmcp", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ac/14/6d950459cc831fa17fe2d1797926b6eb2d2f2af50f830e62d0c098cc1ec8/fastmcp-3.4.7-py3-none-any.whl"}}, {"metadata": {"name": "fastmcp-slim", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b4/97/e0e53642cd029a9a7635ae9c548f9f2cc995af5914e487b3df795664e4be/fastmcp_slim-3.4.7-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/bd/8d001191893178ff8e826e46ad5299446e62b93cd164e17b0ffea08832ec/hf_xet-1.4.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "huggingface_hub", "version": "1.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/03/40a05316cb6616e5b7efd7773656441ab04b4b022c2199e79bb4622a92a3/huggingface_hub-1.18.0-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/96/c1813dcca15c5a370145a448aaea7d1f83f6f0228a5f1130e79340ee385f/jiter-0.17.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "mcp", "version": "1.30.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f5/f4/e58bc33317c92a0203664daaf00bf6f41166cc0149e5d6870a03f7cd004a/mcp-1.30.0-py3-none-any.whl"}}, {"metadata": {"name": "py-key-value-aio", "version": "0.4.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/46/12871550fb0613d149144bb9d41f22680d5f46717bc45a76eb5798c20c3f/py_key_value_aio-0.4.6-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/64/a4e536cb16d7f61a7fd3120b46c577fc7fa7325992f69c4f52bc786d77d8/pydantic_core-2.46.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typer", "version": "0.25.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/f9/2b3ff4e56e5fa7debfaf9eb135d0da96f3e9a1d5b27222223c7296336e5f/typer-0.25.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "ag-ui-protocol", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/b0/850be4576e6443dc575daa54188d8136ae2b2eca3f19e098e7a088fc9ebc/ag_ui_protocol-1.0.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofile", "version": "3.12.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/79/6e45e778c4c3cab39e0937b007b720c15f76c50c6453d153282d0fcc3588/aiofile-3.12.3-py3-none-any.whl"}}, {"metadata": {"name": "caio", "version": "0.12.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/25/81/6b86722be50975b80a636afebed5af1a6e6588afeff0ae1a0a7f8c262707/caio-0.12.4-cp314-cp314t-manylinux_2_34_x86_64.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "argcomplete", "version": "3.7.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/46/bd/551ee6af426af84ca33e02622be722925c196608e9127d731ef17c47f06e/argcomplete-3.7.2-py3-none-any.whl"}}, {"metadata": {"name": "Authlib", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b8/c6/6f124bcfbbfb20fba22c939b4e43a06dccfc0e1ca20e5634ca573cb1e271/authlib-1.8.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "beartype", "version": "0.22.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/cc/18245721fa7747065ab478316c7fea7c74777d07f37ae60db2e84f8172e8/beartype-0.22.9-py3-none-any.whl"}}, {"metadata": {"name": "boto3", "version": "1.43.98"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/46/d29efd46ecac6637065a39418c5fb95500d70ec63e76065b5a72c936172f/boto3-1.43.98-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.98"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/ca/c7617e99c3247f545233ab2181840d142c5f72034e22864172866fb1369a/botocore-1.43.98-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "s3transfer", "version": "0.19.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/e7/5c595c75e9f41a44f30e526eda465ea0b4eec93470e074e4a111b253f13a/s3transfer-0.19.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "cachetools", "version": "7.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cc/bb/1c6e7a89b11da19f137e4ef5a5c5fe47a5bb686449ba343944ccf8fb34b2/cachetools-7.2.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "cohere", "version": "7.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4a/c3/064a44c498bf6ae8621caa14307d3ef5471157f149e33cfd64417c8e9ad3/cohere-7.1.1-py3-none-any.whl"}}, {"metadata": {"name": "fastavro", "version": "1.12.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/bf/4f669e10b6bc38a731ee3400aed1a1e2d0a3e3cf411e72f6b320d3af0eaf/fastavro-1.12.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/ee/e4e10a94d51cd1ee638aa7e00b65399e6b2a4e8376ab6d2eac9f95586671/charset_normalizer-3.5.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "tokenizers", "version": "0.23.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/18/1e/bc6587c5ab643b2e17776cace9070a2ae73549c86bffac9934a600bf3c31/tokenizers-0.23.2.tar.gz"}}, {"metadata": {"name": "types-requests", "version": "2.33.0.20260906"}, "download_info": {"url": "https://files.pythonhosted.org/packages/60/4c/51ec821d22a45b4162fa3f3e9e94ea4c0f8c49e82363b10955baa5438391/types_requests-2.33.0.20260906-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1a/01/0127d11a762b31a9ee0221894f540318761783f3fdc4bc5d057698caebd5/cryptography-50.0.1-cp314-cp314t-manylinux_2_34_x86_64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/95/eff5f0cee78d2eabc7eebffec40d3fc1876b5f3c95582e018bb4b99601f2/cffi-2.1.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "cyclopts", "version": "4.25.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/cc/e879da3d54cf727f90e6d90118e132672c3913338b566740486f8797190d/cyclopts-4.25.3-py3-none-any.whl"}}, {"metadata": {"name": "rich-rst", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/68/1fc93dd759605b5d00fc98b50200739e41ed32bd22d6ba35ca6c3932371b/rich_rst-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "filelock", "version": "4.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/29/33/af0635ab07fe83b1788a1dbe370ff3e226062495a998335cb18a1cac81aa/filelock-4.0.1-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6c/c0/a98505f18594f1bce828bb159cec0fcf9860562f1a2c85913409fc8f3d9e/fsspec-2026.9.0-py3-none-any.whl"}}, {"metadata": {"name": "genai-prices", "version": "0.1.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d5/4a/9e04f3dca5ffe74133779ab5e9925ffb6411afbeac55d26fa0e148722599/genai_prices-0.1.7-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.58.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/59/13/477d90d09591b3938b45c4e11f4d8a51291682112cb5efcac961e815d562/google_auth-2.58.0-py3-none-any.whl"}}, {"metadata": {"name": "google-genai", "version": "2.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/84/5b/87913fe392ba7b6402577259289ed3740c577956554a674b191a2971d33e/google_genai-2.24.0-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b2/39/26762f734113e22da2b942c3aca85798e0c0405d64c256549540ff31e5a1/websockets-16.1.1-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl"}}, {"metadata": {"name": "griffelib", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/63/e876e789525063c840ccfa8857febdabd6523bcef9ce7eb979b9305ea895/griffelib-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "groq", "version": "1.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/f6/c3d8ea3194d7d7d8292edd4dbb4b6832d29c2eab04887dda4a742e83902c/groq-1.7.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "joserfc", "version": "1.7.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/c5/82addfd375e5ee6520644e0553e4aadde92d668c4fc99cc716d337fe7bb3/joserfc-1.7.5-py3-none-any.whl"}}, {"metadata": {"name": "jsonref", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/ec/e1db9922bceb168197a558a2b8c03a7963f1afe93517ddd3cf99f202f996/jsonref-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-path", "version": "0.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/2c/9e69d73c4297508be9e3b64a970ea3971b3eb8db64ffc5802d40bd25981f/jsonschema_path-0.5.0-py3-none-any.whl"}}, {"metadata": {"name": "pathable", "version": "0.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a2/e8/6d75ffd9784bce2e93d1ae4415649427e39a53bb172d4672b2b59c6f0a7b/pathable-0.6.0-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "keyring", "version": "25.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/db/e655086b7f3a705df045bf0933bdd9c2f79bb3c97bfef1384598bb79a217/keyring-25.7.0-py3-none-any.whl"}}, {"metadata": {"name": "jeepney", "version": "0.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b2/a3/e137168c9c44d18eff0376253da9f1e9234d0239e0ee230d2fee6cea8e55/jeepney-0.9.0-py3-none-any.whl"}}, {"metadata": {"name": "logfire", "version": "5.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cd/02/b32c3d5c298e4a9010694d261fb82c2c672747c0bf2b47bffda484aef349/logfire-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-exporter-otlp-proto-http", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cd/d0/fdeb1a98d8d3a6205f5f297c51b4a9bfe65126ab60339669bbe3dd54c2e2/opentelemetry_exporter_otlp_proto_http-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-exporter-otlp-proto-common", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5e/71/65fd9d54c10b860f87c045ccee1264cab7011268895d3528818a29c1172a/opentelemetry_exporter_otlp_proto_common-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-proto", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d1/7c/8be563d68e93bbefa5c8affb82ddcff91b3ad858ce49957ba7b16fd3e0ab/opentelemetry_proto-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "googleapis-common-protos", "version": "1.75.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1a/7a/7d79170c6ce6f12e109df2b3879d6b934010cf4f99aea8de8b7e5408c174/googleapis_common_protos-1.75.3-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/6f/a04e900f465ff3221ccc395522503e2d10e79fa21f2723c8e177aae1e0d1/opentelemetry_api-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-sdk", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e7/23/ff077e61886ee020a17ce9c8b6fa11c601c8d8345b09ea24f605445df62a/opentelemetry_sdk-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-semantic-conventions", "version": "0.65b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/0e/49df70d9b81fb5cbae4bbf2a49d865b09bcbcbc4eb53f5851b1027738d78/opentelemetry_semantic_conventions-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "executing", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "logfire-api", "version": "5.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2d/51/123dab197fb08c0892e3bea1c2266bff159aa2ee82ad43bef93505859705/logfire_api-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "mistralai", "version": "2.10.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/98/f64b54166a607ece4e5c8494c843ac1f9c7c0af6f1014272cc420fe1d519/mistralai-2.10.1-py3-none-any.whl"}}, {"metadata": {"name": "eval_type_backport", "version": "0.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/a7/bb99bf5e6f78736ddb53480f2c3ff3702ffe2196a7c5e1661c03081d398e/eval_type_backport-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonpath-python", "version": "1.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/8a/1270a6803bd821cbfcdda387eaa13cb41a7b1f7b9bd145979b3bfb9d6cb7/jsonpath_python-1.1.6-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "3.16.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/17/72/2b1fe3e303db76ab2ba0c2de2b57822869bcb588db82334d4ff3aea8acf2/openai-3.16.2-py3-none-any.whl"}}, {"metadata": {"name": "openapi-pydantic", "version": "0.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/cf/03675d8bd8ecbf4445504d8071adab19f5f993676795708e36402ab38263/openapi_pydantic-0.5.1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-instrumentation", "version": "0.65b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/40/7b/85eab1215f72adf0e68d3dc4a679b9bff993fa679ff34cd8dd378e2659fd/opentelemetry_instrumentation-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "wrapt", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/a7/cca7fe0f26aa11cbbf09b2e6f4f774db167feeca43ad22fa1772afdccbad/wrapt-2.4.1-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl"}}, {"metadata": {"name": "opentelemetry-instrumentation-httpx", "version": "0.65b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/0f/c6144096b4914bbf44b43ba21c962e8f333ff045770b50a3e79ed8bd455f/opentelemetry_instrumentation_httpx-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-util-http", "version": "0.65b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/23/3f/ab8d29df207ce5f470a07fa96ebb48af4e95b7fab7e7635311b9a32f2fab/opentelemetry_util_http-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "platformdirs", "version": "4.11.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/39/be/3ae887e84c38c4dd1c549cd5825adc93f48069a94fe1cb8ac52a9da16f15/platformdirs-4.11.11-py3-none-any.whl"}}, {"metadata": {"name": "prompt_toolkit", "version": "3.0.53"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/6f/84908cad2d6aa5144abcf7b42709fe4fdb459bc640ec7ac5786e7693dabc/prompt_toolkit-3.0.53-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/3b/6163796d69c3977d1e4287bea4a6979161cbbdd170ebb430511e8e1999ce/pyasn1-0.6.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-handlebars", "version": "0.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/11/364bc401f1d8fdb3947079fc43ffdfbfc9132d065981a03a95d2e87440c4/pydantic_handlebars-0.2.1-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "email-validator", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "dnspython", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/97/672cb32ce0dfea44b740cb7b4f97038463b9cf7c0ead1aacf595572851d6/pyjwt-2.14.0-py3-none-any.whl"}}, {"metadata": {"name": "pyperclip", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/80/fc9d01d5ed37ba4c42ca2b55b4339ae6e200b456be3a1aaddf4a9fa99b8c/pyperclip-1.11.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8e/f4/b7ac49f30013aba8f7b9566b1dd07e81de95e708c1374b7bacc5b9bc5c9c/rpds_py-2026.6.3-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "SecretStorage", "version": "3.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/46/f5af3402b579fd5e11573ce652019a67074317e18c1935cc0b4ba9b35552/secretstorage-3.5.0-py3-none-any.whl"}}, {"metadata": {"name": "shellingham", "version": "1.5.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/6a/2ba3ed4a69babf3afdddf7d8314a48d87562c0a442206bbc2a1b50d5efc0/sse_starlette-3.4.11-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "temporalio", "version": "1.33.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/64/b92769790411fa33ce2d037131f5bc856b90837ab1af3d093036f5144c15/temporalio-1.33.0.tar.gz"}}, {"metadata": {"name": "nexus-rpc", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/11/52/6327a5f4fda01207205038a106a99848a41c83e933cd23ea2cab3d2ebc6c/nexus_rpc-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "types-protobuf", "version": "7.35.1.20260906"}, "download_info": {"url": "https://files.pythonhosted.org/packages/44/4e/f63e826c68f77ef875506d72f225918800346545ee99847bc28f3394f18d/types_protobuf-7.35.1.20260906-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/e8/46de4400d5bf859f640feee85bd7e32235f68ddf25db53c63be78e581e3a/tiktoken-0.14.0-cp314-cp314t-manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/03/921a3d3c75785aca9ebfbfcabfbc3a1be12e2ab5265deb026d55a5a3f83e/tqdm-4.70.1-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uncalled-for", "version": "0.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a2/40/97cec87c077eb3291fc7905e6633e08b7ca593c57d30238444bcb6bb3d53/uncalled_for-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.53.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/76/18/0eea75741ee812e9f598b687619ce2454f6c3a1c5cd21ea990ec6bd26f45/uvicorn-0.53.0-py3-none-any.whl"}}, {"metadata": {"name": "watchfiles", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0e/80/c7472203bad6268e3ef1ad260739704847898938ad7ea8b63a5131f46b50/watchfiles-1.2.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/39/cc/9c0adc5861020de426ec71716b6c1bef8d90694b7d6d0a16202cdb1647f5/wcwidth-0.8.4-py3-none-any.whl"}}, {"metadata": {"name": "xai-sdk", "version": "1.19.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/b5/6f6783b97fb3a5498eb852ccaa706e1a2c0de2409480e3c99428e85234fe/xai_sdk-1.19.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bb/6b/62cbd6577758699525f5c712d1ddef57d9875fbab0ae8d5f5a202fd598f8/aiohttp-3.14.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "grpcio", "version": "1.84.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/4f/4435c0aae54657258d9cfcba78598f3d9e5fe4c82ff18d78558567b90faf/grpcio-1.84.0.tar.gz"}}, {"metadata": {"name": "multidict", "version": "6.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/b0/8ee78b0fbe5fe153e9566055e1107c9bae0011b1ae903e30c7ab2ba3e07f/multidict-6.9.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "packaging", "version": "25.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl"}}, {"metadata": {"name": "protobuf", "version": "6.33.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c4/72/02445137af02769918a93807b2b7890047c32bfb9f90371cbc12688819eb/protobuf-6.33.6-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.25.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d1/38/97d79b81c342b78246cfedb74809e68841f3198d21653e10d3232bd9c622/yarl-1.25.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/1c/3d8622e60d0b767a5510d1d3cf21065b9db874696a51ea6d7a43180a259c/frozenlist-1.8.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fc/57/527910c455b5ec62f6871bef45d4f79fea16cb8c966ba0d4a07f0339ddc4/propcache-0.5.4-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "jaraco.classes", "version": "3.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/66/b15ce62552d84bbfcec9a4873ab79d993a1dd4edb922cbfccae192bd5b5f/jaraco.classes-3.4.0-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.context", "version": "6.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f2/58/bc8954bda5fcda97bd7c19be11b85f91973d67a706ed4a3aec33e7de22db/jaraco_context-6.1.2-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.functools", "version": "4.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/02/36/ecc85bc96c273dc8a11273ed4782272975e6338d4a3e9228621175edf0e3/jaraco_functools-4.6.0-py3-none-any.whl"}}, {"metadata": {"name": "more-itertools", "version": "11.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/3d/1087453384dbde46a8c7f9356eead2c58be8a7bf156bca40243377c85715/more_itertools-11.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.9.10"}, "download_info": {"url": "https://files.pythonhosted.org/packages/86/38/49f8d6fd34fc1a9c75b5b96364ebdde702a8144e5ed63d2213c58d454c27/regex-2026.9.10-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}], "install_targets_hash": "6f4f519d18d963ec7cd5445acdc50e5e"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "pyreqwest", "version": "0.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e4/a4/ae549562ca0210e75925e835626b8945382f79f5e886cd4165a756c4730d/pyreqwest-0.13.0.tar.gz"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}], "install_targets_hash": "6f61e0b03332a8ab3c901a7f00b7fa71"} -{"python_version": "3.14", "dependencies": [{"metadata": {"name": "boto3", "version": "1.43.98"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/46/d29efd46ecac6637065a39418c5fb95500d70ec63e76065b5a72c936172f/boto3-1.43.98-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.98"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/ca/c7617e99c3247f545233ab2181840d142c5f72034e22864172866fb1369a/botocore-1.43.98-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "s3transfer", "version": "0.19.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/e7/5c595c75e9f41a44f30e526eda465ea0b4eec93470e074e4a111b253f13a/s3transfer-0.19.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}], "install_targets_hash": "732c20a252602bec78b6c7ee26050916"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "pyreqwest", "version": "0.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e4/a4/ae549562ca0210e75925e835626b8945382f79f5e886cd4165a756c4730d/pyreqwest-0.13.0.tar.gz"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}], "install_targets_hash": "6f61e0b03332a8ab3c901a7f00b7fa71"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "openai", "version": "3.17.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/57/bc/5b80a0ca4069a6b5ba6c7d48ae7a4f8176b2c0bde0bebccdb867472ec6f6/openai-3.17.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.17.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ac/4a/84a5ec271d09f7590b6073af5ee4abb44eab4ccace453b7e2c5ce45234ca/jiter-0.17.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c5/02/bc19b47a96c2d3109760711acf22369e56bd7e405ca52f7ade164d2ead57/pydantic_core-2.46.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "6fe5caedd83b044975e2a5e20436ed3f"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "openai-agents", "version": "0.18.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/7c/08b9929a15131081898e38c5612d44ee293851d5c80f31ca1153efe82143/openai_agents-0.18.3-py3-none-any.whl"}}, {"metadata": {"name": "griffelib", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/63/e876e789525063c840ccfa8857febdabd6523bcef9ce7eb979b9305ea895/griffelib-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "mcp", "version": "1.30.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f5/f4/e58bc33317c92a0203664daaf00bf6f41166cc0149e5d6870a03f7cd004a/mcp-1.30.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "2.54.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/a8/bb76c7356de8ad57f59d5ff993d434df0607f07f08bcc9c9a5c275e399c0/openai-2.54.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ac/4a/84a5ec271d09f7590b6073af5ee4abb44eab4ccace453b7e2c5ce45234ca/jiter-0.17.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/02/bc19b47a96c2d3109760711acf22369e56bd7e405ca52f7ade164d2ead57/pydantic_core-2.46.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1c/6c/c73fa9d5a85f6ab05395de61c5f6984e0a9ff40bb5ff888d46dff02526c6/charset_normalizer-3.5.1-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/e8/f7dac2e980bacc92bdc26cebae4ae4d50cae5380732c50980598fc0bbae4/websockets-16.1.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/97/672cb32ce0dfea44b740cb7b4f97038463b9cf7c0ead1aacf595572851d6/pyjwt-2.14.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/f0/424cb557d99aa86ac55da5e2add02e2882e44047b6264f93ade1b975a993/cryptography-50.0.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7d/47/5ecf1023850036e674c77ec4de86182d309ae344e39e7cba984b7df5d647/cffi-2.1.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/77bcb1168b33704908295533d27f10eb811e9e3e193e8993dc99572211d3/rpds_py-2026.6.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/6a/2ba3ed4a69babf3afdddf7d8314a48d87562c0a442206bbc2a1b50d5efc0/sse_starlette-3.4.11-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/03/921a3d3c75785aca9ebfbfcabfbc3a1be12e2ab5265deb026d55a5a3f83e/tqdm-4.70.1-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.52.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/79/4a20b54ab0491485ccd8c077db2d39187c7f12b3e15485d38a7be37c81b4/uvicorn-0.52.4-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "72e451893bc86523078d768ca9965660"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "openai", "version": "2.54.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/a8/bb76c7356de8ad57f59d5ff993d434df0607f07f08bcc9c9a5c275e399c0/openai-2.54.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/6b/59127338b86d9fe4d99418f5a15118bea778103ee0fe9d9dd7e0af174e95/jiter-0.16.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "74376afb5a970b70b12c3903563ea5a0"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "openai", "version": "2.54.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/a8/bb76c7356de8ad57f59d5ff993d434df0607f07f08bcc9c9a5c275e399c0/openai-2.54.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/6b/59127338b86d9fe4d99418f5a15118bea778103ee0fe9d9dd7e0af174e95/jiter-0.16.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "74376afb5a970b70b12c3903563ea5a0"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "statsig", "version": "0.72.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/76/f6/72e48d6e3b37aaf866d1ca0c59382a28e67d303b1edee446c1fb5ceaf8ba/statsig-0.72.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "brotli", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f7/16/c92ca344d646e71a43b8bb353f0a6490d7f6e06210f8554c8f874e454285/brotli-1.2.0.tar.gz"}}, {"metadata": {"name": "grpcio", "version": "1.83.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/98/304898ac4e04e2d5e4e4c2eadc178b1f2a16d5f4bc2f91306c87d64680b9/grpcio-1.83.0.tar.gz"}}, {"metadata": {"name": "ijson", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fc/d0/b3beddb96eef0b20bb9902c36e4de30f145be06d7e5e1d780e1a1689d0ce/ijson-3.5.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "ip3country", "version": "0.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d6/b7/48a7f1ab9eee62f1113114207df7e7e6bc29227389d554f42cc11bc98108/ip3country-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "protobuf", "version": "7.36.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/c3/629999e78d46c1115c11886d51c6bd68c17ce4a944f1ea3e153a91316a33/protobuf-7.36.0-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1c/6c/c73fa9d5a85f6ab05395de61c5f6984e0a9ff40bb5ff888d46dff02526c6/charset_normalizer-3.5.1-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "ua-parser", "version": "1.0.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/7c/6367995ff57aaa2d9e1055adbaec2519cf5a979780a83a93fdf8c6ec37be/ua_parser-1.0.2-py3-none-any.whl"}}, {"metadata": {"name": "ua-parser-builtins", "version": "202606"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/a3/f26edd95a2ce2ffbf559da432e5ff544e8dcda3673d1c775f71afffb18b7/ua_parser_builtins-202606-py3-none-any.whl"}}], "install_targets_hash": "763ce761517f8c5492de65d82e642a37"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "statsig", "version": "0.72.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/76/f6/72e48d6e3b37aaf866d1ca0c59382a28e67d303b1edee446c1fb5ceaf8ba/statsig-0.72.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "brotli", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f7/16/c92ca344d646e71a43b8bb353f0a6490d7f6e06210f8554c8f874e454285/brotli-1.2.0.tar.gz"}}, {"metadata": {"name": "grpcio", "version": "1.83.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/98/304898ac4e04e2d5e4e4c2eadc178b1f2a16d5f4bc2f91306c87d64680b9/grpcio-1.83.0.tar.gz"}}, {"metadata": {"name": "ijson", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fc/d0/b3beddb96eef0b20bb9902c36e4de30f145be06d7e5e1d780e1a1689d0ce/ijson-3.5.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "ip3country", "version": "0.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d6/b7/48a7f1ab9eee62f1113114207df7e7e6bc29227389d554f42cc11bc98108/ip3country-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "protobuf", "version": "7.36.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/c3/629999e78d46c1115c11886d51c6bd68c17ce4a944f1ea3e153a91316a33/protobuf-7.36.0-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1c/6c/c73fa9d5a85f6ab05395de61c5f6984e0a9ff40bb5ff888d46dff02526c6/charset_normalizer-3.5.1-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "ua-parser", "version": "1.0.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/7c/6367995ff57aaa2d9e1055adbaec2519cf5a979780a83a93fdf8c6ec37be/ua_parser-1.0.2-py3-none-any.whl"}}, {"metadata": {"name": "ua-parser-builtins", "version": "202606"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/a3/f26edd95a2ce2ffbf559da432e5ff544e8dcda3673d1c775f71afffb18b7/ua_parser_builtins-202606-py3-none-any.whl"}}], "install_targets_hash": "763ce761517f8c5492de65d82e642a37"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "statsig", "version": "0.55.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/17/de62fdea8aab8aa7c4a833378e0e39054b728dfd45ef279e975ed5ef4e86/statsig-0.55.3-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "grpcio", "version": "1.82.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b6/19/e29d3979b420b92d516ee97f0bff4fb88cbb3d724791318f50beb55db549/grpcio-1.82.0.tar.gz"}}, {"metadata": {"name": "ijson", "version": "3.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/35/8b/3e703e8cc4b3ada79f13b28070b51d9550c578f76d1968657905857b2ddd/ijson-3.5.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "ip3country", "version": "0.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d6/b7/48a7f1ab9eee62f1113114207df7e7e6bc29227389d554f42cc11bc98108/ip3country-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "protobuf", "version": "7.35.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/c7/5f7c636ec43e0c545e28d1f1db71990108306f7bdcb89f069ba97e428e7f/protobuf-7.35.1-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "ua-parser", "version": "1.0.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/7c/6367995ff57aaa2d9e1055adbaec2519cf5a979780a83a93fdf8c6ec37be/ua_parser-1.0.2-py3-none-any.whl"}}, {"metadata": {"name": "ua-parser-builtins", "version": "202606"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/a3/f26edd95a2ce2ffbf559da432e5ff544e8dcda3673d1c775f71afffb18b7/ua_parser_builtins-202606-py3-none-any.whl"}}], "install_targets_hash": "7a12a54efcb27f14786026d8ffbb0792"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "statsig", "version": "0.55.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/17/de62fdea8aab8aa7c4a833378e0e39054b728dfd45ef279e975ed5ef4e86/statsig-0.55.3-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "grpcio", "version": "1.82.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b6/19/e29d3979b420b92d516ee97f0bff4fb88cbb3d724791318f50beb55db549/grpcio-1.82.0.tar.gz"}}, {"metadata": {"name": "ijson", "version": "3.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/35/8b/3e703e8cc4b3ada79f13b28070b51d9550c578f76d1968657905857b2ddd/ijson-3.5.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "ip3country", "version": "0.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d6/b7/48a7f1ab9eee62f1113114207df7e7e6bc29227389d554f42cc11bc98108/ip3country-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "protobuf", "version": "7.35.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/c7/5f7c636ec43e0c545e28d1f1db71990108306f7bdcb89f069ba97e428e7f/protobuf-7.35.1-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "ua-parser", "version": "1.0.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/7c/6367995ff57aaa2d9e1055adbaec2519cf5a979780a83a93fdf8c6ec37be/ua_parser-1.0.2-py3-none-any.whl"}}, {"metadata": {"name": "ua-parser-builtins", "version": "202606"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/a3/f26edd95a2ce2ffbf559da432e5ff544e8dcda3673d1c775f71afffb18b7/ua_parser_builtins-202606-py3-none-any.whl"}}], "install_targets_hash": "7a12a54efcb27f14786026d8ffbb0792"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "statsig", "version": "0.55.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/17/de62fdea8aab8aa7c4a833378e0e39054b728dfd45ef279e975ed5ef4e86/statsig-0.55.3-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "grpcio", "version": "1.82.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b6/19/e29d3979b420b92d516ee97f0bff4fb88cbb3d724791318f50beb55db549/grpcio-1.82.0.tar.gz"}}, {"metadata": {"name": "ijson", "version": "3.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/35/8b/3e703e8cc4b3ada79f13b28070b51d9550c578f76d1968657905857b2ddd/ijson-3.5.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "ip3country", "version": "0.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d6/b7/48a7f1ab9eee62f1113114207df7e7e6bc29227389d554f42cc11bc98108/ip3country-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "protobuf", "version": "7.35.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/c7/5f7c636ec43e0c545e28d1f1db71990108306f7bdcb89f069ba97e428e7f/protobuf-7.35.1-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "ua-parser", "version": "1.0.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/7c/6367995ff57aaa2d9e1055adbaec2519cf5a979780a83a93fdf8c6ec37be/ua_parser-1.0.2-py3-none-any.whl"}}, {"metadata": {"name": "ua-parser-builtins", "version": "202606"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/a3/f26edd95a2ce2ffbf559da432e5ff544e8dcda3673d1c775f71afffb18b7/ua_parser_builtins-202606-py3-none-any.whl"}}], "install_targets_hash": "7a12a54efcb27f14786026d8ffbb0792"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "statsig", "version": "0.55.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/17/de62fdea8aab8aa7c4a833378e0e39054b728dfd45ef279e975ed5ef4e86/statsig-0.55.3-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "grpcio", "version": "1.82.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b6/19/e29d3979b420b92d516ee97f0bff4fb88cbb3d724791318f50beb55db549/grpcio-1.82.0.tar.gz"}}, {"metadata": {"name": "ijson", "version": "3.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/35/8b/3e703e8cc4b3ada79f13b28070b51d9550c578f76d1968657905857b2ddd/ijson-3.5.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "ip3country", "version": "0.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d6/b7/48a7f1ab9eee62f1113114207df7e7e6bc29227389d554f42cc11bc98108/ip3country-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "protobuf", "version": "7.35.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/c7/5f7c636ec43e0c545e28d1f1db71990108306f7bdcb89f069ba97e428e7f/protobuf-7.35.1-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "ua-parser", "version": "1.0.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/7c/6367995ff57aaa2d9e1055adbaec2519cf5a979780a83a93fdf8c6ec37be/ua_parser-1.0.2-py3-none-any.whl"}}, {"metadata": {"name": "ua-parser-builtins", "version": "202606"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/a3/f26edd95a2ce2ffbf559da432e5ff544e8dcda3673d1c775f71afffb18b7/ua_parser_builtins-202606-py3-none-any.whl"}}], "install_targets_hash": "7a12a54efcb27f14786026d8ffbb0792"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "statsig", "version": "0.55.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/17/de62fdea8aab8aa7c4a833378e0e39054b728dfd45ef279e975ed5ef4e86/statsig-0.55.3-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "grpcio", "version": "1.82.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b6/19/e29d3979b420b92d516ee97f0bff4fb88cbb3d724791318f50beb55db549/grpcio-1.82.0.tar.gz"}}, {"metadata": {"name": "ijson", "version": "3.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/35/8b/3e703e8cc4b3ada79f13b28070b51d9550c578f76d1968657905857b2ddd/ijson-3.5.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "ip3country", "version": "0.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d6/b7/48a7f1ab9eee62f1113114207df7e7e6bc29227389d554f42cc11bc98108/ip3country-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "protobuf", "version": "7.35.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/c7/5f7c636ec43e0c545e28d1f1db71990108306f7bdcb89f069ba97e428e7f/protobuf-7.35.1-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "ua-parser", "version": "1.0.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/7c/6367995ff57aaa2d9e1055adbaec2519cf5a979780a83a93fdf8c6ec37be/ua_parser-1.0.2-py3-none-any.whl"}}, {"metadata": {"name": "ua-parser-builtins", "version": "202606"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/a3/f26edd95a2ce2ffbf559da432e5ff544e8dcda3673d1c775f71afffb18b7/ua_parser_builtins-202606-py3-none-any.whl"}}], "install_targets_hash": "7a12a54efcb27f14786026d8ffbb0792"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "gql", "version": "4.4.0b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/97/00105a44b645f2234e4540027d2ae4ea34b6a95d40e45f9f01c020d0f5b0/gql-4.4.0b0-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/d8/8ec0e471248c500acdce2be3f46db8fb62b5eb60efef072529cc85ee1d26/aiohttp-3.14.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.57"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/7a/1cfe9c296df0fa6e0143c8622b10f21fa8fb9cce25450e9a8e5cf6523e4b/botocore-1.43.57-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.3.0rc0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8c/89/efd877ac909125f050b9562afc1f4b1bc7c0a90bc2a03ed7b0cb21debca3/graphql_core-3.3.0rc0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/13/b8/cfd91c4ab9134d386d48f0b6ac662ff3d4be6efdee59ee1c67ebc3c0487c/httpx2-2.9.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9f/fb/46c52b781975c335a2bcf1072c7bbc007cbdc8d674217f5ee1daba2c848b/httpcore2-2.9.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/5e/17398df3a139985ba9d11ed072531986f408c8fca952835ef1ab1820c02b/charset_normalizer-3.4.9-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "15.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ff/0b/cfb76b7fe99686db264bff829779a539d923e7564ffd7ef18da6c54c3774/yarl-1.24.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "responses", "version": "0.26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/28/693e1d9ebf72baa062ded80d837a035b86ce75eda5a269379e9e2b1008a8/responses-0.26.2-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/73/daf935ea7048ddd7ec8eec5345b4a40b619d2d178b3c0a0900796bc3c794/propcache-0.5.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}], "install_targets_hash": "7d9f37badbb06455849b77944a0bd79e"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "gql", "version": "4.4.0b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/97/00105a44b645f2234e4540027d2ae4ea34b6a95d40e45f9f01c020d0f5b0/gql-4.4.0b0-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/d8/8ec0e471248c500acdce2be3f46db8fb62b5eb60efef072529cc85ee1d26/aiohttp-3.14.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.57"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/7a/1cfe9c296df0fa6e0143c8622b10f21fa8fb9cce25450e9a8e5cf6523e4b/botocore-1.43.57-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.3.0rc0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8c/89/efd877ac909125f050b9562afc1f4b1bc7c0a90bc2a03ed7b0cb21debca3/graphql_core-3.3.0rc0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/13/b8/cfd91c4ab9134d386d48f0b6ac662ff3d4be6efdee59ee1c67ebc3c0487c/httpx2-2.9.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9f/fb/46c52b781975c335a2bcf1072c7bbc007cbdc8d674217f5ee1daba2c848b/httpcore2-2.9.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/5e/17398df3a139985ba9d11ed072531986f408c8fca952835ef1ab1820c02b/charset_normalizer-3.4.9-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "15.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ff/0b/cfb76b7fe99686db264bff829779a539d923e7564ffd7ef18da6c54c3774/yarl-1.24.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "responses", "version": "0.26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/28/693e1d9ebf72baa062ded80d837a035b86ce75eda5a269379e9e2b1008a8/responses-0.26.2-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/73/daf935ea7048ddd7ec8eec5345b4a40b619d2d178b3c0a0900796bc3c794/propcache-0.5.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}], "install_targets_hash": "7d9f37badbb06455849b77944a0bd79e"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "gql", "version": "4.4.0b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/97/00105a44b645f2234e4540027d2ae4ea34b6a95d40e45f9f01c020d0f5b0/gql-4.4.0b0-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/d8/8ec0e471248c500acdce2be3f46db8fb62b5eb60efef072529cc85ee1d26/aiohttp-3.14.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.57"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/7a/1cfe9c296df0fa6e0143c8622b10f21fa8fb9cce25450e9a8e5cf6523e4b/botocore-1.43.57-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.3.0rc0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8c/89/efd877ac909125f050b9562afc1f4b1bc7c0a90bc2a03ed7b0cb21debca3/graphql_core-3.3.0rc0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/13/b8/cfd91c4ab9134d386d48f0b6ac662ff3d4be6efdee59ee1c67ebc3c0487c/httpx2-2.9.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9f/fb/46c52b781975c335a2bcf1072c7bbc007cbdc8d674217f5ee1daba2c848b/httpcore2-2.9.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/5e/17398df3a139985ba9d11ed072531986f408c8fca952835ef1ab1820c02b/charset_normalizer-3.4.9-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "15.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ff/0b/cfb76b7fe99686db264bff829779a539d923e7564ffd7ef18da6c54c3774/yarl-1.24.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "responses", "version": "0.26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/28/693e1d9ebf72baa062ded80d837a035b86ce75eda5a269379e9e2b1008a8/responses-0.26.2-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/73/daf935ea7048ddd7ec8eec5345b4a40b619d2d178b3c0a0900796bc3c794/propcache-0.5.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}], "install_targets_hash": "7d9f37badbb06455849b77944a0bd79e"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "gql", "version": "4.4.0b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/97/00105a44b645f2234e4540027d2ae4ea34b6a95d40e45f9f01c020d0f5b0/gql-4.4.0b0-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/d8/8ec0e471248c500acdce2be3f46db8fb62b5eb60efef072529cc85ee1d26/aiohttp-3.14.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.57"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/7a/1cfe9c296df0fa6e0143c8622b10f21fa8fb9cce25450e9a8e5cf6523e4b/botocore-1.43.57-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.3.0rc0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8c/89/efd877ac909125f050b9562afc1f4b1bc7c0a90bc2a03ed7b0cb21debca3/graphql_core-3.3.0rc0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/13/b8/cfd91c4ab9134d386d48f0b6ac662ff3d4be6efdee59ee1c67ebc3c0487c/httpx2-2.9.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9f/fb/46c52b781975c335a2bcf1072c7bbc007cbdc8d674217f5ee1daba2c848b/httpcore2-2.9.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/5e/17398df3a139985ba9d11ed072531986f408c8fca952835ef1ab1820c02b/charset_normalizer-3.4.9-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "15.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ff/0b/cfb76b7fe99686db264bff829779a539d923e7564ffd7ef18da6c54c3774/yarl-1.24.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "responses", "version": "0.26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/28/693e1d9ebf72baa062ded80d837a035b86ce75eda5a269379e9e2b1008a8/responses-0.26.2-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/73/daf935ea7048ddd7ec8eec5345b4a40b619d2d178b3c0a0900796bc3c794/propcache-0.5.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}], "install_targets_hash": "7d9f37badbb06455849b77944a0bd79e"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "httpx2", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e6/a7/aea061b450d51cf448c1ccc8e1fc6f04c0d8fdc97c17524c7f835018bb92/httpx2-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2-pytest", "version": "1.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/46/ef/e9b6fb576f1f518f68e9f9cce9776870452ae2b8cfbba53b4127701b9a55/httpx2_pytest-1.0.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b7/76d6baa8c087cf5170f36dbeb92471e77c5c48f8f7ca8e5ba4ad613ea492/httpcore2-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}], "install_targets_hash": "81061e3f7fbd70089dc2dae262e96f28"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "httpx2", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e6/a7/aea061b450d51cf448c1ccc8e1fc6f04c0d8fdc97c17524c7f835018bb92/httpx2-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2-pytest", "version": "1.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/46/ef/e9b6fb576f1f518f68e9f9cce9776870452ae2b8cfbba53b4127701b9a55/httpx2_pytest-1.0.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b7/76d6baa8c087cf5170f36dbeb92471e77c5c48f8f7ca8e5ba4ad613ea492/httpcore2-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}], "install_targets_hash": "81061e3f7fbd70089dc2dae262e96f28"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "httpx2", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e6/a7/aea061b450d51cf448c1ccc8e1fc6f04c0d8fdc97c17524c7f835018bb92/httpx2-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2-pytest", "version": "1.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/46/ef/e9b6fb576f1f518f68e9f9cce9776870452ae2b8cfbba53b4127701b9a55/httpx2_pytest-1.0.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b7/76d6baa8c087cf5170f36dbeb92471e77c5c48f8f7ca8e5ba4ad613ea492/httpcore2-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}], "install_targets_hash": "81061e3f7fbd70089dc2dae262e96f28"} -{"python_version": "3.14", "dependencies": [{"metadata": {"name": "dramatiq", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8c/13/0550ff585ade7b423e2ecaac29c4ab88673a58ae92ef25b6629089a2b92c/dramatiq-2.2.1-py3-none-any.whl"}}], "install_targets_hash": "83dfbbed9bd8bc2ec0e6747a01c98300"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "openai", "version": "3.17.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/57/bc/5b80a0ca4069a6b5ba6c7d48ae7a4f8176b2c0bde0bebccdb867472ec6f6/openai-3.17.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.17.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ac/4a/84a5ec271d09f7590b6073af5ee4abb44eab4ccace453b7e2c5ce45234ca/jiter-0.17.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c5/02/bc19b47a96c2d3109760711acf22369e56bd7e405ca52f7ade164d2ead57/pydantic_core-2.46.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/79/29/46ad8061f57bd9f8b2ea0aa82bf574e0f2aa040b0857a1582adba9957899/tiktoken-0.14.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.9.10"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2b/d1/ee7662561735f90475443c3ca1977e5cecaeaa8f29620dec75580aebc839/regex-2026.9.10-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/1c/6c/c73fa9d5a85f6ab05395de61c5f6984e0a9ff40bb5ff888d46dff02526c6/charset_normalizer-3.5.1-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "urllib3", "version": "2.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "828f8978f312e7020633b81adf747d24"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "dramatiq", "version": "2.2.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/8c/13/0550ff585ade7b423e2ecaac29c4ab88673a58ae92ef25b6629089a2b92c/dramatiq-2.2.1-py3-none-any.whl"}}], "install_targets_hash": "83dfbbed9bd8bc2ec0e6747a01c98300"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "Quart", "version": "0.23.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/5c/c1/26dca56249da1a889ebb946000ab272712476209234f714ad3e8013ee005/quart-0.23.1-py3-none-any.whl"}}, {"metadata": {"name": "quart-auth", "version": "0.12.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ce/6b/e902def52a0c1c32bf872d87eb76cf4bf6109d015ac8c9e6768894676c8d/quart_auth-0.12.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.7.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/18/f1/46d32fe4b9aae09fe397e768ff376d9b6bdbb4f11faaa727f163c3457b43/pytest_forked-1.7.5-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "Hypercorn", "version": "0.18.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/93/35/850277d1b17b206bd10874c8a9a3f52e059452fb49bb0d22cbb908f6038b/hypercorn-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "h2", "version": "4.4.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/22/e85faf23bd72a92d1921e37d674ca56eb298a3c8be31fdecef0ff2b3aaac/h2-4.4.1-py3-none-any.whl"}}, {"metadata": {"name": "hpack", "version": "4.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/b4/4a9fcfb2aef6ba44d9073ecd301443aa00b3dac95de5619f2a7de7ec8a91/hpack-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "hyperframe", "version": "6.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/48/30/47d0bf6072f7252e6521f3447ccfa40b421b6824517f82854703d0f5a98b/hyperframe-6.1.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "wsproto", "version": "1.3.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a4/f5/10b68b7b1544245097b2a1b8238f66f2fc6dcaeb24ba5d917f52bd2eed4f/wsproto-1.3.2-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "priority", "version": "2.0.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/5e/5f/82c8074f7e84978129347c2c6ec8b6c59f3584ff1a20bc3c940a3e061790/priority-2.0.0-py3-none-any.whl"}}], "install_targets_hash": "8466032de3e88e282989c969ffd1cb35"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "Quart", "version": "0.23.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/5c/c1/26dca56249da1a889ebb946000ab272712476209234f714ad3e8013ee005/quart-0.23.1-py3-none-any.whl"}}, {"metadata": {"name": "quart-auth", "version": "0.12.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ce/6b/e902def52a0c1c32bf872d87eb76cf4bf6109d015ac8c9e6768894676c8d/quart_auth-0.12.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.7.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/18/f1/46d32fe4b9aae09fe397e768ff376d9b6bdbb4f11faaa727f163c3457b43/pytest_forked-1.7.5-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "Hypercorn", "version": "0.18.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/93/35/850277d1b17b206bd10874c8a9a3f52e059452fb49bb0d22cbb908f6038b/hypercorn-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "h2", "version": "4.4.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/22/e85faf23bd72a92d1921e37d674ca56eb298a3c8be31fdecef0ff2b3aaac/h2-4.4.1-py3-none-any.whl"}}, {"metadata": {"name": "hpack", "version": "4.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/b4/4a9fcfb2aef6ba44d9073ecd301443aa00b3dac95de5619f2a7de7ec8a91/hpack-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "hyperframe", "version": "6.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/48/30/47d0bf6072f7252e6521f3447ccfa40b421b6824517f82854703d0f5a98b/hyperframe-6.1.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "wsproto", "version": "1.3.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a4/f5/10b68b7b1544245097b2a1b8238f66f2fc6dcaeb24ba5d917f52bd2eed4f/wsproto-1.3.2-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "priority", "version": "2.0.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/5e/5f/82c8074f7e84978129347c2c6ec8b6c59f3584ff1a20bc3c940a3e061790/priority-2.0.0-py3-none-any.whl"}}], "install_targets_hash": "8466032de3e88e282989c969ffd1cb35"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "huggingface_hub", "version": "1.32.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/cf/d98dd561d6d0d7b7d7a64d1563f8aaaa7c235daee41c1c9bcc3da62420ed/huggingface_hub-1.32.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d5/ee/7c0d7b6ab336167531b1c30af2af003f054af4c749becbd7209ae33a77c3/hf_xet-1.6.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "responses", "version": "0.26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6d/86/ca7958de70cb0752350575e98229368a3a2f746a2942034b3364e17312bb/responses-0.26.3-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/ee/e4e10a94d51cd1ee638aa7e00b65399e6b2a4e8376ab6d2eac9f95586671/charset_normalizer-3.5.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-httpx", "version": "0.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/55/1fa65f8e4fceb19dd6daa867c162ad845d547f6058cd92b4b02384a44777/pytest_httpx-0.36.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "filelock", "version": "4.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/29/33/af0635ab07fe83b1788a1dbe370ff3e226062495a998335cb18a1cac81aa/filelock-4.0.1-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6c/c0/a98505f18594f1bce828bb159cec0fcf9860562f1a2c85913409fc8f3d9e/fsspec-2026.9.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/03/921a3d3c75785aca9ebfbfcabfbc3a1be12e2ab5265deb026d55a5a3f83e/tqdm-4.70.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}], "install_targets_hash": "8d3f9781d86e000603a20c010acf0233"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "Flask-Login", "version": "0.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/59/f5/67e9cc5c2036f58115f9fe0f00d203cf6780c3ff8ae0e705e7a9d9e8ff9e/Flask_Login-0.6.3-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}], "install_targets_hash": "8e9f2612223a3ea6906a34018db168cd"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "Flask-Login", "version": "0.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/59/f5/67e9cc5c2036f58115f9fe0f00d203cf6780c3ff8ae0e705e7a9d9e8ff9e/Flask_Login-0.6.3-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}], "install_targets_hash": "8e9f2612223a3ea6906a34018db168cd"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "Flask-Login", "version": "0.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/59/f5/67e9cc5c2036f58115f9fe0f00d203cf6780c3ff8ae0e705e7a9d9e8ff9e/Flask_Login-0.6.3-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}], "install_targets_hash": "8e9f2612223a3ea6906a34018db168cd"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "Flask-Login", "version": "0.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/59/f5/67e9cc5c2036f58115f9fe0f00d203cf6780c3ff8ae0e705e7a9d9e8ff9e/Flask_Login-0.6.3-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}], "install_targets_hash": "8e9f2612223a3ea6906a34018db168cd"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "Flask-Login", "version": "0.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/59/f5/67e9cc5c2036f58115f9fe0f00d203cf6780c3ff8ae0e705e7a9d9e8ff9e/Flask_Login-0.6.3-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}], "install_targets_hash": "8e9f2612223a3ea6906a34018db168cd"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "Flask-Login", "version": "0.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/59/f5/67e9cc5c2036f58115f9fe0f00d203cf6780c3ff8ae0e705e7a9d9e8ff9e/Flask_Login-0.6.3-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}], "install_targets_hash": "8e9f2612223a3ea6906a34018db168cd"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "Flask-Login", "version": "0.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/59/f5/67e9cc5c2036f58115f9fe0f00d203cf6780c3ff8ae0e705e7a9d9e8ff9e/Flask_Login-0.6.3-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}], "install_targets_hash": "8e9f2612223a3ea6906a34018db168cd"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "Flask-Login", "version": "0.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/59/f5/67e9cc5c2036f58115f9fe0f00d203cf6780c3ff8ae0e705e7a9d9e8ff9e/Flask_Login-0.6.3-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}], "install_targets_hash": "8e9f2612223a3ea6906a34018db168cd"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "typer", "version": "0.27.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/dc/bf/205d0004930ede8f542fb58f601526fccf4ae7626075ca1e6c4de5d3d652/typer-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "shellingham", "version": "1.5.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}], "install_targets_hash": "8ea02a85ddecd330a24e7e8daff773d1"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "typer", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/bf/205d0004930ede8f542fb58f601526fccf4ae7626075ca1e6c4de5d3d652/typer-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "shellingham", "version": "1.5.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}], "install_targets_hash": "8ea02a85ddecd330a24e7e8daff773d1"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "typer", "version": "0.27.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/dc/bf/205d0004930ede8f542fb58f601526fccf4ae7626075ca1e6c4de5d3d652/typer-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "shellingham", "version": "1.5.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}], "install_targets_hash": "8ea02a85ddecd330a24e7e8daff773d1"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "typer", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/bf/205d0004930ede8f542fb58f601526fccf4ae7626075ca1e6c4de5d3d652/typer-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "shellingham", "version": "1.5.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}], "install_targets_hash": "8ea02a85ddecd330a24e7e8daff773d1"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "mcp", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/ff/8e7eade68b8a28f7da0ed1085544341b51f9c935dbf6b95c76b7edfea6a0/mcp-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mcp-types", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8f/d7/6ffba5d8cd5dd9b8a19478875c50e04945314ba5074e84d749283f27f62d/mcp_types-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/95/411ba65569158e862368917aaf56597f3e5fa3b91b0502919638465a08f3/httpx2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/74/d370e55600d9bcfa0d9794b0166126d49291a3d2b20c268fc98c453a4948/httpcore2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/6f/a04e900f465ff3221ccc395522503e2d10e79fa21f2723c8e177aae1e0d1/opentelemetry_api-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/02/bc19b47a96c2d3109760711acf22369e56bd7e405ca52f7ade164d2ead57/pydantic_core-2.46.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/97/672cb32ce0dfea44b740cb7b4f97038463b9cf7c0ead1aacf595572851d6/pyjwt-2.14.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/f0/424cb557d99aa86ac55da5e2add02e2882e44047b6264f93ade1b975a993/cryptography-50.0.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7d/47/5ecf1023850036e674c77ec4de86182d309ae344e39e7cba984b7df5d647/cffi-2.1.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/77bcb1168b33704908295533d27f10eb811e9e3e193e8993dc99572211d3/rpds_py-2026.6.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/6a/2ba3ed4a69babf3afdddf7d8314a48d87562c0a442206bbc2a1b50d5efc0/sse_starlette-3.4.11-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.53.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/76/18/0eea75741ee812e9f598b687619ce2454f6c3a1c5cd21ea990ec6bd26f45/uvicorn-0.53.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "92894b9de86e2bb0e11c5c76350def3a"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "mcp", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/ff/8e7eade68b8a28f7da0ed1085544341b51f9c935dbf6b95c76b7edfea6a0/mcp-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mcp-types", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8f/d7/6ffba5d8cd5dd9b8a19478875c50e04945314ba5074e84d749283f27f62d/mcp_types-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/95/411ba65569158e862368917aaf56597f3e5fa3b91b0502919638465a08f3/httpx2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/74/d370e55600d9bcfa0d9794b0166126d49291a3d2b20c268fc98c453a4948/httpcore2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/6f/a04e900f465ff3221ccc395522503e2d10e79fa21f2723c8e177aae1e0d1/opentelemetry_api-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/64/a4e536cb16d7f61a7fd3120b46c577fc7fa7325992f69c4f52bc786d77d8/pydantic_core-2.46.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/97/672cb32ce0dfea44b740cb7b4f97038463b9cf7c0ead1aacf595572851d6/pyjwt-2.14.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1a/01/0127d11a762b31a9ee0221894f540318761783f3fdc4bc5d057698caebd5/cryptography-50.0.1-cp314-cp314t-manylinux_2_34_x86_64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/95/eff5f0cee78d2eabc7eebffec40d3fc1876b5f3c95582e018bb4b99601f2/cffi-2.1.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8e/f4/b7ac49f30013aba8f7b9566b1dd07e81de95e708c1374b7bacc5b9bc5c9c/rpds_py-2026.6.3-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/6a/2ba3ed4a69babf3afdddf7d8314a48d87562c0a442206bbc2a1b50d5efc0/sse_starlette-3.4.11-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.52.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/79/4a20b54ab0491485ccd8c077db2d39187c7f12b3e15485d38a7be37c81b4/uvicorn-0.52.4-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "92894b9de86e2bb0e11c5c76350def3a"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "Django", "version": "5.2.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/f8/ce120525ca78f12b07daf65786679c5d0b54a75285a8958d3ae55e39da35/django-5.2.17-py3-none-any.whl"}}, {"metadata": {"name": "coverage", "version": "7.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/d1/7f645fc2eccd318369a8a9948acc447bb7c1ade2911e31d3c5620544c22b/coverage-7.11.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "psycopg2-binary", "version": "2.9.12"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/60/a3624f79acea344c16fbef3a94d28b89a8042ddfb8f3e4ca83f538671409/psycopg2_binary-2.9.12.tar.gz"}}, {"metadata": {"name": "djangorestframework", "version": "3.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/d7/7461738e819b853275b35fd35712a85806c09a327e1fd5f8ff766bdd317e/djangorestframework-3.18.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-django", "version": "4.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/27/88/52db7a840fdbd74934f8df11b7450c9919ac00f61c02e88827f3d58180f7/pytest_django-4.13.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.7.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/18/f1/46d32fe4b9aae09fe397e768ff376d9b6bdbb4f11faaa727f163c3457b43/pytest_forked-1.7.5-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "channels", "version": "4.3.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/16/34/c32915288b7ef482377b6adc401192f98c6a99b3a145423d3b8aed807898/channels-4.3.2-py3-none-any.whl"}}, {"metadata": {"name": "asgiref", "version": "3.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c0/1b/54f4ad77cd8a584fa70746c47df988e002cf1ee1eba43364d46f87803647/asgiref-3.12.1-py3-none-any.whl"}}, {"metadata": {"name": "executing", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "daphne", "version": "4.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/0c/59e966c167880904f2e6a235c63169760dce58ba8062a7a153a6183539cc/daphne-4.2.3-py3-none-any.whl"}}, {"metadata": {"name": "autobahn", "version": "26.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/de/73/f109f563c27e048e45d135d81af19e6ca391e24905550b06bd1c9d674c57/autobahn-26.7.1.tar.gz"}}, {"metadata": {"name": "cbor2", "version": "6.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/41/3b28184154f6cbf7e47c1b7fb4a7a291c54f27a6f3a0a2f64b078c6a13e1/cbor2-6.1.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7d/47/5ecf1023850036e674c77ec4de86182d309ae344e39e7cba984b7df5d647/cffi-2.1.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c3/fb/951032a3bf22a5697c83183fb6294a4843772947a70e616c57b3ff5f522e/cryptography-50.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "hyperlink", "version": "21.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/aa/8caf6a0a3e62863cbb9dab27135660acba46903b703e224f14f447e57934/hyperlink-21.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "msgpack", "version": "1.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/74/0b797484013128837f3b1cbb6cea019277c4de4e377dc512b4d9a0f92940/msgpack-1.2.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "sqlparse", "version": "0.5.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/4b/359f28a903c13438ef59ebeee215fb25da53066db67b305c125f1c6d2a25/sqlparse-0.5.5-py3-none-any.whl"}}, {"metadata": {"name": "Twisted", "version": "26.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/57/bcf4e2370dd218c9aa68a9140a65d86729c73f1d529f7e94786c2766fc72/twisted-26.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "Automat", "version": "25.4.16"}, "download_info": {"url": "https://files.pythonhosted.org/packages/02/ff/1175b0b7371e46244032d43a56862d0af455823b5280a50c63d99cc50f18/automat-25.4.16-py3-none-any.whl"}}, {"metadata": {"name": "constantly", "version": "23.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b8/40/c199d095151addf69efdb4b9ca3a4f20f70e20508d6222bffb9b76f58573/constantly-23.10.4-py3-none-any.whl"}}, {"metadata": {"name": "Incremental", "version": "24.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1d/55/0f4df2a44053867ea9cbea73fc588b03c55605cd695cee0a3d86f0029cb2/incremental-24.11.0-py3-none-any.whl"}}, {"metadata": {"name": "pyOpenSSL", "version": "26.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ad/2cf6d3fa2fae5c79e1ed9960c0d42badd0f94d81dd12b50604cdc839e648/pyopenssl-26.4.0-py3-none-any.whl"}}, {"metadata": {"name": "service-identity", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/eb/2433e1af4ff903499144de4846569fb3300b816179ae99a03c2f011b666a/service_identity-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "txaio", "version": "26.6.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/91/68/075bf851e11c9ef65bd6a0426791f0d9a0c7dae0e7f6e0b16ca67334b456/txaio-26.6.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "5.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/e4/39862f0f7174ff07cfd1e2d0c9065ded34aeebdb7db8daf2f0e5bf89b46f/ujson-5.13.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "zope.interface", "version": "8.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f3/55/de0c3459ff717fce3342f9a29464c281fdeb0d36c3171ee88d119d5f0650/zope_interface-8.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "929f80d9f3977f1e1657f716043a13fa"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "Django", "version": "5.2.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/f8/ce120525ca78f12b07daf65786679c5d0b54a75285a8958d3ae55e39da35/django-5.2.17-py3-none-any.whl"}}, {"metadata": {"name": "coverage", "version": "7.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/d1/7f645fc2eccd318369a8a9948acc447bb7c1ade2911e31d3c5620544c22b/coverage-7.11.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "psycopg2-binary", "version": "2.9.12"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/60/a3624f79acea344c16fbef3a94d28b89a8042ddfb8f3e4ca83f538671409/psycopg2_binary-2.9.12.tar.gz"}}, {"metadata": {"name": "djangorestframework", "version": "3.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/d7/7461738e819b853275b35fd35712a85806c09a327e1fd5f8ff766bdd317e/djangorestframework-3.18.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-django", "version": "4.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/27/88/52db7a840fdbd74934f8df11b7450c9919ac00f61c02e88827f3d58180f7/pytest_django-4.13.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.7.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/18/f1/46d32fe4b9aae09fe397e768ff376d9b6bdbb4f11faaa727f163c3457b43/pytest_forked-1.7.5-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "channels", "version": "4.3.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/16/34/c32915288b7ef482377b6adc401192f98c6a99b3a145423d3b8aed807898/channels-4.3.2-py3-none-any.whl"}}, {"metadata": {"name": "asgiref", "version": "3.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c0/1b/54f4ad77cd8a584fa70746c47df988e002cf1ee1eba43364d46f87803647/asgiref-3.12.1-py3-none-any.whl"}}, {"metadata": {"name": "executing", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "daphne", "version": "4.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/0c/59e966c167880904f2e6a235c63169760dce58ba8062a7a153a6183539cc/daphne-4.2.3-py3-none-any.whl"}}, {"metadata": {"name": "autobahn", "version": "26.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/de/73/f109f563c27e048e45d135d81af19e6ca391e24905550b06bd1c9d674c57/autobahn-26.7.1.tar.gz"}}, {"metadata": {"name": "cbor2", "version": "6.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/41/3b28184154f6cbf7e47c1b7fb4a7a291c54f27a6f3a0a2f64b078c6a13e1/cbor2-6.1.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7d/47/5ecf1023850036e674c77ec4de86182d309ae344e39e7cba984b7df5d647/cffi-2.1.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c3/fb/951032a3bf22a5697c83183fb6294a4843772947a70e616c57b3ff5f522e/cryptography-50.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "hyperlink", "version": "21.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/aa/8caf6a0a3e62863cbb9dab27135660acba46903b703e224f14f447e57934/hyperlink-21.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "msgpack", "version": "1.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/74/0b797484013128837f3b1cbb6cea019277c4de4e377dc512b4d9a0f92940/msgpack-1.2.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "sqlparse", "version": "0.5.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/4b/359f28a903c13438ef59ebeee215fb25da53066db67b305c125f1c6d2a25/sqlparse-0.5.5-py3-none-any.whl"}}, {"metadata": {"name": "Twisted", "version": "26.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/57/bcf4e2370dd218c9aa68a9140a65d86729c73f1d529f7e94786c2766fc72/twisted-26.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "Automat", "version": "25.4.16"}, "download_info": {"url": "https://files.pythonhosted.org/packages/02/ff/1175b0b7371e46244032d43a56862d0af455823b5280a50c63d99cc50f18/automat-25.4.16-py3-none-any.whl"}}, {"metadata": {"name": "constantly", "version": "23.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b8/40/c199d095151addf69efdb4b9ca3a4f20f70e20508d6222bffb9b76f58573/constantly-23.10.4-py3-none-any.whl"}}, {"metadata": {"name": "Incremental", "version": "24.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1d/55/0f4df2a44053867ea9cbea73fc588b03c55605cd695cee0a3d86f0029cb2/incremental-24.11.0-py3-none-any.whl"}}, {"metadata": {"name": "pyOpenSSL", "version": "26.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ad/2cf6d3fa2fae5c79e1ed9960c0d42badd0f94d81dd12b50604cdc839e648/pyopenssl-26.4.0-py3-none-any.whl"}}, {"metadata": {"name": "service-identity", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/eb/2433e1af4ff903499144de4846569fb3300b816179ae99a03c2f011b666a/service_identity-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "txaio", "version": "26.6.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/91/68/075bf851e11c9ef65bd6a0426791f0d9a0c7dae0e7f6e0b16ca67334b456/txaio-26.6.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "5.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/e4/39862f0f7174ff07cfd1e2d0c9065ded34aeebdb7db8daf2f0e5bf89b46f/ujson-5.13.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "zope.interface", "version": "8.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f3/55/de0c3459ff717fce3342f9a29464c281fdeb0d36c3171ee88d119d5f0650/zope_interface-8.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "929f80d9f3977f1e1657f716043a13fa"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "Django", "version": "5.2.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/f8/ce120525ca78f12b07daf65786679c5d0b54a75285a8958d3ae55e39da35/django-5.2.17-py3-none-any.whl"}}, {"metadata": {"name": "coverage", "version": "7.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/d1/7f645fc2eccd318369a8a9948acc447bb7c1ade2911e31d3c5620544c22b/coverage-7.11.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "psycopg2-binary", "version": "2.9.12"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/60/a3624f79acea344c16fbef3a94d28b89a8042ddfb8f3e4ca83f538671409/psycopg2_binary-2.9.12.tar.gz"}}, {"metadata": {"name": "djangorestframework", "version": "3.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/d7/7461738e819b853275b35fd35712a85806c09a327e1fd5f8ff766bdd317e/djangorestframework-3.18.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-django", "version": "4.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/27/88/52db7a840fdbd74934f8df11b7450c9919ac00f61c02e88827f3d58180f7/pytest_django-4.13.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.7.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/18/f1/46d32fe4b9aae09fe397e768ff376d9b6bdbb4f11faaa727f163c3457b43/pytest_forked-1.7.5-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "channels", "version": "4.3.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/16/34/c32915288b7ef482377b6adc401192f98c6a99b3a145423d3b8aed807898/channels-4.3.2-py3-none-any.whl"}}, {"metadata": {"name": "asgiref", "version": "3.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c0/1b/54f4ad77cd8a584fa70746c47df988e002cf1ee1eba43364d46f87803647/asgiref-3.12.1-py3-none-any.whl"}}, {"metadata": {"name": "executing", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "daphne", "version": "4.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/0c/59e966c167880904f2e6a235c63169760dce58ba8062a7a153a6183539cc/daphne-4.2.3-py3-none-any.whl"}}, {"metadata": {"name": "autobahn", "version": "26.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/de/73/f109f563c27e048e45d135d81af19e6ca391e24905550b06bd1c9d674c57/autobahn-26.7.1.tar.gz"}}, {"metadata": {"name": "cbor2", "version": "6.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/41/3b28184154f6cbf7e47c1b7fb4a7a291c54f27a6f3a0a2f64b078c6a13e1/cbor2-6.1.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7d/47/5ecf1023850036e674c77ec4de86182d309ae344e39e7cba984b7df5d647/cffi-2.1.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c3/fb/951032a3bf22a5697c83183fb6294a4843772947a70e616c57b3ff5f522e/cryptography-50.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "hyperlink", "version": "21.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/aa/8caf6a0a3e62863cbb9dab27135660acba46903b703e224f14f447e57934/hyperlink-21.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "msgpack", "version": "1.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/74/0b797484013128837f3b1cbb6cea019277c4de4e377dc512b4d9a0f92940/msgpack-1.2.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "sqlparse", "version": "0.5.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/4b/359f28a903c13438ef59ebeee215fb25da53066db67b305c125f1c6d2a25/sqlparse-0.5.5-py3-none-any.whl"}}, {"metadata": {"name": "Twisted", "version": "26.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/57/bcf4e2370dd218c9aa68a9140a65d86729c73f1d529f7e94786c2766fc72/twisted-26.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "Automat", "version": "25.4.16"}, "download_info": {"url": "https://files.pythonhosted.org/packages/02/ff/1175b0b7371e46244032d43a56862d0af455823b5280a50c63d99cc50f18/automat-25.4.16-py3-none-any.whl"}}, {"metadata": {"name": "constantly", "version": "23.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b8/40/c199d095151addf69efdb4b9ca3a4f20f70e20508d6222bffb9b76f58573/constantly-23.10.4-py3-none-any.whl"}}, {"metadata": {"name": "Incremental", "version": "24.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1d/55/0f4df2a44053867ea9cbea73fc588b03c55605cd695cee0a3d86f0029cb2/incremental-24.11.0-py3-none-any.whl"}}, {"metadata": {"name": "pyOpenSSL", "version": "26.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ad/2cf6d3fa2fae5c79e1ed9960c0d42badd0f94d81dd12b50604cdc839e648/pyopenssl-26.4.0-py3-none-any.whl"}}, {"metadata": {"name": "service-identity", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/eb/2433e1af4ff903499144de4846569fb3300b816179ae99a03c2f011b666a/service_identity-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "txaio", "version": "26.6.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/91/68/075bf851e11c9ef65bd6a0426791f0d9a0c7dae0e7f6e0b16ca67334b456/txaio-26.6.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "5.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/e4/39862f0f7174ff07cfd1e2d0c9065ded34aeebdb7db8daf2f0e5bf89b46f/ujson-5.13.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "zope.interface", "version": "8.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f3/55/de0c3459ff717fce3342f9a29464c281fdeb0d36c3171ee88d119d5f0650/zope_interface-8.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "929f80d9f3977f1e1657f716043a13fa"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "strawberry-graphql", "version": "0.327.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/09/e0deac5d4f466f6ecae1b91a91d1a291aad1890960a5d891bb80bda3425c/strawberry_graphql-0.327.7-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.12"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/b6/304c572e79b9e82982dbd5091e26a89f5018e565868091d804c2142f6ba5/graphql_core-3.2.12-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "cross-web", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7a/4a/78b52ec2edcbd9b123638f4e0421fd8699ebe653ebf63ac5f82abd2665bc/cross_web-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "fastapi", "version": "0.141.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/03/10388a42375ee7e4ac9b94eb2c5c569c8b5795e377e701c9ac3ad63de890/fastapi-0.141.1-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/02/bc19b47a96c2d3109760711acf22369e56bd7e405ca52f7ade164d2ead57/pydantic_core-2.46.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}], "install_targets_hash": "973f4a5847325907761d52b88b87e613"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "strawberry-graphql", "version": "0.327.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/09/e0deac5d4f466f6ecae1b91a91d1a291aad1890960a5d891bb80bda3425c/strawberry_graphql-0.327.7-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.12"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/b6/304c572e79b9e82982dbd5091e26a89f5018e565868091d804c2142f6ba5/graphql_core-3.2.12-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "cross-web", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7a/4a/78b52ec2edcbd9b123638f4e0421fd8699ebe653ebf63ac5f82abd2665bc/cross_web-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "fastapi", "version": "0.141.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/03/10388a42375ee7e4ac9b94eb2c5c569c8b5795e377e701c9ac3ad63de890/fastapi-0.141.1-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/09/c419f6f5a92e5fadde27efd190eca90f05e1261b10dbd8cbcb39cd8ea1dc/markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/64/a4e536cb16d7f61a7fd3120b46c577fc7fa7325992f69c4f52bc786d77d8/pydantic_core-2.46.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}], "install_targets_hash": "973f4a5847325907761d52b88b87e613"} -{"python_version": "3.14", "dependencies": [{"metadata": {"name": "pydantic-ai", "version": "2.46.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/01/20a5fda50b3e30067450d43ecd7ac1ddf41055982540ee6a48626a4e748b/pydantic_ai-2.46.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-ai-slim", "version": "2.46.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8c/fc/6a28534bc4b27026225fec76b4a2cb97274a0bda601a90890676b09c5132/pydantic_ai_slim-2.46.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-evals", "version": "2.46.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/89/83921db264a4d76561c641dd785472e68877525848228876a949565dd6b2/pydantic_evals-2.46.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-graph", "version": "2.46.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8b/7d/711d5e3a1ca9f560a365080779858be76510ff615a5106121ba0430b5f55/pydantic_graph-2.46.0-py3-none-any.whl"}}, {"metadata": {"name": "fastmcp-slim", "version": "4.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ed/76/8dc551ef1f222bd146537ae100baf7441628aa1050494b567249ece997c2/fastmcp_slim-4.0.5-py3-none-any.whl"}}, {"metadata": {"name": "mcp", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/ff/8e7eade68b8a28f7da0ed1085544341b51f9c935dbf6b95c76b7edfea6a0/mcp-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mcp-types", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8f/d7/6ffba5d8cd5dd9b8a19478875c50e04945314ba5074e84d749283f27f62d/mcp_types-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "py-key-value-aio", "version": "0.4.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/46/12871550fb0613d149144bb9d41f22680d5f46717bc45a76eb5798c20c3f/py_key_value_aio-0.4.6-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofile", "version": "3.12.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/79/6e45e778c4c3cab39e0937b007b720c15f76c50c6453d153282d0fcc3588/aiofile-3.12.3-py3-none-any.whl"}}, {"metadata": {"name": "caio", "version": "0.12.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/25/81/6b86722be50975b80a636afebed5af1a6e6588afeff0ae1a0a7f8c262707/caio-0.12.4-cp314-cp314t-manylinux_2_34_x86_64.whl"}}, {"metadata": {"name": "anthropic", "version": "1.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c0/dc/74995efda028421917f4caabd24db1373ee0742573a2363fff1a21191441/anthropic-1.7.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/96/c1813dcca15c5a370145a448aaea7d1f83f6f0228a5f1130e79340ee385f/jiter-0.17.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/64/a4e536cb16d7f61a7fd3120b46c577fc7fa7325992f69c4f52bc786d77d8/pydantic_core-2.46.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "argcomplete", "version": "3.7.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/46/bd/551ee6af426af84ca33e02622be722925c196608e9127d731ef17c47f06e/argcomplete-3.7.2-py3-none-any.whl"}}, {"metadata": {"name": "Authlib", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b8/c6/6f124bcfbbfb20fba22c939b4e43a06dccfc0e1ca20e5634ca573cb1e271/authlib-1.8.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "beartype", "version": "0.22.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/cc/18245721fa7747065ab478316c7fea7c74777d07f37ae60db2e84f8172e8/beartype-0.22.9-py3-none-any.whl"}}, {"metadata": {"name": "cachetools", "version": "7.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cc/bb/1c6e7a89b11da19f137e4ef5a5c5fe47a5bb686449ba343944ccf8fb34b2/cachetools-7.2.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1a/01/0127d11a762b31a9ee0221894f540318761783f3fdc4bc5d057698caebd5/cryptography-50.0.1-cp314-cp314t-manylinux_2_34_x86_64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/95/eff5f0cee78d2eabc7eebffec40d3fc1876b5f3c95582e018bb4b99601f2/cffi-2.1.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "genai-prices", "version": "0.1.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d5/4a/9e04f3dca5ffe74133779ab5e9925ffb6411afbeac55d26fa0e148722599/genai_prices-0.1.7-py3-none-any.whl"}}, {"metadata": {"name": "google-genai", "version": "2.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/84/5b/87913fe392ba7b6402577259289ed3740c577956554a674b191a2971d33e/google_genai-2.24.0-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.58.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/59/13/477d90d09591b3938b45c4e11f4d8a51291682112cb5efcac961e815d562/google_auth-2.58.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/ee/e4e10a94d51cd1ee638aa7e00b65399e6b2a4e8376ab6d2eac9f95586671/charset_normalizer-3.5.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b2/39/26762f734113e22da2b942c3aca85798e0c0405d64c256549540ff31e5a1/websockets-16.1.1-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "griffelib", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/63/e876e789525063c840ccfa8857febdabd6523bcef9ce7eb979b9305ea895/griffelib-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "joserfc", "version": "1.7.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/c5/82addfd375e5ee6520644e0553e4aadde92d668c4fc99cc716d337fe7bb3/joserfc-1.7.5-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "keyring", "version": "25.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/db/e655086b7f3a705df045bf0933bdd9c2f79bb3c97bfef1384598bb79a217/keyring-25.7.0-py3-none-any.whl"}}, {"metadata": {"name": "jeepney", "version": "0.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b2/a3/e137168c9c44d18eff0376253da9f1e9234d0239e0ee230d2fee6cea8e55/jeepney-0.9.0-py3-none-any.whl"}}, {"metadata": {"name": "logfire", "version": "5.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cd/02/b32c3d5c298e4a9010694d261fb82c2c672747c0bf2b47bffda484aef349/logfire-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-exporter-otlp-proto-http", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cd/d0/fdeb1a98d8d3a6205f5f297c51b4a9bfe65126ab60339669bbe3dd54c2e2/opentelemetry_exporter_otlp_proto_http-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-exporter-otlp-proto-common", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5e/71/65fd9d54c10b860f87c045ccee1264cab7011268895d3528818a29c1172a/opentelemetry_exporter_otlp_proto_common-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-proto", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d1/7c/8be563d68e93bbefa5c8affb82ddcff91b3ad858ce49957ba7b16fd3e0ab/opentelemetry_proto-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "googleapis-common-protos", "version": "1.75.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1a/7a/7d79170c6ce6f12e109df2b3879d6b934010cf4f99aea8de8b7e5408c174/googleapis_common_protos-1.75.3-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/6f/a04e900f465ff3221ccc395522503e2d10e79fa21f2723c8e177aae1e0d1/opentelemetry_api-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-sdk", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e7/23/ff077e61886ee020a17ce9c8b6fa11c601c8d8345b09ea24f605445df62a/opentelemetry_sdk-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-semantic-conventions", "version": "0.65b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/0e/49df70d9b81fb5cbae4bbf2a49d865b09bcbcbc4eb53f5851b1027738d78/opentelemetry_semantic_conventions-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "protobuf", "version": "7.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e4/04/d52c7016b04b6c5108f26691f9d33ec82a9b65d041f1a9c771137693d618/protobuf-7.36.2-py3-none-any.whl"}}, {"metadata": {"name": "executing", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "logfire-api", "version": "5.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2d/51/123dab197fb08c0892e3bea1c2266bff159aa2ee82ad43bef93505859705/logfire_api-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "3.16.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/17/72/2b1fe3e303db76ab2ba0c2de2b57822869bcb588db82334d4ff3aea8acf2/openai-3.16.2-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-instrumentation", "version": "0.65b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/40/7b/85eab1215f72adf0e68d3dc4a679b9bff993fa679ff34cd8dd378e2659fd/opentelemetry_instrumentation-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "wrapt", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/a7/cca7fe0f26aa11cbbf09b2e6f4f774db167feeca43ad22fa1772afdccbad/wrapt-2.4.1-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl"}}, {"metadata": {"name": "opentelemetry-instrumentation-httpx", "version": "0.65b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/0f/c6144096b4914bbf44b43ba21c962e8f333ff045770b50a3e79ed8bd455f/opentelemetry_instrumentation_httpx-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-util-http", "version": "0.65b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/23/3f/ab8d29df207ce5f470a07fa96ebb48af4e95b7fab7e7635311b9a32f2fab/opentelemetry_util_http-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "platformdirs", "version": "4.11.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/39/be/3ae887e84c38c4dd1c549cd5825adc93f48069a94fe1cb8ac52a9da16f15/platformdirs-4.11.11-py3-none-any.whl"}}, {"metadata": {"name": "prompt_toolkit", "version": "3.0.53"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/6f/84908cad2d6aa5144abcf7b42709fe4fdb459bc640ec7ac5786e7693dabc/prompt_toolkit-3.0.53-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/3b/6163796d69c3977d1e4287bea4a6979161cbbdd170ebb430511e8e1999ce/pyasn1-0.6.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "email-validator", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "dnspython", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/97/672cb32ce0dfea44b740cb7b4f97038463b9cf7c0ead1aacf595572851d6/pyjwt-2.14.0-py3-none-any.whl"}}, {"metadata": {"name": "pyperclip", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/80/fc9d01d5ed37ba4c42ca2b55b4339ae6e200b456be3a1aaddf4a9fa99b8c/pyperclip-1.11.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8e/f4/b7ac49f30013aba8f7b9566b1dd07e81de95e708c1374b7bacc5b9bc5c9c/rpds_py-2026.6.3-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "SecretStorage", "version": "3.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/46/f5af3402b579fd5e11573ce652019a67074317e18c1935cc0b4ba9b35552/secretstorage-3.5.0-py3-none-any.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/6a/2ba3ed4a69babf3afdddf7d8314a48d87562c0a442206bbc2a1b50d5efc0/sse_starlette-3.4.11-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/e8/46de4400d5bf859f640feee85bd7e32235f68ddf25db53c63be78e581e3a/tiktoken-0.14.0-cp314-cp314t-manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.53.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/76/18/0eea75741ee812e9f598b687619ce2454f6c3a1c5cd21ea990ec6bd26f45/uvicorn-0.53.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/39/cc/9c0adc5861020de426ec71716b6c1bef8d90694b7d6d0a16202cdb1647f5/wcwidth-0.8.4-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.classes", "version": "3.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/66/b15ce62552d84bbfcec9a4873ab79d993a1dd4edb922cbfccae192bd5b5f/jaraco.classes-3.4.0-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.context", "version": "6.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f2/58/bc8954bda5fcda97bd7c19be11b85f91973d67a706ed4a3aec33e7de22db/jaraco_context-6.1.2-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.functools", "version": "4.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/02/36/ecc85bc96c273dc8a11273ed4782272975e6338d4a3e9228621175edf0e3/jaraco_functools-4.6.0-py3-none-any.whl"}}, {"metadata": {"name": "more-itertools", "version": "11.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/3d/1087453384dbde46a8c7f9356eead2c58be8a7bf156bca40243377c85715/more_itertools-11.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.9.10"}, "download_info": {"url": "https://files.pythonhosted.org/packages/86/38/49f8d6fd34fc1a9c75b5b96364ebdde702a8144e5ed63d2213c58d454c27/regex-2026.9.10-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}], "install_targets_hash": "99070e5a015df9ed8efe12e4aa3cf88a"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "mistralai", "version": "2.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c0/ab/a565e4bec9b5496eb3b44b8799b6ad8378b2cd0be4cd5e6b7d098e8cedcc/mistralai-2.0.5-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-semantic-conventions", "version": "0.60b1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7a/5e/5958555e09635d09b75de3c4f8b9cae7335ca545d77392ffe7331534c402/opentelemetry_semantic_conventions-0.60b1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.39.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/df/d3f1ddf4bb4cb50ed9b1139cc7b1c54c34a1e7ce8fd1b9a37c0d1551a6bd/opentelemetry_api-1.39.1-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fa/5e/f8e9a1d23b9c20a551a8a02ea3637b4642e22c2626e3a13a9a29cdea99eb/importlib_metadata-8.7.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "eval_type_backport", "version": "0.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/a7/bb99bf5e6f78736ddb53480f2c3ff3702ffe2196a7c5e1661c03081d398e/eval_type_backport-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/02/bc19b47a96c2d3109760711acf22369e56bd7e405ca52f7ade164d2ead57/pydantic_core-2.46.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "zipp", "version": "4.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}], "install_targets_hash": "994d711e6ebda622f4cced8803ee9a73"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "google-genai", "version": "1.75.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2d/b6/552d40e96da22921eb1fead7c14b00b5b5473a20e45959488660fab35ee2/google_genai-1.75.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.55.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/1d/f6d3ca1ad0725f2e08a1c6915640748a52de2e66596160a4d53b010cccf0/google_auth-2.55.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/74/9b/6158d4e459b984f949dcbbb0c5d270154c7618e11c01029b9bbd1bb4c4f9/websockets-16.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/9e/db72b3ae7fc9cfad53e630e56c6ae83b9b6ff0bf3718ffb8012d20b3aabf/cryptography-49.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/a0/7d793dce3fa811fe047d6ae2431c672364b462850c6235ae306c0efd025f/pyasn1-0.6.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "a021ecf98104048960d17180bcdfc8fa"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "google-genai", "version": "1.75.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2d/b6/552d40e96da22921eb1fead7c14b00b5b5473a20e45959488660fab35ee2/google_genai-1.75.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.55.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/1d/f6d3ca1ad0725f2e08a1c6915640748a52de2e66596160a4d53b010cccf0/google_auth-2.55.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/74/9b/6158d4e459b984f949dcbbb0c5d270154c7618e11c01029b9bbd1bb4c4f9/websockets-16.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/9e/db72b3ae7fc9cfad53e630e56c6ae83b9b6ff0bf3718ffb8012d20b3aabf/cryptography-49.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/a0/7d793dce3fa811fe047d6ae2431c672364b462850c6235ae306c0efd025f/pyasn1-0.6.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "a021ecf98104048960d17180bcdfc8fa"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "langchain", "version": "1.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/85/86/cc13651cfda820d96ca8c612538166334935e8cf4331a31f5dd369d27760/langchain-1.4.2-py3-none-any.whl"}}, {"metadata": {"name": "langchain-core", "version": "1.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e6/18/cf18cfec118b02e003f35300b54d6a1173dc6e4905cffdf5ea49e390a7f9/langchain_core-1.6.3-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "jsonpatch", "version": "1.33"}, "download_info": {"url": "https://files.pythonhosted.org/packages/73/07/02e16ed01e04a374e644b575638ec7987ae846d25ad97bcc9945a3ee4b0e/jsonpatch-1.33-py2.py3-none-any.whl"}}, {"metadata": {"name": "langgraph", "version": "1.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0a/7f/c5c30e4be99ff821029c7ac872a480676bb179c9f3df85ea3f38d13f86d4/langgraph-1.2.11-py3-none-any.whl"}}, {"metadata": {"name": "langgraph-checkpoint", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/71/3b475f09bd57d3a5649792c66353312b4432afd843f301739dfcebd157f0/langgraph_checkpoint-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "langgraph-prebuilt", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/43/3fe1a700b8490ed02679cdbbc8c915eb23a092faf496c9c1118abcd10be3/langgraph_prebuilt-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "langgraph-sdk", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/43/d5/2ad7f3a835c6fcebf58b6669552536ecd52d2dfe4cf49c6c36648fd83572/langgraph_sdk-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "langsmith", "version": "0.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/51/892ff5a2efc8e222ca114dd0e19b56978f78a5ee62d3b33783588dd8e6d4/langsmith-0.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/64/a4e536cb16d7f61a7fd3120b46c577fc7fa7325992f69c4f52bc786d77d8/pydantic_core-2.46.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "uuid_utils", "version": "0.17.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/33/11/a2ef25dc4a3dcae5ddf8a7c2debc0d10719a991e327e43913605fd3b9c90/uuid_utils-0.17.1-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b2/39/26762f734113e22da2b942c3aca85798e0c0405d64c256549540ff31e5a1/websockets-16.1.1-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "3.16.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/17/72/2b1fe3e303db76ab2ba0c2de2b57822869bcb588db82334d4ff3aea8acf2/openai-3.16.2-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/96/c1813dcca15c5a370145a448aaea7d1f83f6f0228a5f1130e79340ee385f/jiter-0.17.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/e8/46de4400d5bf859f640feee85bd7e32235f68ddf25db53c63be78e581e3a/tiktoken-0.14.0-cp314-cp314t-manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "langchain-openai", "version": "1.6.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b2/47/b87a3c372e52678eb4408360eadbe04cdd5371e21fe2560b6efd66989624/langchain_openai-1.6.2-py3-none-any.whl"}}, {"metadata": {"name": "langchain-community", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8f/39/5d97e42a3e95dc2a6d71b2f902a3fae71786131e11d01bddb604accb0ebe/langchain_community-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "langchain-classic", "version": "1.0.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/9a/b8f5cb7490fdbf233088031fc69c9c747439d4097f67f196c1eb4869916d/langchain_classic-1.0.8-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bb/6b/62cbd6577758699525f5c712d1ddef57d9875fbab0ae8d5f5a202fd598f8/aiohttp-3.14.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "langchain-text-splitters", "version": "1.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d3/26/1ef06f56198d631296d646a6223de35bcc6cf9795ceb2442816bc963b84c/langchain_text_splitters-1.1.2-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/b0/8ee78b0fbe5fe153e9566055e1107c9bae0011b1ae903e30c7ab2ba3e07f/multidict-6.9.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/ee/e4e10a94d51cd1ee638aa7e00b65399e6b2a4e8376ab6d2eac9f95586671/charset_normalizer-3.5.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "SQLAlchemy", "version": "2.0.54"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/25/15dfe6814847eeda773bd58ab6cf42a94b0176e5cf25a578fc1165777160/sqlalchemy-2.0.54-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "urllib3", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.25.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d1/38/97d79b81c342b78246cfedb74809e68841f3198d21653e10d3232bd9c622/yarl-1.25.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "google-genai", "version": "2.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/84/5b/87913fe392ba7b6402577259289ed3740c577956554a674b191a2971d33e/google_genai-2.24.0-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.58.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/59/13/477d90d09591b3938b45c4e11f4d8a51291682112cb5efcac961e815d562/google_auth-2.58.0-py3-none-any.whl"}}, {"metadata": {"name": "langchain-google-genai", "version": "4.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/10/83bb535e78c2cf767a6193c2f3b00b2894c1581a36ef85911ebaa3b9a891/langchain_google_genai-4.4.0-py3-none-any.whl"}}, {"metadata": {"name": "filetype", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/18/79/1b8fa1bb3568781e84c9200f951c735f3f157429f44be0495da55894d620/filetype-1.2.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1a/01/0127d11a762b31a9ee0221894f540318761783f3fdc4bc5d057698caebd5/cryptography-50.0.1-cp314-cp314t-manylinux_2_34_x86_64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/95/eff5f0cee78d2eabc7eebffec40d3fc1876b5f3c95582e018bb4b99601f2/cffi-2.1.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/1c/3d8622e60d0b767a5510d1d3cf21065b9db874696a51ea6d7a43180a259c/frozenlist-1.8.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl"}}, {"metadata": {"name": "greenlet", "version": "3.5.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/c5/2b6c721ba8b8963da42d5a0f57f25b8aaeb1fe9bdd156875e57f3be648a2/greenlet-3.5.6-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonpointer", "version": "3.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/6a/a83720e953b1682d2d109d3c2dbb0bc9bf28cc1cbc205be4ef4be5da709d/jsonpointer-3.1.1-py3-none-any.whl"}}, {"metadata": {"name": "langchain-protocol", "version": "0.0.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/80/c9/f6cbf357d48ccbd18bb394433b1fd7ad9be004eed9377ad08bb85777e5e6/langchain_protocol-0.0.19-py3-none-any.whl"}}, {"metadata": {"name": "numpy", "version": "2.5.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/59/08/9df04103947b95e3b6b1f2ed1a70521f325647a31b82da6a2aae3a485508/numpy-2.5.3-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "orjson", "version": "3.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0f/f3/742fb1f62b825f2c010697eaf4e828004bc2a81e7e806666989c132c7c42/orjson-3.12.0.tar.gz"}}, {"metadata": {"name": "ormsgpack", "version": "1.12.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/87/4c/27a95466354606b256f24fad464d7c97ab62bce6cc529dd4673e1179b8fb/ormsgpack-1.12.2-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fc/57/527910c455b5ec62f6871bef45d4f79fea16cb8c966ba0d4a07f0339ddc4/propcache-0.5.4-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/3b/6163796d69c3977d1e4287bea4a6979161cbbdd170ebb430511e8e1999ce/pyasn1-0.6.4-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "xxhash", "version": "4.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/0c/16b5e419f24e59507ee05626d2bb0deafdb03f9f27783bc0785a9849602e/xxhash-4.0.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "zstandard", "version": "0.25.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/aa/3e0508d5a5dd96529cdc5a97011299056e14c6505b678fd58938792794b1/zstandard-0.25.0.tar.gz"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.9.10"}, "download_info": {"url": "https://files.pythonhosted.org/packages/86/38/49f8d6fd34fc1a9c75b5b96364ebdde702a8144e5ed63d2213c58d454c27/regex-2026.9.10-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}], "install_targets_hash": "a282ef4988626dc6ebb6ab9deadd8e4b"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "trytond", "version": "8.0.10"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/db/57a3be9504273276216dde241d3bc3602c9cae62f60afb1944cf651fe638/trytond-8.0.10-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "lxml", "version": "6.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d0/9c/733682a0c2de9f5779ba207bbb3f3f6be8c6bda863fc01739b186b38783a/lxml-6.1.3-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/09/c419f6f5a92e5fadde27efd190eca90f05e1261b10dbd8cbcb39cd8ea1dc/markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "pwdlib", "version": "0.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6b/2e/51979293b2337f508597d13ee20db1ac1d43e48086b2ed7de6da213ed46b/pwdlib-0.3.1-py3-none-any.whl"}}, {"metadata": {"name": "argon2-cffi", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/d3/a8b22fa575b297cd6e3e3b0155c7e25db170edf1c74783d6a31a2490b8d9/argon2_cffi-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "python-sql", "version": "1.8.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/77/ac/3603bbdde340f7354c975431c94b70ef3e99966c5b170fa121f8e64d269e/python_sql-1.8.1-py3-none-any.whl"}}, {"metadata": {"name": "relatorio", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/74/eb/798c426ebd54f52c27aed6593eaf96ed07dca3ca1d084822cc34f0db5159/relatorio-1.0.0-py3-none-any.whl"}}, {"metadata": {"name": "Genshi", "version": "0.7.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/27/503016bc329720ba2856eb4831d6ba36089cd6f15bc4fe85db69fea5b563/genshi-0.7.11-py3-none-any.whl"}}, {"metadata": {"name": "argon2-cffi-bindings", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/ee/f84b28e4afd13d3cac36c1d8fa8c239d2dc2c51cd978d02ee5d5ad98d9bb/argon2_cffi_bindings-26.1.0-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/95/eff5f0cee78d2eabc7eebffec40d3fc1876b5f3c95582e018bb4b99601f2/cffi-2.1.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "defusedxml", "version": "0.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "polib", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6b/99/45bb1f9926efe370c6dbe324741c749658e44cb060124f28dad201202274/polib-1.2.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "puremagic", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/81/314320aeffd88dadeac553ff9eb10f54507ab41deccd0c69f6221d254a0a/puremagic-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "simpleeval", "version": "1.0.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/33/d1ecd9f4f5f272b36ad7b268e307ba0a59c109d8ad134a231cda780baac9/simpleeval-1.0.8-py3-none-any.whl"}}], "install_targets_hash": "ab391832abd062e60ebbad762fe1f443"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "cohere", "version": "7.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/4a/c3/064a44c498bf6ae8621caa14307d3ef5471157f149e33cfd64417c8e9ad3/cohere-7.1.1-py3-none-any.whl"}}, {"metadata": {"name": "fastavro", "version": "1.12.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/dd/8f/18f60329b627d2118a4a2b19e8741fbd807d60bf0470554e1bbfb7f1bca3/fastavro-1.12.2-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/1c/6c/c73fa9d5a85f6ab05395de61c5f6984e0a9ff40bb5ff888d46dff02526c6/charset_normalizer-3.5.1-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "tokenizers", "version": "0.23.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c1/60/21f715d9faba5f5407ff759472ade058ec4a507ad62bcea47cb847239a73/tokenizers-0.23.1.tar.gz"}}, {"metadata": {"name": "huggingface_hub", "version": "1.29.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/4e/a5/47c2ea9b228ccbcba8467e9a64823146e8ebbad29855e591d8f5eedcc9c7/huggingface_hub-1.29.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/bb/1e/c0ad437dd267a8e435bef594acf781bbc3874ff0b6435b4962d03ecf7cc4/hf_xet-1.6.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "types-requests", "version": "2.33.0.20260712"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/62/e7/010c87f559e216d83f9dc51e939633fd0d0ead3377340181ab0e223cd3b5/types_requests-2.33.0.20260712-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "filelock", "version": "3.32.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/36/d2/b70a31e13d04456d28493f31d2aa087e99eeb2767ef0293b2625727ccb8c/filelock-3.32.5-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.7.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/fd/3c/6a2bf344106328fd04963664a60b9bb6496fc25df8e962fcdc1367285fb9/fsspec-2026.7.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c5/02/bc19b47a96c2d3109760711acf22369e56bd7e405ca52f7ade164d2ead57/pydantic_core-2.46.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}], "install_targets_hash": "ab733f16537c82282cb23e3e0416c9fc"} -{"python_version": "3.14", "dependencies": [{"metadata": {"name": "openai", "version": "3.16.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/17/72/2b1fe3e303db76ab2ba0c2de2b57822869bcb588db82334d4ff3aea8acf2/openai-3.16.2-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/96/c1813dcca15c5a370145a448aaea7d1f83f6f0228a5f1130e79340ee385f/jiter-0.17.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/64/a4e536cb16d7f61a7fd3120b46c577fc7fa7325992f69c4f52bc786d77d8/pydantic_core-2.46.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/e8/46de4400d5bf859f640feee85bd7e32235f68ddf25db53c63be78e581e3a/tiktoken-0.14.0-cp314-cp314t-manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.9.10"}, "download_info": {"url": "https://files.pythonhosted.org/packages/86/38/49f8d6fd34fc1a9c75b5b96364ebdde702a8144e5ed63d2213c58d454c27/regex-2026.9.10-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/ee/e4e10a94d51cd1ee638aa7e00b65399e6b2a4e8376ab6d2eac9f95586671/charset_normalizer-3.5.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "urllib3", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "ac0b70b42bbda50724e182bcf918e944"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "cohere", "version": "7.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/4a/c3/064a44c498bf6ae8621caa14307d3ef5471157f149e33cfd64417c8e9ad3/cohere-7.1.1-py3-none-any.whl"}}, {"metadata": {"name": "fastavro", "version": "1.12.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/dd/8f/18f60329b627d2118a4a2b19e8741fbd807d60bf0470554e1bbfb7f1bca3/fastavro-1.12.2-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/1c/6c/c73fa9d5a85f6ab05395de61c5f6984e0a9ff40bb5ff888d46dff02526c6/charset_normalizer-3.5.1-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "tokenizers", "version": "0.23.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c1/60/21f715d9faba5f5407ff759472ade058ec4a507ad62bcea47cb847239a73/tokenizers-0.23.1.tar.gz"}}, {"metadata": {"name": "huggingface_hub", "version": "1.29.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/4e/a5/47c2ea9b228ccbcba8467e9a64823146e8ebbad29855e591d8f5eedcc9c7/huggingface_hub-1.29.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/bb/1e/c0ad437dd267a8e435bef594acf781bbc3874ff0b6435b4962d03ecf7cc4/hf_xet-1.6.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "types-requests", "version": "2.33.0.20260712"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/62/e7/010c87f559e216d83f9dc51e939633fd0d0ead3377340181ab0e223cd3b5/types_requests-2.33.0.20260712-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "filelock", "version": "3.32.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/36/d2/b70a31e13d04456d28493f31d2aa087e99eeb2767ef0293b2625727ccb8c/filelock-3.32.5-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.7.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/fd/3c/6a2bf344106328fd04963664a60b9bb6496fc25df8e962fcdc1367285fb9/fsspec-2026.7.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c5/02/bc19b47a96c2d3109760711acf22369e56bd7e405ca52f7ade164d2ead57/pydantic_core-2.46.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}], "install_targets_hash": "ab733f16537c82282cb23e3e0416c9fc"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "grpcio", "version": "1.84.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/4f/4435c0aae54657258d9cfcba78598f3d9e5fe4c82ff18d78558567b90faf/grpcio-1.84.0.tar.gz"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "protobuf", "version": "7.36.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/39/ca/c47f91d3cab175b01fd8c4f0d80fdf8613be876cc616e66ad281a59c5ddf/protobuf-7.36.1-py3-none-any.whl"}}, {"metadata": {"name": "mypy-protobuf", "version": "5.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/ec/5ffcf8f5f53757e01afdece10c664e694ac60d2f17c2036811b85b842a5b/mypy_protobuf-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "types-protobuf", "version": "7.35.1.20260906"}, "download_info": {"url": "https://files.pythonhosted.org/packages/44/4e/f63e826c68f77ef875506d72f225918800346545ee99847bc28f3394f18d/types_protobuf-7.35.1.20260906-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.7.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/18/f1/46d32fe4b9aae09fe397e768ff376d9b6bdbb4f11faaa727f163c3457b43/pytest_forked-1.7.5-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}], "install_targets_hash": "b000c682d30e09087f05bd957ebe7664"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "grpcio", "version": "1.84.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/4f/4435c0aae54657258d9cfcba78598f3d9e5fe4c82ff18d78558567b90faf/grpcio-1.84.0.tar.gz"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "protobuf", "version": "7.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e4/04/d52c7016b04b6c5108f26691f9d33ec82a9b65d041f1a9c771137693d618/protobuf-7.36.2-py3-none-any.whl"}}, {"metadata": {"name": "mypy-protobuf", "version": "5.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/ec/5ffcf8f5f53757e01afdece10c664e694ac60d2f17c2036811b85b842a5b/mypy_protobuf-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "types-protobuf", "version": "7.35.1.20260906"}, "download_info": {"url": "https://files.pythonhosted.org/packages/44/4e/f63e826c68f77ef875506d72f225918800346545ee99847bc28f3394f18d/types_protobuf-7.35.1.20260906-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.7.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/18/f1/46d32fe4b9aae09fe397e768ff376d9b6bdbb4f11faaa727f163c3457b43/pytest_forked-1.7.5-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}], "install_targets_hash": "b000c682d30e09087f05bd957ebe7664"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/d8/8ec0e471248c500acdce2be3f46db8fb62b5eb60efef072529cc85ee1d26/aiohttp-3.14.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ff/0b/cfb76b7fe99686db264bff829779a539d923e7564ffd7ef18da6c54c3774/yarl-1.24.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-aiohttp", "version": "1.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fa/b0/5056ed4c3f68a4db2b4a39fb0ec61b1e4cf1d89ee14effe5261cc587264c/pytest_aiohttp-1.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/73/daf935ea7048ddd7ec8eec5345b4a40b619d2d178b3c0a0900796bc3c794/propcache-0.5.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "b580cd1bfd98254876a1e968bf8d9af2"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "tornado", "version": "6.6a1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/8b/b1/cbe70b014bf2ee46f9d262ca16ed3221c218c391994198ab108fb0996517/tornado-6.6a1-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}], "install_targets_hash": "b883316dda3824a719a7fb8ca38112ff"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "sanic", "version": "25.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/91/5ecd9a91374a7b2831cf183357ceeb609fdfc8b390adb5cac90a261fe1f8/sanic-25.12.1-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/85/dc/549a807a53c13fd4a8dac286f117a7a71260defea9ec0c05d6027f2ae273/websockets-10.4.tar.gz"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/c8/14ce60ec31a2e5f5274bb17d383a6f7a3aabca31ac04eee05585bbadab16/aiohttp-3.14.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/b2/845cf2074a015e6fe0d0808cf1a2d9e868386c4220d657ebd8302b199043/yarl-1.24.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-testing", "version": "24.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/93/1d588f1cb9b710b9f22fa78b53d699a8062edc94204d50dd0d78c5f5b495/sanic_testing-24.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "html5tagger", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/12/2f5d43ee912ea14a6baba4b3db6d309b02d932e3b7074c3339b4aded98ff/html5tagger-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "httptools", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/b0/312a062ae741ae3e8baa8c8bf20be81b2e67337b259ab4349bebc7b6142e/httptools-0.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/73/daf935ea7048ddd7ec8eec5345b4a40b619d2d178b3c0a0900796bc3c794/propcache-0.5.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-routing", "version": "23.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/e3/3425c9a8773807ac2c01d6a56c8521733f09b627e5827e733c5cd36b9ac5/sanic_routing-23.12.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "83.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/40/e1e72872c6354b306daef1703549e8e83b4d43cfea356311bf722a043752/setuptools-83.0.0-py3-none-any.whl"}}, {"metadata": {"name": "tracerite", "version": "2.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b6/62/3f385a67ff3cc91209f107d20bbebdecf7a4e4aba55a43f9f71bddc424a9/tracerite-2.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "5.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/e4/39862f0f7174ff07cfd1e2d0c9065ded34aeebdb7db8daf2f0e5bf89b46f/ujson-5.13.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "uvloop", "version": "0.22.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/7b/b01414f31546caf0919da80ad57cbfe24c56b151d12af68cee1b04922ca8/uvloop-0.22.1-cp314-cp314t-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}], "install_targets_hash": "bdb1f2a8b2b051b4d694fd87001bee9b"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "sanic", "version": "25.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/91/5ecd9a91374a7b2831cf183357ceeb609fdfc8b390adb5cac90a261fe1f8/sanic-25.12.1-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/85/dc/549a807a53c13fd4a8dac286f117a7a71260defea9ec0c05d6027f2ae273/websockets-10.4.tar.gz"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/c8/14ce60ec31a2e5f5274bb17d383a6f7a3aabca31ac04eee05585bbadab16/aiohttp-3.14.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/b2/845cf2074a015e6fe0d0808cf1a2d9e868386c4220d657ebd8302b199043/yarl-1.24.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-testing", "version": "24.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/93/1d588f1cb9b710b9f22fa78b53d699a8062edc94204d50dd0d78c5f5b495/sanic_testing-24.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "html5tagger", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/12/2f5d43ee912ea14a6baba4b3db6d309b02d932e3b7074c3339b4aded98ff/html5tagger-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "httptools", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/b0/312a062ae741ae3e8baa8c8bf20be81b2e67337b259ab4349bebc7b6142e/httptools-0.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/73/daf935ea7048ddd7ec8eec5345b4a40b619d2d178b3c0a0900796bc3c794/propcache-0.5.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-routing", "version": "23.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/e3/3425c9a8773807ac2c01d6a56c8521733f09b627e5827e733c5cd36b9ac5/sanic_routing-23.12.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "83.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/40/e1e72872c6354b306daef1703549e8e83b4d43cfea356311bf722a043752/setuptools-83.0.0-py3-none-any.whl"}}, {"metadata": {"name": "tracerite", "version": "2.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b6/62/3f385a67ff3cc91209f107d20bbebdecf7a4e4aba55a43f9f71bddc424a9/tracerite-2.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "5.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/e4/39862f0f7174ff07cfd1e2d0c9065ded34aeebdb7db8daf2f0e5bf89b46f/ujson-5.13.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "uvloop", "version": "0.22.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/7b/b01414f31546caf0919da80ad57cbfe24c56b151d12af68cee1b04922ca8/uvloop-0.22.1-cp314-cp314t-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}], "install_targets_hash": "bdb1f2a8b2b051b4d694fd87001bee9b"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "sanic", "version": "25.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/91/5ecd9a91374a7b2831cf183357ceeb609fdfc8b390adb5cac90a261fe1f8/sanic-25.12.1-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/85/dc/549a807a53c13fd4a8dac286f117a7a71260defea9ec0c05d6027f2ae273/websockets-10.4.tar.gz"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/c8/14ce60ec31a2e5f5274bb17d383a6f7a3aabca31ac04eee05585bbadab16/aiohttp-3.14.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/b2/845cf2074a015e6fe0d0808cf1a2d9e868386c4220d657ebd8302b199043/yarl-1.24.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-testing", "version": "24.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/93/1d588f1cb9b710b9f22fa78b53d699a8062edc94204d50dd0d78c5f5b495/sanic_testing-24.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "html5tagger", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/12/2f5d43ee912ea14a6baba4b3db6d309b02d932e3b7074c3339b4aded98ff/html5tagger-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "httptools", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/b0/312a062ae741ae3e8baa8c8bf20be81b2e67337b259ab4349bebc7b6142e/httptools-0.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/73/daf935ea7048ddd7ec8eec5345b4a40b619d2d178b3c0a0900796bc3c794/propcache-0.5.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-routing", "version": "23.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/e3/3425c9a8773807ac2c01d6a56c8521733f09b627e5827e733c5cd36b9ac5/sanic_routing-23.12.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "83.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/40/e1e72872c6354b306daef1703549e8e83b4d43cfea356311bf722a043752/setuptools-83.0.0-py3-none-any.whl"}}, {"metadata": {"name": "tracerite", "version": "2.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b6/62/3f385a67ff3cc91209f107d20bbebdecf7a4e4aba55a43f9f71bddc424a9/tracerite-2.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "5.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/e4/39862f0f7174ff07cfd1e2d0c9065ded34aeebdb7db8daf2f0e5bf89b46f/ujson-5.13.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "uvloop", "version": "0.22.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/7b/b01414f31546caf0919da80ad57cbfe24c56b151d12af68cee1b04922ca8/uvloop-0.22.1-cp314-cp314t-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}], "install_targets_hash": "bdb1f2a8b2b051b4d694fd87001bee9b"} -{"python_version": "3.14", "dependencies": [{"metadata": {"name": "mcp", "version": "1.30.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f5/f4/e58bc33317c92a0203664daaf00bf6f41166cc0149e5d6870a03f7cd004a/mcp-1.30.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/64/a4e536cb16d7f61a7fd3120b46c577fc7fa7325992f69c4f52bc786d77d8/pydantic_core-2.46.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/97/672cb32ce0dfea44b740cb7b4f97038463b9cf7c0ead1aacf595572851d6/pyjwt-2.14.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1a/01/0127d11a762b31a9ee0221894f540318761783f3fdc4bc5d057698caebd5/cryptography-50.0.1-cp314-cp314t-manylinux_2_34_x86_64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/95/eff5f0cee78d2eabc7eebffec40d3fc1876b5f3c95582e018bb4b99601f2/cffi-2.1.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8e/f4/b7ac49f30013aba8f7b9566b1dd07e81de95e708c1374b7bacc5b9bc5c9c/rpds_py-2026.6.3-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/6a/2ba3ed4a69babf3afdddf7d8314a48d87562c0a442206bbc2a1b50d5efc0/sse_starlette-3.4.11-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.52.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/79/4a20b54ab0491485ccd8c077db2d39187c7f12b3e15485d38a7be37c81b4/uvicorn-0.52.4-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "c22f32eaa2bf5c7f62806b63fcde2d83"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "sanic", "version": "25.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/91/5ecd9a91374a7b2831cf183357ceeb609fdfc8b390adb5cac90a261fe1f8/sanic-25.12.1-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/85/dc/549a807a53c13fd4a8dac286f117a7a71260defea9ec0c05d6027f2ae273/websockets-10.4.tar.gz"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/c8/14ce60ec31a2e5f5274bb17d383a6f7a3aabca31ac04eee05585bbadab16/aiohttp-3.14.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/b2/845cf2074a015e6fe0d0808cf1a2d9e868386c4220d657ebd8302b199043/yarl-1.24.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-testing", "version": "24.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/93/1d588f1cb9b710b9f22fa78b53d699a8062edc94204d50dd0d78c5f5b495/sanic_testing-24.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "html5tagger", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/12/2f5d43ee912ea14a6baba4b3db6d309b02d932e3b7074c3339b4aded98ff/html5tagger-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "httptools", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/b0/312a062ae741ae3e8baa8c8bf20be81b2e67337b259ab4349bebc7b6142e/httptools-0.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/73/daf935ea7048ddd7ec8eec5345b4a40b619d2d178b3c0a0900796bc3c794/propcache-0.5.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-routing", "version": "23.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/e3/3425c9a8773807ac2c01d6a56c8521733f09b627e5827e733c5cd36b9ac5/sanic_routing-23.12.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "83.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/40/e1e72872c6354b306daef1703549e8e83b4d43cfea356311bf722a043752/setuptools-83.0.0-py3-none-any.whl"}}, {"metadata": {"name": "tracerite", "version": "2.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b6/62/3f385a67ff3cc91209f107d20bbebdecf7a4e4aba55a43f9f71bddc424a9/tracerite-2.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "5.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/e4/39862f0f7174ff07cfd1e2d0c9065ded34aeebdb7db8daf2f0e5bf89b46f/ujson-5.13.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "uvloop", "version": "0.22.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/7b/b01414f31546caf0919da80ad57cbfe24c56b151d12af68cee1b04922ca8/uvloop-0.22.1-cp314-cp314t-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}], "install_targets_hash": "bdb1f2a8b2b051b4d694fd87001bee9b"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}], "install_targets_hash": "c4e67585767bde6ea034db94a448f267"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}], "install_targets_hash": "c4e67585767bde6ea034db94a448f267"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}], "install_targets_hash": "c4e67585767bde6ea034db94a448f267"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}], "install_targets_hash": "c4e67585767bde6ea034db94a448f267"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}], "install_targets_hash": "c4e67585767bde6ea034db94a448f267"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}], "install_targets_hash": "c4e67585767bde6ea034db94a448f267"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}], "install_targets_hash": "c4e67585767bde6ea034db94a448f267"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}], "install_targets_hash": "c4e67585767bde6ea034db94a448f267"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "litellm", "version": "1.96.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d0/92/1171e76f2a4204a65adb5c827475e4f1d30e7c6a89d3d3e944d58b6fd8a6/litellm-1.96.0.tar.gz"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/d8/8ec0e471248c500acdce2be3f46db8fb62b5eb60efef072529cc85ee1d26/aiohttp-3.14.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "fastuuid", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c3/7d/d9daedf0f2ebcacd20d599928f8913e9d2aea1d56d2d355a93bfa2b611d7/fastuuid-0.14.0.tar.gz"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7d/f9/97f2ca8bb3ec6e4b1d64f983ebe98b9a192faddff67fac3d6303a537e670/importlib_metadata-8.9.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "openai", "version": "2.54.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/a8/bb76c7356de8ad57f59d5ff993d434df0607f07f08bcc9c9a5c275e399c0/openai-2.54.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/6b/59127338b86d9fe4d99418f5a15118bea778103ee0fe9d9dd7e0af174e95/jiter-0.16.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/29/46ad8061f57bd9f8b2ea0aa82bf574e0f2aa040b0857a1582adba9957899/tiktoken-0.14.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tokenizers", "version": "0.23.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/60/21f715d9faba5f5407ff759472ade058ec4a507ad62bcea47cb847239a73/tokenizers-0.23.1.tar.gz"}}, {"metadata": {"name": "huggingface_hub", "version": "1.28.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/0e/eafef18f1a75e125e68395db21131db0cf868a128ecd2fce69b4df6c584b/huggingface_hub-1.28.0-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bb/1e/c0ad437dd267a8e435bef594acf781bbc3874ff0b6435b4962d03ecf7cc4/hf_xet-1.6.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ff/0b/cfb76b7fe99686db264bff829779a539d923e7564ffd7ef18da6c54c3774/yarl-1.24.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anthropic", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/5b/db4a854aebf5d33a5ab714c46af6eb85ee44f390ed29b7b325c00b9f11ed/anthropic-1.0.0-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/95/411ba65569158e862368917aaf56597f3e5fa3b91b0502919638465a08f3/httpx2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/74/d370e55600d9bcfa0d9794b0166126d49291a3d2b20c268fc98c453a4948/httpcore2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "google-genai", "version": "2.19.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/e8/de0accd8cd004cf11252ca53fc5c3dda59bcf1856abfc7609842ceba7363/google_genai-2.19.0-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.56.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/b3/6117b2f24065cd7e2c4f140e9a193e215f089ca8ba314cf91eb9d0b7fe0a/google_auth-2.56.3-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1c/6c/c73fa9d5a85f6ab05395de61c5f6984e0a9ff40bb5ff888d46dff02526c6/charset_normalizer-3.5.1-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/e8/f7dac2e980bacc92bdc26cebae4ae4d50cae5380732c50980598fc0bbae4/websockets-16.1.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c3/fb/951032a3bf22a5697c83183fb6294a4843772947a70e616c57b3ff5f522e/cryptography-50.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7d/47/5ecf1023850036e674c77ec4de86182d309ae344e39e7cba984b7df5d647/cffi-2.1.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "filelock", "version": "3.32.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/a4/9b63d595d748e3aff8812b65eacc1a2c4bd90b7c2012e08e72373b4835eb/filelock-3.32.4-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/3c/6a2bf344106328fd04963664a60b9bb6496fc25df8e962fcdc1367285fb9/fsspec-2026.7.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/73/daf935ea7048ddd7ec8eec5345b4a40b619d2d178b3c0a0900796bc3c794/propcache-0.5.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/3b/6163796d69c3977d1e4287bea4a6979161cbbdd170ebb430511e8e1999ce/pyasn1-0.6.4-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/77bcb1168b33704908295533d27f10eb811e9e3e193e8993dc99572211d3/rpds_py-2026.6.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "zipp", "version": "4.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.7.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cd/d6/0dd1a321afaab95eb7ff44aa0f637301786f1dc71c6b797b9ed236ed8890/regex-2026.7.19-cp314-cp314t-macosx_11_0_arm64.whl"}}], "install_targets_hash": "c8297c467689232f577381977852ce9e"} -{"python_version": "3.14", "dependencies": [{"metadata": {"name": "fastmcp", "version": "0.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/0b/008a340435fe8f0879e9d608f48af2737ad48440e09bd33b83b3fd03798b/fastmcp-0.4.1-py3-none-any.whl"}}, {"metadata": {"name": "mcp", "version": "1.29.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/c8/248b201f6d753d69fd5d6506011abbb35a946d9142b2ae311a948fd0be3d/mcp-1.29.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/77/c1/6e422f34e569cf8e18df68d1939c81c099d2b61e4f7d9621c8a77560799c/pydantic_settings-2.14.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/9e/db72b3ae7fc9cfad53e630e56c6ae83b9b6ff0bf3718ffb8012d20b3aabf/cryptography-49.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/d8/3b86aba791cb610d24e8a3e1b2cd529e71fa15096b04e4d4e360049d4a4c/cffi-2.1.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/77bcb1168b33704908295533d27f10eb811e9e3e193e8993dc99572211d3/rpds_py-2026.6.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/36/e10c1d1b7ca881d2625db2ec28508578499187bb1c389952c398474e1834/sse_starlette-3.4.6-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typer", "version": "0.27.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/40/03/26a383c9e58c213199d1aad1c3d353cfc22d4444ec6d2c0bf8ad02523843/typer-0.27.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "shellingham", "version": "1.5.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.52.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/39/e6/b5c0630ace9757232aec07112be8146b812787db52141ff9d50674aa7634/uvicorn-0.52.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "d3ba412b13e2cfc8f79cd31c37175dca"} -{"python_version": "3.14", "dependencies": [{"metadata": {"name": "fastmcp", "version": "0.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/0b/008a340435fe8f0879e9d608f48af2737ad48440e09bd33b83b3fd03798b/fastmcp-0.4.1-py3-none-any.whl"}}, {"metadata": {"name": "mcp", "version": "1.29.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/c8/248b201f6d753d69fd5d6506011abbb35a946d9142b2ae311a948fd0be3d/mcp-1.29.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/77/c1/6e422f34e569cf8e18df68d1939c81c099d2b61e4f7d9621c8a77560799c/pydantic_settings-2.14.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/9e/db72b3ae7fc9cfad53e630e56c6ae83b9b6ff0bf3718ffb8012d20b3aabf/cryptography-49.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/d8/3b86aba791cb610d24e8a3e1b2cd529e71fa15096b04e4d4e360049d4a4c/cffi-2.1.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/77bcb1168b33704908295533d27f10eb811e9e3e193e8993dc99572211d3/rpds_py-2026.6.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/36/e10c1d1b7ca881d2625db2ec28508578499187bb1c389952c398474e1834/sse_starlette-3.4.6-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typer", "version": "0.27.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/40/03/26a383c9e58c213199d1aad1c3d353cfc22d4444ec6d2c0bf8ad02523843/typer-0.27.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "shellingham", "version": "1.5.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.52.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/39/e6/b5c0630ace9757232aec07112be8146b812787db52141ff9d50674aa7634/uvicorn-0.52.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "d3ba412b13e2cfc8f79cd31c37175dca"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "litellm", "version": "1.96.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d0/92/1171e76f2a4204a65adb5c827475e4f1d30e7c6a89d3d3e944d58b6fd8a6/litellm-1.96.0.tar.gz"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/d8/8ec0e471248c500acdce2be3f46db8fb62b5eb60efef072529cc85ee1d26/aiohttp-3.14.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "fastuuid", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c3/7d/d9daedf0f2ebcacd20d599928f8913e9d2aea1d56d2d355a93bfa2b611d7/fastuuid-0.14.0.tar.gz"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7d/f9/97f2ca8bb3ec6e4b1d64f983ebe98b9a192faddff67fac3d6303a537e670/importlib_metadata-8.9.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "openai", "version": "2.54.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/a8/bb76c7356de8ad57f59d5ff993d434df0607f07f08bcc9c9a5c275e399c0/openai-2.54.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/6b/59127338b86d9fe4d99418f5a15118bea778103ee0fe9d9dd7e0af174e95/jiter-0.16.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/29/46ad8061f57bd9f8b2ea0aa82bf574e0f2aa040b0857a1582adba9957899/tiktoken-0.14.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tokenizers", "version": "0.23.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/60/21f715d9faba5f5407ff759472ade058ec4a507ad62bcea47cb847239a73/tokenizers-0.23.1.tar.gz"}}, {"metadata": {"name": "huggingface_hub", "version": "1.28.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/0e/eafef18f1a75e125e68395db21131db0cf868a128ecd2fce69b4df6c584b/huggingface_hub-1.28.0-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bb/1e/c0ad437dd267a8e435bef594acf781bbc3874ff0b6435b4962d03ecf7cc4/hf_xet-1.6.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ff/0b/cfb76b7fe99686db264bff829779a539d923e7564ffd7ef18da6c54c3774/yarl-1.24.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anthropic", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/5b/db4a854aebf5d33a5ab714c46af6eb85ee44f390ed29b7b325c00b9f11ed/anthropic-1.0.0-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/95/411ba65569158e862368917aaf56597f3e5fa3b91b0502919638465a08f3/httpx2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/74/d370e55600d9bcfa0d9794b0166126d49291a3d2b20c268fc98c453a4948/httpcore2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "google-genai", "version": "2.19.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/e8/de0accd8cd004cf11252ca53fc5c3dda59bcf1856abfc7609842ceba7363/google_genai-2.19.0-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.56.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/b3/6117b2f24065cd7e2c4f140e9a193e215f089ca8ba314cf91eb9d0b7fe0a/google_auth-2.56.3-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1c/6c/c73fa9d5a85f6ab05395de61c5f6984e0a9ff40bb5ff888d46dff02526c6/charset_normalizer-3.5.1-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/e8/f7dac2e980bacc92bdc26cebae4ae4d50cae5380732c50980598fc0bbae4/websockets-16.1.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c3/fb/951032a3bf22a5697c83183fb6294a4843772947a70e616c57b3ff5f522e/cryptography-50.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7d/47/5ecf1023850036e674c77ec4de86182d309ae344e39e7cba984b7df5d647/cffi-2.1.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "filelock", "version": "3.32.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/a4/9b63d595d748e3aff8812b65eacc1a2c4bd90b7c2012e08e72373b4835eb/filelock-3.32.4-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/3c/6a2bf344106328fd04963664a60b9bb6496fc25df8e962fcdc1367285fb9/fsspec-2026.7.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/73/daf935ea7048ddd7ec8eec5345b4a40b619d2d178b3c0a0900796bc3c794/propcache-0.5.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/3b/6163796d69c3977d1e4287bea4a6979161cbbdd170ebb430511e8e1999ce/pyasn1-0.6.4-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/77bcb1168b33704908295533d27f10eb811e9e3e193e8993dc99572211d3/rpds_py-2026.6.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "zipp", "version": "4.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.7.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cd/d6/0dd1a321afaab95eb7ff44aa0f637301786f1dc71c6b797b9ed236ed8890/regex-2026.7.19-cp314-cp314t-macosx_11_0_arm64.whl"}}], "install_targets_hash": "c8297c467689232f577381977852ce9e"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "mcp", "version": "2.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/75/20/312acf5fd37b90589269349b2c4d5c056b4603c964d181e91f9bf4a79f97/mcp-2.0.1-py3-none-any.whl"}}, {"metadata": {"name": "mcp-types", "version": "2.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b6/49/37a1f580d94ee0f16c1f3d1c6e32bbb264e607f1739a4c0cb9232619dfd9/mcp_types-2.0.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/6f/a04e900f465ff3221ccc395522503e2d10e79fa21f2723c8e177aae1e0d1/opentelemetry_api-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/02/bc19b47a96c2d3109760711acf22369e56bd7e405ca52f7ade164d2ead57/pydantic_core-2.46.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/97/672cb32ce0dfea44b740cb7b4f97038463b9cf7c0ead1aacf595572851d6/pyjwt-2.14.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/f0/424cb557d99aa86ac55da5e2add02e2882e44047b6264f93ade1b975a993/cryptography-50.0.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7d/47/5ecf1023850036e674c77ec4de86182d309ae344e39e7cba984b7df5d647/cffi-2.1.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/77bcb1168b33704908295533d27f10eb811e9e3e193e8993dc99572211d3/rpds_py-2026.6.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/6a/2ba3ed4a69babf3afdddf7d8314a48d87562c0a442206bbc2a1b50d5efc0/sse_starlette-3.4.11-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.53.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/76/18/0eea75741ee812e9f598b687619ce2454f6c3a1c5cd21ea990ec6bd26f45/uvicorn-0.53.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "cce7f3c3feff18eeb00efa85d75073cb"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "google-genai", "version": "2.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/84/5b/87913fe392ba7b6402577259289ed3740c577956554a674b191a2971d33e/google_genai-2.24.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.58.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/59/13/477d90d09591b3938b45c4e11f4d8a51291682112cb5efcac961e815d562/google_auth-2.58.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/64/a4e536cb16d7f61a7fd3120b46c577fc7fa7325992f69c4f52bc786d77d8/pydantic_core-2.46.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/ee/e4e10a94d51cd1ee638aa7e00b65399e6b2a4e8376ab6d2eac9f95586671/charset_normalizer-3.5.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b2/39/26762f734113e22da2b942c3aca85798e0c0405d64c256549540ff31e5a1/websockets-16.1.1-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1a/01/0127d11a762b31a9ee0221894f540318761783f3fdc4bc5d057698caebd5/cryptography-50.0.1-cp314-cp314t-manylinux_2_34_x86_64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/95/eff5f0cee78d2eabc7eebffec40d3fc1876b5f3c95582e018bb4b99601f2/cffi-2.1.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/3b/6163796d69c3977d1e4287bea4a6979161cbbdd170ebb430511e8e1999ce/pyasn1-0.6.4-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "d5f17eff9efc836f1883edb6f7bfdfbc"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2-pytest", "version": "1.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/46/ef/e9b6fb576f1f518f68e9f9cce9776870452ae2b8cfbba53b4127701b9a55/httpx2_pytest-1.0.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}], "install_targets_hash": "d6da1d54536a49d0f25beda4d7a148f5"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "pyreqwest", "version": "0.11.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b5/e7/78188f6a88888da9523d18313369fc68df03dba7e1a123391832df56c440/pyreqwest-0.11.8.tar.gz"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "ddbeddd6367dc3ba2a81dfa0d1d7c186"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "pyreqwest", "version": "0.11.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b5/e7/78188f6a88888da9523d18313369fc68df03dba7e1a123391832df56c440/pyreqwest-0.11.8.tar.gz"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "ddbeddd6367dc3ba2a81dfa0d1d7c186"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "pyreqwest", "version": "0.11.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b5/e7/78188f6a88888da9523d18313369fc68df03dba7e1a123391832df56c440/pyreqwest-0.11.8.tar.gz"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "ddbeddd6367dc3ba2a81dfa0d1d7c186"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "pyreqwest", "version": "0.11.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b5/e7/78188f6a88888da9523d18313369fc68df03dba7e1a123391832df56c440/pyreqwest-0.11.8.tar.gz"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "ddbeddd6367dc3ba2a81dfa0d1d7c186"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "pyreqwest", "version": "0.11.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b5/e7/78188f6a88888da9523d18313369fc68df03dba7e1a123391832df56c440/pyreqwest-0.11.8.tar.gz"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "ddbeddd6367dc3ba2a81dfa0d1d7c186"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "launchdarkly-server-sdk", "version": "9.17.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c1/58/bcede9c0f11b5c37b492ea993ed0599099e15f803b9fe98452558cfd6e96/launchdarkly_server_sdk-9.17.0-py3-none-any.whl"}}, {"metadata": {"name": "launchdarkly-eventsource", "version": "1.7.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/49/8592c1d9c156d3c2d3f8c02e1c00260c3e0a7a10bcb50c942bd80c285c62/launchdarkly_eventsource-1.7.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "expiringdict", "version": "1.2.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cb/84/a04c59324445f4bcc98dc05b39a1cd07c242dde643c1a3c21e4f7beaf2f2/expiringdict-1.2.2-py3-none-any.whl"}}, {"metadata": {"name": "pyRFC3339", "version": "2.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/34/90/0200184d2124484f918054751ef997ed6409cb05b7e8dcbf5a22da4c4748/pyrfc3339-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "semver", "version": "3.0.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a6/24/4d91e05817e92e3a61c8a21e08fd0f390f5301f1c448b137c57c4bc6e543/semver-3.0.4-py3-none-any.whl"}}], "install_targets_hash": "e039dc9ecf1b28450bdeec6c73e7b68c"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "launchdarkly-server-sdk", "version": "9.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/58/bcede9c0f11b5c37b492ea993ed0599099e15f803b9fe98452558cfd6e96/launchdarkly_server_sdk-9.17.0-py3-none-any.whl"}}, {"metadata": {"name": "launchdarkly-eventsource", "version": "1.7.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/49/8592c1d9c156d3c2d3f8c02e1c00260c3e0a7a10bcb50c942bd80c285c62/launchdarkly_eventsource-1.7.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "expiringdict", "version": "1.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/84/a04c59324445f4bcc98dc05b39a1cd07c242dde643c1a3c21e4f7beaf2f2/expiringdict-1.2.2-py3-none-any.whl"}}, {"metadata": {"name": "pyRFC3339", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/34/90/0200184d2124484f918054751ef997ed6409cb05b7e8dcbf5a22da4c4748/pyrfc3339-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "semver", "version": "3.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/24/4d91e05817e92e3a61c8a21e08fd0f390f5301f1c448b137c57c4bc6e543/semver-3.0.4-py3-none-any.whl"}}], "install_targets_hash": "e039dc9ecf1b28450bdeec6c73e7b68c"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "openai-agents", "version": "0.14.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/af/6e/1e9adcedcde7b163579b88a68f765a4915be4ead0713270386d9432cfd2f/openai_agents-0.14.8-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "2.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ae/f4/561ed79fd94876160018a5e75254cfcb9b0e62d4dded9dcb20072e86d623/openai-2.44.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "griffelib", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/63/e876e789525063c840ccfa8857febdabd6523bcef9ce7eb979b9305ea895/griffelib-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ac/4a/84a5ec271d09f7590b6073af5ee4abb44eab4ccace453b7e2c5ce45234ca/jiter-0.17.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "mcp", "version": "1.30.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f5/f4/e58bc33317c92a0203664daaf00bf6f41166cc0149e5d6870a03f7cd004a/mcp-1.30.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/02/bc19b47a96c2d3109760711acf22369e56bd7e405ca52f7ade164d2ead57/pydantic_core-2.46.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1c/6c/c73fa9d5a85f6ab05395de61c5f6984e0a9ff40bb5ff888d46dff02526c6/charset_normalizer-3.5.1-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "types-requests", "version": "2.33.0.20260906"}, "download_info": {"url": "https://files.pythonhosted.org/packages/60/4c/51ec821d22a45b4162fa3f3e9e94ea4c0f8c49e82363b10955baa5438391/types_requests-2.33.0.20260906-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/e8/f7dac2e980bacc92bdc26cebae4ae4d50cae5380732c50980598fc0bbae4/websockets-16.1.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/97/672cb32ce0dfea44b740cb7b4f97038463b9cf7c0ead1aacf595572851d6/pyjwt-2.14.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/f0/424cb557d99aa86ac55da5e2add02e2882e44047b6264f93ade1b975a993/cryptography-50.0.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7d/47/5ecf1023850036e674c77ec4de86182d309ae344e39e7cba984b7df5d647/cffi-2.1.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/77bcb1168b33704908295533d27f10eb811e9e3e193e8993dc99572211d3/rpds_py-2026.6.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/6a/2ba3ed4a69babf3afdddf7d8314a48d87562c0a442206bbc2a1b50d5efc0/sse_starlette-3.4.11-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/03/921a3d3c75785aca9ebfbfcabfbc3a1be12e2ab5265deb026d55a5a3f83e/tqdm-4.70.1-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.52.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/79/4a20b54ab0491485ccd8c077db2d39187c7f12b3e15485d38a7be37c81b4/uvicorn-0.52.4-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "e39da8a431d3f40f0c1638f060e9b600"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "openai-agents", "version": "0.14.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/af/6e/1e9adcedcde7b163579b88a68f765a4915be4ead0713270386d9432cfd2f/openai_agents-0.14.8-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "2.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ae/f4/561ed79fd94876160018a5e75254cfcb9b0e62d4dded9dcb20072e86d623/openai-2.44.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "griffelib", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/b6/f65ac785d4ac90dcf7c831ac6256f5dd4a19780f4e1575b2c0d6eeebe319/griffelib-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/6b/59127338b86d9fe4d99418f5a15118bea778103ee0fe9d9dd7e0af174e95/jiter-0.16.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "mcp", "version": "1.29.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/c8/248b201f6d753d69fd5d6506011abbb35a946d9142b2ae311a948fd0be3d/mcp-1.29.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1c/6c/c73fa9d5a85f6ab05395de61c5f6984e0a9ff40bb5ff888d46dff02526c6/charset_normalizer-3.5.1-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "types-requests", "version": "2.33.0.20260712"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/e7/010c87f559e216d83f9dc51e939633fd0d0ead3377340181ab0e223cd3b5/types_requests-2.33.0.20260712-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/e8/f7dac2e980bacc92bdc26cebae4ae4d50cae5380732c50980598fc0bbae4/websockets-16.1.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c3/fb/951032a3bf22a5697c83183fb6294a4843772947a70e616c57b3ff5f522e/cryptography-50.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7d/47/5ecf1023850036e674c77ec4de86182d309ae344e39e7cba984b7df5d647/cffi-2.1.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/77bcb1168b33704908295533d27f10eb811e9e3e193e8993dc99572211d3/rpds_py-2026.6.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/3a/764912c58293d95b6dcdf4cc255f9d10de310580ced547b082eb9d72018c/sse_starlette-3.4.8-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.52.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/79/4a20b54ab0491485ccd8c077db2d39187c7f12b3e15485d38a7be37c81b4/uvicorn-0.52.4-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "e39da8a431d3f40f0c1638f060e9b600"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "openai-agents", "version": "0.14.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/af/6e/1e9adcedcde7b163579b88a68f765a4915be4ead0713270386d9432cfd2f/openai_agents-0.14.8-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "2.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ae/f4/561ed79fd94876160018a5e75254cfcb9b0e62d4dded9dcb20072e86d623/openai-2.44.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "griffelib", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/b6/f65ac785d4ac90dcf7c831ac6256f5dd4a19780f4e1575b2c0d6eeebe319/griffelib-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/6b/59127338b86d9fe4d99418f5a15118bea778103ee0fe9d9dd7e0af174e95/jiter-0.16.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "mcp", "version": "1.29.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/c8/248b201f6d753d69fd5d6506011abbb35a946d9142b2ae311a948fd0be3d/mcp-1.29.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1c/6c/c73fa9d5a85f6ab05395de61c5f6984e0a9ff40bb5ff888d46dff02526c6/charset_normalizer-3.5.1-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "types-requests", "version": "2.33.0.20260712"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/e7/010c87f559e216d83f9dc51e939633fd0d0ead3377340181ab0e223cd3b5/types_requests-2.33.0.20260712-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/e8/f7dac2e980bacc92bdc26cebae4ae4d50cae5380732c50980598fc0bbae4/websockets-16.1.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c3/fb/951032a3bf22a5697c83183fb6294a4843772947a70e616c57b3ff5f522e/cryptography-50.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7d/47/5ecf1023850036e674c77ec4de86182d309ae344e39e7cba984b7df5d647/cffi-2.1.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/77bcb1168b33704908295533d27f10eb811e9e3e193e8993dc99572211d3/rpds_py-2026.6.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/3a/764912c58293d95b6dcdf4cc255f9d10de310580ced547b082eb9d72018c/sse_starlette-3.4.8-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.52.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/79/4a20b54ab0491485ccd8c077db2d39187c7f12b3e15485d38a7be37c81b4/uvicorn-0.52.4-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "e39da8a431d3f40f0c1638f060e9b600"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "pydantic-ai", "version": "1.76.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e5/c2/8f762847db3f76cafbfad18aea49305b82f15cd8c67f644d0abfc51fc92c/pydantic_ai-1.76.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-ai-slim", "version": "1.76.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/c6/7801af6853502bd53f00e88560f60270d8a2ab3bd8e19732d5ae8f261503/pydantic_ai_slim-1.76.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-evals", "version": "1.76.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e7/ab/14335e6c988ef2af23d33bb89cde4c737b904f84fb237758acf156bb0748/pydantic_evals-1.76.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-graph", "version": "1.76.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/4f/60b018568a33c907734613fb089ff288168faa6affb634e05e1a53f1f9e8/pydantic_graph-1.76.0-py3-none-any.whl"}}, {"metadata": {"name": "huggingface_hub", "version": "1.30.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c3/0e/3e45bbe0dd48f4e56b1d46649d342de853cd1c7e815323472ab62687f153/huggingface_hub-1.30.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bb/1e/c0ad437dd267a8e435bef594acf781bbc3874ff0b6435b4962d03ecf7cc4/hf_xet-1.6.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "mcp", "version": "1.30.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f5/f4/e58bc33317c92a0203664daaf00bf6f41166cc0149e5d6870a03f7cd004a/mcp-1.30.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/02/bc19b47a96c2d3109760711acf22369e56bd7e405ca52f7ade164d2ead57/pydantic_core-2.46.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "ag-ui-protocol", "version": "0.1.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/be/6c/af3d577e68c9474c99600e65b2c6283772aae187edca6f0f2f5cbd9f565a/ag_ui_protocol-0.1.22-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "anthropic", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/e3/34a88f0e1e854022a352d67f72ca9baa8b952d4541315088411ba2bfbc2a/anthropic-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/95/411ba65569158e862368917aaf56597f3e5fa3b91b0502919638465a08f3/httpx2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/74/d370e55600d9bcfa0d9794b0166126d49291a3d2b20c268fc98c453a4948/httpcore2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/6b/59127338b86d9fe4d99418f5a15118bea778103ee0fe9d9dd7e0af174e95/jiter-0.16.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "argcomplete", "version": "3.7.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/46/bd/551ee6af426af84ca33e02622be722925c196608e9127d731ef17c47f06e/argcomplete-3.7.2-py3-none-any.whl"}}, {"metadata": {"name": "boto3", "version": "1.43.90"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/c3/1d5c5ea7f599e2b80d122beeb2a9c1a8daff78325ea2391521e5fd5af1fd/boto3-1.43.90-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.90"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/b8/65cbd0d65553c3e51d27159de4c74308ea008c652b05ed3f830f32667efb/botocore-1.43.90-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "s3transfer", "version": "0.19.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/e7/5c595c75e9f41a44f30e526eda465ea0b4eec93470e074e4a111b253f13a/s3transfer-0.19.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "cohere", "version": "7.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4a/c3/064a44c498bf6ae8621caa14307d3ef5471157f149e33cfd64417c8e9ad3/cohere-7.1.1-py3-none-any.whl"}}, {"metadata": {"name": "fastavro", "version": "1.12.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/8f/18f60329b627d2118a4a2b19e8741fbd807d60bf0470554e1bbfb7f1bca3/fastavro-1.12.2-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1c/6c/c73fa9d5a85f6ab05395de61c5f6984e0a9ff40bb5ff888d46dff02526c6/charset_normalizer-3.5.1-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "tokenizers", "version": "0.23.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/18/1e/bc6587c5ab643b2e17776cace9070a2ae73549c86bffac9934a600bf3c31/tokenizers-0.23.2.tar.gz"}}, {"metadata": {"name": "types-requests", "version": "2.33.0.20260906"}, "download_info": {"url": "https://files.pythonhosted.org/packages/60/4c/51ec821d22a45b4162fa3f3e9e94ea4c0f8c49e82363b10955baa5438391/types_requests-2.33.0.20260906-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "fastmcp", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ac/14/6d950459cc831fa17fe2d1797926b6eb2d2f2af50f830e62d0c098cc1ec8/fastmcp-3.4.7-py3-none-any.whl"}}, {"metadata": {"name": "fastmcp-slim", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b4/97/e0e53642cd029a9a7635ae9c548f9f2cc995af5914e487b3df795664e4be/fastmcp_slim-3.4.7-py3-none-any.whl"}}, {"metadata": {"name": "py-key-value-aio", "version": "0.4.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/95/b8ba862968712caa12a19666175334fa979e1f198b896a430adb3bacfe87/py_key_value_aio-0.4.5-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiofile", "version": "3.12.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/79/6e45e778c4c3cab39e0937b007b720c15f76c50c6453d153282d0fcc3588/aiofile-3.12.3-py3-none-any.whl"}}, {"metadata": {"name": "caio", "version": "0.12.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d3/f4/c39ed874d420bb2719d52932d763953c28371c536d6bf264de1febeb27d5/caio-0.12.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "Authlib", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b8/c6/6f124bcfbbfb20fba22c939b4e43a06dccfc0e1ca20e5634ca573cb1e271/authlib-1.8.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "beartype", "version": "0.22.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/cc/18245721fa7747065ab478316c7fea7c74777d07f37ae60db2e84f8172e8/beartype-0.22.9-py3-none-any.whl"}}, {"metadata": {"name": "cachetools", "version": "7.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/3d/9487690d0e937854db587205c66bab3c3cf88d9f00ed380b74cb88cc94ee/cachetools-7.1.8-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/f0/424cb557d99aa86ac55da5e2add02e2882e44047b6264f93ade1b975a993/cryptography-50.0.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7d/47/5ecf1023850036e674c77ec4de86182d309ae344e39e7cba984b7df5d647/cffi-2.1.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cyclopts", "version": "4.25.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/0e/eadf712ca776fd96982c09348dd8f141ae6f96746a4eabc3e3fb54dea738/cyclopts-4.25.2-py3-none-any.whl"}}, {"metadata": {"name": "rich-rst", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/68/1fc93dd759605b5d00fc98b50200739e41ed32bd22d6ba35ca6c3932371b/rich_rst-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "filelock", "version": "3.32.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cc/06/4f138f618dbea66803291274f228f01daf29f306fe8b96bc30dab765df75/filelock-3.32.6-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/3c/6a2bf344106328fd04963664a60b9bb6496fc25df8e962fcdc1367285fb9/fsspec-2026.7.0-py3-none-any.whl"}}, {"metadata": {"name": "genai-prices", "version": "0.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/48/a1/43fa2a4c5557cd977e83eecec265b0b77b726b0c7b9f2f180b46c6fdb458/genai_prices-0.1.6-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.57.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3b/27/0f7247b8002a1404fdb5412aeb15fb0fe70288eb8f88a5873d1c0d8262cf/google_auth-2.57.1-py3-none-any.whl"}}, {"metadata": {"name": "google-genai", "version": "2.22.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/de/96/0120d214958cb54f2b9c48da9f564a0e6eae269e9dd702415fb1d0551cc7/google_genai-2.22.0-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/e8/f7dac2e980bacc92bdc26cebae4ae4d50cae5380732c50980598fc0bbae4/websockets-16.1.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "griffelib", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/63/e876e789525063c840ccfa8857febdabd6523bcef9ce7eb979b9305ea895/griffelib-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "groq", "version": "1.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/f6/c3d8ea3194d7d7d8292edd4dbb4b6832d29c2eab04887dda4a742e83902c/groq-1.7.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "joserfc", "version": "1.7.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/c5/82addfd375e5ee6520644e0553e4aadde92d668c4fc99cc716d337fe7bb3/joserfc-1.7.5-py3-none-any.whl"}}, {"metadata": {"name": "jsonref", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/ec/e1db9922bceb168197a558a2b8c03a7963f1afe93517ddd3cf99f202f996/jsonref-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-path", "version": "0.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/2c/9e69d73c4297508be9e3b64a970ea3971b3eb8db64ffc5802d40bd25981f/jsonschema_path-0.5.0-py3-none-any.whl"}}, {"metadata": {"name": "pathable", "version": "0.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a2/e8/6d75ffd9784bce2e93d1ae4415649427e39a53bb172d4672b2b59c6f0a7b/pathable-0.6.0-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "keyring", "version": "25.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/db/e655086b7f3a705df045bf0933bdd9c2f79bb3c97bfef1384598bb79a217/keyring-25.7.0-py3-none-any.whl"}}, {"metadata": {"name": "logfire", "version": "5.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/a0/f3a6a31587b85283cbb878446b2e55c9152624586d8d7322adab124fbc96/logfire-5.0.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-exporter-otlp-proto-http", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cd/d0/fdeb1a98d8d3a6205f5f297c51b4a9bfe65126ab60339669bbe3dd54c2e2/opentelemetry_exporter_otlp_proto_http-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-exporter-otlp-proto-common", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5e/71/65fd9d54c10b860f87c045ccee1264cab7011268895d3528818a29c1172a/opentelemetry_exporter_otlp_proto_common-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-proto", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d1/7c/8be563d68e93bbefa5c8affb82ddcff91b3ad858ce49957ba7b16fd3e0ab/opentelemetry_proto-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "googleapis-common-protos", "version": "1.75.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1a/7a/7d79170c6ce6f12e109df2b3879d6b934010cf4f99aea8de8b7e5408c174/googleapis_common_protos-1.75.3-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/6f/a04e900f465ff3221ccc395522503e2d10e79fa21f2723c8e177aae1e0d1/opentelemetry_api-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-sdk", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e7/23/ff077e61886ee020a17ce9c8b6fa11c601c8d8345b09ea24f605445df62a/opentelemetry_sdk-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-semantic-conventions", "version": "0.65b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/0e/49df70d9b81fb5cbae4bbf2a49d865b09bcbcbc4eb53f5851b1027738d78/opentelemetry_semantic_conventions-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "executing", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "logfire-api", "version": "5.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/36/67/282646935c5af564ca89447f745aa292e2d36b554fac3d1effe5c75495ca/logfire_api-5.0.0-py3-none-any.whl"}}, {"metadata": {"name": "mistralai", "version": "2.9.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ac/c6/ce6371bd7a56e8c01a8f59baf4bc16d134eed4f3e2c593b5733087012936/mistralai-2.9.4-py3-none-any.whl"}}, {"metadata": {"name": "eval_type_backport", "version": "0.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/a7/bb99bf5e6f78736ddb53480f2c3ff3702ffe2196a7c5e1661c03081d398e/eval_type_backport-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonpath-python", "version": "1.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/8a/1270a6803bd821cbfcdda387eaa13cb41a7b1f7b9bd145979b3bfb9d6cb7/jsonpath_python-1.1.6-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "3.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/50/0d796ada2d1222cfe609cf435ce7a688450735cee401b24737882c9b9612/openai-3.10.0-py3-none-any.whl"}}, {"metadata": {"name": "openapi-pydantic", "version": "0.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/cf/03675d8bd8ecbf4445504d8071adab19f5f993676795708e36402ab38263/openapi_pydantic-0.5.1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-instrumentation", "version": "0.65b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/40/7b/85eab1215f72adf0e68d3dc4a679b9bff993fa679ff34cd8dd378e2659fd/opentelemetry_instrumentation-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "wrapt", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b2/da/c1d3245abb911a42584f8f7e9781995bdc41345c7affba75cf7e376c85ac/wrapt-2.4.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "opentelemetry-instrumentation-httpx", "version": "0.65b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/0f/c6144096b4914bbf44b43ba21c962e8f333ff045770b50a3e79ed8bd455f/opentelemetry_instrumentation_httpx-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-util-http", "version": "0.65b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/23/3f/ab8d29df207ce5f470a07fa96ebb48af4e95b7fab7e7635311b9a32f2fab/opentelemetry_util_http-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "platformdirs", "version": "4.11.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/e1/5b7b8bbb55084d1425bcb9bc823ff519e1b2be05f6ebb0089e2eacc38413/platformdirs-4.11.8-py3-none-any.whl"}}, {"metadata": {"name": "prompt_toolkit", "version": "3.0.53"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/6f/84908cad2d6aa5144abcf7b42709fe4fdb459bc640ec7ac5786e7693dabc/prompt_toolkit-3.0.53-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/3b/6163796d69c3977d1e4287bea4a6979161cbbdd170ebb430511e8e1999ce/pyasn1-0.6.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-handlebars", "version": "0.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/11/364bc401f1d8fdb3947079fc43ffdfbfc9132d065981a03a95d2e87440c4/pydantic_handlebars-0.2.1-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "email-validator", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "dnspython", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "pyperclip", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/80/fc9d01d5ed37ba4c42ca2b55b4339ae6e200b456be3a1aaddf4a9fa99b8c/pyperclip-1.11.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/77bcb1168b33704908295533d27f10eb811e9e3e193e8993dc99572211d3/rpds_py-2026.6.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/6a/2ba3ed4a69babf3afdddf7d8314a48d87562c0a442206bbc2a1b50d5efc0/sse_starlette-3.4.11-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "temporalio", "version": "1.32.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/d8/18cf5bbbcc4b4c884d7723c9b54bf8d1d2556d9fbef3e99599dd3db12034/temporalio-1.32.0.tar.gz"}}, {"metadata": {"name": "nexus-rpc", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/11/52/6327a5f4fda01207205038a106a99848a41c83e933cd23ea2cab3d2ebc6c/nexus_rpc-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "types-protobuf", "version": "7.35.1.20260906"}, "download_info": {"url": "https://files.pythonhosted.org/packages/44/4e/f63e826c68f77ef875506d72f225918800346545ee99847bc28f3394f18d/types_protobuf-7.35.1.20260906-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/29/46ad8061f57bd9f8b2ea0aa82bf574e0f2aa040b0857a1582adba9957899/tiktoken-0.14.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uncalled-for", "version": "0.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a2/40/97cec87c077eb3291fc7905e6633e08b7ca593c57d30238444bcb6bb3d53/uncalled_for-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.52.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/79/4a20b54ab0491485ccd8c077db2d39187c7f12b3e15485d38a7be37c81b4/uvicorn-0.52.4-py3-none-any.whl"}}, {"metadata": {"name": "watchfiles", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/73/4e/9f7adf01754cbf81843722ccfec169d8f26c69778281a302855cecd2ee08/watchfiles-1.2.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c4/0e/57f6bb3024a597b2e8ec4aee710ffe62ddc95af2e2bb1ee7a7abdc22c68c/wcwidth-0.8.3-py3-none-any.whl"}}, {"metadata": {"name": "xai-sdk", "version": "1.19.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/b5/6f6783b97fb3a5498eb852ccaa706e1a2c0de2409480e3c99428e85234fe/xai_sdk-1.19.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/d8/8ec0e471248c500acdce2be3f46db8fb62b5eb60efef072529cc85ee1d26/aiohttp-3.14.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "grpcio", "version": "1.83.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e2/b1/46539f5050d7c316a13396d185451f95084a74ddc68b12d818595bef0377/grpcio-1.83.1.tar.gz"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "25.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl"}}, {"metadata": {"name": "protobuf", "version": "6.33.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c4/72/02445137af02769918a93807b2b7890047c32bfb9f90371cbc12688819eb/protobuf-6.33.6-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ff/0b/cfb76b7fe99686db264bff829779a539d923e7564ffd7ef18da6c54c3774/yarl-1.24.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/73/daf935ea7048ddd7ec8eec5345b4a40b619d2d178b3c0a0900796bc3c794/propcache-0.5.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "jaraco.classes", "version": "3.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/66/b15ce62552d84bbfcec9a4873ab79d993a1dd4edb922cbfccae192bd5b5f/jaraco.classes-3.4.0-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.context", "version": "6.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f2/58/bc8954bda5fcda97bd7c19be11b85f91973d67a706ed4a3aec33e7de22db/jaraco_context-6.1.2-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.functools", "version": "4.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/02/36/ecc85bc96c273dc8a11273ed4782272975e6338d4a3e9228621175edf0e3/jaraco_functools-4.6.0-py3-none-any.whl"}}, {"metadata": {"name": "more-itertools", "version": "11.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/3d/1087453384dbde46a8c7f9356eead2c58be8a7bf156bca40243377c85715/more_itertools-11.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.9.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/48/ec/c646df2b62c1b1334e28581715ed776814c8ac80c0c9106175f0c61ce12a/regex-2026.9.3-cp314-cp314t-macosx_11_0_arm64.whl"}}], "install_targets_hash": "e7b1126e413bef21402b41f19a1e7222"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "pure_eval", "version": "0.2.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6d/18/83376915176eb058cb86470eb7396388a13350b09a8f233a79303bbcbc5b/pure_eval-0.2.4-py3-none-any.whl"}}, {"metadata": {"name": "asttokens", "version": "3.0.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d4/2b/04b8a15f3a1c77bc79ddf5c73875327f34b4fa75982df2b76e45e402d364/asttokens-3.0.2-py3-none-any.whl"}}, {"metadata": {"name": "executing", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl"}}], "install_targets_hash": "ef91391ff2fb8720438fb9fbd1e2fc94"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "mcp", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/af/8644cc5fa26a59afd2df2e98eeb19e72926887fa4b7441aba4ff661140db/mcp-2.1.1-py3-none-any.whl"}}, {"metadata": {"name": "mcp-types", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/d0/242e63c510f4a17381f55b1549a3f94f5687a0595984febd2b6f87a687a0/mcp_types-2.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/6f/a04e900f465ff3221ccc395522503e2d10e79fa21f2723c8e177aae1e0d1/opentelemetry_api-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/02/bc19b47a96c2d3109760711acf22369e56bd7e405ca52f7ade164d2ead57/pydantic_core-2.46.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/97/672cb32ce0dfea44b740cb7b4f97038463b9cf7c0ead1aacf595572851d6/pyjwt-2.14.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/f0/424cb557d99aa86ac55da5e2add02e2882e44047b6264f93ade1b975a993/cryptography-50.0.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7d/47/5ecf1023850036e674c77ec4de86182d309ae344e39e7cba984b7df5d647/cffi-2.1.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/77bcb1168b33704908295533d27f10eb811e9e3e193e8993dc99572211d3/rpds_py-2026.6.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/6a/2ba3ed4a69babf3afdddf7d8314a48d87562c0a442206bbc2a1b50d5efc0/sse_starlette-3.4.11-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.53.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/76/18/0eea75741ee812e9f598b687619ce2454f6c3a1c5cd21ea990ec6bd26f45/uvicorn-0.53.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "f0d2472e8e45f37ecbb75fd658385dd5"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "mistralai", "version": "2.10.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/98/f64b54166a607ece4e5c8494c843ac1f9c7c0af6f1014272cc420fe1d519/mistralai-2.10.1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/6f/a04e900f465ff3221ccc395522503e2d10e79fa21f2723c8e177aae1e0d1/opentelemetry_api-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "eval_type_backport", "version": "0.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/a7/bb99bf5e6f78736ddb53480f2c3ff3702ffe2196a7c5e1661c03081d398e/eval_type_backport-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonpath-python", "version": "1.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/8a/1270a6803bd821cbfcdda387eaa13cb41a7b1f7b9bd145979b3bfb9d6cb7/jsonpath_python-1.1.6-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-semantic-conventions", "version": "0.65b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/0e/49df70d9b81fb5cbae4bbf2a49d865b09bcbcbc4eb53f5851b1027738d78/opentelemetry_semantic_conventions-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/02/bc19b47a96c2d3109760711acf22369e56bd7e405ca52f7ade164d2ead57/pydantic_core-2.46.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}], "install_targets_hash": "f60e32909a4363f0d8cc05916d4da67a"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "asyncpg", "version": "0.31.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6a/81/e6be6e37e560bd91e6c23ea8a6138a04fd057b08cf63d3c5055c98e81c1d/asyncpg-0.31.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "f737563b075b37dba35f4a4e7631e9cd"} {"python_version": "3.14", "dependencies": [{"metadata": {"name": "asyncpg", "version": "0.31.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6a/81/e6be6e37e560bd91e6c23ea8a6138a04fd057b08cf63d3c5055c98e81c1d/asyncpg-0.31.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "f737563b075b37dba35f4a4e7631e9cd"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "asyncpg", "version": "0.31.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6a/81/e6be6e37e560bd91e6c23ea8a6138a04fd057b08cf63d3c5055c98e81c1d/asyncpg-0.31.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "f737563b075b37dba35f4a4e7631e9cd"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "asyncpg", "version": "0.31.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6a/81/e6be6e37e560bd91e6c23ea8a6138a04fd057b08cf63d3c5055c98e81c1d/asyncpg-0.31.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "f737563b075b37dba35f4a4e7631e9cd"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "asyncpg", "version": "0.31.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6a/81/e6be6e37e560bd91e6c23ea8a6138a04fd057b08cf63d3c5055c98e81c1d/asyncpg-0.31.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "f737563b075b37dba35f4a4e7631e9cd"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "asyncpg", "version": "0.31.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6a/81/e6be6e37e560bd91e6c23ea8a6138a04fd057b08cf63d3c5055c98e81c1d/asyncpg-0.31.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "f737563b075b37dba35f4a4e7631e9cd"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "asyncpg", "version": "0.31.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6a/81/e6be6e37e560bd91e6c23ea8a6138a04fd057b08cf63d3c5055c98e81c1d/asyncpg-0.31.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "f737563b075b37dba35f4a4e7631e9cd"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "asyncpg", "version": "0.31.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6a/81/e6be6e37e560bd91e6c23ea8a6138a04fd057b08cf63d3c5055c98e81c1d/asyncpg-0.31.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "f737563b075b37dba35f4a4e7631e9cd"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "asyncpg", "version": "0.31.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6a/81/e6be6e37e560bd91e6c23ea8a6138a04fd057b08cf63d3c5055c98e81c1d/asyncpg-0.31.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "f737563b075b37dba35f4a4e7631e9cd"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "asyncpg", "version": "0.31.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6a/81/e6be6e37e560bd91e6c23ea8a6138a04fd057b08cf63d3c5055c98e81c1d/asyncpg-0.31.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "f737563b075b37dba35f4a4e7631e9cd"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "asyncpg", "version": "0.31.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6a/81/e6be6e37e560bd91e6c23ea8a6138a04fd057b08cf63d3c5055c98e81c1d/asyncpg-0.31.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "f737563b075b37dba35f4a4e7631e9cd"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "asyncpg", "version": "0.31.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6a/81/e6be6e37e560bd91e6c23ea8a6138a04fd057b08cf63d3c5055c98e81c1d/asyncpg-0.31.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "f737563b075b37dba35f4a4e7631e9cd"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "asyncpg", "version": "0.31.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6a/81/e6be6e37e560bd91e6c23ea8a6138a04fd057b08cf63d3c5055c98e81c1d/asyncpg-0.31.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "f737563b075b37dba35f4a4e7631e9cd"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "asyncpg", "version": "0.31.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6a/81/e6be6e37e560bd91e6c23ea8a6138a04fd057b08cf63d3c5055c98e81c1d/asyncpg-0.31.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "f737563b075b37dba35f4a4e7631e9cd"} +{"python_version": "3.14", "dependencies": [{"metadata": {"name": "asyncpg", "version": "0.31.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6a/81/e6be6e37e560bd91e6c23ea8a6138a04fd057b08cf63d3c5055c98e81c1d/asyncpg-0.31.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "f737563b075b37dba35f4a4e7631e9cd"} {"python_version": "3.14t", "dependencies": [{"metadata": {"name": "openai-agents", "version": "0.22.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f8/56/f5d32edb2e890a5dea9824cb76d179cef47c6a5ea8269d3559d092936106/openai_agents-0.22.3-py3-none-any.whl"}}, {"metadata": {"name": "griffelib", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/63/e876e789525063c840ccfa8857febdabd6523bcef9ce7eb979b9305ea895/griffelib-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "mcp", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/ff/8e7eade68b8a28f7da0ed1085544341b51f9c935dbf6b95c76b7edfea6a0/mcp-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mcp-types", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8f/d7/6ffba5d8cd5dd9b8a19478875c50e04945314ba5074e84d749283f27f62d/mcp_types-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "3.16.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/17/72/2b1fe3e303db76ab2ba0c2de2b57822869bcb588db82334d4ff3aea8acf2/openai-3.16.2-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/96/c1813dcca15c5a370145a448aaea7d1f83f6f0228a5f1130e79340ee385f/jiter-0.17.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/64/a4e536cb16d7f61a7fd3120b46c577fc7fa7325992f69c4f52bc786d77d8/pydantic_core-2.46.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/ee/e4e10a94d51cd1ee638aa7e00b65399e6b2a4e8376ab6d2eac9f95586671/charset_normalizer-3.5.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b2/39/26762f734113e22da2b942c3aca85798e0c0405d64c256549540ff31e5a1/websockets-16.1.1-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/6f/a04e900f465ff3221ccc395522503e2d10e79fa21f2723c8e177aae1e0d1/opentelemetry_api-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/97/672cb32ce0dfea44b740cb7b4f97038463b9cf7c0ead1aacf595572851d6/pyjwt-2.14.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1a/01/0127d11a762b31a9ee0221894f540318761783f3fdc4bc5d057698caebd5/cryptography-50.0.1-cp314-cp314t-manylinux_2_34_x86_64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/95/eff5f0cee78d2eabc7eebffec40d3fc1876b5f3c95582e018bb4b99601f2/cffi-2.1.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8e/f4/b7ac49f30013aba8f7b9566b1dd07e81de95e708c1374b7bacc5b9bc5c9c/rpds_py-2026.6.3-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/6a/2ba3ed4a69babf3afdddf7d8314a48d87562c0a442206bbc2a1b50d5efc0/sse_starlette-3.4.11-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.53.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/76/18/0eea75741ee812e9f598b687619ce2454f6c3a1c5cd21ea990ec6bd26f45/uvicorn-0.53.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "00309e9160aac64c6c329f5b3a40b95e"} {"python_version": "3.14t", "dependencies": [{"metadata": {"name": "litestar", "version": "2.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/ce/4697b547790f23d2fcc37a928d48c38140cf86360e4041ca8177e3367c14/litestar-2.24.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/9e/db72b3ae7fc9cfad53e630e56c6ae83b9b6ff0bf3718ffb8012d20b3aabf/cryptography-49.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "litestar-htmx", "version": "0.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f2/24/8d99982f0aa9c1cd82073c6232b54a0dbe6797c7d63c0583a6c68ee3ddf2/litestar_htmx-0.5.0-py3-none-any.whl"}}, {"metadata": {"name": "msgspec", "version": "0.21.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/70/9b/ce0cca6d2d87fcd4b6ff97600790494e64f26a2c55d61507cd2755c16193/msgspec-0.21.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multipart", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/ed/e1f03200ee1f0bf4a2b9b72709afefbf5319b68df654e0b84b35c65613ee/multipart-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "polyfactory", "version": "3.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/34/b6f19941adcdaf415b5e8a8d577499f5b6a76b59cbae37f9b125a9ffe9f2/polyfactory-3.3.0-py3-none-any.whl"}}, {"metadata": {"name": "Faker", "version": "40.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/a6/6111b9f13c1564b0e2f5dbeeb611fd00dc731e6add2336f62b798598c73d/faker-40.28.1-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "rich-click", "version": "1.9.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6d/97/a87901aef6b7e7e4a34c6dd6cc17dca8594a592ef9d9dd765fca2b7facf7/rich_click-1.9.8-py3-none-any.whl"}}], "install_targets_hash": "030c889f2cc15fac775b2cc21c8d01e4"} {"python_version": "3.14t", "dependencies": [{"metadata": {"name": "litestar", "version": "2.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/ce/4697b547790f23d2fcc37a928d48c38140cf86360e4041ca8177e3367c14/litestar-2.24.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/9e/db72b3ae7fc9cfad53e630e56c6ae83b9b6ff0bf3718ffb8012d20b3aabf/cryptography-49.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "litestar-htmx", "version": "0.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f2/24/8d99982f0aa9c1cd82073c6232b54a0dbe6797c7d63c0583a6c68ee3ddf2/litestar_htmx-0.5.0-py3-none-any.whl"}}, {"metadata": {"name": "msgspec", "version": "0.21.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/70/9b/ce0cca6d2d87fcd4b6ff97600790494e64f26a2c55d61507cd2755c16193/msgspec-0.21.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multipart", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/ed/e1f03200ee1f0bf4a2b9b72709afefbf5319b68df654e0b84b35c65613ee/multipart-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "polyfactory", "version": "3.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/34/b6f19941adcdaf415b5e8a8d577499f5b6a76b59cbae37f9b125a9ffe9f2/polyfactory-3.3.0-py3-none-any.whl"}}, {"metadata": {"name": "Faker", "version": "40.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/a6/6111b9f13c1564b0e2f5dbeeb611fd00dc731e6add2336f62b798598c73d/faker-40.28.1-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "rich-click", "version": "1.9.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6d/97/a87901aef6b7e7e4a34c6dd6cc17dca8594a592ef9d9dd765fca2b7facf7/rich_click-1.9.8-py3-none-any.whl"}}], "install_targets_hash": "030c889f2cc15fac775b2cc21c8d01e4"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "litestar", "version": "2.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/ce/4697b547790f23d2fcc37a928d48c38140cf86360e4041ca8177e3367c14/litestar-2.24.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/9e/db72b3ae7fc9cfad53e630e56c6ae83b9b6ff0bf3718ffb8012d20b3aabf/cryptography-49.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "litestar-htmx", "version": "0.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f2/24/8d99982f0aa9c1cd82073c6232b54a0dbe6797c7d63c0583a6c68ee3ddf2/litestar_htmx-0.5.0-py3-none-any.whl"}}, {"metadata": {"name": "msgspec", "version": "0.21.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/70/9b/ce0cca6d2d87fcd4b6ff97600790494e64f26a2c55d61507cd2755c16193/msgspec-0.21.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multipart", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/ed/e1f03200ee1f0bf4a2b9b72709afefbf5319b68df654e0b84b35c65613ee/multipart-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "polyfactory", "version": "3.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/34/b6f19941adcdaf415b5e8a8d577499f5b6a76b59cbae37f9b125a9ffe9f2/polyfactory-3.3.0-py3-none-any.whl"}}, {"metadata": {"name": "Faker", "version": "40.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/a6/6111b9f13c1564b0e2f5dbeeb611fd00dc731e6add2336f62b798598c73d/faker-40.28.1-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "rich-click", "version": "1.9.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6d/97/a87901aef6b7e7e4a34c6dd6cc17dca8594a592ef9d9dd765fca2b7facf7/rich_click-1.9.8-py3-none-any.whl"}}], "install_targets_hash": "030c889f2cc15fac775b2cc21c8d01e4"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "litestar", "version": "2.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/ce/4697b547790f23d2fcc37a928d48c38140cf86360e4041ca8177e3367c14/litestar-2.24.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/9e/db72b3ae7fc9cfad53e630e56c6ae83b9b6ff0bf3718ffb8012d20b3aabf/cryptography-49.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "litestar-htmx", "version": "0.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f2/24/8d99982f0aa9c1cd82073c6232b54a0dbe6797c7d63c0583a6c68ee3ddf2/litestar_htmx-0.5.0-py3-none-any.whl"}}, {"metadata": {"name": "msgspec", "version": "0.21.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/70/9b/ce0cca6d2d87fcd4b6ff97600790494e64f26a2c55d61507cd2755c16193/msgspec-0.21.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multipart", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/ed/e1f03200ee1f0bf4a2b9b72709afefbf5319b68df654e0b84b35c65613ee/multipart-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "polyfactory", "version": "3.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/34/b6f19941adcdaf415b5e8a8d577499f5b6a76b59cbae37f9b125a9ffe9f2/polyfactory-3.3.0-py3-none-any.whl"}}, {"metadata": {"name": "Faker", "version": "40.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/a6/6111b9f13c1564b0e2f5dbeeb611fd00dc731e6add2336f62b798598c73d/faker-40.28.1-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "rich-click", "version": "1.9.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6d/97/a87901aef6b7e7e4a34c6dd6cc17dca8594a592ef9d9dd765fca2b7facf7/rich_click-1.9.8-py3-none-any.whl"}}], "install_targets_hash": "030c889f2cc15fac775b2cc21c8d01e4"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "litestar", "version": "2.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/ce/4697b547790f23d2fcc37a928d48c38140cf86360e4041ca8177e3367c14/litestar-2.24.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/9e/db72b3ae7fc9cfad53e630e56c6ae83b9b6ff0bf3718ffb8012d20b3aabf/cryptography-49.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "litestar-htmx", "version": "0.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f2/24/8d99982f0aa9c1cd82073c6232b54a0dbe6797c7d63c0583a6c68ee3ddf2/litestar_htmx-0.5.0-py3-none-any.whl"}}, {"metadata": {"name": "msgspec", "version": "0.21.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/70/9b/ce0cca6d2d87fcd4b6ff97600790494e64f26a2c55d61507cd2755c16193/msgspec-0.21.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multipart", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/ed/e1f03200ee1f0bf4a2b9b72709afefbf5319b68df654e0b84b35c65613ee/multipart-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "polyfactory", "version": "3.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/34/b6f19941adcdaf415b5e8a8d577499f5b6a76b59cbae37f9b125a9ffe9f2/polyfactory-3.3.0-py3-none-any.whl"}}, {"metadata": {"name": "Faker", "version": "40.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/a6/6111b9f13c1564b0e2f5dbeeb611fd00dc731e6add2336f62b798598c73d/faker-40.28.1-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "rich-click", "version": "1.9.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6d/97/a87901aef6b7e7e4a34c6dd6cc17dca8594a592ef9d9dd765fca2b7facf7/rich_click-1.9.8-py3-none-any.whl"}}], "install_targets_hash": "030c889f2cc15fac775b2cc21c8d01e4"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "litestar", "version": "2.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/ce/4697b547790f23d2fcc37a928d48c38140cf86360e4041ca8177e3367c14/litestar-2.24.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/9e/db72b3ae7fc9cfad53e630e56c6ae83b9b6ff0bf3718ffb8012d20b3aabf/cryptography-49.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "litestar-htmx", "version": "0.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f2/24/8d99982f0aa9c1cd82073c6232b54a0dbe6797c7d63c0583a6c68ee3ddf2/litestar_htmx-0.5.0-py3-none-any.whl"}}, {"metadata": {"name": "msgspec", "version": "0.21.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/70/9b/ce0cca6d2d87fcd4b6ff97600790494e64f26a2c55d61507cd2755c16193/msgspec-0.21.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multipart", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/ed/e1f03200ee1f0bf4a2b9b72709afefbf5319b68df654e0b84b35c65613ee/multipart-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "polyfactory", "version": "3.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/34/b6f19941adcdaf415b5e8a8d577499f5b6a76b59cbae37f9b125a9ffe9f2/polyfactory-3.3.0-py3-none-any.whl"}}, {"metadata": {"name": "Faker", "version": "40.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/a6/6111b9f13c1564b0e2f5dbeeb611fd00dc731e6add2336f62b798598c73d/faker-40.28.1-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "rich-click", "version": "1.9.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6d/97/a87901aef6b7e7e4a34c6dd6cc17dca8594a592ef9d9dd765fca2b7facf7/rich_click-1.9.8-py3-none-any.whl"}}], "install_targets_hash": "030c889f2cc15fac775b2cc21c8d01e4"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "litestar", "version": "2.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/ce/4697b547790f23d2fcc37a928d48c38140cf86360e4041ca8177e3367c14/litestar-2.24.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/9e/db72b3ae7fc9cfad53e630e56c6ae83b9b6ff0bf3718ffb8012d20b3aabf/cryptography-49.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "litestar-htmx", "version": "0.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f2/24/8d99982f0aa9c1cd82073c6232b54a0dbe6797c7d63c0583a6c68ee3ddf2/litestar_htmx-0.5.0-py3-none-any.whl"}}, {"metadata": {"name": "msgspec", "version": "0.21.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/70/9b/ce0cca6d2d87fcd4b6ff97600790494e64f26a2c55d61507cd2755c16193/msgspec-0.21.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multipart", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/ed/e1f03200ee1f0bf4a2b9b72709afefbf5319b68df654e0b84b35c65613ee/multipart-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "polyfactory", "version": "3.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/34/b6f19941adcdaf415b5e8a8d577499f5b6a76b59cbae37f9b125a9ffe9f2/polyfactory-3.3.0-py3-none-any.whl"}}, {"metadata": {"name": "Faker", "version": "40.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/a6/6111b9f13c1564b0e2f5dbeeb611fd00dc731e6add2336f62b798598c73d/faker-40.28.1-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "rich-click", "version": "1.9.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6d/97/a87901aef6b7e7e4a34c6dd6cc17dca8594a592ef9d9dd765fca2b7facf7/rich_click-1.9.8-py3-none-any.whl"}}], "install_targets_hash": "030c889f2cc15fac775b2cc21c8d01e4"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "litestar", "version": "2.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/ce/4697b547790f23d2fcc37a928d48c38140cf86360e4041ca8177e3367c14/litestar-2.24.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/9e/db72b3ae7fc9cfad53e630e56c6ae83b9b6ff0bf3718ffb8012d20b3aabf/cryptography-49.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "litestar-htmx", "version": "0.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f2/24/8d99982f0aa9c1cd82073c6232b54a0dbe6797c7d63c0583a6c68ee3ddf2/litestar_htmx-0.5.0-py3-none-any.whl"}}, {"metadata": {"name": "msgspec", "version": "0.21.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/70/9b/ce0cca6d2d87fcd4b6ff97600790494e64f26a2c55d61507cd2755c16193/msgspec-0.21.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multipart", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/ed/e1f03200ee1f0bf4a2b9b72709afefbf5319b68df654e0b84b35c65613ee/multipart-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "polyfactory", "version": "3.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/34/b6f19941adcdaf415b5e8a8d577499f5b6a76b59cbae37f9b125a9ffe9f2/polyfactory-3.3.0-py3-none-any.whl"}}, {"metadata": {"name": "Faker", "version": "40.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/a6/6111b9f13c1564b0e2f5dbeeb611fd00dc731e6add2336f62b798598c73d/faker-40.28.1-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "rich-click", "version": "1.9.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6d/97/a87901aef6b7e7e4a34c6dd6cc17dca8594a592ef9d9dd765fca2b7facf7/rich_click-1.9.8-py3-none-any.whl"}}], "install_targets_hash": "030c889f2cc15fac775b2cc21c8d01e4"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "litestar", "version": "2.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/ce/4697b547790f23d2fcc37a928d48c38140cf86360e4041ca8177e3367c14/litestar-2.24.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/9e/db72b3ae7fc9cfad53e630e56c6ae83b9b6ff0bf3718ffb8012d20b3aabf/cryptography-49.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "litestar-htmx", "version": "0.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f2/24/8d99982f0aa9c1cd82073c6232b54a0dbe6797c7d63c0583a6c68ee3ddf2/litestar_htmx-0.5.0-py3-none-any.whl"}}, {"metadata": {"name": "msgspec", "version": "0.21.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/70/9b/ce0cca6d2d87fcd4b6ff97600790494e64f26a2c55d61507cd2755c16193/msgspec-0.21.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multipart", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/ed/e1f03200ee1f0bf4a2b9b72709afefbf5319b68df654e0b84b35c65613ee/multipart-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "polyfactory", "version": "3.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/34/b6f19941adcdaf415b5e8a8d577499f5b6a76b59cbae37f9b125a9ffe9f2/polyfactory-3.3.0-py3-none-any.whl"}}, {"metadata": {"name": "Faker", "version": "40.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/a6/6111b9f13c1564b0e2f5dbeeb611fd00dc731e6add2336f62b798598c73d/faker-40.28.1-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "rich-click", "version": "1.9.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6d/97/a87901aef6b7e7e4a34c6dd6cc17dca8594a592ef9d9dd765fca2b7facf7/rich_click-1.9.8-py3-none-any.whl"}}], "install_targets_hash": "030c889f2cc15fac775b2cc21c8d01e4"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "statsig", "version": "0.72.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/76/f6/72e48d6e3b37aaf866d1ca0c59382a28e67d303b1edee446c1fb5ceaf8ba/statsig-0.72.1-py3-none-any.whl"}}, {"metadata": {"name": "brotli", "version": "1.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/f7/16/c92ca344d646e71a43b8bb353f0a6490d7f6e06210f8554c8f874e454285/brotli-1.2.0.tar.gz"}}, {"metadata": {"name": "grpcio", "version": "1.84.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/3f/4f/4435c0aae54657258d9cfcba78598f3d9e5fe4c82ff18d78558567b90faf/grpcio-1.84.0.tar.gz"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ijson", "version": "3.5.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/fc/d0/b3beddb96eef0b20bb9902c36e4de30f145be06d7e5e1d780e1a1689d0ce/ijson-3.5.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "ip3country", "version": "0.4.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/d6/b7/48a7f1ab9eee62f1113114207df7e7e6bc29227389d554f42cc11bc98108/ip3country-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "protobuf", "version": "7.36.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e4/04/d52c7016b04b6c5108f26691f9d33ec82a9b65d041f1a9c771137693d618/protobuf-7.36.2-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/1c/6c/c73fa9d5a85f6ab05395de61c5f6984e0a9ff40bb5ff888d46dff02526c6/charset_normalizer-3.5.1-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "ua-parser", "version": "1.0.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a9/7c/6367995ff57aaa2d9e1055adbaec2519cf5a979780a83a93fdf8c6ec37be/ua_parser-1.0.2-py3-none-any.whl"}}, {"metadata": {"name": "ua-parser-builtins", "version": "202606"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/51/a3/f26edd95a2ce2ffbf559da432e5ff544e8dcda3673d1c775f71afffb18b7/ua_parser_builtins-202606-py3-none-any.whl"}}], "install_targets_hash": "031727d1d340ad25520b3e3bed55caf7"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "pyramid", "version": "2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1f/d4/03a8f9b60b8f2a9198c962d08fd9b657c1c0797cbbde3793babbad200845/pyramid-2.1-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "2.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/f3/22afbdb20cc4654b10c98043414a14057cd27fdba9d4ae61cea596000ba2/Werkzeug-2.0.3-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "81.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/e3/c164c88b2e5ce7b24d667b9bd83589cf4f3520d97cad01534cd3c4f55fdb/setuptools-81.0.0-py3-none-any.whl"}}, {"metadata": {"name": "hupper", "version": "1.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/86/7d/3888833e4f5ea56af4a9935066ec09a83228e533d7b8877f65889d706ee4/hupper-1.12.1-py3-none-any.whl"}}, {"metadata": {"name": "translationstring", "version": "1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3b/98/36187601a15e3d37e9bfcf0e0e1055532b39d044353b06861c3a519737a9/translationstring-1.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "venusian", "version": "3.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5a/4b/34d926eba40db81b204066a60b4efdc5d8867a8efcbfe44d69b634b1c907/venusian-3.1.1-py3-none-any.whl"}}, {"metadata": {"name": "WebOb", "version": "1.8.10"}, "download_info": {"url": "https://files.pythonhosted.org/packages/83/21/fce134877fb6fc6ad3c464e4a07ede0ee9219f705d26a981ae58ea36ca13/webob-1.8.10-py2.py3-none-any.whl"}}, {"metadata": {"name": "legacy-cgi", "version": "2.6.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8c/7e/e7394eeb49a41cc514b3eb49020223666cbf40d86f5721c2f07871e6d84a/legacy_cgi-2.6.4-py3-none-any.whl"}}, {"metadata": {"name": "zope.deprecation", "version": "6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/ed/da7f8b1c73caf989a0ff7096cc73c59e6c36f35a8f967c51104098602e2d/zope_deprecation-6.0-py3-none-any.whl"}}, {"metadata": {"name": "zope.interface", "version": "8.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f3/55/de0c3459ff717fce3342f9a29464c281fdeb0d36c3171ee88d119d5f0650/zope_interface-8.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "plaster", "version": "1.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e7/8b/3f98db1448e3b4d2d142716874a7e02f6101685fdaa0f55a8668e9ffa048/plaster-1.1.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "plaster-pastedeploy", "version": "1.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/30/2d4cf89035c22a89bf0e34dbc50fdc07c42c9bdc90fd972d495257ad2b6e/plaster_pastedeploy-1.0.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "PasteDeploy", "version": "3.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/85/30/cdddd9a88969683a59222a6d61cd6dce923977f2e9f9ffba38e1324149cd/PasteDeploy-3.1.0-py3-none-any.whl"}}], "install_targets_hash": "060f93eb8052b63b08924e439967bba6"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "pyramid", "version": "2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1f/d4/03a8f9b60b8f2a9198c962d08fd9b657c1c0797cbbde3793babbad200845/pyramid-2.1-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "2.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/f3/22afbdb20cc4654b10c98043414a14057cd27fdba9d4ae61cea596000ba2/Werkzeug-2.0.3-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "81.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/e3/c164c88b2e5ce7b24d667b9bd83589cf4f3520d97cad01534cd3c4f55fdb/setuptools-81.0.0-py3-none-any.whl"}}, {"metadata": {"name": "hupper", "version": "1.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/86/7d/3888833e4f5ea56af4a9935066ec09a83228e533d7b8877f65889d706ee4/hupper-1.12.1-py3-none-any.whl"}}, {"metadata": {"name": "translationstring", "version": "1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3b/98/36187601a15e3d37e9bfcf0e0e1055532b39d044353b06861c3a519737a9/translationstring-1.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "venusian", "version": "3.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5a/4b/34d926eba40db81b204066a60b4efdc5d8867a8efcbfe44d69b634b1c907/venusian-3.1.1-py3-none-any.whl"}}, {"metadata": {"name": "WebOb", "version": "1.8.10"}, "download_info": {"url": "https://files.pythonhosted.org/packages/83/21/fce134877fb6fc6ad3c464e4a07ede0ee9219f705d26a981ae58ea36ca13/webob-1.8.10-py2.py3-none-any.whl"}}, {"metadata": {"name": "legacy-cgi", "version": "2.6.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8c/7e/e7394eeb49a41cc514b3eb49020223666cbf40d86f5721c2f07871e6d84a/legacy_cgi-2.6.4-py3-none-any.whl"}}, {"metadata": {"name": "zope.deprecation", "version": "6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/ed/da7f8b1c73caf989a0ff7096cc73c59e6c36f35a8f967c51104098602e2d/zope_deprecation-6.0-py3-none-any.whl"}}, {"metadata": {"name": "zope.interface", "version": "8.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f3/55/de0c3459ff717fce3342f9a29464c281fdeb0d36c3171ee88d119d5f0650/zope_interface-8.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "plaster", "version": "1.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e7/8b/3f98db1448e3b4d2d142716874a7e02f6101685fdaa0f55a8668e9ffa048/plaster-1.1.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "plaster-pastedeploy", "version": "1.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/30/2d4cf89035c22a89bf0e34dbc50fdc07c42c9bdc90fd972d495257ad2b6e/plaster_pastedeploy-1.0.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "PasteDeploy", "version": "3.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/85/30/cdddd9a88969683a59222a6d61cd6dce923977f2e9f9ffba38e1324149cd/PasteDeploy-3.1.0-py3-none-any.whl"}}], "install_targets_hash": "060f93eb8052b63b08924e439967bba6"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "pyramid", "version": "2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1f/d4/03a8f9b60b8f2a9198c962d08fd9b657c1c0797cbbde3793babbad200845/pyramid-2.1-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "2.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/f3/22afbdb20cc4654b10c98043414a14057cd27fdba9d4ae61cea596000ba2/Werkzeug-2.0.3-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "81.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/e3/c164c88b2e5ce7b24d667b9bd83589cf4f3520d97cad01534cd3c4f55fdb/setuptools-81.0.0-py3-none-any.whl"}}, {"metadata": {"name": "hupper", "version": "1.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/86/7d/3888833e4f5ea56af4a9935066ec09a83228e533d7b8877f65889d706ee4/hupper-1.12.1-py3-none-any.whl"}}, {"metadata": {"name": "translationstring", "version": "1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3b/98/36187601a15e3d37e9bfcf0e0e1055532b39d044353b06861c3a519737a9/translationstring-1.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "venusian", "version": "3.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5a/4b/34d926eba40db81b204066a60b4efdc5d8867a8efcbfe44d69b634b1c907/venusian-3.1.1-py3-none-any.whl"}}, {"metadata": {"name": "WebOb", "version": "1.8.10"}, "download_info": {"url": "https://files.pythonhosted.org/packages/83/21/fce134877fb6fc6ad3c464e4a07ede0ee9219f705d26a981ae58ea36ca13/webob-1.8.10-py2.py3-none-any.whl"}}, {"metadata": {"name": "legacy-cgi", "version": "2.6.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8c/7e/e7394eeb49a41cc514b3eb49020223666cbf40d86f5721c2f07871e6d84a/legacy_cgi-2.6.4-py3-none-any.whl"}}, {"metadata": {"name": "zope.deprecation", "version": "6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/ed/da7f8b1c73caf989a0ff7096cc73c59e6c36f35a8f967c51104098602e2d/zope_deprecation-6.0-py3-none-any.whl"}}, {"metadata": {"name": "zope.interface", "version": "8.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f3/55/de0c3459ff717fce3342f9a29464c281fdeb0d36c3171ee88d119d5f0650/zope_interface-8.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "plaster", "version": "1.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e7/8b/3f98db1448e3b4d2d142716874a7e02f6101685fdaa0f55a8668e9ffa048/plaster-1.1.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "plaster-pastedeploy", "version": "1.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/30/2d4cf89035c22a89bf0e34dbc50fdc07c42c9bdc90fd972d495257ad2b6e/plaster_pastedeploy-1.0.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "PasteDeploy", "version": "3.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/85/30/cdddd9a88969683a59222a6d61cd6dce923977f2e9f9ffba38e1324149cd/PasteDeploy-3.1.0-py3-none-any.whl"}}], "install_targets_hash": "060f93eb8052b63b08924e439967bba6"} {"python_version": "3.14t", "dependencies": [{"metadata": {"name": "pyramid", "version": "2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1f/d4/03a8f9b60b8f2a9198c962d08fd9b657c1c0797cbbde3793babbad200845/pyramid-2.1-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "2.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/f3/22afbdb20cc4654b10c98043414a14057cd27fdba9d4ae61cea596000ba2/Werkzeug-2.0.3-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "81.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/e3/c164c88b2e5ce7b24d667b9bd83589cf4f3520d97cad01534cd3c4f55fdb/setuptools-81.0.0-py3-none-any.whl"}}, {"metadata": {"name": "hupper", "version": "1.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/86/7d/3888833e4f5ea56af4a9935066ec09a83228e533d7b8877f65889d706ee4/hupper-1.12.1-py3-none-any.whl"}}, {"metadata": {"name": "translationstring", "version": "1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3b/98/36187601a15e3d37e9bfcf0e0e1055532b39d044353b06861c3a519737a9/translationstring-1.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "venusian", "version": "3.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5a/4b/34d926eba40db81b204066a60b4efdc5d8867a8efcbfe44d69b634b1c907/venusian-3.1.1-py3-none-any.whl"}}, {"metadata": {"name": "WebOb", "version": "1.8.10"}, "download_info": {"url": "https://files.pythonhosted.org/packages/83/21/fce134877fb6fc6ad3c464e4a07ede0ee9219f705d26a981ae58ea36ca13/webob-1.8.10-py2.py3-none-any.whl"}}, {"metadata": {"name": "legacy-cgi", "version": "2.6.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8c/7e/e7394eeb49a41cc514b3eb49020223666cbf40d86f5721c2f07871e6d84a/legacy_cgi-2.6.4-py3-none-any.whl"}}, {"metadata": {"name": "zope.deprecation", "version": "6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/ed/da7f8b1c73caf989a0ff7096cc73c59e6c36f35a8f967c51104098602e2d/zope_deprecation-6.0-py3-none-any.whl"}}, {"metadata": {"name": "zope.interface", "version": "8.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f3/55/de0c3459ff717fce3342f9a29464c281fdeb0d36c3171ee88d119d5f0650/zope_interface-8.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "plaster", "version": "1.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e7/8b/3f98db1448e3b4d2d142716874a7e02f6101685fdaa0f55a8668e9ffa048/plaster-1.1.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "plaster-pastedeploy", "version": "1.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/30/2d4cf89035c22a89bf0e34dbc50fdc07c42c9bdc90fd972d495257ad2b6e/plaster_pastedeploy-1.0.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "PasteDeploy", "version": "3.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/85/30/cdddd9a88969683a59222a6d61cd6dce923977f2e9f9ffba38e1324149cd/PasteDeploy-3.1.0-py3-none-any.whl"}}], "install_targets_hash": "060f93eb8052b63b08924e439967bba6"} -{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "fastapi", "version": "0.121.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/b6/4f620d7720fc0a754c8c1b7501d73777f6ba43b57c8ab99671f4d7441eb8/fastapi-0.121.3-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"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"}}, {"metadata": {"name": "starlette", "version": "0.50.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d9/52/1064f510b141bd54025f9b55105e26d1fa970b9be67ad766380a3c9b74b0/starlette-0.50.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d4/ce/9af95f7876194bd7a14e3dfe4a4de2e0bff02666a3910d72beafd06cc297/charset_normalizer-3.4.9-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/09/c419f6f5a92e5fadde27efd190eca90f05e1261b10dbd8cbcb39cd8ea1dc/markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}], "install_targets_hash": "07dedda23092a79cd219b98e946eb134"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "pyramid", "version": "2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1f/d4/03a8f9b60b8f2a9198c962d08fd9b657c1c0797cbbde3793babbad200845/pyramid-2.1-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "2.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/f3/22afbdb20cc4654b10c98043414a14057cd27fdba9d4ae61cea596000ba2/Werkzeug-2.0.3-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "81.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/e3/c164c88b2e5ce7b24d667b9bd83589cf4f3520d97cad01534cd3c4f55fdb/setuptools-81.0.0-py3-none-any.whl"}}, {"metadata": {"name": "hupper", "version": "1.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/86/7d/3888833e4f5ea56af4a9935066ec09a83228e533d7b8877f65889d706ee4/hupper-1.12.1-py3-none-any.whl"}}, {"metadata": {"name": "translationstring", "version": "1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3b/98/36187601a15e3d37e9bfcf0e0e1055532b39d044353b06861c3a519737a9/translationstring-1.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "venusian", "version": "3.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5a/4b/34d926eba40db81b204066a60b4efdc5d8867a8efcbfe44d69b634b1c907/venusian-3.1.1-py3-none-any.whl"}}, {"metadata": {"name": "WebOb", "version": "1.8.10"}, "download_info": {"url": "https://files.pythonhosted.org/packages/83/21/fce134877fb6fc6ad3c464e4a07ede0ee9219f705d26a981ae58ea36ca13/webob-1.8.10-py2.py3-none-any.whl"}}, {"metadata": {"name": "legacy-cgi", "version": "2.6.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8c/7e/e7394eeb49a41cc514b3eb49020223666cbf40d86f5721c2f07871e6d84a/legacy_cgi-2.6.4-py3-none-any.whl"}}, {"metadata": {"name": "zope.deprecation", "version": "6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/ed/da7f8b1c73caf989a0ff7096cc73c59e6c36f35a8f967c51104098602e2d/zope_deprecation-6.0-py3-none-any.whl"}}, {"metadata": {"name": "zope.interface", "version": "8.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f3/55/de0c3459ff717fce3342f9a29464c281fdeb0d36c3171ee88d119d5f0650/zope_interface-8.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "plaster", "version": "1.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e7/8b/3f98db1448e3b4d2d142716874a7e02f6101685fdaa0f55a8668e9ffa048/plaster-1.1.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "plaster-pastedeploy", "version": "1.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/30/2d4cf89035c22a89bf0e34dbc50fdc07c42c9bdc90fd972d495257ad2b6e/plaster_pastedeploy-1.0.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "PasteDeploy", "version": "3.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/85/30/cdddd9a88969683a59222a6d61cd6dce923977f2e9f9ffba38e1324149cd/PasteDeploy-3.1.0-py3-none-any.whl"}}], "install_targets_hash": "060f93eb8052b63b08924e439967bba6"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "pyramid", "version": "2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1f/d4/03a8f9b60b8f2a9198c962d08fd9b657c1c0797cbbde3793babbad200845/pyramid-2.1-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "2.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/f3/22afbdb20cc4654b10c98043414a14057cd27fdba9d4ae61cea596000ba2/Werkzeug-2.0.3-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "81.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/e3/c164c88b2e5ce7b24d667b9bd83589cf4f3520d97cad01534cd3c4f55fdb/setuptools-81.0.0-py3-none-any.whl"}}, {"metadata": {"name": "hupper", "version": "1.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/86/7d/3888833e4f5ea56af4a9935066ec09a83228e533d7b8877f65889d706ee4/hupper-1.12.1-py3-none-any.whl"}}, {"metadata": {"name": "translationstring", "version": "1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3b/98/36187601a15e3d37e9bfcf0e0e1055532b39d044353b06861c3a519737a9/translationstring-1.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "venusian", "version": "3.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5a/4b/34d926eba40db81b204066a60b4efdc5d8867a8efcbfe44d69b634b1c907/venusian-3.1.1-py3-none-any.whl"}}, {"metadata": {"name": "WebOb", "version": "1.8.10"}, "download_info": {"url": "https://files.pythonhosted.org/packages/83/21/fce134877fb6fc6ad3c464e4a07ede0ee9219f705d26a981ae58ea36ca13/webob-1.8.10-py2.py3-none-any.whl"}}, {"metadata": {"name": "legacy-cgi", "version": "2.6.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8c/7e/e7394eeb49a41cc514b3eb49020223666cbf40d86f5721c2f07871e6d84a/legacy_cgi-2.6.4-py3-none-any.whl"}}, {"metadata": {"name": "zope.deprecation", "version": "6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/ed/da7f8b1c73caf989a0ff7096cc73c59e6c36f35a8f967c51104098602e2d/zope_deprecation-6.0-py3-none-any.whl"}}, {"metadata": {"name": "zope.interface", "version": "8.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f3/55/de0c3459ff717fce3342f9a29464c281fdeb0d36c3171ee88d119d5f0650/zope_interface-8.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "plaster", "version": "1.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e7/8b/3f98db1448e3b4d2d142716874a7e02f6101685fdaa0f55a8668e9ffa048/plaster-1.1.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "plaster-pastedeploy", "version": "1.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/30/2d4cf89035c22a89bf0e34dbc50fdc07c42c9bdc90fd972d495257ad2b6e/plaster_pastedeploy-1.0.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "PasteDeploy", "version": "3.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/85/30/cdddd9a88969683a59222a6d61cd6dce923977f2e9f9ffba38e1324149cd/PasteDeploy-3.1.0-py3-none-any.whl"}}], "install_targets_hash": "060f93eb8052b63b08924e439967bba6"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "pyramid", "version": "2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1f/d4/03a8f9b60b8f2a9198c962d08fd9b657c1c0797cbbde3793babbad200845/pyramid-2.1-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "2.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/f3/22afbdb20cc4654b10c98043414a14057cd27fdba9d4ae61cea596000ba2/Werkzeug-2.0.3-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "81.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/e3/c164c88b2e5ce7b24d667b9bd83589cf4f3520d97cad01534cd3c4f55fdb/setuptools-81.0.0-py3-none-any.whl"}}, {"metadata": {"name": "hupper", "version": "1.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/86/7d/3888833e4f5ea56af4a9935066ec09a83228e533d7b8877f65889d706ee4/hupper-1.12.1-py3-none-any.whl"}}, {"metadata": {"name": "translationstring", "version": "1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3b/98/36187601a15e3d37e9bfcf0e0e1055532b39d044353b06861c3a519737a9/translationstring-1.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "venusian", "version": "3.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5a/4b/34d926eba40db81b204066a60b4efdc5d8867a8efcbfe44d69b634b1c907/venusian-3.1.1-py3-none-any.whl"}}, {"metadata": {"name": "WebOb", "version": "1.8.10"}, "download_info": {"url": "https://files.pythonhosted.org/packages/83/21/fce134877fb6fc6ad3c464e4a07ede0ee9219f705d26a981ae58ea36ca13/webob-1.8.10-py2.py3-none-any.whl"}}, {"metadata": {"name": "legacy-cgi", "version": "2.6.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8c/7e/e7394eeb49a41cc514b3eb49020223666cbf40d86f5721c2f07871e6d84a/legacy_cgi-2.6.4-py3-none-any.whl"}}, {"metadata": {"name": "zope.deprecation", "version": "6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/ed/da7f8b1c73caf989a0ff7096cc73c59e6c36f35a8f967c51104098602e2d/zope_deprecation-6.0-py3-none-any.whl"}}, {"metadata": {"name": "zope.interface", "version": "8.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f3/55/de0c3459ff717fce3342f9a29464c281fdeb0d36c3171ee88d119d5f0650/zope_interface-8.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "plaster", "version": "1.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e7/8b/3f98db1448e3b4d2d142716874a7e02f6101685fdaa0f55a8668e9ffa048/plaster-1.1.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "plaster-pastedeploy", "version": "1.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/30/2d4cf89035c22a89bf0e34dbc50fdc07c42c9bdc90fd972d495257ad2b6e/plaster_pastedeploy-1.0.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "PasteDeploy", "version": "3.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/85/30/cdddd9a88969683a59222a6d61cd6dce923977f2e9f9ffba38e1324149cd/PasteDeploy-3.1.0-py3-none-any.whl"}}], "install_targets_hash": "060f93eb8052b63b08924e439967bba6"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "boto3", "version": "1.43.99"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/6f/37/d59247c882bc078b73cfa6f6bb247ac51bedc7637f6a8800def385dcfbba/boto3-1.43.99-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.99"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/9a/2a62da42bc8bd55d99e5b9599c112260dfe9872bedf335bdc5a10dbb653a/botocore-1.43.99-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "s3transfer", "version": "0.19.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/bc/e7/5c595c75e9f41a44f30e526eda465ea0b4eec93470e074e4a111b253f13a/s3transfer-0.19.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}], "install_targets_hash": "0757b3ed0bd295834a1bf3155319b4f9"} {"python_version": "3.14t", "dependencies": [{"metadata": {"name": "mistralai", "version": "2.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c0/ab/a565e4bec9b5496eb3b44b8799b6ad8378b2cd0be4cd5e6b7d098e8cedcc/mistralai-2.0.5-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-semantic-conventions", "version": "0.60b1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7a/5e/5958555e09635d09b75de3c4f8b9cae7335ca545d77392ffe7331534c402/opentelemetry_semantic_conventions-0.60b1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.39.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/df/d3f1ddf4bb4cb50ed9b1139cc7b1c54c34a1e7ce8fd1b9a37c0d1551a6bd/opentelemetry_api-1.39.1-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fa/5e/f8e9a1d23b9c20a551a8a02ea3637b4642e22c2626e3a13a9a29cdea99eb/importlib_metadata-8.7.1-py3-none-any.whl"}}, {"metadata": {"name": "eval_type_backport", "version": "0.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/a7/bb99bf5e6f78736ddb53480f2c3ff3702ffe2196a7c5e1661c03081d398e/eval_type_backport-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/02/bc19b47a96c2d3109760711acf22369e56bd7e405ca52f7ade164d2ead57/pydantic_core-2.46.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "zipp", "version": "4.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}], "install_targets_hash": "09f62d5b2b308b2b3cee9c7a73dc8d2c"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "cohere", "version": "6.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/9e/b4/00c2f9f8387a2e77faf8410210466c46d55dd30a0388de41c54441b148fb/cohere-6.1.0-py3-none-any.whl"}}, {"metadata": {"name": "fastavro", "version": "1.12.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/dd/8f/18f60329b627d2118a4a2b19e8741fbd807d60bf0470554e1bbfb7f1bca3/fastavro-1.12.2-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/1c/6c/c73fa9d5a85f6ab05395de61c5f6984e0a9ff40bb5ff888d46dff02526c6/charset_normalizer-3.5.1-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "tokenizers", "version": "0.23.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/18/1e/bc6587c5ab643b2e17776cace9070a2ae73549c86bffac9934a600bf3c31/tokenizers-0.23.2.tar.gz"}}, {"metadata": {"name": "huggingface_hub", "version": "1.32.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/1b/cf/d98dd561d6d0d7b7d7a64d1563f8aaaa7c235daee41c1c9bcc3da62420ed/huggingface_hub-1.32.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/bb/1e/c0ad437dd267a8e435bef594acf781bbc3874ff0b6435b4962d03ecf7cc4/hf_xet-1.6.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "types-requests", "version": "2.33.0.20260906"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/60/4c/51ec821d22a45b4162fa3f3e9e94ea4c0f8c49e82363b10955baa5438391/types_requests-2.33.0.20260906-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "filelock", "version": "4.0.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/29/33/af0635ab07fe83b1788a1dbe370ff3e226062495a998335cb18a1cac81aa/filelock-4.0.1-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.9.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/6c/c0/a98505f18594f1bce828bb159cec0fcf9860562f1a2c85913409fc8f3d9e/fsspec-2026.9.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.12.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.41.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/bb/3d/6913dde84d5be21e284439676168b28d8bbba5600d838b9dca99de0fad71/pydantic_core-2.41.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a7/03/921a3d3c75785aca9ebfbfcabfbc3a1be12e2ab5265deb026d55a5a3f83e/tqdm-4.70.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}], "install_targets_hash": "0ad658fae5aa5a77bc7d2271d7f24fcf"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "google-genai", "version": "1.75.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2d/b6/552d40e96da22921eb1fead7c14b00b5b5473a20e45959488660fab35ee2/google_genai-1.75.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.58.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/59/13/477d90d09591b3938b45c4e11f4d8a51291682112cb5efcac961e815d562/google_auth-2.58.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c5/02/bc19b47a96c2d3109760711acf22369e56bd7e405ca52f7ade164d2ead57/pydantic_core-2.46.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/1c/6c/c73fa9d5a85f6ab05395de61c5f6984e0a9ff40bb5ff888d46dff02526c6/charset_normalizer-3.5.1-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0c/e8/f7dac2e980bacc92bdc26cebae4ae4d50cae5380732c50980598fc0bbae4/websockets-16.1.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/5b/f0/424cb557d99aa86ac55da5e2add02e2882e44047b6264f93ade1b975a993/cryptography-50.0.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7d/47/5ecf1023850036e674c77ec4de86182d309ae344e39e7cba984b7df5d647/cffi-2.1.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/9a/3b/6163796d69c3977d1e4287bea4a6979161cbbdd170ebb430511e8e1999ce/pyasn1-0.6.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "0bc3a5b64fc00b681ab59c895de8d0e4"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "httpx2", "version": "2.4.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/29/45/82bc57c3d9c3314f663b67cc057f1c017a6450685dde513f4f8db5cf431f/httpx2-2.4.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.4.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7c/72/4fdf2306143a92a471fad9f3655aa542d43aa9188a7c9534e82c9aecf837/httpcore2-2.4.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}], "install_targets_hash": "0c787a25e015d5fd533f80926f6fb57d"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "openai-agents", "version": "0.10.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e2/07/ad27018fb42d6f1e70f471a5ca3f6398a2159575b623edf86e1ddde66ce4/openai_agents-0.10.5-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "2.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ae/f4/561ed79fd94876160018a5e75254cfcb9b0e62d4dded9dcb20072e86d623/openai-2.44.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "griffe", "version": "1.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/83/3b1d03d36f224edded98e9affd0467630fc09d766c0e56fb1498cbb04a9b/griffe-1.15.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ac/4a/84a5ec271d09f7590b6073af5ee4abb44eab4ccace453b7e2c5ce45234ca/jiter-0.17.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "mcp", "version": "1.30.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f5/f4/e58bc33317c92a0203664daaf00bf6f41166cc0149e5d6870a03f7cd004a/mcp-1.30.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/02/bc19b47a96c2d3109760711acf22369e56bd7e405ca52f7ade164d2ead57/pydantic_core-2.46.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1c/6c/c73fa9d5a85f6ab05395de61c5f6984e0a9ff40bb5ff888d46dff02526c6/charset_normalizer-3.5.1-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "types-requests", "version": "2.33.0.20260906"}, "download_info": {"url": "https://files.pythonhosted.org/packages/60/4c/51ec821d22a45b4162fa3f3e9e94ea4c0f8c49e82363b10955baa5438391/types_requests-2.33.0.20260906-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "colorama", "version": "0.4.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/97/672cb32ce0dfea44b740cb7b4f97038463b9cf7c0ead1aacf595572851d6/pyjwt-2.14.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/f0/424cb557d99aa86ac55da5e2add02e2882e44047b6264f93ade1b975a993/cryptography-50.0.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7d/47/5ecf1023850036e674c77ec4de86182d309ae344e39e7cba984b7df5d647/cffi-2.1.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/77bcb1168b33704908295533d27f10eb811e9e3e193e8993dc99572211d3/rpds_py-2026.6.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/6a/2ba3ed4a69babf3afdddf7d8314a48d87562c0a442206bbc2a1b50d5efc0/sse_starlette-3.4.11-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/03/921a3d3c75785aca9ebfbfcabfbc3a1be12e2ab5265deb026d55a5a3f83e/tqdm-4.70.1-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.52.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/79/4a20b54ab0491485ccd8c077db2d39187c7f12b3e15485d38a7be37c81b4/uvicorn-0.52.4-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "0ce5e787d33b4cfe2c733e90e400524e"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "openai", "version": "2.54.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/a8/bb76c7356de8ad57f59d5ff993d434df0607f07f08bcc9c9a5c275e399c0/openai-2.54.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/6b/59127338b86d9fe4d99418f5a15118bea778103ee0fe9d9dd7e0af174e95/jiter-0.16.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/29/46ad8061f57bd9f8b2ea0aa82bf574e0f2aa040b0857a1582adba9957899/tiktoken-0.14.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.7.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cd/d6/0dd1a321afaab95eb7ff44aa0f637301786f1dc71c6b797b9ed236ed8890/regex-2026.7.19-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1c/6c/c73fa9d5a85f6ab05395de61c5f6984e0a9ff40bb5ff888d46dff02526c6/charset_normalizer-3.5.1-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "0e0a649708de8e981a20111ea63dbf51"} {"python_version": "3.14t", "dependencies": [{"metadata": {"name": "openai", "version": "2.54.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/a8/bb76c7356de8ad57f59d5ff993d434df0607f07f08bcc9c9a5c275e399c0/openai-2.54.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/6b/59127338b86d9fe4d99418f5a15118bea778103ee0fe9d9dd7e0af174e95/jiter-0.16.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/29/46ad8061f57bd9f8b2ea0aa82bf574e0f2aa040b0857a1582adba9957899/tiktoken-0.14.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.7.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cd/d6/0dd1a321afaab95eb7ff44aa0f637301786f1dc71c6b797b9ed236ed8890/regex-2026.7.19-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1c/6c/c73fa9d5a85f6ab05395de61c5f6984e0a9ff40bb5ff888d46dff02526c6/charset_normalizer-3.5.1-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "0e0a649708de8e981a20111ea63dbf51"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "langgraph", "version": "0.6.11"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/df/94/430f0341c5c2fe3e3b9f5ab2622f35e2bda12c4a7d655c519468e853d1b0/langgraph-0.6.11-py3-none-any.whl"}}, {"metadata": {"name": "langgraph-checkpoint", "version": "3.0.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/48/e3/616e3a7ff737d98c1bbb5700dd62278914e2a9ded09a79a1fa93cf24ce12/langgraph_checkpoint-3.0.1-py3-none-any.whl"}}, {"metadata": {"name": "langgraph-prebuilt", "version": "0.6.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/8e/d1/e4727f4822943befc3b7046f79049b1086c9493a34b4d44a1adf78577693/langgraph_prebuilt-0.6.5-py3-none-any.whl"}}, {"metadata": {"name": "langgraph-sdk", "version": "0.2.15"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/6b/c9/bf2bff18f85bb7973fa5280838580049574bd7649c36e3dd346c49304997/langgraph_sdk-0.2.15-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "langchain-core", "version": "1.6.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e6/18/cf18cfec118b02e003f35300b54d6a1173dc6e4905cffdf5ea49e390a7f9/langchain_core-1.6.3-py3-none-any.whl"}}, {"metadata": {"name": "jsonpatch", "version": "1.33"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/73/07/02e16ed01e04a374e644b575638ec7987ae846d25ad97bcc9945a3ee4b0e/jsonpatch-1.33-py2.py3-none-any.whl"}}, {"metadata": {"name": "langsmith", "version": "0.13.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/12/51/892ff5a2efc8e222ca114dd0e19b56978f78a5ee62d3b33783588dd8e6d4/langsmith-0.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c5/02/bc19b47a96c2d3109760711acf22369e56bd7e405ca52f7ade164d2ead57/pydantic_core-2.46.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "uuid_utils", "version": "0.17.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cd/3f/095e8eed10949c6ca1adde77d405268e88eeaf6e23a3968b29e549d0765e/uuid_utils-0.17.1-cp314-cp314t-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "jsonpointer", "version": "3.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/9e/6a/a83720e953b1682d2d109d3c2dbb0bc9bf28cc1cbc205be4ef4be5da709d/jsonpointer-3.1.1-py3-none-any.whl"}}, {"metadata": {"name": "langchain-protocol", "version": "0.0.19"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/80/c9/f6cbf357d48ccbd18bb394433b1fd7ad9be004eed9377ad08bb85777e5e6/langchain_protocol-0.0.19-py3-none-any.whl"}}, {"metadata": {"name": "orjson", "version": "3.12.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0f/f3/742fb1f62b825f2c010697eaf4e828004bc2a81e7e806666989c132c7c42/orjson-3.12.0.tar.gz"}}, {"metadata": {"name": "ormsgpack", "version": "1.12.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/c2/6feb972dc87285ad381749d3882d8aecbde9f6ecf908dd717d33d66df095/ormsgpack-1.12.2-cp314-cp314t-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/1c/6c/c73fa9d5a85f6ab05395de61c5f6984e0a9ff40bb5ff888d46dff02526c6/charset_normalizer-3.5.1-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "urllib3", "version": "2.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "17.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/6e/4587e8406d7c1188e97b9cf466c081e93399380d447f885bfce81626cd37/websockets-17.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "xxhash", "version": "4.0.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c5/8e/e18998ec465fb977bc74272e5bf3c2e886c13b014cbef916cd607802c709/xxhash-4.0.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "zstandard", "version": "0.25.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/fd/aa/3e0508d5a5dd96529cdc5a97011299056e14c6505b678fd58938792794b1/zstandard-0.25.0.tar.gz"}}], "install_targets_hash": "0ee3a52436b4f61e9cdbe5013bf352c3"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "openfeature_sdk", "version": "0.7.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/9b/20/cb043f54b11505d993e4dd84652cfc44c1260dc94b7f41aa35489af58277/openfeature_sdk-0.7.5-py3-none-any.whl"}}], "install_targets_hash": "1014994e190575f0710da79951d7f561"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "mcp", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/af/8644cc5fa26a59afd2df2e98eeb19e72926887fa4b7441aba4ff661140db/mcp-2.1.1-py3-none-any.whl"}}, {"metadata": {"name": "mcp-types", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/d0/242e63c510f4a17381f55b1549a3f94f5687a0595984febd2b6f87a687a0/mcp_types-2.1.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/6f/a04e900f465ff3221ccc395522503e2d10e79fa21f2723c8e177aae1e0d1/opentelemetry_api-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/02/bc19b47a96c2d3109760711acf22369e56bd7e405ca52f7ade164d2ead57/pydantic_core-2.46.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/97/672cb32ce0dfea44b740cb7b4f97038463b9cf7c0ead1aacf595572851d6/pyjwt-2.14.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/f0/424cb557d99aa86ac55da5e2add02e2882e44047b6264f93ade1b975a993/cryptography-50.0.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7d/47/5ecf1023850036e674c77ec4de86182d309ae344e39e7cba984b7df5d647/cffi-2.1.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/77bcb1168b33704908295533d27f10eb811e9e3e193e8993dc99572211d3/rpds_py-2026.6.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/6a/2ba3ed4a69babf3afdddf7d8314a48d87562c0a442206bbc2a1b50d5efc0/sse_starlette-3.4.11-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.53.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/76/18/0eea75741ee812e9f598b687619ce2454f6c3a1c5cd21ea990ec6bd26f45/uvicorn-0.53.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "10c02ebb2702bce4298a06292dd7286d"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "cohere", "version": "5.21.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0a/50/5538f02ec6d10fbb84f29c1b18c68ff2a03d7877926a80275efdf8755a9f/cohere-5.21.1-py3-none-any.whl"}}, {"metadata": {"name": "fastavro", "version": "1.12.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/dd/8f/18f60329b627d2118a4a2b19e8741fbd807d60bf0470554e1bbfb7f1bca3/fastavro-1.12.2-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/1c/6c/c73fa9d5a85f6ab05395de61c5f6984e0a9ff40bb5ff888d46dff02526c6/charset_normalizer-3.5.1-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "tokenizers", "version": "0.23.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/18/1e/bc6587c5ab643b2e17776cace9070a2ae73549c86bffac9934a600bf3c31/tokenizers-0.23.2.tar.gz"}}, {"metadata": {"name": "huggingface_hub", "version": "1.32.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/1b/cf/d98dd561d6d0d7b7d7a64d1563f8aaaa7c235daee41c1c9bcc3da62420ed/huggingface_hub-1.32.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/bb/1e/c0ad437dd267a8e435bef594acf781bbc3874ff0b6435b4962d03ecf7cc4/hf_xet-1.6.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "types-requests", "version": "2.33.0.20260906"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/60/4c/51ec821d22a45b4162fa3f3e9e94ea4c0f8c49e82363b10955baa5438391/types_requests-2.33.0.20260906-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "filelock", "version": "4.0.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/29/33/af0635ab07fe83b1788a1dbe370ff3e226062495a998335cb18a1cac81aa/filelock-4.0.1-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.9.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/6c/c0/a98505f18594f1bce828bb159cec0fcf9860562f1a2c85913409fc8f3d9e/fsspec-2026.9.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c5/02/bc19b47a96c2d3109760711acf22369e56bd7e405ca52f7ade164d2ead57/pydantic_core-2.46.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a7/03/921a3d3c75785aca9ebfbfcabfbc3a1be12e2ab5265deb026d55a5a3f83e/tqdm-4.70.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}], "install_targets_hash": "1119e874aeb67089151365fd5430145a"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "openfeature-sdk", "version": "0.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/44/8a4f5225e930ff0d999fd43f5d743a4babeb6c7e76dddc00f0e118878ef3/openfeature_sdk-0.10.0-py3-none-any.whl"}}], "install_targets_hash": "113a6c8b15a3b8283663d37f7b69e71e"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "openfeature-sdk", "version": "0.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/44/8a4f5225e930ff0d999fd43f5d743a4babeb6c7e76dddc00f0e118878ef3/openfeature_sdk-0.10.0-py3-none-any.whl"}}], "install_targets_hash": "113a6c8b15a3b8283663d37f7b69e71e"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "openfeature-sdk", "version": "0.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/44/8a4f5225e930ff0d999fd43f5d743a4babeb6c7e76dddc00f0e118878ef3/openfeature_sdk-0.10.0-py3-none-any.whl"}}], "install_targets_hash": "113a6c8b15a3b8283663d37f7b69e71e"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "openfeature-sdk", "version": "0.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/44/8a4f5225e930ff0d999fd43f5d743a4babeb6c7e76dddc00f0e118878ef3/openfeature_sdk-0.10.0-py3-none-any.whl"}}], "install_targets_hash": "113a6c8b15a3b8283663d37f7b69e71e"} {"python_version": "3.14t", "dependencies": [{"metadata": {"name": "openfeature-sdk", "version": "0.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/44/8a4f5225e930ff0d999fd43f5d743a4babeb6c7e76dddc00f0e118878ef3/openfeature_sdk-0.10.0-py3-none-any.whl"}}], "install_targets_hash": "113a6c8b15a3b8283663d37f7b69e71e"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "openfeature-sdk", "version": "0.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/44/8a4f5225e930ff0d999fd43f5d743a4babeb6c7e76dddc00f0e118878ef3/openfeature_sdk-0.10.0-py3-none-any.whl"}}], "install_targets_hash": "113a6c8b15a3b8283663d37f7b69e71e"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "openfeature-sdk", "version": "0.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/44/8a4f5225e930ff0d999fd43f5d743a4babeb6c7e76dddc00f0e118878ef3/openfeature_sdk-0.10.0-py3-none-any.whl"}}], "install_targets_hash": "113a6c8b15a3b8283663d37f7b69e71e"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "openfeature-sdk", "version": "0.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/44/8a4f5225e930ff0d999fd43f5d743a4babeb6c7e76dddc00f0e118878ef3/openfeature_sdk-0.10.0-py3-none-any.whl"}}], "install_targets_hash": "113a6c8b15a3b8283663d37f7b69e71e"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "openfeature-sdk", "version": "0.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/44/8a4f5225e930ff0d999fd43f5d743a4babeb6c7e76dddc00f0e118878ef3/openfeature_sdk-0.10.0-py3-none-any.whl"}}], "install_targets_hash": "113a6c8b15a3b8283663d37f7b69e71e"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "fastapi", "version": "0.123.10"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/f0/7cb92c4a720def85240fd63fbbcf147ce19e7a731c8e1032376bb5a486ac/fastapi-0.123.10-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "starlette", "version": "0.50.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d9/52/1064f510b141bd54025f9b55105e26d1fa970b9be67ad766380a3c9b74b0/starlette-0.50.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/5e/17398df3a139985ba9d11ed072531986f408c8fca952835ef1ab1820c02b/charset_normalizer-3.4.9-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}], "install_targets_hash": "11d8ddfacb08ef9d446aa4936e0d4ecd"} {"python_version": "3.14t", "dependencies": [{"metadata": {"name": "mistralai", "version": "2.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e3/d5/6b9c08ab9b5b890970e8949bf00a9f8f82653826de5cc5ad506fe1c1fb73/mistralai-2.6.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-semantic-conventions", "version": "0.60b1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7a/5e/5958555e09635d09b75de3c4f8b9cae7335ca545d77392ffe7331534c402/opentelemetry_semantic_conventions-0.60b1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.39.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/df/d3f1ddf4bb4cb50ed9b1139cc7b1c54c34a1e7ce8fd1b9a37c0d1551a6bd/opentelemetry_api-1.39.1-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fa/5e/f8e9a1d23b9c20a551a8a02ea3637b4642e22c2626e3a13a9a29cdea99eb/importlib_metadata-8.7.1-py3-none-any.whl"}}, {"metadata": {"name": "eval_type_backport", "version": "0.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/a7/bb99bf5e6f78736ddb53480f2c3ff3702ffe2196a7c5e1661c03081d398e/eval_type_backport-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonpath-python", "version": "1.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/8a/1270a6803bd821cbfcdda387eaa13cb41a7b1f7b9bd145979b3bfb9d6cb7/jsonpath_python-1.1.6-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/02/bc19b47a96c2d3109760711acf22369e56bd7e405ca52f7ade164d2ead57/pydantic_core-2.46.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "zipp", "version": "4.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}], "install_targets_hash": "18668385af67bc3f77e3be8664774dca"} {"python_version": "3.14t", "dependencies": [{"metadata": {"name": "redis", "version": "7.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4a/2e/2677f3f93dae0497e7e33b6637302e7f3744efc553f34231183e32584885/redis-7.4.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "7.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ff/f6e8b8f39e08547faece4bd80f89d5a8de68a38b2d179cc1c4490ffa3286/pytest-7.4.4-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/76/e2/964e6ef372770dd7c32f9738b50ff4924f1d3cccd665b568680e4bcb0167/fakeredis-2.37.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.23.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ee/82/62e2d63639ecb0fbe8a7ee59ef0bc69a4669ec50f6d3459f74ad4e4189a2/pytest_asyncio-0.23.8-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}], "install_targets_hash": "186c82b63ae560049b87efb5870e7d53"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "redis", "version": "7.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4a/2e/2677f3f93dae0497e7e33b6637302e7f3744efc553f34231183e32584885/redis-7.4.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "7.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ff/f6e8b8f39e08547faece4bd80f89d5a8de68a38b2d179cc1c4490ffa3286/pytest-7.4.4-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/76/e2/964e6ef372770dd7c32f9738b50ff4924f1d3cccd665b568680e4bcb0167/fakeredis-2.37.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.23.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ee/82/62e2d63639ecb0fbe8a7ee59ef0bc69a4669ec50f6d3459f74ad4e4189a2/pytest_asyncio-0.23.8-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}], "install_targets_hash": "186c82b63ae560049b87efb5870e7d53"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "redis", "version": "7.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4a/2e/2677f3f93dae0497e7e33b6637302e7f3744efc553f34231183e32584885/redis-7.4.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "7.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ff/f6e8b8f39e08547faece4bd80f89d5a8de68a38b2d179cc1c4490ffa3286/pytest-7.4.4-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/76/e2/964e6ef372770dd7c32f9738b50ff4924f1d3cccd665b568680e4bcb0167/fakeredis-2.37.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.23.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ee/82/62e2d63639ecb0fbe8a7ee59ef0bc69a4669ec50f6d3459f74ad4e4189a2/pytest_asyncio-0.23.8-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}], "install_targets_hash": "186c82b63ae560049b87efb5870e7d53"} {"python_version": "3.14t", "dependencies": [{"metadata": {"name": "anthropic", "version": "0.125.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2f/1a/b1bd30cda3790557e8791bec5922a6ec8fabb6fa8b008c76a39cf7be6152/anthropic-0.125.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/6b/59127338b86d9fe4d99418f5a15118bea778103ee0fe9d9dd7e0af174e95/jiter-0.16.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}], "install_targets_hash": "1c358b0efef217a40b276bd14601c7b4"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "anthropic", "version": "0.125.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2f/1a/b1bd30cda3790557e8791bec5922a6ec8fabb6fa8b008c76a39cf7be6152/anthropic-0.125.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/6b/59127338b86d9fe4d99418f5a15118bea778103ee0fe9d9dd7e0af174e95/jiter-0.16.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}], "install_targets_hash": "1c358b0efef217a40b276bd14601c7b4"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}], "install_targets_hash": "1e45025f67a3d865a4071044e1969927"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "fastapi", "version": "0.141.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/03/10388a42375ee7e4ac9b94eb2c5c569c8b5795e377e701c9ac3ad63de890/fastapi-0.141.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/5e/17398df3a139985ba9d11ed072531986f408c8fca952835ef1ab1820c02b/charset_normalizer-3.4.9-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}], "install_targets_hash": "20b998148dda6aa7b3fb3474012892c8"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "fastapi", "version": "0.141.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/03/10388a42375ee7e4ac9b94eb2c5c569c8b5795e377e701c9ac3ad63de890/fastapi-0.141.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/5e/17398df3a139985ba9d11ed072531986f408c8fca952835ef1ab1820c02b/charset_normalizer-3.4.9-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}], "install_targets_hash": "20b998148dda6aa7b3fb3474012892c8"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "fastapi", "version": "0.141.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/03/10388a42375ee7e4ac9b94eb2c5c569c8b5795e377e701c9ac3ad63de890/fastapi-0.141.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/5e/17398df3a139985ba9d11ed072531986f408c8fca952835ef1ab1820c02b/charset_normalizer-3.4.9-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}], "install_targets_hash": "20b998148dda6aa7b3fb3474012892c8"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "fastapi", "version": "0.141.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/03/10388a42375ee7e4ac9b94eb2c5c569c8b5795e377e701c9ac3ad63de890/fastapi-0.141.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/5e/17398df3a139985ba9d11ed072531986f408c8fca952835ef1ab1820c02b/charset_normalizer-3.4.9-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}], "install_targets_hash": "20b998148dda6aa7b3fb3474012892c8"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "fastapi", "version": "0.141.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/03/10388a42375ee7e4ac9b94eb2c5c569c8b5795e377e701c9ac3ad63de890/fastapi-0.141.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/5e/17398df3a139985ba9d11ed072531986f408c8fca952835ef1ab1820c02b/charset_normalizer-3.4.9-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}], "install_targets_hash": "20b998148dda6aa7b3fb3474012892c8"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "fastapi", "version": "0.141.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/03/10388a42375ee7e4ac9b94eb2c5c569c8b5795e377e701c9ac3ad63de890/fastapi-0.141.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d4/ce/9af95f7876194bd7a14e3dfe4a4de2e0bff02666a3910d72beafd06cc297/charset_normalizer-3.4.9-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/09/c419f6f5a92e5fadde27efd190eca90f05e1261b10dbd8cbcb39cd8ea1dc/markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"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"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}], "install_targets_hash": "20b998148dda6aa7b3fb3474012892c8"} {"python_version": "3.14t", "dependencies": [{"metadata": {"name": "fastapi", "version": "0.141.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/03/10388a42375ee7e4ac9b94eb2c5c569c8b5795e377e701c9ac3ad63de890/fastapi-0.141.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d4/ce/9af95f7876194bd7a14e3dfe4a4de2e0bff02666a3910d72beafd06cc297/charset_normalizer-3.4.9-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/09/c419f6f5a92e5fadde27efd190eca90f05e1261b10dbd8cbcb39cd8ea1dc/markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"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"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}], "install_targets_hash": "20b998148dda6aa7b3fb3474012892c8"} {"python_version": "3.14t", "dependencies": [{"metadata": {"name": "httpx2", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/29/45/82bc57c3d9c3314f663b67cc057f1c017a6450685dde513f4f8db5cf431f/httpx2-2.4.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2-pytest", "version": "1.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/46/ef/e9b6fb576f1f518f68e9f9cce9776870452ae2b8cfbba53b4127701b9a55/httpx2_pytest-1.0.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/72/4fdf2306143a92a471fad9f3655aa542d43aa9188a7c9534e82c9aecf837/httpcore2-2.4.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}], "install_targets_hash": "20f77812852d7e4a68656d7028ccce45"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "httpx2", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/29/45/82bc57c3d9c3314f663b67cc057f1c017a6450685dde513f4f8db5cf431f/httpx2-2.4.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2-pytest", "version": "1.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/46/ef/e9b6fb576f1f518f68e9f9cce9776870452ae2b8cfbba53b4127701b9a55/httpx2_pytest-1.0.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/72/4fdf2306143a92a471fad9f3655aa542d43aa9188a7c9534e82c9aecf837/httpcore2-2.4.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}], "install_targets_hash": "20f77812852d7e4a68656d7028ccce45"} {"python_version": "3.14t", "dependencies": [{"metadata": {"name": "mistralai", "version": "2.3.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/83/e0/9f246d18f8fe6e815f7cae88c437c986b342d3ff568607c8e0d53f4710d0/mistralai-2.3.2-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-semantic-conventions", "version": "0.60b1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7a/5e/5958555e09635d09b75de3c4f8b9cae7335ca545d77392ffe7331534c402/opentelemetry_semantic_conventions-0.60b1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.39.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/df/d3f1ddf4bb4cb50ed9b1139cc7b1c54c34a1e7ce8fd1b9a37c0d1551a6bd/opentelemetry_api-1.39.1-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fa/5e/f8e9a1d23b9c20a551a8a02ea3637b4642e22c2626e3a13a9a29cdea99eb/importlib_metadata-8.7.1-py3-none-any.whl"}}, {"metadata": {"name": "eval_type_backport", "version": "0.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/a7/bb99bf5e6f78736ddb53480f2c3ff3702ffe2196a7c5e1661c03081d398e/eval_type_backport-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonpath-python", "version": "1.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/8a/1270a6803bd821cbfcdda387eaa13cb41a7b1f7b9bd145979b3bfb9d6cb7/jsonpath_python-1.1.6-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/02/bc19b47a96c2d3109760711acf22369e56bd7e405ca52f7ade164d2ead57/pydantic_core-2.46.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "zipp", "version": "4.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}], "install_targets_hash": "249823eb259de4caefbecfd82d608107"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}], "install_targets_hash": "2544ffc140307d915c4ba79d5aafc0dd"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "openai-agents", "version": "0.22.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/f8/56/f5d32edb2e890a5dea9824cb76d179cef47c6a5ea8269d3559d092936106/openai_agents-0.22.3-py3-none-any.whl"}}, {"metadata": {"name": "griffelib", "version": "2.3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/41/63/e876e789525063c840ccfa8857febdabd6523bcef9ce7eb979b9305ea895/griffelib-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "mcp", "version": "2.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/1b/ff/8e7eade68b8a28f7da0ed1085544341b51f9c935dbf6b95c76b7edfea6a0/mcp-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mcp-types", "version": "2.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/8f/d7/6ffba5d8cd5dd9b8a19478875c50e04945314ba5074e84d749283f27f62d/mcp_types-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "3.17.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/57/bc/5b80a0ca4069a6b5ba6c7d48ae7a4f8176b2c0bde0bebccdb867472ec6f6/openai-3.17.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.17.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ac/4a/84a5ec271d09f7590b6073af5ee4abb44eab4ccace453b7e2c5ce45234ca/jiter-0.17.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c5/02/bc19b47a96c2d3109760711acf22369e56bd7e405ca52f7ade164d2ead57/pydantic_core-2.46.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/1c/6c/c73fa9d5a85f6ab05395de61c5f6984e0a9ff40bb5ff888d46dff02526c6/charset_normalizer-3.5.1-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0c/e8/f7dac2e980bacc92bdc26cebae4ae4d50cae5380732c50980598fc0bbae4/websockets-16.1.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.44.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ca/6f/a04e900f465ff3221ccc395522503e2d10e79fa21f2723c8e177aae1e0d1/opentelemetry_api-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.14.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/9c/97/672cb32ce0dfea44b740cb7b4f97038463b9cf7c0ead1aacf595572851d6/pyjwt-2.14.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/5b/f0/424cb557d99aa86ac55da5e2add02e2882e44047b6264f93ade1b975a993/cryptography-50.0.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7d/47/5ecf1023850036e674c77ec4de86182d309ae344e39e7cba984b7df5d647/cffi-2.1.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e9/44/77bcb1168b33704908295533d27f10eb811e9e3e193e8993dc99572211d3/rpds_py-2026.6.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.11"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/98/6a/2ba3ed4a69babf3afdddf7d8314a48d87562c0a442206bbc2a1b50d5efc0/sse_starlette-3.4.11-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.53.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/76/18/0eea75741ee812e9f598b687619ce2454f6c3a1c5cd21ea990ec6bd26f45/uvicorn-0.53.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "2eaa7cd64d608e53bb289d036713dbc5"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "starlette", "version": "0.52.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/0d/13d1d239a25cbfb19e740db83143e95c772a1fe10202dda4b76792b114dd/starlette-0.52.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "30eeef4352d79f7d31c630da4104816d"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "starlette", "version": "0.52.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/0d/13d1d239a25cbfb19e740db83143e95c772a1fe10202dda4b76792b114dd/starlette-0.52.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "30eeef4352d79f7d31c630da4104816d"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "starlette", "version": "0.52.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/0d/13d1d239a25cbfb19e740db83143e95c772a1fe10202dda4b76792b114dd/starlette-0.52.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "30eeef4352d79f7d31c630da4104816d"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "starlette", "version": "0.52.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/0d/13d1d239a25cbfb19e740db83143e95c772a1fe10202dda4b76792b114dd/starlette-0.52.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "30eeef4352d79f7d31c630da4104816d"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "starlette", "version": "0.52.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/0d/13d1d239a25cbfb19e740db83143e95c772a1fe10202dda4b76792b114dd/starlette-0.52.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "30eeef4352d79f7d31c630da4104816d"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "starlette", "version": "0.52.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/0d/13d1d239a25cbfb19e740db83143e95c772a1fe10202dda4b76792b114dd/starlette-0.52.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "30eeef4352d79f7d31c630da4104816d"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "starlette", "version": "0.52.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/0d/13d1d239a25cbfb19e740db83143e95c772a1fe10202dda4b76792b114dd/starlette-0.52.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "30eeef4352d79f7d31c630da4104816d"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "starlette", "version": "0.52.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/0d/13d1d239a25cbfb19e740db83143e95c772a1fe10202dda4b76792b114dd/starlette-0.52.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "30eeef4352d79f7d31c630da4104816d"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "starlette", "version": "0.52.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/0d/13d1d239a25cbfb19e740db83143e95c772a1fe10202dda4b76792b114dd/starlette-0.52.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "30eeef4352d79f7d31c630da4104816d"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "starlette", "version": "0.52.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/0d/13d1d239a25cbfb19e740db83143e95c772a1fe10202dda4b76792b114dd/starlette-0.52.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "30eeef4352d79f7d31c630da4104816d"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "starlette", "version": "0.52.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/0d/13d1d239a25cbfb19e740db83143e95c772a1fe10202dda4b76792b114dd/starlette-0.52.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "30eeef4352d79f7d31c630da4104816d"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "starlette", "version": "0.52.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/0d/13d1d239a25cbfb19e740db83143e95c772a1fe10202dda4b76792b114dd/starlette-0.52.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "30eeef4352d79f7d31c630da4104816d"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "starlette", "version": "0.52.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/0d/13d1d239a25cbfb19e740db83143e95c772a1fe10202dda4b76792b114dd/starlette-0.52.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "30eeef4352d79f7d31c630da4104816d"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "starlette", "version": "0.52.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/0d/13d1d239a25cbfb19e740db83143e95c772a1fe10202dda4b76792b114dd/starlette-0.52.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "30eeef4352d79f7d31c630da4104816d"} {"python_version": "3.14t", "dependencies": [{"metadata": {"name": "starlette", "version": "0.52.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/0d/13d1d239a25cbfb19e740db83143e95c772a1fe10202dda4b76792b114dd/starlette-0.52.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "30eeef4352d79f7d31c630da4104816d"} {"python_version": "3.14t", "dependencies": [{"metadata": {"name": "starlette", "version": "0.52.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/0d/13d1d239a25cbfb19e740db83143e95c772a1fe10202dda4b76792b114dd/starlette-0.52.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "30eeef4352d79f7d31c630da4104816d"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "starlette", "version": "0.52.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/0d/13d1d239a25cbfb19e740db83143e95c772a1fe10202dda4b76792b114dd/starlette-0.52.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "30eeef4352d79f7d31c630da4104816d"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "starlette", "version": "0.52.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/0d/13d1d239a25cbfb19e740db83143e95c772a1fe10202dda4b76792b114dd/starlette-0.52.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "30eeef4352d79f7d31c630da4104816d"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "rq", "version": "2.12.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a4/c2/995863e88669133a058c2a6a912b62d18a64fa7baaf78eb66aaa4350b48d/rq-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.35.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/6f/27/b8b057a23f7777177e92d3a602fd866751b6b45014964548997e92e048fd/fakeredis-2.35.1-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "redis", "version": "8.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/66/9d/c5731f6e3608663d4d3656fd8d3aecee8b509c3082818f5a13eae925baea/redis-8.1.0-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "croniter", "version": "6.2.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cd/ba/d678e5bd329646ca51d3c92addbc77804e86d21f4b6b6a027218e6abb010/croniter-6.2.4-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}], "install_targets_hash": "39c8ef325254f7a619a821794c33e958"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "rq", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a4/c2/995863e88669133a058c2a6a912b62d18a64fa7baaf78eb66aaa4350b48d/rq-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.35.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6f/27/b8b057a23f7777177e92d3a602fd866751b6b45014964548997e92e048fd/fakeredis-2.35.1-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "redis", "version": "8.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/66/9d/c5731f6e3608663d4d3656fd8d3aecee8b509c3082818f5a13eae925baea/redis-8.1.0-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "croniter", "version": "6.2.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cd/ba/d678e5bd329646ca51d3c92addbc77804e86d21f4b6b6a027218e6abb010/croniter-6.2.4-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}], "install_targets_hash": "39c8ef325254f7a619a821794c33e958"} {"python_version": "3.14t", "dependencies": [{"metadata": {"name": "rq", "version": "2.12.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a4/c2/995863e88669133a058c2a6a912b62d18a64fa7baaf78eb66aaa4350b48d/rq-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.35.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/6f/27/b8b057a23f7777177e92d3a602fd866751b6b45014964548997e92e048fd/fakeredis-2.35.1-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "redis", "version": "8.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/66/9d/c5731f6e3608663d4d3656fd8d3aecee8b509c3082818f5a13eae925baea/redis-8.1.0-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "croniter", "version": "6.2.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cd/ba/d678e5bd329646ca51d3c92addbc77804e86d21f4b6b6a027218e6abb010/croniter-6.2.4-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}], "install_targets_hash": "39c8ef325254f7a619a821794c33e958"} {"python_version": "3.14t", "dependencies": [{"metadata": {"name": "rq", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a4/c2/995863e88669133a058c2a6a912b62d18a64fa7baaf78eb66aaa4350b48d/rq-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.35.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6f/27/b8b057a23f7777177e92d3a602fd866751b6b45014964548997e92e048fd/fakeredis-2.35.1-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "redis", "version": "8.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/66/9d/c5731f6e3608663d4d3656fd8d3aecee8b509c3082818f5a13eae925baea/redis-8.1.0-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "croniter", "version": "6.2.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cd/ba/d678e5bd329646ca51d3c92addbc77804e86d21f4b6b6a027218e6abb010/croniter-6.2.4-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}], "install_targets_hash": "39c8ef325254f7a619a821794c33e958"} -{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "openai", "version": "3.16.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/17/72/2b1fe3e303db76ab2ba0c2de2b57822869bcb588db82334d4ff3aea8acf2/openai-3.16.2-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/96/c1813dcca15c5a370145a448aaea7d1f83f6f0228a5f1130e79340ee385f/jiter-0.17.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/64/a4e536cb16d7f61a7fd3120b46c577fc7fa7325992f69c4f52bc786d77d8/pydantic_core-2.46.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "41aa894704882aa63f37bce872a4e2a2"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "Flask", "version": "2.3.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/fd/56/26f0be8adc2b4257df20c1c4260ddd0aa396cf8e75d90ab2f7ff99bc34f9/flask-2.3.3-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}], "install_targets_hash": "3d3346a121c9335e59917ef88d9c8e69"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "huey", "version": "3.4.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/57/31/cee585bd4d1e39947a426a6736f4e17d22b454952370fb9cf48eb3103085/huey-3.4.0-py3-none-any.whl"}}], "install_targets_hash": "40f9e0b7b0afb09fe34d19285f3f89c9"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "chalice", "version": "1.33.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/ed/c721931d966d135387ab2d5404a026ca0ae205325fbac4b8f9ac91a45186/chalice-1.33.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "81.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/e3/c164c88b2e5ce7b24d667b9bd83589cf4f3520d97cad01534cd3c4f55fdb/setuptools-81.0.0-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.40"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/8c/5f7e73fd66b28f0705bc55d7060d41ef72328b656b86ca53e75765b3ba2c/botocore-1.43.40-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "inquirer", "version": "3.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f0/fd/7c404169a3e04a908df0644893a331f253a7f221961f2b6c0cf44430ae5a/inquirer-3.4.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pip", "version": "26.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/95/6b5cb3461ea5673ba0995989746db58eb18b91b54dbf331e72f569540946/pip-26.1.2-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-chalice", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/0f/3344996a9ca6d1b301f55805bd2aa0daf9055f13317720b4567226e4cb38/pytest-chalice-0.0.5.tar.gz"}}, {"metadata": {"name": "blessed", "version": "1.46.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/8f/c10d44ba50d5d298699c3c5698ce4e89b397ec72e2139381b9964f87356c/blessed-1.46.0-py3-none-any.whl"}}, {"metadata": {"name": "jinxed", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/1d/0a6be99b69bb448448403a45a241aff0dca751832ae54f027ed940d2eb52/jinxed-2.1.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "editor", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/b8/6648cadf38b61045262bf2a534e526f04eb833275ad1fc77a2026e9f7e3a/editor-1.8.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "readchar", "version": "4.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/ca/36133653e00939922dd1416f4c56177361289172a30563fcb9552c9ccde4/readchar-4.2.2-py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl"}}, {"metadata": {"name": "runs", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/b6/049c75d399ccf6e25abea0652b85bf7e7e101e0300aa9c1d284ad7061c0b/runs-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "wheel", "version": "0.47.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/87/1b/9e33c09813d65e248f7f773119148a612516a4bea93e9c6f545f78455b7c/wheel-0.47.0-py3-none-any.whl"}}, {"metadata": {"name": "xmod", "version": "1.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/e9/c362d47ed2b1928d65d61888c1419fae8ef69417fba2067d2fd3da1d400b/xmod-1.10.0-py3-none-any.whl"}}], "install_targets_hash": "41e4a9a78e14781d2190b51041252959"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "chalice", "version": "1.33.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/ed/c721931d966d135387ab2d5404a026ca0ae205325fbac4b8f9ac91a45186/chalice-1.33.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "81.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/e3/c164c88b2e5ce7b24d667b9bd83589cf4f3520d97cad01534cd3c4f55fdb/setuptools-81.0.0-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.40"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/8c/5f7e73fd66b28f0705bc55d7060d41ef72328b656b86ca53e75765b3ba2c/botocore-1.43.40-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "inquirer", "version": "3.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f0/fd/7c404169a3e04a908df0644893a331f253a7f221961f2b6c0cf44430ae5a/inquirer-3.4.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pip", "version": "26.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/95/6b5cb3461ea5673ba0995989746db58eb18b91b54dbf331e72f569540946/pip-26.1.2-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-chalice", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/0f/3344996a9ca6d1b301f55805bd2aa0daf9055f13317720b4567226e4cb38/pytest-chalice-0.0.5.tar.gz"}}, {"metadata": {"name": "blessed", "version": "1.46.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/8f/c10d44ba50d5d298699c3c5698ce4e89b397ec72e2139381b9964f87356c/blessed-1.46.0-py3-none-any.whl"}}, {"metadata": {"name": "jinxed", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/1d/0a6be99b69bb448448403a45a241aff0dca751832ae54f027ed940d2eb52/jinxed-2.1.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "editor", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/b8/6648cadf38b61045262bf2a534e526f04eb833275ad1fc77a2026e9f7e3a/editor-1.8.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "readchar", "version": "4.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/ca/36133653e00939922dd1416f4c56177361289172a30563fcb9552c9ccde4/readchar-4.2.2-py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl"}}, {"metadata": {"name": "runs", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/b6/049c75d399ccf6e25abea0652b85bf7e7e101e0300aa9c1d284ad7061c0b/runs-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "wheel", "version": "0.47.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/87/1b/9e33c09813d65e248f7f773119148a612516a4bea93e9c6f545f78455b7c/wheel-0.47.0-py3-none-any.whl"}}, {"metadata": {"name": "xmod", "version": "1.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/e9/c362d47ed2b1928d65d61888c1419fae8ef69417fba2067d2fd3da1d400b/xmod-1.10.0-py3-none-any.whl"}}], "install_targets_hash": "41e4a9a78e14781d2190b51041252959"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "chalice", "version": "1.33.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/ed/c721931d966d135387ab2d5404a026ca0ae205325fbac4b8f9ac91a45186/chalice-1.33.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "81.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/e3/c164c88b2e5ce7b24d667b9bd83589cf4f3520d97cad01534cd3c4f55fdb/setuptools-81.0.0-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.40"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/8c/5f7e73fd66b28f0705bc55d7060d41ef72328b656b86ca53e75765b3ba2c/botocore-1.43.40-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "inquirer", "version": "3.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f0/fd/7c404169a3e04a908df0644893a331f253a7f221961f2b6c0cf44430ae5a/inquirer-3.4.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pip", "version": "26.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/95/6b5cb3461ea5673ba0995989746db58eb18b91b54dbf331e72f569540946/pip-26.1.2-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-chalice", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/0f/3344996a9ca6d1b301f55805bd2aa0daf9055f13317720b4567226e4cb38/pytest-chalice-0.0.5.tar.gz"}}, {"metadata": {"name": "blessed", "version": "1.46.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/8f/c10d44ba50d5d298699c3c5698ce4e89b397ec72e2139381b9964f87356c/blessed-1.46.0-py3-none-any.whl"}}, {"metadata": {"name": "jinxed", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/1d/0a6be99b69bb448448403a45a241aff0dca751832ae54f027ed940d2eb52/jinxed-2.1.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "editor", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/b8/6648cadf38b61045262bf2a534e526f04eb833275ad1fc77a2026e9f7e3a/editor-1.8.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "readchar", "version": "4.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/ca/36133653e00939922dd1416f4c56177361289172a30563fcb9552c9ccde4/readchar-4.2.2-py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl"}}, {"metadata": {"name": "runs", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/b6/049c75d399ccf6e25abea0652b85bf7e7e101e0300aa9c1d284ad7061c0b/runs-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "wheel", "version": "0.47.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/87/1b/9e33c09813d65e248f7f773119148a612516a4bea93e9c6f545f78455b7c/wheel-0.47.0-py3-none-any.whl"}}, {"metadata": {"name": "xmod", "version": "1.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/e9/c362d47ed2b1928d65d61888c1419fae8ef69417fba2067d2fd3da1d400b/xmod-1.10.0-py3-none-any.whl"}}], "install_targets_hash": "41e4a9a78e14781d2190b51041252959"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "chalice", "version": "1.33.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/ed/c721931d966d135387ab2d5404a026ca0ae205325fbac4b8f9ac91a45186/chalice-1.33.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "81.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/e3/c164c88b2e5ce7b24d667b9bd83589cf4f3520d97cad01534cd3c4f55fdb/setuptools-81.0.0-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.40"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/8c/5f7e73fd66b28f0705bc55d7060d41ef72328b656b86ca53e75765b3ba2c/botocore-1.43.40-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "inquirer", "version": "3.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f0/fd/7c404169a3e04a908df0644893a331f253a7f221961f2b6c0cf44430ae5a/inquirer-3.4.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pip", "version": "26.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/95/6b5cb3461ea5673ba0995989746db58eb18b91b54dbf331e72f569540946/pip-26.1.2-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-chalice", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/0f/3344996a9ca6d1b301f55805bd2aa0daf9055f13317720b4567226e4cb38/pytest-chalice-0.0.5.tar.gz"}}, {"metadata": {"name": "blessed", "version": "1.46.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/8f/c10d44ba50d5d298699c3c5698ce4e89b397ec72e2139381b9964f87356c/blessed-1.46.0-py3-none-any.whl"}}, {"metadata": {"name": "jinxed", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/1d/0a6be99b69bb448448403a45a241aff0dca751832ae54f027ed940d2eb52/jinxed-2.1.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "editor", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/b8/6648cadf38b61045262bf2a534e526f04eb833275ad1fc77a2026e9f7e3a/editor-1.8.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "readchar", "version": "4.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/ca/36133653e00939922dd1416f4c56177361289172a30563fcb9552c9ccde4/readchar-4.2.2-py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl"}}, {"metadata": {"name": "runs", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/b6/049c75d399ccf6e25abea0652b85bf7e7e101e0300aa9c1d284ad7061c0b/runs-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "wheel", "version": "0.47.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/87/1b/9e33c09813d65e248f7f773119148a612516a4bea93e9c6f545f78455b7c/wheel-0.47.0-py3-none-any.whl"}}, {"metadata": {"name": "xmod", "version": "1.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/e9/c362d47ed2b1928d65d61888c1419fae8ef69417fba2067d2fd3da1d400b/xmod-1.10.0-py3-none-any.whl"}}], "install_targets_hash": "41e4a9a78e14781d2190b51041252959"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "chalice", "version": "1.33.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/ed/c721931d966d135387ab2d5404a026ca0ae205325fbac4b8f9ac91a45186/chalice-1.33.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "81.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/e3/c164c88b2e5ce7b24d667b9bd83589cf4f3520d97cad01534cd3c4f55fdb/setuptools-81.0.0-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.40"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/8c/5f7e73fd66b28f0705bc55d7060d41ef72328b656b86ca53e75765b3ba2c/botocore-1.43.40-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "inquirer", "version": "3.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f0/fd/7c404169a3e04a908df0644893a331f253a7f221961f2b6c0cf44430ae5a/inquirer-3.4.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pip", "version": "26.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/95/6b5cb3461ea5673ba0995989746db58eb18b91b54dbf331e72f569540946/pip-26.1.2-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-chalice", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/0f/3344996a9ca6d1b301f55805bd2aa0daf9055f13317720b4567226e4cb38/pytest-chalice-0.0.5.tar.gz"}}, {"metadata": {"name": "blessed", "version": "1.46.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/8f/c10d44ba50d5d298699c3c5698ce4e89b397ec72e2139381b9964f87356c/blessed-1.46.0-py3-none-any.whl"}}, {"metadata": {"name": "jinxed", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/1d/0a6be99b69bb448448403a45a241aff0dca751832ae54f027ed940d2eb52/jinxed-2.1.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "editor", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/b8/6648cadf38b61045262bf2a534e526f04eb833275ad1fc77a2026e9f7e3a/editor-1.8.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "readchar", "version": "4.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/ca/36133653e00939922dd1416f4c56177361289172a30563fcb9552c9ccde4/readchar-4.2.2-py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl"}}, {"metadata": {"name": "runs", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/b6/049c75d399ccf6e25abea0652b85bf7e7e101e0300aa9c1d284ad7061c0b/runs-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "wheel", "version": "0.47.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/87/1b/9e33c09813d65e248f7f773119148a612516a4bea93e9c6f545f78455b7c/wheel-0.47.0-py3-none-any.whl"}}, {"metadata": {"name": "xmod", "version": "1.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/e9/c362d47ed2b1928d65d61888c1419fae8ef69417fba2067d2fd3da1d400b/xmod-1.10.0-py3-none-any.whl"}}], "install_targets_hash": "41e4a9a78e14781d2190b51041252959"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "chalice", "version": "1.33.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/ed/c721931d966d135387ab2d5404a026ca0ae205325fbac4b8f9ac91a45186/chalice-1.33.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "81.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/e3/c164c88b2e5ce7b24d667b9bd83589cf4f3520d97cad01534cd3c4f55fdb/setuptools-81.0.0-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.40"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/8c/5f7e73fd66b28f0705bc55d7060d41ef72328b656b86ca53e75765b3ba2c/botocore-1.43.40-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "inquirer", "version": "3.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f0/fd/7c404169a3e04a908df0644893a331f253a7f221961f2b6c0cf44430ae5a/inquirer-3.4.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pip", "version": "26.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/95/6b5cb3461ea5673ba0995989746db58eb18b91b54dbf331e72f569540946/pip-26.1.2-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-chalice", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/0f/3344996a9ca6d1b301f55805bd2aa0daf9055f13317720b4567226e4cb38/pytest-chalice-0.0.5.tar.gz"}}, {"metadata": {"name": "blessed", "version": "1.46.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/8f/c10d44ba50d5d298699c3c5698ce4e89b397ec72e2139381b9964f87356c/blessed-1.46.0-py3-none-any.whl"}}, {"metadata": {"name": "jinxed", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/1d/0a6be99b69bb448448403a45a241aff0dca751832ae54f027ed940d2eb52/jinxed-2.1.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "editor", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/b8/6648cadf38b61045262bf2a534e526f04eb833275ad1fc77a2026e9f7e3a/editor-1.8.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "readchar", "version": "4.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/ca/36133653e00939922dd1416f4c56177361289172a30563fcb9552c9ccde4/readchar-4.2.2-py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl"}}, {"metadata": {"name": "runs", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/b6/049c75d399ccf6e25abea0652b85bf7e7e101e0300aa9c1d284ad7061c0b/runs-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "wheel", "version": "0.47.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/87/1b/9e33c09813d65e248f7f773119148a612516a4bea93e9c6f545f78455b7c/wheel-0.47.0-py3-none-any.whl"}}, {"metadata": {"name": "xmod", "version": "1.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/e9/c362d47ed2b1928d65d61888c1419fae8ef69417fba2067d2fd3da1d400b/xmod-1.10.0-py3-none-any.whl"}}], "install_targets_hash": "41e4a9a78e14781d2190b51041252959"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "chalice", "version": "1.33.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/ed/c721931d966d135387ab2d5404a026ca0ae205325fbac4b8f9ac91a45186/chalice-1.33.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "81.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/e3/c164c88b2e5ce7b24d667b9bd83589cf4f3520d97cad01534cd3c4f55fdb/setuptools-81.0.0-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.40"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/8c/5f7e73fd66b28f0705bc55d7060d41ef72328b656b86ca53e75765b3ba2c/botocore-1.43.40-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "inquirer", "version": "3.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f0/fd/7c404169a3e04a908df0644893a331f253a7f221961f2b6c0cf44430ae5a/inquirer-3.4.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pip", "version": "26.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/95/6b5cb3461ea5673ba0995989746db58eb18b91b54dbf331e72f569540946/pip-26.1.2-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-chalice", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/0f/3344996a9ca6d1b301f55805bd2aa0daf9055f13317720b4567226e4cb38/pytest-chalice-0.0.5.tar.gz"}}, {"metadata": {"name": "blessed", "version": "1.46.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/8f/c10d44ba50d5d298699c3c5698ce4e89b397ec72e2139381b9964f87356c/blessed-1.46.0-py3-none-any.whl"}}, {"metadata": {"name": "jinxed", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/1d/0a6be99b69bb448448403a45a241aff0dca751832ae54f027ed940d2eb52/jinxed-2.1.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "editor", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/b8/6648cadf38b61045262bf2a534e526f04eb833275ad1fc77a2026e9f7e3a/editor-1.8.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "readchar", "version": "4.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/ca/36133653e00939922dd1416f4c56177361289172a30563fcb9552c9ccde4/readchar-4.2.2-py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl"}}, {"metadata": {"name": "runs", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/b6/049c75d399ccf6e25abea0652b85bf7e7e101e0300aa9c1d284ad7061c0b/runs-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "wheel", "version": "0.47.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/87/1b/9e33c09813d65e248f7f773119148a612516a4bea93e9c6f545f78455b7c/wheel-0.47.0-py3-none-any.whl"}}, {"metadata": {"name": "xmod", "version": "1.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/e9/c362d47ed2b1928d65d61888c1419fae8ef69417fba2067d2fd3da1d400b/xmod-1.10.0-py3-none-any.whl"}}], "install_targets_hash": "41e4a9a78e14781d2190b51041252959"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "chalice", "version": "1.33.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/ed/c721931d966d135387ab2d5404a026ca0ae205325fbac4b8f9ac91a45186/chalice-1.33.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "81.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/e3/c164c88b2e5ce7b24d667b9bd83589cf4f3520d97cad01534cd3c4f55fdb/setuptools-81.0.0-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.40"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/8c/5f7e73fd66b28f0705bc55d7060d41ef72328b656b86ca53e75765b3ba2c/botocore-1.43.40-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "inquirer", "version": "3.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f0/fd/7c404169a3e04a908df0644893a331f253a7f221961f2b6c0cf44430ae5a/inquirer-3.4.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pip", "version": "26.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/95/6b5cb3461ea5673ba0995989746db58eb18b91b54dbf331e72f569540946/pip-26.1.2-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-chalice", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/0f/3344996a9ca6d1b301f55805bd2aa0daf9055f13317720b4567226e4cb38/pytest-chalice-0.0.5.tar.gz"}}, {"metadata": {"name": "blessed", "version": "1.46.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/8f/c10d44ba50d5d298699c3c5698ce4e89b397ec72e2139381b9964f87356c/blessed-1.46.0-py3-none-any.whl"}}, {"metadata": {"name": "jinxed", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/1d/0a6be99b69bb448448403a45a241aff0dca751832ae54f027ed940d2eb52/jinxed-2.1.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "editor", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/b8/6648cadf38b61045262bf2a534e526f04eb833275ad1fc77a2026e9f7e3a/editor-1.8.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "readchar", "version": "4.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/ca/36133653e00939922dd1416f4c56177361289172a30563fcb9552c9ccde4/readchar-4.2.2-py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl"}}, {"metadata": {"name": "runs", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/b6/049c75d399ccf6e25abea0652b85bf7e7e101e0300aa9c1d284ad7061c0b/runs-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "wheel", "version": "0.47.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/87/1b/9e33c09813d65e248f7f773119148a612516a4bea93e9c6f545f78455b7c/wheel-0.47.0-py3-none-any.whl"}}, {"metadata": {"name": "xmod", "version": "1.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/e9/c362d47ed2b1928d65d61888c1419fae8ef69417fba2067d2fd3da1d400b/xmod-1.10.0-py3-none-any.whl"}}], "install_targets_hash": "41e4a9a78e14781d2190b51041252959"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "chalice", "version": "1.33.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/ed/c721931d966d135387ab2d5404a026ca0ae205325fbac4b8f9ac91a45186/chalice-1.33.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "81.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/e3/c164c88b2e5ce7b24d667b9bd83589cf4f3520d97cad01534cd3c4f55fdb/setuptools-81.0.0-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.40"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/8c/5f7e73fd66b28f0705bc55d7060d41ef72328b656b86ca53e75765b3ba2c/botocore-1.43.40-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "inquirer", "version": "3.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f0/fd/7c404169a3e04a908df0644893a331f253a7f221961f2b6c0cf44430ae5a/inquirer-3.4.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pip", "version": "26.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/95/6b5cb3461ea5673ba0995989746db58eb18b91b54dbf331e72f569540946/pip-26.1.2-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-chalice", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/0f/3344996a9ca6d1b301f55805bd2aa0daf9055f13317720b4567226e4cb38/pytest-chalice-0.0.5.tar.gz"}}, {"metadata": {"name": "blessed", "version": "1.46.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/8f/c10d44ba50d5d298699c3c5698ce4e89b397ec72e2139381b9964f87356c/blessed-1.46.0-py3-none-any.whl"}}, {"metadata": {"name": "jinxed", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/1d/0a6be99b69bb448448403a45a241aff0dca751832ae54f027ed940d2eb52/jinxed-2.1.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "editor", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/b8/6648cadf38b61045262bf2a534e526f04eb833275ad1fc77a2026e9f7e3a/editor-1.8.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "readchar", "version": "4.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/ca/36133653e00939922dd1416f4c56177361289172a30563fcb9552c9ccde4/readchar-4.2.2-py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl"}}, {"metadata": {"name": "runs", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/b6/049c75d399ccf6e25abea0652b85bf7e7e101e0300aa9c1d284ad7061c0b/runs-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "wheel", "version": "0.47.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/87/1b/9e33c09813d65e248f7f773119148a612516a4bea93e9c6f545f78455b7c/wheel-0.47.0-py3-none-any.whl"}}, {"metadata": {"name": "xmod", "version": "1.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/e9/c362d47ed2b1928d65d61888c1419fae8ef69417fba2067d2fd3da1d400b/xmod-1.10.0-py3-none-any.whl"}}], "install_targets_hash": "41e4a9a78e14781d2190b51041252959"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "chalice", "version": "1.33.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/ed/c721931d966d135387ab2d5404a026ca0ae205325fbac4b8f9ac91a45186/chalice-1.33.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "81.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/e3/c164c88b2e5ce7b24d667b9bd83589cf4f3520d97cad01534cd3c4f55fdb/setuptools-81.0.0-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.40"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/8c/5f7e73fd66b28f0705bc55d7060d41ef72328b656b86ca53e75765b3ba2c/botocore-1.43.40-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "inquirer", "version": "3.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f0/fd/7c404169a3e04a908df0644893a331f253a7f221961f2b6c0cf44430ae5a/inquirer-3.4.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pip", "version": "26.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/95/6b5cb3461ea5673ba0995989746db58eb18b91b54dbf331e72f569540946/pip-26.1.2-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-chalice", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/0f/3344996a9ca6d1b301f55805bd2aa0daf9055f13317720b4567226e4cb38/pytest-chalice-0.0.5.tar.gz"}}, {"metadata": {"name": "blessed", "version": "1.46.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/8f/c10d44ba50d5d298699c3c5698ce4e89b397ec72e2139381b9964f87356c/blessed-1.46.0-py3-none-any.whl"}}, {"metadata": {"name": "jinxed", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/1d/0a6be99b69bb448448403a45a241aff0dca751832ae54f027ed940d2eb52/jinxed-2.1.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "editor", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/b8/6648cadf38b61045262bf2a534e526f04eb833275ad1fc77a2026e9f7e3a/editor-1.8.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "readchar", "version": "4.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/ca/36133653e00939922dd1416f4c56177361289172a30563fcb9552c9ccde4/readchar-4.2.2-py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl"}}, {"metadata": {"name": "runs", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/b6/049c75d399ccf6e25abea0652b85bf7e7e101e0300aa9c1d284ad7061c0b/runs-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "wheel", "version": "0.47.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/87/1b/9e33c09813d65e248f7f773119148a612516a4bea93e9c6f545f78455b7c/wheel-0.47.0-py3-none-any.whl"}}, {"metadata": {"name": "xmod", "version": "1.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/e9/c362d47ed2b1928d65d61888c1419fae8ef69417fba2067d2fd3da1d400b/xmod-1.10.0-py3-none-any.whl"}}], "install_targets_hash": "41e4a9a78e14781d2190b51041252959"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "chalice", "version": "1.33.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/ed/c721931d966d135387ab2d5404a026ca0ae205325fbac4b8f9ac91a45186/chalice-1.33.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "81.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/e3/c164c88b2e5ce7b24d667b9bd83589cf4f3520d97cad01534cd3c4f55fdb/setuptools-81.0.0-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.40"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/8c/5f7e73fd66b28f0705bc55d7060d41ef72328b656b86ca53e75765b3ba2c/botocore-1.43.40-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "inquirer", "version": "3.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f0/fd/7c404169a3e04a908df0644893a331f253a7f221961f2b6c0cf44430ae5a/inquirer-3.4.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pip", "version": "26.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/95/6b5cb3461ea5673ba0995989746db58eb18b91b54dbf331e72f569540946/pip-26.1.2-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-chalice", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/0f/3344996a9ca6d1b301f55805bd2aa0daf9055f13317720b4567226e4cb38/pytest-chalice-0.0.5.tar.gz"}}, {"metadata": {"name": "blessed", "version": "1.46.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/8f/c10d44ba50d5d298699c3c5698ce4e89b397ec72e2139381b9964f87356c/blessed-1.46.0-py3-none-any.whl"}}, {"metadata": {"name": "jinxed", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/1d/0a6be99b69bb448448403a45a241aff0dca751832ae54f027ed940d2eb52/jinxed-2.1.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "editor", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/b8/6648cadf38b61045262bf2a534e526f04eb833275ad1fc77a2026e9f7e3a/editor-1.8.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "readchar", "version": "4.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/ca/36133653e00939922dd1416f4c56177361289172a30563fcb9552c9ccde4/readchar-4.2.2-py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl"}}, {"metadata": {"name": "runs", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/b6/049c75d399ccf6e25abea0652b85bf7e7e101e0300aa9c1d284ad7061c0b/runs-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "wheel", "version": "0.47.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/87/1b/9e33c09813d65e248f7f773119148a612516a4bea93e9c6f545f78455b7c/wheel-0.47.0-py3-none-any.whl"}}, {"metadata": {"name": "xmod", "version": "1.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/e9/c362d47ed2b1928d65d61888c1419fae8ef69417fba2067d2fd3da1d400b/xmod-1.10.0-py3-none-any.whl"}}], "install_targets_hash": "41e4a9a78e14781d2190b51041252959"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "chalice", "version": "1.33.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/ed/c721931d966d135387ab2d5404a026ca0ae205325fbac4b8f9ac91a45186/chalice-1.33.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "81.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/e3/c164c88b2e5ce7b24d667b9bd83589cf4f3520d97cad01534cd3c4f55fdb/setuptools-81.0.0-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.40"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/8c/5f7e73fd66b28f0705bc55d7060d41ef72328b656b86ca53e75765b3ba2c/botocore-1.43.40-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "inquirer", "version": "3.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f0/fd/7c404169a3e04a908df0644893a331f253a7f221961f2b6c0cf44430ae5a/inquirer-3.4.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pip", "version": "26.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/95/6b5cb3461ea5673ba0995989746db58eb18b91b54dbf331e72f569540946/pip-26.1.2-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-chalice", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/0f/3344996a9ca6d1b301f55805bd2aa0daf9055f13317720b4567226e4cb38/pytest-chalice-0.0.5.tar.gz"}}, {"metadata": {"name": "blessed", "version": "1.46.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/8f/c10d44ba50d5d298699c3c5698ce4e89b397ec72e2139381b9964f87356c/blessed-1.46.0-py3-none-any.whl"}}, {"metadata": {"name": "jinxed", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/1d/0a6be99b69bb448448403a45a241aff0dca751832ae54f027ed940d2eb52/jinxed-2.1.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "editor", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/b8/6648cadf38b61045262bf2a534e526f04eb833275ad1fc77a2026e9f7e3a/editor-1.8.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "readchar", "version": "4.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/ca/36133653e00939922dd1416f4c56177361289172a30563fcb9552c9ccde4/readchar-4.2.2-py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl"}}, {"metadata": {"name": "runs", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/b6/049c75d399ccf6e25abea0652b85bf7e7e101e0300aa9c1d284ad7061c0b/runs-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "wheel", "version": "0.47.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/87/1b/9e33c09813d65e248f7f773119148a612516a4bea93e9c6f545f78455b7c/wheel-0.47.0-py3-none-any.whl"}}, {"metadata": {"name": "xmod", "version": "1.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/e9/c362d47ed2b1928d65d61888c1419fae8ef69417fba2067d2fd3da1d400b/xmod-1.10.0-py3-none-any.whl"}}], "install_targets_hash": "41e4a9a78e14781d2190b51041252959"} {"python_version": "3.14t", "dependencies": [{"metadata": {"name": "chalice", "version": "1.33.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/ed/c721931d966d135387ab2d5404a026ca0ae205325fbac4b8f9ac91a45186/chalice-1.33.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "81.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/e3/c164c88b2e5ce7b24d667b9bd83589cf4f3520d97cad01534cd3c4f55fdb/setuptools-81.0.0-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.40"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/8c/5f7e73fd66b28f0705bc55d7060d41ef72328b656b86ca53e75765b3ba2c/botocore-1.43.40-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "inquirer", "version": "3.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f0/fd/7c404169a3e04a908df0644893a331f253a7f221961f2b6c0cf44430ae5a/inquirer-3.4.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pip", "version": "26.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/95/6b5cb3461ea5673ba0995989746db58eb18b91b54dbf331e72f569540946/pip-26.1.2-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-chalice", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/0f/3344996a9ca6d1b301f55805bd2aa0daf9055f13317720b4567226e4cb38/pytest-chalice-0.0.5.tar.gz"}}, {"metadata": {"name": "blessed", "version": "1.46.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/8f/c10d44ba50d5d298699c3c5698ce4e89b397ec72e2139381b9964f87356c/blessed-1.46.0-py3-none-any.whl"}}, {"metadata": {"name": "jinxed", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/1d/0a6be99b69bb448448403a45a241aff0dca751832ae54f027ed940d2eb52/jinxed-2.1.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "editor", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/b8/6648cadf38b61045262bf2a534e526f04eb833275ad1fc77a2026e9f7e3a/editor-1.8.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "readchar", "version": "4.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/ca/36133653e00939922dd1416f4c56177361289172a30563fcb9552c9ccde4/readchar-4.2.2-py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl"}}, {"metadata": {"name": "runs", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/b6/049c75d399ccf6e25abea0652b85bf7e7e101e0300aa9c1d284ad7061c0b/runs-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "wheel", "version": "0.47.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/87/1b/9e33c09813d65e248f7f773119148a612516a4bea93e9c6f545f78455b7c/wheel-0.47.0-py3-none-any.whl"}}, {"metadata": {"name": "xmod", "version": "1.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/e9/c362d47ed2b1928d65d61888c1419fae8ef69417fba2067d2fd3da1d400b/xmod-1.10.0-py3-none-any.whl"}}], "install_targets_hash": "41e4a9a78e14781d2190b51041252959"} {"python_version": "3.14t", "dependencies": [{"metadata": {"name": "chalice", "version": "1.33.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/ed/c721931d966d135387ab2d5404a026ca0ae205325fbac4b8f9ac91a45186/chalice-1.33.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "81.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/e3/c164c88b2e5ce7b24d667b9bd83589cf4f3520d97cad01534cd3c4f55fdb/setuptools-81.0.0-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.40"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/8c/5f7e73fd66b28f0705bc55d7060d41ef72328b656b86ca53e75765b3ba2c/botocore-1.43.40-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "inquirer", "version": "3.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f0/fd/7c404169a3e04a908df0644893a331f253a7f221961f2b6c0cf44430ae5a/inquirer-3.4.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pip", "version": "26.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/95/6b5cb3461ea5673ba0995989746db58eb18b91b54dbf331e72f569540946/pip-26.1.2-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-chalice", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/0f/3344996a9ca6d1b301f55805bd2aa0daf9055f13317720b4567226e4cb38/pytest-chalice-0.0.5.tar.gz"}}, {"metadata": {"name": "blessed", "version": "1.46.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/8f/c10d44ba50d5d298699c3c5698ce4e89b397ec72e2139381b9964f87356c/blessed-1.46.0-py3-none-any.whl"}}, {"metadata": {"name": "jinxed", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/1d/0a6be99b69bb448448403a45a241aff0dca751832ae54f027ed940d2eb52/jinxed-2.1.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "editor", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/b8/6648cadf38b61045262bf2a534e526f04eb833275ad1fc77a2026e9f7e3a/editor-1.8.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "readchar", "version": "4.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/ca/36133653e00939922dd1416f4c56177361289172a30563fcb9552c9ccde4/readchar-4.2.2-py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl"}}, {"metadata": {"name": "runs", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/b6/049c75d399ccf6e25abea0652b85bf7e7e101e0300aa9c1d284ad7061c0b/runs-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "wheel", "version": "0.47.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/87/1b/9e33c09813d65e248f7f773119148a612516a4bea93e9c6f545f78455b7c/wheel-0.47.0-py3-none-any.whl"}}, {"metadata": {"name": "xmod", "version": "1.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/e9/c362d47ed2b1928d65d61888c1419fae8ef69417fba2067d2fd3da1d400b/xmod-1.10.0-py3-none-any.whl"}}], "install_targets_hash": "41e4a9a78e14781d2190b51041252959"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "chalice", "version": "1.33.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/ed/c721931d966d135387ab2d5404a026ca0ae205325fbac4b8f9ac91a45186/chalice-1.33.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "81.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/e3/c164c88b2e5ce7b24d667b9bd83589cf4f3520d97cad01534cd3c4f55fdb/setuptools-81.0.0-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.40"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/8c/5f7e73fd66b28f0705bc55d7060d41ef72328b656b86ca53e75765b3ba2c/botocore-1.43.40-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "inquirer", "version": "3.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f0/fd/7c404169a3e04a908df0644893a331f253a7f221961f2b6c0cf44430ae5a/inquirer-3.4.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pip", "version": "26.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/95/6b5cb3461ea5673ba0995989746db58eb18b91b54dbf331e72f569540946/pip-26.1.2-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-chalice", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/0f/3344996a9ca6d1b301f55805bd2aa0daf9055f13317720b4567226e4cb38/pytest-chalice-0.0.5.tar.gz"}}, {"metadata": {"name": "blessed", "version": "1.46.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/8f/c10d44ba50d5d298699c3c5698ce4e89b397ec72e2139381b9964f87356c/blessed-1.46.0-py3-none-any.whl"}}, {"metadata": {"name": "jinxed", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/1d/0a6be99b69bb448448403a45a241aff0dca751832ae54f027ed940d2eb52/jinxed-2.1.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "editor", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/b8/6648cadf38b61045262bf2a534e526f04eb833275ad1fc77a2026e9f7e3a/editor-1.8.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "readchar", "version": "4.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/ca/36133653e00939922dd1416f4c56177361289172a30563fcb9552c9ccde4/readchar-4.2.2-py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl"}}, {"metadata": {"name": "runs", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/b6/049c75d399ccf6e25abea0652b85bf7e7e101e0300aa9c1d284ad7061c0b/runs-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "wheel", "version": "0.47.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/87/1b/9e33c09813d65e248f7f773119148a612516a4bea93e9c6f545f78455b7c/wheel-0.47.0-py3-none-any.whl"}}, {"metadata": {"name": "xmod", "version": "1.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/e9/c362d47ed2b1928d65d61888c1419fae8ef69417fba2067d2fd3da1d400b/xmod-1.10.0-py3-none-any.whl"}}], "install_targets_hash": "41e4a9a78e14781d2190b51041252959"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "chalice", "version": "1.33.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/ed/c721931d966d135387ab2d5404a026ca0ae205325fbac4b8f9ac91a45186/chalice-1.33.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "81.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/e3/c164c88b2e5ce7b24d667b9bd83589cf4f3520d97cad01534cd3c4f55fdb/setuptools-81.0.0-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.40"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/8c/5f7e73fd66b28f0705bc55d7060d41ef72328b656b86ca53e75765b3ba2c/botocore-1.43.40-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "inquirer", "version": "3.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f0/fd/7c404169a3e04a908df0644893a331f253a7f221961f2b6c0cf44430ae5a/inquirer-3.4.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pip", "version": "26.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/95/6b5cb3461ea5673ba0995989746db58eb18b91b54dbf331e72f569540946/pip-26.1.2-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-chalice", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/0f/3344996a9ca6d1b301f55805bd2aa0daf9055f13317720b4567226e4cb38/pytest-chalice-0.0.5.tar.gz"}}, {"metadata": {"name": "blessed", "version": "1.46.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/8f/c10d44ba50d5d298699c3c5698ce4e89b397ec72e2139381b9964f87356c/blessed-1.46.0-py3-none-any.whl"}}, {"metadata": {"name": "jinxed", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/1d/0a6be99b69bb448448403a45a241aff0dca751832ae54f027ed940d2eb52/jinxed-2.1.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "editor", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/b8/6648cadf38b61045262bf2a534e526f04eb833275ad1fc77a2026e9f7e3a/editor-1.8.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "readchar", "version": "4.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/ca/36133653e00939922dd1416f4c56177361289172a30563fcb9552c9ccde4/readchar-4.2.2-py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl"}}, {"metadata": {"name": "runs", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/b6/049c75d399ccf6e25abea0652b85bf7e7e101e0300aa9c1d284ad7061c0b/runs-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "wheel", "version": "0.47.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/87/1b/9e33c09813d65e248f7f773119148a612516a4bea93e9c6f545f78455b7c/wheel-0.47.0-py3-none-any.whl"}}, {"metadata": {"name": "xmod", "version": "1.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/e9/c362d47ed2b1928d65d61888c1419fae8ef69417fba2067d2fd3da1d400b/xmod-1.10.0-py3-none-any.whl"}}], "install_targets_hash": "41e4a9a78e14781d2190b51041252959"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "statsig", "version": "0.55.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/9d/17/de62fdea8aab8aa7c4a833378e0e39054b728dfd45ef279e975ed5ef4e86/statsig-0.55.3-py3-none-any.whl"}}, {"metadata": {"name": "grpcio", "version": "1.84.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/3f/4f/4435c0aae54657258d9cfcba78598f3d9e5fe4c82ff18d78558567b90faf/grpcio-1.84.0.tar.gz"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ijson", "version": "3.5.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/fc/d0/b3beddb96eef0b20bb9902c36e4de30f145be06d7e5e1d780e1a1689d0ce/ijson-3.5.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "ip3country", "version": "0.4.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/d6/b7/48a7f1ab9eee62f1113114207df7e7e6bc29227389d554f42cc11bc98108/ip3country-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "protobuf", "version": "7.36.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e4/04/d52c7016b04b6c5108f26691f9d33ec82a9b65d041f1a9c771137693d618/protobuf-7.36.2-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/1c/6c/c73fa9d5a85f6ab05395de61c5f6984e0a9ff40bb5ff888d46dff02526c6/charset_normalizer-3.5.1-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "ua-parser", "version": "1.0.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a9/7c/6367995ff57aaa2d9e1055adbaec2519cf5a979780a83a93fdf8c6ec37be/ua_parser-1.0.2-py3-none-any.whl"}}, {"metadata": {"name": "ua-parser-builtins", "version": "202606"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/51/a3/f26edd95a2ce2ffbf559da432e5ff544e8dcda3673d1c775f71afffb18b7/ua_parser_builtins-202606-py3-none-any.whl"}}], "install_targets_hash": "41fe0380bec9843f568c986c9f32bfe6"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "redis", "version": "8.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/66/9d/c5731f6e3608663d4d3656fd8d3aecee8b509c3082818f5a13eae925baea/redis-8.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "7.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ff/f6e8b8f39e08547faece4bd80f89d5a8de68a38b2d179cc1c4490ffa3286/pytest-7.4.4-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/76/e2/964e6ef372770dd7c32f9738b50ff4924f1d3cccd665b568680e4bcb0167/fakeredis-2.37.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.23.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ee/82/62e2d63639ecb0fbe8a7ee59ef0bc69a4669ec50f6d3459f74ad4e4189a2/pytest_asyncio-0.23.8-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}], "install_targets_hash": "42549a00e196f5a73560e967c6bf368f"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "redis", "version": "8.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/66/9d/c5731f6e3608663d4d3656fd8d3aecee8b509c3082818f5a13eae925baea/redis-8.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "7.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ff/f6e8b8f39e08547faece4bd80f89d5a8de68a38b2d179cc1c4490ffa3286/pytest-7.4.4-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/76/e2/964e6ef372770dd7c32f9738b50ff4924f1d3cccd665b568680e4bcb0167/fakeredis-2.37.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.23.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ee/82/62e2d63639ecb0fbe8a7ee59ef0bc69a4669ec50f6d3459f74ad4e4189a2/pytest_asyncio-0.23.8-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}], "install_targets_hash": "42549a00e196f5a73560e967c6bf368f"} {"python_version": "3.14t", "dependencies": [{"metadata": {"name": "redis", "version": "8.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/66/9d/c5731f6e3608663d4d3656fd8d3aecee8b509c3082818f5a13eae925baea/redis-8.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "7.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ff/f6e8b8f39e08547faece4bd80f89d5a8de68a38b2d179cc1c4490ffa3286/pytest-7.4.4-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/76/e2/964e6ef372770dd7c32f9738b50ff4924f1d3cccd665b568680e4bcb0167/fakeredis-2.37.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.23.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ee/82/62e2d63639ecb0fbe8a7ee59ef0bc69a4669ec50f6d3459f74ad4e4189a2/pytest_asyncio-0.23.8-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}], "install_targets_hash": "42549a00e196f5a73560e967c6bf368f"} {"python_version": "3.14t", "dependencies": [{"metadata": {"name": "anthropic", "version": "1.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c0/dc/74995efda028421917f4caabd24db1373ee0742573a2363fff1a21191441/anthropic-1.7.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/96/c1813dcca15c5a370145a448aaea7d1f83f6f0228a5f1130e79340ee385f/jiter-0.17.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/64/a4e536cb16d7f61a7fd3120b46c577fc7fa7325992f69c4f52bc786d77d8/pydantic_core-2.46.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}], "install_targets_hash": "4727845e3afb2745d5e910cf0c6cbc97"} {"python_version": "3.14t", "dependencies": [{"metadata": {"name": "arq", "version": "0.28.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/48/32/66b616976c5058d434ca2017979bfffd784888177b16b5038abcec93954a/arq-0.28.0-py3-none-any.whl"}}, {"metadata": {"name": "redis", "version": "5.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/26/5c5fa0e83c3621db835cfc1f1d789b37e7fa99ed54423b5f519beb931aa7/redis-5.3.1-py3-none-any.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/4d/e6e40f93031adbf654d34e542bd396e9f3bc1c6209b40c920d58c9e1317a/fakeredis-2.36.2-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "hiredis", "version": "3.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9f/09/ee568562f36f481395d5cea3ab75fd9350cd77d98d55ee5f9b395f3fc358/hiredis-3.4.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}], "install_targets_hash": "4bd147206b5343b7421e83fb1f8cf3a4"} {"python_version": "3.14t", "dependencies": [{"metadata": {"name": "arq", "version": "0.28.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/48/32/66b616976c5058d434ca2017979bfffd784888177b16b5038abcec93954a/arq-0.28.0-py3-none-any.whl"}}, {"metadata": {"name": "redis", "version": "5.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/26/5c5fa0e83c3621db835cfc1f1d789b37e7fa99ed54423b5f519beb931aa7/redis-5.3.1-py3-none-any.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/4d/e6e40f93031adbf654d34e542bd396e9f3bc1c6209b40c920d58c9e1317a/fakeredis-2.36.2-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "hiredis", "version": "3.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9f/09/ee568562f36f481395d5cea3ab75fd9350cd77d98d55ee5f9b395f3fc358/hiredis-3.4.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}], "install_targets_hash": "4bd147206b5343b7421e83fb1f8cf3a4"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "arq", "version": "0.28.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/48/32/66b616976c5058d434ca2017979bfffd784888177b16b5038abcec93954a/arq-0.28.0-py3-none-any.whl"}}, {"metadata": {"name": "redis", "version": "5.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/26/5c5fa0e83c3621db835cfc1f1d789b37e7fa99ed54423b5f519beb931aa7/redis-5.3.1-py3-none-any.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/4d/e6e40f93031adbf654d34e542bd396e9f3bc1c6209b40c920d58c9e1317a/fakeredis-2.36.2-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "hiredis", "version": "3.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9f/09/ee568562f36f481395d5cea3ab75fd9350cd77d98d55ee5f9b395f3fc358/hiredis-3.4.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}], "install_targets_hash": "4bd147206b5343b7421e83fb1f8cf3a4"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "arq", "version": "0.28.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/48/32/66b616976c5058d434ca2017979bfffd784888177b16b5038abcec93954a/arq-0.28.0-py3-none-any.whl"}}, {"metadata": {"name": "redis", "version": "5.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/26/5c5fa0e83c3621db835cfc1f1d789b37e7fa99ed54423b5f519beb931aa7/redis-5.3.1-py3-none-any.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/4d/e6e40f93031adbf654d34e542bd396e9f3bc1c6209b40c920d58c9e1317a/fakeredis-2.36.2-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "hiredis", "version": "3.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9f/09/ee568562f36f481395d5cea3ab75fd9350cd77d98d55ee5f9b395f3fc358/hiredis-3.4.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}], "install_targets_hash": "4bd147206b5343b7421e83fb1f8cf3a4"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "arq", "version": "0.28.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/48/32/66b616976c5058d434ca2017979bfffd784888177b16b5038abcec93954a/arq-0.28.0-py3-none-any.whl"}}, {"metadata": {"name": "redis", "version": "5.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/26/5c5fa0e83c3621db835cfc1f1d789b37e7fa99ed54423b5f519beb931aa7/redis-5.3.1-py3-none-any.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/4d/e6e40f93031adbf654d34e542bd396e9f3bc1c6209b40c920d58c9e1317a/fakeredis-2.36.2-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "hiredis", "version": "3.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9f/09/ee568562f36f481395d5cea3ab75fd9350cd77d98d55ee5f9b395f3fc358/hiredis-3.4.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}], "install_targets_hash": "4bd147206b5343b7421e83fb1f8cf3a4"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "ariadne", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/48/e0bd1918ef56b1a570dfc1882a036286bf4b3f13e5a659a8d9e16d888c69/ariadne-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "fastapi", "version": "0.139.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/7c/8e3c6ad324ea5cb36604fc3f968554887891c316d9dfde57761611d907ad/fastapi-0.139.0-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/15/b92b4e1d88d02c6eff9733c9eea21846ab435cc4d813d84ccc5d335955df/graphql_core-3.2.11-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "4be724db1412c7b7718411b02cd97084"} {"python_version": "3.14t", "dependencies": [{"metadata": {"name": "ariadne", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/48/e0bd1918ef56b1a570dfc1882a036286bf4b3f13e5a659a8d9e16d888c69/ariadne-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "fastapi", "version": "0.139.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/7c/8e3c6ad324ea5cb36604fc3f968554887891c316d9dfde57761611d907ad/fastapi-0.139.0-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/15/b92b4e1d88d02c6eff9733c9eea21846ab435cc4d813d84ccc5d335955df/graphql_core-3.2.11-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "4be724db1412c7b7718411b02cd97084"} {"python_version": "3.14t", "dependencies": [{"metadata": {"name": "ariadne", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/48/e0bd1918ef56b1a570dfc1882a036286bf4b3f13e5a659a8d9e16d888c69/ariadne-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "fastapi", "version": "0.139.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/7c/8e3c6ad324ea5cb36604fc3f968554887891c316d9dfde57761611d907ad/fastapi-0.139.0-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/15/b92b4e1d88d02c6eff9733c9eea21846ab435cc4d813d84ccc5d335955df/graphql_core-3.2.11-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "4be724db1412c7b7718411b02cd97084"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "ariadne", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/48/e0bd1918ef56b1a570dfc1882a036286bf4b3f13e5a659a8d9e16d888c69/ariadne-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "fastapi", "version": "0.139.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/7c/8e3c6ad324ea5cb36604fc3f968554887891c316d9dfde57761611d907ad/fastapi-0.139.0-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/15/b92b4e1d88d02c6eff9733c9eea21846ab435cc4d813d84ccc5d335955df/graphql_core-3.2.11-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "4be724db1412c7b7718411b02cd97084"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "ariadne", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/48/e0bd1918ef56b1a570dfc1882a036286bf4b3f13e5a659a8d9e16d888c69/ariadne-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "fastapi", "version": "0.139.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/7c/8e3c6ad324ea5cb36604fc3f968554887891c316d9dfde57761611d907ad/fastapi-0.139.0-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/15/b92b4e1d88d02c6eff9733c9eea21846ab435cc4d813d84ccc5d335955df/graphql_core-3.2.11-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "4be724db1412c7b7718411b02cd97084"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "Django", "version": "6.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8d/ca/c1040a4fd15754ede7df15fd72fc2e123045b473b253ab5f5284e11c651e/django-6.1.1-py3-none-any.whl"}}, {"metadata": {"name": "coverage", "version": "7.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/d1/7f645fc2eccd318369a8a9948acc447bb7c1ade2911e31d3c5620544c22b/coverage-7.11.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "psycopg2-binary", "version": "2.9.13"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ed/76/7b4383014be0fcc6c1c0e24292845a14e1672cf17fca62ca0a2bd5f4563d/psycopg2_binary-2.9.13.tar.gz"}}, {"metadata": {"name": "djangorestframework", "version": "3.18.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/83/5ed615e47339d8e65f62eb1a8133f8f046492eb3a25ad40d90acb9a208b3/djangorestframework-3.18.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-django", "version": "4.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/03/850bffad2b581c440ca51c039d74504d5a422c94bda0bdb8a8ba5068d48b/pytest_django-4.14.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.7.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/18/f1/46d32fe4b9aae09fe397e768ff376d9b6bdbb4f11faaa727f163c3457b43/pytest_forked-1.7.5-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "channels", "version": "4.3.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/16/34/c32915288b7ef482377b6adc401192f98c6a99b3a145423d3b8aed807898/channels-4.3.2-py3-none-any.whl"}}, {"metadata": {"name": "asgiref", "version": "3.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c0/1b/54f4ad77cd8a584fa70746c47df988e002cf1ee1eba43364d46f87803647/asgiref-3.12.1-py3-none-any.whl"}}, {"metadata": {"name": "executing", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "daphne", "version": "4.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/0c/59e966c167880904f2e6a235c63169760dce58ba8062a7a153a6183539cc/daphne-4.2.3-py3-none-any.whl"}}, {"metadata": {"name": "autobahn", "version": "26.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/de/73/f109f563c27e048e45d135d81af19e6ca391e24905550b06bd1c9d674c57/autobahn-26.7.1.tar.gz"}}, {"metadata": {"name": "cbor2", "version": "6.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/41/3b28184154f6cbf7e47c1b7fb4a7a291c54f27a6f3a0a2f64b078c6a13e1/cbor2-6.1.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7d/47/5ecf1023850036e674c77ec4de86182d309ae344e39e7cba984b7df5d647/cffi-2.1.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/f0/424cb557d99aa86ac55da5e2add02e2882e44047b6264f93ade1b975a993/cryptography-50.0.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "hyperlink", "version": "21.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/aa/8caf6a0a3e62863cbb9dab27135660acba46903b703e224f14f447e57934/hyperlink-21.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "msgpack", "version": "1.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ae/f0/250f5985b6ee533e60d357571a808aaae03c54118294dc3db7158e27feb1/msgpack-1.2.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "sqlparse", "version": "0.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d9/50/f00935da0ec7cbf325f8dc4f772ae46fbc7b672dd62876e73f0a94adda57/sqlparse-0.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Twisted", "version": "26.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/57/bcf4e2370dd218c9aa68a9140a65d86729c73f1d529f7e94786c2766fc72/twisted-26.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "Automat", "version": "25.4.16"}, "download_info": {"url": "https://files.pythonhosted.org/packages/02/ff/1175b0b7371e46244032d43a56862d0af455823b5280a50c63d99cc50f18/automat-25.4.16-py3-none-any.whl"}}, {"metadata": {"name": "constantly", "version": "23.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b8/40/c199d095151addf69efdb4b9ca3a4f20f70e20508d6222bffb9b76f58573/constantly-23.10.4-py3-none-any.whl"}}, {"metadata": {"name": "Incremental", "version": "24.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1d/55/0f4df2a44053867ea9cbea73fc588b03c55605cd695cee0a3d86f0029cb2/incremental-24.11.0-py3-none-any.whl"}}, {"metadata": {"name": "pyOpenSSL", "version": "26.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ad/2cf6d3fa2fae5c79e1ed9960c0d42badd0f94d81dd12b50604cdc839e648/pyopenssl-26.4.0-py3-none-any.whl"}}, {"metadata": {"name": "service-identity", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/eb/2433e1af4ff903499144de4846569fb3300b816179ae99a03c2f011b666a/service_identity-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "txaio", "version": "26.6.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/91/68/075bf851e11c9ef65bd6a0426791f0d9a0c7dae0e7f6e0b16ca67334b456/txaio-26.6.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "6.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/29/33891cfee86cc13e00a1de6fa326378a637dad786078aaf56ab6336c60cf/ujson-6.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "zope.interface", "version": "8.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/c1/889dc114e9a9e8d59fec53facb71dd26345f60c504ad20fd17121af0449c/zope_interface-8.6-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "51cd9fff1aee44191ca961c35fd304e6"} {"python_version": "3.14t", "dependencies": [{"metadata": {"name": "Django", "version": "6.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8d/ca/c1040a4fd15754ede7df15fd72fc2e123045b473b253ab5f5284e11c651e/django-6.1.1-py3-none-any.whl"}}, {"metadata": {"name": "coverage", "version": "7.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6c/3f/6f5922f80dc6f2d8b2c6f974835c43f53eb4257a7797727e6ca5b7b2ec1f/coverage-7.11.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl"}}, {"metadata": {"name": "psycopg2-binary", "version": "2.9.12"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/60/a3624f79acea344c16fbef3a94d28b89a8042ddfb8f3e4ca83f538671409/psycopg2_binary-2.9.12.tar.gz"}}, {"metadata": {"name": "djangorestframework", "version": "3.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/d7/7461738e819b853275b35fd35712a85806c09a327e1fd5f8ff766bdd317e/djangorestframework-3.18.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-django", "version": "4.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/03/850bffad2b581c440ca51c039d74504d5a422c94bda0bdb8a8ba5068d48b/pytest_django-4.14.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.7.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/18/f1/46d32fe4b9aae09fe397e768ff376d9b6bdbb4f11faaa727f163c3457b43/pytest_forked-1.7.5-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "channels", "version": "4.3.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/16/34/c32915288b7ef482377b6adc401192f98c6a99b3a145423d3b8aed807898/channels-4.3.2-py3-none-any.whl"}}, {"metadata": {"name": "asgiref", "version": "3.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c0/1b/54f4ad77cd8a584fa70746c47df988e002cf1ee1eba43364d46f87803647/asgiref-3.12.1-py3-none-any.whl"}}, {"metadata": {"name": "executing", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "daphne", "version": "4.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/0c/59e966c167880904f2e6a235c63169760dce58ba8062a7a153a6183539cc/daphne-4.2.3-py3-none-any.whl"}}, {"metadata": {"name": "autobahn", "version": "26.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/de/73/f109f563c27e048e45d135d81af19e6ca391e24905550b06bd1c9d674c57/autobahn-26.7.1.tar.gz"}}, {"metadata": {"name": "cbor2", "version": "6.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/60/39/07dd0ea957c1f48673d3947f97ee36826efd4a824053dd0ec4df2f0c89d6/cbor2-6.1.4-cp314-cp314t-manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/95/eff5f0cee78d2eabc7eebffec40d3fc1876b5f3c95582e018bb4b99601f2/cffi-2.1.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1a/01/0127d11a762b31a9ee0221894f540318761783f3fdc4bc5d057698caebd5/cryptography-50.0.1-cp314-cp314t-manylinux_2_34_x86_64.whl"}}, {"metadata": {"name": "hyperlink", "version": "21.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/aa/8caf6a0a3e62863cbb9dab27135660acba46903b703e224f14f447e57934/hyperlink-21.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/09/c419f6f5a92e5fadde27efd190eca90f05e1261b10dbd8cbcb39cd8ea1dc/markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "msgpack", "version": "1.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/21/d2d81d50aaedb14147d01f22094185794db3ad8a8791b60afacba0627c89/msgpack-1.2.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "sqlparse", "version": "0.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d9/50/f00935da0ec7cbf325f8dc4f772ae46fbc7b672dd62876e73f0a94adda57/sqlparse-0.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Twisted", "version": "26.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/57/bcf4e2370dd218c9aa68a9140a65d86729c73f1d529f7e94786c2766fc72/twisted-26.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "Automat", "version": "25.4.16"}, "download_info": {"url": "https://files.pythonhosted.org/packages/02/ff/1175b0b7371e46244032d43a56862d0af455823b5280a50c63d99cc50f18/automat-25.4.16-py3-none-any.whl"}}, {"metadata": {"name": "constantly", "version": "23.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b8/40/c199d095151addf69efdb4b9ca3a4f20f70e20508d6222bffb9b76f58573/constantly-23.10.4-py3-none-any.whl"}}, {"metadata": {"name": "Incremental", "version": "24.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1d/55/0f4df2a44053867ea9cbea73fc588b03c55605cd695cee0a3d86f0029cb2/incremental-24.11.0-py3-none-any.whl"}}, {"metadata": {"name": "pyOpenSSL", "version": "26.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ad/2cf6d3fa2fae5c79e1ed9960c0d42badd0f94d81dd12b50604cdc839e648/pyopenssl-26.4.0-py3-none-any.whl"}}, {"metadata": {"name": "service-identity", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/eb/2433e1af4ff903499144de4846569fb3300b816179ae99a03c2f011b666a/service_identity-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "txaio", "version": "26.6.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/91/68/075bf851e11c9ef65bd6a0426791f0d9a0c7dae0e7f6e0b16ca67334b456/txaio-26.6.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "6.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/c9/9ab8d5ab9ca362381d0fcc8c6e6a831e96385a908792b2378db6282a374e/ujson-6.0.0-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "zope.interface", "version": "8.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a2/54/4df4bb0b1aace2298386375ab2fb752378683b558d2db713e25c40a3e96a/zope_interface-8.6-cp314-cp314t-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "51cd9fff1aee44191ca961c35fd304e6"} -{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "openai-agents", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a2/92/9cbbdd604f858056d4e4f105a1b99779128bae61b6a3681db0f035ef73b4/openai_agents-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "2.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ae/f4/561ed79fd94876160018a5e75254cfcb9b0e62d4dded9dcb20072e86d623/openai-2.44.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "griffe", "version": "1.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/83/3b1d03d36f224edded98e9affd0467630fc09d766c0e56fb1498cbb04a9b/griffe-1.15.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/6b/59127338b86d9fe4d99418f5a15118bea778103ee0fe9d9dd7e0af174e95/jiter-0.16.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "mcp", "version": "1.29.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/c8/248b201f6d753d69fd5d6506011abbb35a946d9142b2ae311a948fd0be3d/mcp-1.29.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1c/6c/c73fa9d5a85f6ab05395de61c5f6984e0a9ff40bb5ff888d46dff02526c6/charset_normalizer-3.5.1-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "types-requests", "version": "2.33.0.20260712"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/e7/010c87f559e216d83f9dc51e939633fd0d0ead3377340181ab0e223cd3b5/types_requests-2.33.0.20260712-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "colorama", "version": "0.4.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c3/fb/951032a3bf22a5697c83183fb6294a4843772947a70e616c57b3ff5f522e/cryptography-50.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7d/47/5ecf1023850036e674c77ec4de86182d309ae344e39e7cba984b7df5d647/cffi-2.1.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/77bcb1168b33704908295533d27f10eb811e9e3e193e8993dc99572211d3/rpds_py-2026.6.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/3a/764912c58293d95b6dcdf4cc255f9d10de310580ced547b082eb9d72018c/sse_starlette-3.4.8-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.52.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/79/4a20b54ab0491485ccd8c077db2d39187c7f12b3e15485d38a7be37c81b4/uvicorn-0.52.4-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "54acb8a9a6cd450523a6e79a8e22ef0c"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "Django", "version": "6.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8d/ca/c1040a4fd15754ede7df15fd72fc2e123045b473b253ab5f5284e11c651e/django-6.1.1-py3-none-any.whl"}}, {"metadata": {"name": "coverage", "version": "7.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6c/3f/6f5922f80dc6f2d8b2c6f974835c43f53eb4257a7797727e6ca5b7b2ec1f/coverage-7.11.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl"}}, {"metadata": {"name": "psycopg2-binary", "version": "2.9.12"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/60/a3624f79acea344c16fbef3a94d28b89a8042ddfb8f3e4ca83f538671409/psycopg2_binary-2.9.12.tar.gz"}}, {"metadata": {"name": "djangorestframework", "version": "3.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/d7/7461738e819b853275b35fd35712a85806c09a327e1fd5f8ff766bdd317e/djangorestframework-3.18.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-django", "version": "4.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/03/850bffad2b581c440ca51c039d74504d5a422c94bda0bdb8a8ba5068d48b/pytest_django-4.14.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.7.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/18/f1/46d32fe4b9aae09fe397e768ff376d9b6bdbb4f11faaa727f163c3457b43/pytest_forked-1.7.5-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "channels", "version": "4.3.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/16/34/c32915288b7ef482377b6adc401192f98c6a99b3a145423d3b8aed807898/channels-4.3.2-py3-none-any.whl"}}, {"metadata": {"name": "asgiref", "version": "3.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c0/1b/54f4ad77cd8a584fa70746c47df988e002cf1ee1eba43364d46f87803647/asgiref-3.12.1-py3-none-any.whl"}}, {"metadata": {"name": "executing", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "daphne", "version": "4.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/0c/59e966c167880904f2e6a235c63169760dce58ba8062a7a153a6183539cc/daphne-4.2.3-py3-none-any.whl"}}, {"metadata": {"name": "autobahn", "version": "26.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/de/73/f109f563c27e048e45d135d81af19e6ca391e24905550b06bd1c9d674c57/autobahn-26.7.1.tar.gz"}}, {"metadata": {"name": "cbor2", "version": "6.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/60/39/07dd0ea957c1f48673d3947f97ee36826efd4a824053dd0ec4df2f0c89d6/cbor2-6.1.4-cp314-cp314t-manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/95/eff5f0cee78d2eabc7eebffec40d3fc1876b5f3c95582e018bb4b99601f2/cffi-2.1.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1a/01/0127d11a762b31a9ee0221894f540318761783f3fdc4bc5d057698caebd5/cryptography-50.0.1-cp314-cp314t-manylinux_2_34_x86_64.whl"}}, {"metadata": {"name": "hyperlink", "version": "21.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/aa/8caf6a0a3e62863cbb9dab27135660acba46903b703e224f14f447e57934/hyperlink-21.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/09/c419f6f5a92e5fadde27efd190eca90f05e1261b10dbd8cbcb39cd8ea1dc/markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "msgpack", "version": "1.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/21/d2d81d50aaedb14147d01f22094185794db3ad8a8791b60afacba0627c89/msgpack-1.2.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "sqlparse", "version": "0.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d9/50/f00935da0ec7cbf325f8dc4f772ae46fbc7b672dd62876e73f0a94adda57/sqlparse-0.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Twisted", "version": "26.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/57/bcf4e2370dd218c9aa68a9140a65d86729c73f1d529f7e94786c2766fc72/twisted-26.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "Automat", "version": "25.4.16"}, "download_info": {"url": "https://files.pythonhosted.org/packages/02/ff/1175b0b7371e46244032d43a56862d0af455823b5280a50c63d99cc50f18/automat-25.4.16-py3-none-any.whl"}}, {"metadata": {"name": "constantly", "version": "23.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b8/40/c199d095151addf69efdb4b9ca3a4f20f70e20508d6222bffb9b76f58573/constantly-23.10.4-py3-none-any.whl"}}, {"metadata": {"name": "Incremental", "version": "24.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1d/55/0f4df2a44053867ea9cbea73fc588b03c55605cd695cee0a3d86f0029cb2/incremental-24.11.0-py3-none-any.whl"}}, {"metadata": {"name": "pyOpenSSL", "version": "26.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ad/2cf6d3fa2fae5c79e1ed9960c0d42badd0f94d81dd12b50604cdc839e648/pyopenssl-26.4.0-py3-none-any.whl"}}, {"metadata": {"name": "service-identity", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/eb/2433e1af4ff903499144de4846569fb3300b816179ae99a03c2f011b666a/service_identity-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "txaio", "version": "26.6.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/91/68/075bf851e11c9ef65bd6a0426791f0d9a0c7dae0e7f6e0b16ca67334b456/txaio-26.6.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "6.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/c9/9ab8d5ab9ca362381d0fcc8c6e6a831e96385a908792b2378db6282a374e/ujson-6.0.0-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "zope.interface", "version": "8.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a2/54/4df4bb0b1aace2298386375ab2fb752378683b558d2db713e25c40a3e96a/zope_interface-8.6-cp314-cp314t-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "51cd9fff1aee44191ca961c35fd304e6"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "sanic", "version": "25.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/91/5ecd9a91374a7b2831cf183357ceeb609fdfc8b390adb5cac90a261fe1f8/sanic-25.12.1-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "html5tagger", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/d7/410f7b8109958405f6fb3d104f094e2a96f9d5b2670de73a68fb1fbc391f/html5tagger-2.0.0-py3-none-any.whl"}}, {"metadata": {"name": "httptools", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/b0/312a062ae741ae3e8baa8c8bf20be81b2e67337b259ab4349bebc7b6142e/httptools-0.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-routing", "version": "23.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/e3/3425c9a8773807ac2c01d6a56c8521733f09b627e5827e733c5cd36b9ac5/sanic_routing-23.12.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "84.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/9c/c510029fc6ef33a6275cd2c5d3cecd6613dfd6aa401d57c54f1c18852ccf/setuptools-84.0.0-py3-none-any.whl"}}, {"metadata": {"name": "tracerite", "version": "2.6.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/73/510b204e9543645031656e42b3e12b70ebc692facf0293700348ee27a35b/tracerite-2.6.5-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "5.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/e4/39862f0f7174ff07cfd1e2d0c9065ded34aeebdb7db8daf2f0e5bf89b46f/ujson-5.13.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "uvloop", "version": "0.22.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/7b/b01414f31546caf0919da80ad57cbfe24c56b151d12af68cee1b04922ca8/uvloop-0.22.1-cp314-cp314t-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "websockets", "version": "17.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cd/d8/ad2b3e8f867e1e8cac3077e2f33ffb60b71bd763d6cfc71bd916f113c3bf/websockets-17.0.1-cp314-cp314t-macosx_11_0_arm64.whl"}}], "install_targets_hash": "5384c86155c4b35f2c0802fac0846529"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "gql", "version": "4.4.0b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/97/00105a44b645f2234e4540027d2ae4ea34b6a95d40e45f9f01c020d0f5b0/gql-4.4.0b0-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/d8/8ec0e471248c500acdce2be3f46db8fb62b5eb60efef072529cc85ee1d26/aiohttp-3.14.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.78"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/5b/b7c5c22767c0e8eb4bb2bd0a972d77bd0be3dd9908e15d4487094a31fa4b/botocore-1.43.78-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.3.0rc0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8c/89/efd877ac909125f050b9562afc1f4b1bc7c0a90bc2a03ed7b0cb21debca3/graphql_core-3.3.0rc0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/95/411ba65569158e862368917aaf56597f3e5fa3b91b0502919638465a08f3/httpx2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/74/d370e55600d9bcfa0d9794b0166126d49291a3d2b20c268fc98c453a4948/httpcore2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1c/6c/c73fa9d5a85f6ab05395de61c5f6984e0a9ff40bb5ff888d46dff02526c6/charset_normalizer-3.5.1-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "15.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ff/0b/cfb76b7fe99686db264bff829779a539d923e7564ffd7ef18da6c54c3774/yarl-1.24.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/73/daf935ea7048ddd7ec8eec5345b4a40b619d2d178b3c0a0900796bc3c794/propcache-0.5.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}], "install_targets_hash": "56ce6d1f6e8d22d4fccb0afa8d0c143d"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "celery", "version": "5.7.0a1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/de/bf/72703e2ac184cc9c4c641ba5abaec725cbdcf48755c7582f006005d38848/celery-5.7.0a1-py3-none-any.whl"}}, {"metadata": {"name": "billiard", "version": "4.3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/60/60/ade6d336983b82fbc330d0d0371f945249b448152852952f643787a3288d/billiard-4.3.0-py3-none-any.whl"}}, {"metadata": {"name": "click-repl", "version": "0.4.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e0/ae/63d94d251d2e1a7bf3794ea47cb1c99fe6de055b732ea79d7bcdabef8ff5/click_repl-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "newrelic", "version": "10.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/d4/71/07c41fd5e8c94e95216b000d00c3cf735f769cb406c0f33c6ff83b7b7418/newrelic-10.16.0.tar.gz"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "vine", "version": "5.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/03/ff/7c0c86c43b3cbb927e0ccc0255cb4057ceba4799cd44ae95174ce8e8b5b2/vine-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "redis", "version": "8.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/66/9d/c5731f6e3608663d4d3656fd8d3aecee8b509c3082818f5a13eae925baea/redis-8.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.7.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/18/f1/46d32fe4b9aae09fe397e768ff376d9b6bdbb4f11faaa727f163c3457b43/pytest_forked-1.7.5-py3-none-any.whl"}}, {"metadata": {"name": "click-didyoumean", "version": "0.3.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/1b/5b/974430b5ffdb7a4f1941d13d83c64a0395114503cc357c6b9ae4ce5047ed/click_didyoumean-0.3.1-py3-none-any.whl"}}, {"metadata": {"name": "click-plugins", "version": "1.1.1.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/3d/9a/2abecb28ae875e39c8cad711eb1186d8d14eab564705325e77e4e6ab9ae5/click_plugins-1.1.1.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "kombu", "version": "5.7.0a1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b6/d9/1b98be4b45c3cb6737663ea5e7847fcc8f6c21de204a0411ae12874fbfc0/kombu-5.7.0a1-py3-none-any.whl"}}, {"metadata": {"name": "amqp", "version": "5.4.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/07/99/6b965aa99a32630c1c61ce57c9dcf81cec6fec354274a87f14525302b7f7/amqp-5.4.0-py3-none-any.whl"}}, {"metadata": {"name": "prompt_toolkit", "version": "3.0.53"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/54/6f/84908cad2d6aa5144abcf7b42709fe4fdb459bc640ec7ac5786e7693dabc/prompt_toolkit-3.0.53-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "tzdata", "version": "2026.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/f9/bc/8737e8d54cf51106118039b83f485a4783112fab49ea9d044b234978a46e/tzdata-2026.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/39/cc/9c0adc5861020de426ec71716b6c1bef8d90694b7d6d0a16202cdb1647f5/wcwidth-0.8.4-py3-none-any.whl"}}, {"metadata": {"name": "tzlocal", "version": "5.4.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/9e/a4/017a7a6cbe387d961a688ec31364ae60a5c4e22c96ae9921b79a947c855d/tzlocal-5.4.4-py3-none-any.whl"}}], "install_targets_hash": "571b466b11beb803cdcf782ce81876e3"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "pydantic-ai", "version": "2.47.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/12/1a/a46dad48b18c004eb686596d360d2310fc9c928b5b9b31341c03c6c813f1/pydantic_ai-2.47.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-ai-slim", "version": "2.47.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/eb/94/5d8a27dbe4a9e27378698c31c5848310d7a7727e22e1334f683dfbe5397d/pydantic_ai_slim-2.47.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-evals", "version": "2.47.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a9/81/34504d9426f420cc3ea05eb5d3f387a17f14d5ea678b6ced18d6f4be9da4/pydantic_evals-2.47.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-graph", "version": "2.47.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/3c/b0/4630a964201fb04dba730cbe54b7941309d97d59c01537465b075c26cae7/pydantic_graph-2.47.0-py3-none-any.whl"}}, {"metadata": {"name": "fastmcp-slim", "version": "4.0.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ed/76/8dc551ef1f222bd146537ae100baf7441628aa1050494b567249ece997c2/fastmcp_slim-4.0.5-py3-none-any.whl"}}, {"metadata": {"name": "mcp", "version": "2.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/1b/ff/8e7eade68b8a28f7da0ed1085544341b51f9c935dbf6b95c76b7edfea6a0/mcp-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mcp-types", "version": "2.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/8f/d7/6ffba5d8cd5dd9b8a19478875c50e04945314ba5074e84d749283f27f62d/mcp_types-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "py-key-value-aio", "version": "0.4.6"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/9a/46/12871550fb0613d149144bb9d41f22680d5f46717bc45a76eb5798c20c3f/py_key_value_aio-0.4.6-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofile", "version": "3.12.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/4e/79/6e45e778c4c3cab39e0937b007b720c15f76c50c6453d153282d0fcc3588/aiofile-3.12.3-py3-none-any.whl"}}, {"metadata": {"name": "caio", "version": "0.12.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/d3/f4/c39ed874d420bb2719d52932d763953c28371c536d6bf264de1febeb27d5/caio-0.12.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anthropic", "version": "1.7.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c0/dc/74995efda028421917f4caabd24db1373ee0742573a2363fff1a21191441/anthropic-1.7.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.17.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ac/4a/84a5ec271d09f7590b6073af5ee4abb44eab4ccace453b7e2c5ce45234ca/jiter-0.17.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c5/02/bc19b47a96c2d3109760711acf22369e56bd7e405ca52f7ade164d2ead57/pydantic_core-2.46.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "argcomplete", "version": "3.7.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/46/bd/551ee6af426af84ca33e02622be722925c196608e9127d731ef17c47f06e/argcomplete-3.7.2-py3-none-any.whl"}}, {"metadata": {"name": "Authlib", "version": "1.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b8/c6/6f124bcfbbfb20fba22c939b4e43a06dccfc0e1ca20e5634ca573cb1e271/authlib-1.8.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "beartype", "version": "0.22.9"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/cc/18245721fa7747065ab478316c7fea7c74777d07f37ae60db2e84f8172e8/beartype-0.22.9-py3-none-any.whl"}}, {"metadata": {"name": "cachetools", "version": "7.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cc/bb/1c6e7a89b11da19f137e4ef5a5c5fe47a5bb686449ba343944ccf8fb34b2/cachetools-7.2.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/5b/f0/424cb557d99aa86ac55da5e2add02e2882e44047b6264f93ade1b975a993/cryptography-50.0.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7d/47/5ecf1023850036e674c77ec4de86182d309ae344e39e7cba984b7df5d647/cffi-2.1.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "genai-prices", "version": "0.1.7"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/d5/4a/9e04f3dca5ffe74133779ab5e9925ffb6411afbeac55d26fa0e148722599/genai_prices-0.1.7-py3-none-any.whl"}}, {"metadata": {"name": "google-genai", "version": "2.24.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/84/5b/87913fe392ba7b6402577259289ed3740c577956554a674b191a2971d33e/google_genai-2.24.0-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.58.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/59/13/477d90d09591b3938b45c4e11f4d8a51291682112cb5efcac961e815d562/google_auth-2.58.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/1c/6c/c73fa9d5a85f6ab05395de61c5f6984e0a9ff40bb5ff888d46dff02526c6/charset_normalizer-3.5.1-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0c/e8/f7dac2e980bacc92bdc26cebae4ae4d50cae5380732c50980598fc0bbae4/websockets-16.1.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "griffelib", "version": "2.3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/41/63/e876e789525063c840ccfa8857febdabd6523bcef9ce7eb979b9305ea895/griffelib-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "joserfc", "version": "1.7.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/67/c5/82addfd375e5ee6520644e0553e4aadde92d668c4fc99cc716d337fe7bb3/joserfc-1.7.5-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "keyring", "version": "25.7.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/81/db/e655086b7f3a705df045bf0933bdd9c2f79bb3c97bfef1384598bb79a217/keyring-25.7.0-py3-none-any.whl"}}, {"metadata": {"name": "logfire", "version": "5.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cd/02/b32c3d5c298e4a9010694d261fb82c2c672747c0bf2b47bffda484aef349/logfire-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-exporter-otlp-proto-http", "version": "1.44.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cd/d0/fdeb1a98d8d3a6205f5f297c51b4a9bfe65126ab60339669bbe3dd54c2e2/opentelemetry_exporter_otlp_proto_http-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-exporter-otlp-proto-common", "version": "1.44.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/5e/71/65fd9d54c10b860f87c045ccee1264cab7011268895d3528818a29c1172a/opentelemetry_exporter_otlp_proto_common-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-proto", "version": "1.44.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/d1/7c/8be563d68e93bbefa5c8affb82ddcff91b3ad858ce49957ba7b16fd3e0ab/opentelemetry_proto-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "googleapis-common-protos", "version": "1.75.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/1a/7a/7d79170c6ce6f12e109df2b3879d6b934010cf4f99aea8de8b7e5408c174/googleapis_common_protos-1.75.3-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.44.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ca/6f/a04e900f465ff3221ccc395522503e2d10e79fa21f2723c8e177aae1e0d1/opentelemetry_api-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-sdk", "version": "1.44.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e7/23/ff077e61886ee020a17ce9c8b6fa11c601c8d8345b09ea24f605445df62a/opentelemetry_sdk-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-semantic-conventions", "version": "0.65b0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a6/0e/49df70d9b81fb5cbae4bbf2a49d865b09bcbcbc4eb53f5851b1027738d78/opentelemetry_semantic_conventions-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "protobuf", "version": "7.36.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e4/04/d52c7016b04b6c5108f26691f9d33ec82a9b65d041f1a9c771137693d618/protobuf-7.36.2-py3-none-any.whl"}}, {"metadata": {"name": "executing", "version": "2.2.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "logfire-api", "version": "5.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2d/51/123dab197fb08c0892e3bea1c2266bff159aa2ee82ad43bef93505859705/logfire_api-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "3.17.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/57/bc/5b80a0ca4069a6b5ba6c7d48ae7a4f8176b2c0bde0bebccdb867472ec6f6/openai-3.17.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-instrumentation", "version": "0.65b0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/40/7b/85eab1215f72adf0e68d3dc4a679b9bff993fa679ff34cd8dd378e2659fd/opentelemetry_instrumentation-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "wrapt", "version": "2.4.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/72/26/7435de516099b528e2232770b459d6706002736f41d8f092bbb11ea01575/wrapt-2.4.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "opentelemetry-instrumentation-httpx", "version": "0.65b0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/9d/0f/c6144096b4914bbf44b43ba21c962e8f333ff045770b50a3e79ed8bd455f/opentelemetry_instrumentation_httpx-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-util-http", "version": "0.65b0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/23/3f/ab8d29df207ce5f470a07fa96ebb48af4e95b7fab7e7635311b9a32f2fab/opentelemetry_util_http-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "platformdirs", "version": "4.11.12"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ec/2b/69de6317fbf48865bb12aa56c9cfcfff46b3add0cd45250725d96146dce0/platformdirs-4.11.12-py3-none-any.whl"}}, {"metadata": {"name": "prompt_toolkit", "version": "3.0.53"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/54/6f/84908cad2d6aa5144abcf7b42709fe4fdb459bc640ec7ac5786e7693dabc/prompt_toolkit-3.0.53-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/9a/3b/6163796d69c3977d1e4287bea4a6979161cbbdd170ebb430511e8e1999ce/pyasn1-0.6.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "email-validator", "version": "2.3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "dnspython", "version": "2.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.14.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/9c/97/672cb32ce0dfea44b740cb7b4f97038463b9cf7c0ead1aacf595572851d6/pyjwt-2.14.0-py3-none-any.whl"}}, {"metadata": {"name": "pyperclip", "version": "1.11.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/df/80/fc9d01d5ed37ba4c42ca2b55b4339ae6e200b456be3a1aaddf4a9fa99b8c/pyperclip-1.11.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e9/44/77bcb1168b33704908295533d27f10eb811e9e3e193e8993dc99572211d3/rpds_py-2026.6.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.11"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/98/6a/2ba3ed4a69babf3afdddf7d8314a48d87562c0a442206bbc2a1b50d5efc0/sse_starlette-3.4.11-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/79/29/46ad8061f57bd9f8b2ea0aa82bf574e0f2aa040b0857a1582adba9957899/tiktoken-0.14.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.53.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/76/18/0eea75741ee812e9f598b687619ce2454f6c3a1c5cd21ea990ec6bd26f45/uvicorn-0.53.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/39/cc/9c0adc5861020de426ec71716b6c1bef8d90694b7d6d0a16202cdb1647f5/wcwidth-0.8.4-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.classes", "version": "3.4.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7f/66/b15ce62552d84bbfcec9a4873ab79d993a1dd4edb922cbfccae192bd5b5f/jaraco.classes-3.4.0-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.context", "version": "6.1.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/f2/58/bc8954bda5fcda97bd7c19be11b85f91973d67a706ed4a3aec33e7de22db/jaraco_context-6.1.2-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.functools", "version": "4.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/02/36/ecc85bc96c273dc8a11273ed4782272975e6338d4a3e9228621175edf0e3/jaraco_functools-4.6.0-py3-none-any.whl"}}, {"metadata": {"name": "more-itertools", "version": "11.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e8/3d/1087453384dbde46a8c7f9356eead2c58be8a7bf156bca40243377c85715/more_itertools-11.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.9.10"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2b/d1/ee7662561735f90475443c3ca1977e5cecaeaa8f29620dec75580aebc839/regex-2026.9.10-cp314-cp314t-macosx_11_0_arm64.whl"}}], "install_targets_hash": "59d07114fce5d52fca16194a659dc9bf"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "pydantic-ai", "version": "1.107.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/64/72ff998a79459c41f0e40f079a06ad45934fb2c095f604b9d44b983620b8/pydantic_ai-1.107.6-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-ai-slim", "version": "1.107.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/41/140a5e2d339e20d50e7685ffdc463977ae708f139a035fc658eced234afb/pydantic_ai_slim-1.107.6-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-evals", "version": "1.107.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/21/bc/299d19d27e237c407a77edb3f72d81a1cac0dd09964ea8cc9beac4e61f96/pydantic_evals-1.107.6-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-graph", "version": "1.107.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/2f/4f94314f952d242de53e6ae0f250d249609710ce500209f0acf46a7133a8/pydantic_graph-1.107.6-py3-none-any.whl"}}, {"metadata": {"name": "anthropic", "version": "0.125.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2f/1a/b1bd30cda3790557e8791bec5922a6ec8fabb6fa8b008c76a39cf7be6152/anthropic-0.125.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "fastmcp", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ac/14/6d950459cc831fa17fe2d1797926b6eb2d2f2af50f830e62d0c098cc1ec8/fastmcp-3.4.7-py3-none-any.whl"}}, {"metadata": {"name": "fastmcp-slim", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b4/97/e0e53642cd029a9a7635ae9c548f9f2cc995af5914e487b3df795664e4be/fastmcp_slim-3.4.7-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/bd/8d001191893178ff8e826e46ad5299446e62b93cd164e17b0ffea08832ec/hf_xet-1.4.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "huggingface_hub", "version": "1.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/03/40a05316cb6616e5b7efd7773656441ab04b4b022c2199e79bb4622a92a3/huggingface_hub-1.18.0-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/96/c1813dcca15c5a370145a448aaea7d1f83f6f0228a5f1130e79340ee385f/jiter-0.17.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "mcp", "version": "1.30.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f5/f4/e58bc33317c92a0203664daaf00bf6f41166cc0149e5d6870a03f7cd004a/mcp-1.30.0-py3-none-any.whl"}}, {"metadata": {"name": "py-key-value-aio", "version": "0.4.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/46/12871550fb0613d149144bb9d41f22680d5f46717bc45a76eb5798c20c3f/py_key_value_aio-0.4.6-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/64/a4e536cb16d7f61a7fd3120b46c577fc7fa7325992f69c4f52bc786d77d8/pydantic_core-2.46.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typer", "version": "0.25.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/f9/2b3ff4e56e5fa7debfaf9eb135d0da96f3e9a1d5b27222223c7296336e5f/typer-0.25.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ag-ui-protocol", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/b0/850be4576e6443dc575daa54188d8136ae2b2eca3f19e098e7a088fc9ebc/ag_ui_protocol-1.0.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofile", "version": "3.12.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/79/6e45e778c4c3cab39e0937b007b720c15f76c50c6453d153282d0fcc3588/aiofile-3.12.3-py3-none-any.whl"}}, {"metadata": {"name": "caio", "version": "0.12.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/25/81/6b86722be50975b80a636afebed5af1a6e6588afeff0ae1a0a7f8c262707/caio-0.12.4-cp314-cp314t-manylinux_2_34_x86_64.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "argcomplete", "version": "3.7.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/46/bd/551ee6af426af84ca33e02622be722925c196608e9127d731ef17c47f06e/argcomplete-3.7.2-py3-none-any.whl"}}, {"metadata": {"name": "Authlib", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b8/c6/6f124bcfbbfb20fba22c939b4e43a06dccfc0e1ca20e5634ca573cb1e271/authlib-1.8.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "beartype", "version": "0.22.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/cc/18245721fa7747065ab478316c7fea7c74777d07f37ae60db2e84f8172e8/beartype-0.22.9-py3-none-any.whl"}}, {"metadata": {"name": "boto3", "version": "1.43.98"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/46/d29efd46ecac6637065a39418c5fb95500d70ec63e76065b5a72c936172f/boto3-1.43.98-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.98"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/ca/c7617e99c3247f545233ab2181840d142c5f72034e22864172866fb1369a/botocore-1.43.98-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "s3transfer", "version": "0.19.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/e7/5c595c75e9f41a44f30e526eda465ea0b4eec93470e074e4a111b253f13a/s3transfer-0.19.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "cachetools", "version": "7.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cc/bb/1c6e7a89b11da19f137e4ef5a5c5fe47a5bb686449ba343944ccf8fb34b2/cachetools-7.2.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "cohere", "version": "7.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4a/c3/064a44c498bf6ae8621caa14307d3ef5471157f149e33cfd64417c8e9ad3/cohere-7.1.1-py3-none-any.whl"}}, {"metadata": {"name": "fastavro", "version": "1.12.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/bf/4f669e10b6bc38a731ee3400aed1a1e2d0a3e3cf411e72f6b320d3af0eaf/fastavro-1.12.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/ee/e4e10a94d51cd1ee638aa7e00b65399e6b2a4e8376ab6d2eac9f95586671/charset_normalizer-3.5.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "tokenizers", "version": "0.23.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/18/1e/bc6587c5ab643b2e17776cace9070a2ae73549c86bffac9934a600bf3c31/tokenizers-0.23.2.tar.gz"}}, {"metadata": {"name": "types-requests", "version": "2.33.0.20260906"}, "download_info": {"url": "https://files.pythonhosted.org/packages/60/4c/51ec821d22a45b4162fa3f3e9e94ea4c0f8c49e82363b10955baa5438391/types_requests-2.33.0.20260906-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1a/01/0127d11a762b31a9ee0221894f540318761783f3fdc4bc5d057698caebd5/cryptography-50.0.1-cp314-cp314t-manylinux_2_34_x86_64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/95/eff5f0cee78d2eabc7eebffec40d3fc1876b5f3c95582e018bb4b99601f2/cffi-2.1.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "cyclopts", "version": "4.25.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/cc/e879da3d54cf727f90e6d90118e132672c3913338b566740486f8797190d/cyclopts-4.25.3-py3-none-any.whl"}}, {"metadata": {"name": "rich-rst", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/68/1fc93dd759605b5d00fc98b50200739e41ed32bd22d6ba35ca6c3932371b/rich_rst-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "filelock", "version": "4.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/29/33/af0635ab07fe83b1788a1dbe370ff3e226062495a998335cb18a1cac81aa/filelock-4.0.1-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6c/c0/a98505f18594f1bce828bb159cec0fcf9860562f1a2c85913409fc8f3d9e/fsspec-2026.9.0-py3-none-any.whl"}}, {"metadata": {"name": "genai-prices", "version": "0.1.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d5/4a/9e04f3dca5ffe74133779ab5e9925ffb6411afbeac55d26fa0e148722599/genai_prices-0.1.7-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.58.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/59/13/477d90d09591b3938b45c4e11f4d8a51291682112cb5efcac961e815d562/google_auth-2.58.0-py3-none-any.whl"}}, {"metadata": {"name": "google-genai", "version": "2.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/84/5b/87913fe392ba7b6402577259289ed3740c577956554a674b191a2971d33e/google_genai-2.24.0-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b2/39/26762f734113e22da2b942c3aca85798e0c0405d64c256549540ff31e5a1/websockets-16.1.1-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl"}}, {"metadata": {"name": "griffelib", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/63/e876e789525063c840ccfa8857febdabd6523bcef9ce7eb979b9305ea895/griffelib-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "groq", "version": "1.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/f6/c3d8ea3194d7d7d8292edd4dbb4b6832d29c2eab04887dda4a742e83902c/groq-1.7.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "joserfc", "version": "1.7.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/c5/82addfd375e5ee6520644e0553e4aadde92d668c4fc99cc716d337fe7bb3/joserfc-1.7.5-py3-none-any.whl"}}, {"metadata": {"name": "jsonref", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/ec/e1db9922bceb168197a558a2b8c03a7963f1afe93517ddd3cf99f202f996/jsonref-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-path", "version": "0.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/2c/9e69d73c4297508be9e3b64a970ea3971b3eb8db64ffc5802d40bd25981f/jsonschema_path-0.5.0-py3-none-any.whl"}}, {"metadata": {"name": "pathable", "version": "0.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a2/e8/6d75ffd9784bce2e93d1ae4415649427e39a53bb172d4672b2b59c6f0a7b/pathable-0.6.0-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "keyring", "version": "25.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/db/e655086b7f3a705df045bf0933bdd9c2f79bb3c97bfef1384598bb79a217/keyring-25.7.0-py3-none-any.whl"}}, {"metadata": {"name": "jeepney", "version": "0.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b2/a3/e137168c9c44d18eff0376253da9f1e9234d0239e0ee230d2fee6cea8e55/jeepney-0.9.0-py3-none-any.whl"}}, {"metadata": {"name": "logfire", "version": "5.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cd/02/b32c3d5c298e4a9010694d261fb82c2c672747c0bf2b47bffda484aef349/logfire-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-exporter-otlp-proto-http", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cd/d0/fdeb1a98d8d3a6205f5f297c51b4a9bfe65126ab60339669bbe3dd54c2e2/opentelemetry_exporter_otlp_proto_http-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-exporter-otlp-proto-common", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5e/71/65fd9d54c10b860f87c045ccee1264cab7011268895d3528818a29c1172a/opentelemetry_exporter_otlp_proto_common-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-proto", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d1/7c/8be563d68e93bbefa5c8affb82ddcff91b3ad858ce49957ba7b16fd3e0ab/opentelemetry_proto-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "googleapis-common-protos", "version": "1.75.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1a/7a/7d79170c6ce6f12e109df2b3879d6b934010cf4f99aea8de8b7e5408c174/googleapis_common_protos-1.75.3-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/6f/a04e900f465ff3221ccc395522503e2d10e79fa21f2723c8e177aae1e0d1/opentelemetry_api-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-sdk", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e7/23/ff077e61886ee020a17ce9c8b6fa11c601c8d8345b09ea24f605445df62a/opentelemetry_sdk-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-semantic-conventions", "version": "0.65b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/0e/49df70d9b81fb5cbae4bbf2a49d865b09bcbcbc4eb53f5851b1027738d78/opentelemetry_semantic_conventions-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "executing", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "logfire-api", "version": "5.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2d/51/123dab197fb08c0892e3bea1c2266bff159aa2ee82ad43bef93505859705/logfire_api-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "mistralai", "version": "2.10.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/98/f64b54166a607ece4e5c8494c843ac1f9c7c0af6f1014272cc420fe1d519/mistralai-2.10.1-py3-none-any.whl"}}, {"metadata": {"name": "eval_type_backport", "version": "0.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/a7/bb99bf5e6f78736ddb53480f2c3ff3702ffe2196a7c5e1661c03081d398e/eval_type_backport-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonpath-python", "version": "1.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/8a/1270a6803bd821cbfcdda387eaa13cb41a7b1f7b9bd145979b3bfb9d6cb7/jsonpath_python-1.1.6-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "3.16.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/17/72/2b1fe3e303db76ab2ba0c2de2b57822869bcb588db82334d4ff3aea8acf2/openai-3.16.2-py3-none-any.whl"}}, {"metadata": {"name": "openapi-pydantic", "version": "0.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/cf/03675d8bd8ecbf4445504d8071adab19f5f993676795708e36402ab38263/openapi_pydantic-0.5.1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-instrumentation", "version": "0.65b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/40/7b/85eab1215f72adf0e68d3dc4a679b9bff993fa679ff34cd8dd378e2659fd/opentelemetry_instrumentation-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "wrapt", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/a7/cca7fe0f26aa11cbbf09b2e6f4f774db167feeca43ad22fa1772afdccbad/wrapt-2.4.1-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl"}}, {"metadata": {"name": "opentelemetry-instrumentation-httpx", "version": "0.65b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/0f/c6144096b4914bbf44b43ba21c962e8f333ff045770b50a3e79ed8bd455f/opentelemetry_instrumentation_httpx-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-util-http", "version": "0.65b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/23/3f/ab8d29df207ce5f470a07fa96ebb48af4e95b7fab7e7635311b9a32f2fab/opentelemetry_util_http-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "platformdirs", "version": "4.11.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/39/be/3ae887e84c38c4dd1c549cd5825adc93f48069a94fe1cb8ac52a9da16f15/platformdirs-4.11.11-py3-none-any.whl"}}, {"metadata": {"name": "prompt_toolkit", "version": "3.0.53"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/6f/84908cad2d6aa5144abcf7b42709fe4fdb459bc640ec7ac5786e7693dabc/prompt_toolkit-3.0.53-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/3b/6163796d69c3977d1e4287bea4a6979161cbbdd170ebb430511e8e1999ce/pyasn1-0.6.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-handlebars", "version": "0.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/11/364bc401f1d8fdb3947079fc43ffdfbfc9132d065981a03a95d2e87440c4/pydantic_handlebars-0.2.1-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "email-validator", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "dnspython", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/97/672cb32ce0dfea44b740cb7b4f97038463b9cf7c0ead1aacf595572851d6/pyjwt-2.14.0-py3-none-any.whl"}}, {"metadata": {"name": "pyperclip", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/80/fc9d01d5ed37ba4c42ca2b55b4339ae6e200b456be3a1aaddf4a9fa99b8c/pyperclip-1.11.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8e/f4/b7ac49f30013aba8f7b9566b1dd07e81de95e708c1374b7bacc5b9bc5c9c/rpds_py-2026.6.3-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "SecretStorage", "version": "3.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/46/f5af3402b579fd5e11573ce652019a67074317e18c1935cc0b4ba9b35552/secretstorage-3.5.0-py3-none-any.whl"}}, {"metadata": {"name": "shellingham", "version": "1.5.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/6a/2ba3ed4a69babf3afdddf7d8314a48d87562c0a442206bbc2a1b50d5efc0/sse_starlette-3.4.11-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "temporalio", "version": "1.33.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/64/b92769790411fa33ce2d037131f5bc856b90837ab1af3d093036f5144c15/temporalio-1.33.0.tar.gz"}}, {"metadata": {"name": "nexus-rpc", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/11/52/6327a5f4fda01207205038a106a99848a41c83e933cd23ea2cab3d2ebc6c/nexus_rpc-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "types-protobuf", "version": "7.35.1.20260906"}, "download_info": {"url": "https://files.pythonhosted.org/packages/44/4e/f63e826c68f77ef875506d72f225918800346545ee99847bc28f3394f18d/types_protobuf-7.35.1.20260906-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/e8/46de4400d5bf859f640feee85bd7e32235f68ddf25db53c63be78e581e3a/tiktoken-0.14.0-cp314-cp314t-manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/03/921a3d3c75785aca9ebfbfcabfbc3a1be12e2ab5265deb026d55a5a3f83e/tqdm-4.70.1-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uncalled-for", "version": "0.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a2/40/97cec87c077eb3291fc7905e6633e08b7ca593c57d30238444bcb6bb3d53/uncalled_for-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.53.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/76/18/0eea75741ee812e9f598b687619ce2454f6c3a1c5cd21ea990ec6bd26f45/uvicorn-0.53.0-py3-none-any.whl"}}, {"metadata": {"name": "watchfiles", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0e/80/c7472203bad6268e3ef1ad260739704847898938ad7ea8b63a5131f46b50/watchfiles-1.2.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/39/cc/9c0adc5861020de426ec71716b6c1bef8d90694b7d6d0a16202cdb1647f5/wcwidth-0.8.4-py3-none-any.whl"}}, {"metadata": {"name": "xai-sdk", "version": "1.19.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/b5/6f6783b97fb3a5498eb852ccaa706e1a2c0de2409480e3c99428e85234fe/xai_sdk-1.19.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bb/6b/62cbd6577758699525f5c712d1ddef57d9875fbab0ae8d5f5a202fd598f8/aiohttp-3.14.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "grpcio", "version": "1.84.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/4f/4435c0aae54657258d9cfcba78598f3d9e5fe4c82ff18d78558567b90faf/grpcio-1.84.0.tar.gz"}}, {"metadata": {"name": "multidict", "version": "6.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/b0/8ee78b0fbe5fe153e9566055e1107c9bae0011b1ae903e30c7ab2ba3e07f/multidict-6.9.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "packaging", "version": "25.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl"}}, {"metadata": {"name": "protobuf", "version": "6.33.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c4/72/02445137af02769918a93807b2b7890047c32bfb9f90371cbc12688819eb/protobuf-6.33.6-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.25.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d1/38/97d79b81c342b78246cfedb74809e68841f3198d21653e10d3232bd9c622/yarl-1.25.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/1c/3d8622e60d0b767a5510d1d3cf21065b9db874696a51ea6d7a43180a259c/frozenlist-1.8.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fc/57/527910c455b5ec62f6871bef45d4f79fea16cb8c966ba0d4a07f0339ddc4/propcache-0.5.4-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "jaraco.classes", "version": "3.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/66/b15ce62552d84bbfcec9a4873ab79d993a1dd4edb922cbfccae192bd5b5f/jaraco.classes-3.4.0-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.context", "version": "6.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f2/58/bc8954bda5fcda97bd7c19be11b85f91973d67a706ed4a3aec33e7de22db/jaraco_context-6.1.2-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.functools", "version": "4.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/02/36/ecc85bc96c273dc8a11273ed4782272975e6338d4a3e9228621175edf0e3/jaraco_functools-4.6.0-py3-none-any.whl"}}, {"metadata": {"name": "more-itertools", "version": "11.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/3d/1087453384dbde46a8c7f9356eead2c58be8a7bf156bca40243377c85715/more_itertools-11.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.9.10"}, "download_info": {"url": "https://files.pythonhosted.org/packages/86/38/49f8d6fd34fc1a9c75b5b96364ebdde702a8144e5ed63d2213c58d454c27/regex-2026.9.10-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}], "install_targets_hash": "5bee9553e16db70083e14421c9e22d12"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "mcp", "version": "2.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/75/20/312acf5fd37b90589269349b2c4d5c056b4603c964d181e91f9bf4a79f97/mcp-2.0.1-py3-none-any.whl"}}, {"metadata": {"name": "mcp-types", "version": "2.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b6/49/37a1f580d94ee0f16c1f3d1c6e32bbb264e607f1739a4c0cb9232619dfd9/mcp_types-2.0.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/6f/a04e900f465ff3221ccc395522503e2d10e79fa21f2723c8e177aae1e0d1/opentelemetry_api-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/02/bc19b47a96c2d3109760711acf22369e56bd7e405ca52f7ade164d2ead57/pydantic_core-2.46.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/97/672cb32ce0dfea44b740cb7b4f97038463b9cf7c0ead1aacf595572851d6/pyjwt-2.14.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/f0/424cb557d99aa86ac55da5e2add02e2882e44047b6264f93ade1b975a993/cryptography-50.0.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7d/47/5ecf1023850036e674c77ec4de86182d309ae344e39e7cba984b7df5d647/cffi-2.1.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/77bcb1168b33704908295533d27f10eb811e9e3e193e8993dc99572211d3/rpds_py-2026.6.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/6a/2ba3ed4a69babf3afdddf7d8314a48d87562c0a442206bbc2a1b50d5efc0/sse_starlette-3.4.11-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.53.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/76/18/0eea75741ee812e9f598b687619ce2454f6c3a1c5cd21ea990ec6bd26f45/uvicorn-0.53.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "61d70df9c1d5a208ed8d56dcc8bbfd3d"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/5e/17398df3a139985ba9d11ed072531986f408c8fca952835ef1ab1820c02b/charset_normalizer-3.4.9-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "623a652072a7d5d73d07fc99e6bd44fb"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/5e/17398df3a139985ba9d11ed072531986f408c8fca952835ef1ab1820c02b/charset_normalizer-3.4.9-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "623a652072a7d5d73d07fc99e6bd44fb"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/5e/17398df3a139985ba9d11ed072531986f408c8fca952835ef1ab1820c02b/charset_normalizer-3.4.9-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "623a652072a7d5d73d07fc99e6bd44fb"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/5e/17398df3a139985ba9d11ed072531986f408c8fca952835ef1ab1820c02b/charset_normalizer-3.4.9-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "623a652072a7d5d73d07fc99e6bd44fb"} {"python_version": "3.14t", "dependencies": [{"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/5e/17398df3a139985ba9d11ed072531986f408c8fca952835ef1ab1820c02b/charset_normalizer-3.4.9-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "623a652072a7d5d73d07fc99e6bd44fb"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/5e/17398df3a139985ba9d11ed072531986f408c8fca952835ef1ab1820c02b/charset_normalizer-3.4.9-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "623a652072a7d5d73d07fc99e6bd44fb"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "trytond", "version": "8.0.10"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/db/57a3be9504273276216dde241d3bc3602c9cae62f60afb1944cf651fe638/trytond-8.0.10-py3-none-any.whl"}}, {"metadata": {"name": "lxml", "version": "6.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d0/9c/733682a0c2de9f5779ba207bbb3f3f6be8c6bda863fc01739b186b38783a/lxml-6.1.3-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "pwdlib", "version": "0.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6b/2e/51979293b2337f508597d13ee20db1ac1d43e48086b2ed7de6da213ed46b/pwdlib-0.3.1-py3-none-any.whl"}}, {"metadata": {"name": "argon2-cffi", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/d3/a8b22fa575b297cd6e3e3b0155c7e25db170edf1c74783d6a31a2490b8d9/argon2_cffi-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "python-sql", "version": "1.8.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/77/ac/3603bbdde340f7354c975431c94b70ef3e99966c5b170fa121f8e64d269e/python_sql-1.8.1-py3-none-any.whl"}}, {"metadata": {"name": "relatorio", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/74/eb/798c426ebd54f52c27aed6593eaf96ed07dca3ca1d084822cc34f0db5159/relatorio-1.0.0-py3-none-any.whl"}}, {"metadata": {"name": "Genshi", "version": "0.7.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/27/503016bc329720ba2856eb4831d6ba36089cd6f15bc4fe85db69fea5b563/genshi-0.7.11-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/09/c419f6f5a92e5fadde27efd190eca90f05e1261b10dbd8cbcb39cd8ea1dc/markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "argon2-cffi-bindings", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/ee/f84b28e4afd13d3cac36c1d8fa8c239d2dc2c51cd978d02ee5d5ad98d9bb/argon2_cffi_bindings-26.1.0-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/95/eff5f0cee78d2eabc7eebffec40d3fc1876b5f3c95582e018bb4b99601f2/cffi-2.1.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "defusedxml", "version": "0.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "polib", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6b/99/45bb1f9926efe370c6dbe324741c749658e44cb060124f28dad201202274/polib-1.2.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "puremagic", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/81/314320aeffd88dadeac553ff9eb10f54507ab41deccd0c69f6221d254a0a/puremagic-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "simpleeval", "version": "1.0.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/33/d1ecd9f4f5f272b36ad7b268e307ba0a59c109d8ad134a231cda780baac9/simpleeval-1.0.8-py3-none-any.whl"}}], "install_targets_hash": "62a0dc5ad5a6cf00b6e38ecd95dcba64"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "openai-agents", "version": "0.14.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/af/6e/1e9adcedcde7b163579b88a68f765a4915be4ead0713270386d9432cfd2f/openai_agents-0.14.8-py3-none-any.whl"}}, {"metadata": {"name": "griffelib", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/b6/f65ac785d4ac90dcf7c831ac6256f5dd4a19780f4e1575b2c0d6eeebe319/griffelib-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mcp", "version": "1.29.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/c8/248b201f6d753d69fd5d6506011abbb35a946d9142b2ae311a948fd0be3d/mcp-1.29.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "2.54.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/a8/bb76c7356de8ad57f59d5ff993d434df0607f07f08bcc9c9a5c275e399c0/openai-2.54.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/6b/59127338b86d9fe4d99418f5a15118bea778103ee0fe9d9dd7e0af174e95/jiter-0.16.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1c/6c/c73fa9d5a85f6ab05395de61c5f6984e0a9ff40bb5ff888d46dff02526c6/charset_normalizer-3.5.1-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "types-requests", "version": "2.33.0.20260712"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/e7/010c87f559e216d83f9dc51e939633fd0d0ead3377340181ab0e223cd3b5/types_requests-2.33.0.20260712-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/e8/f7dac2e980bacc92bdc26cebae4ae4d50cae5380732c50980598fc0bbae4/websockets-16.1.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c3/fb/951032a3bf22a5697c83183fb6294a4843772947a70e616c57b3ff5f522e/cryptography-50.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7d/47/5ecf1023850036e674c77ec4de86182d309ae344e39e7cba984b7df5d647/cffi-2.1.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/77bcb1168b33704908295533d27f10eb811e9e3e193e8993dc99572211d3/rpds_py-2026.6.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/3a/764912c58293d95b6dcdf4cc255f9d10de310580ced547b082eb9d72018c/sse_starlette-3.4.8-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.52.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/79/4a20b54ab0491485ccd8c077db2d39187c7f12b3e15485d38a7be37c81b4/uvicorn-0.52.4-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "673aff7a9ee31625e7c42f92bc69b7ca"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "pymongo", "version": "4.18.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9f/cf/41c06f9cce2035bf061248d1576439bc60701852f75118fd2b5a3408abd0/pymongo-4.18.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "dnspython", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "mockupdb", "version": "1.8.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2f/c0/bc0c3e82bf91993bf2337b125c4d49c3cadae39f5a4c642baada958f976e/mockupdb-1.8.1-py2.py3-none-any.whl"}}], "install_targets_hash": "69c2fba3fd9077f55ce7488963967c53"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "pymongo", "version": "4.18.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c4/42/aa057e91930209d731ec3fed03edf32cf6aa59838f7766227ee219142574/pymongo-4.18.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "dnspython", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "mockupdb", "version": "1.8.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2f/c0/bc0c3e82bf91993bf2337b125c4d49c3cadae39f5a4c642baada958f976e/mockupdb-1.8.1-py2.py3-none-any.whl"}}], "install_targets_hash": "69c2fba3fd9077f55ce7488963967c53"} {"python_version": "3.14t", "dependencies": [{"metadata": {"name": "pymongo", "version": "4.18.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c4/42/aa057e91930209d731ec3fed03edf32cf6aa59838f7766227ee219142574/pymongo-4.18.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "dnspython", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "mockupdb", "version": "1.8.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2f/c0/bc0c3e82bf91993bf2337b125c4d49c3cadae39f5a4c642baada958f976e/mockupdb-1.8.1-py2.py3-none-any.whl"}}], "install_targets_hash": "69c2fba3fd9077f55ce7488963967c53"} -{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "boto3", "version": "1.43.98"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/46/d29efd46ecac6637065a39418c5fb95500d70ec63e76065b5a72c936172f/boto3-1.43.98-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.98"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/ca/c7617e99c3247f545233ab2181840d142c5f72034e22864172866fb1369a/botocore-1.43.98-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "s3transfer", "version": "0.19.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/e7/5c595c75e9f41a44f30e526eda465ea0b4eec93470e074e4a111b253f13a/s3transfer-0.19.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}], "install_targets_hash": "732c20a252602bec78b6c7ee26050916"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "pydantic-ai", "version": "1.76.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e5/c2/8f762847db3f76cafbfad18aea49305b82f15cd8c67f644d0abfc51fc92c/pydantic_ai-1.76.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-ai-slim", "version": "1.76.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/bd/c6/7801af6853502bd53f00e88560f60270d8a2ab3bd8e19732d5ae8f261503/pydantic_ai_slim-1.76.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-evals", "version": "1.76.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e7/ab/14335e6c988ef2af23d33bb89cde4c737b904f84fb237758acf156bb0748/pydantic_evals-1.76.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-graph", "version": "1.76.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/56/4f/60b018568a33c907734613fb089ff288168faa6affb634e05e1a53f1f9e8/pydantic_graph-1.76.0-py3-none-any.whl"}}, {"metadata": {"name": "huggingface_hub", "version": "1.32.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/1b/cf/d98dd561d6d0d7b7d7a64d1563f8aaaa7c235daee41c1c9bcc3da62420ed/huggingface_hub-1.32.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/bb/1e/c0ad437dd267a8e435bef594acf781bbc3874ff0b6435b4962d03ecf7cc4/hf_xet-1.6.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "mcp", "version": "1.30.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/f5/f4/e58bc33317c92a0203664daaf00bf6f41166cc0149e5d6870a03f7cd004a/mcp-1.30.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c5/02/bc19b47a96c2d3109760711acf22369e56bd7e405ca52f7ade164d2ead57/pydantic_core-2.46.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "ag-ui-protocol", "version": "1.0.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/82/b0/850be4576e6443dc575daa54188d8136ae2b2eca3f19e098e7a088fc9ebc/ag_ui_protocol-1.0.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "anthropic", "version": "1.7.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c0/dc/74995efda028421917f4caabd24db1373ee0742573a2363fff1a21191441/anthropic-1.7.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.17.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ac/4a/84a5ec271d09f7590b6073af5ee4abb44eab4ccace453b7e2c5ce45234ca/jiter-0.17.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "argcomplete", "version": "3.7.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/46/bd/551ee6af426af84ca33e02622be722925c196608e9127d731ef17c47f06e/argcomplete-3.7.2-py3-none-any.whl"}}, {"metadata": {"name": "boto3", "version": "1.43.98"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/bc/46/d29efd46ecac6637065a39418c5fb95500d70ec63e76065b5a72c936172f/boto3-1.43.98-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.98"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/65/ca/c7617e99c3247f545233ab2181840d142c5f72034e22864172866fb1369a/botocore-1.43.98-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "s3transfer", "version": "0.19.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/bc/e7/5c595c75e9f41a44f30e526eda465ea0b4eec93470e074e4a111b253f13a/s3transfer-0.19.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "cohere", "version": "7.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/4a/c3/064a44c498bf6ae8621caa14307d3ef5471157f149e33cfd64417c8e9ad3/cohere-7.1.1-py3-none-any.whl"}}, {"metadata": {"name": "fastavro", "version": "1.12.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/dd/8f/18f60329b627d2118a4a2b19e8741fbd807d60bf0470554e1bbfb7f1bca3/fastavro-1.12.2-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/1c/6c/c73fa9d5a85f6ab05395de61c5f6984e0a9ff40bb5ff888d46dff02526c6/charset_normalizer-3.5.1-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "tokenizers", "version": "0.23.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/18/1e/bc6587c5ab643b2e17776cace9070a2ae73549c86bffac9934a600bf3c31/tokenizers-0.23.2.tar.gz"}}, {"metadata": {"name": "types-requests", "version": "2.33.0.20260906"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/60/4c/51ec821d22a45b4162fa3f3e9e94ea4c0f8c49e82363b10955baa5438391/types_requests-2.33.0.20260906-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "fastmcp", "version": "3.4.7"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ac/14/6d950459cc831fa17fe2d1797926b6eb2d2f2af50f830e62d0c098cc1ec8/fastmcp-3.4.7-py3-none-any.whl"}}, {"metadata": {"name": "fastmcp-slim", "version": "3.4.7"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b4/97/e0e53642cd029a9a7635ae9c548f9f2cc995af5914e487b3df795664e4be/fastmcp_slim-3.4.7-py3-none-any.whl"}}, {"metadata": {"name": "py-key-value-aio", "version": "0.4.6"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/9a/46/12871550fb0613d149144bb9d41f22680d5f46717bc45a76eb5798c20c3f/py_key_value_aio-0.4.6-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiofile", "version": "3.12.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/4e/79/6e45e778c4c3cab39e0937b007b720c15f76c50c6453d153282d0fcc3588/aiofile-3.12.3-py3-none-any.whl"}}, {"metadata": {"name": "caio", "version": "0.12.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/d3/f4/c39ed874d420bb2719d52932d763953c28371c536d6bf264de1febeb27d5/caio-0.12.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "Authlib", "version": "1.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b8/c6/6f124bcfbbfb20fba22c939b4e43a06dccfc0e1ca20e5634ca573cb1e271/authlib-1.8.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "beartype", "version": "0.22.9"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/cc/18245721fa7747065ab478316c7fea7c74777d07f37ae60db2e84f8172e8/beartype-0.22.9-py3-none-any.whl"}}, {"metadata": {"name": "cachetools", "version": "7.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cc/bb/1c6e7a89b11da19f137e4ef5a5c5fe47a5bb686449ba343944ccf8fb34b2/cachetools-7.2.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/5b/f0/424cb557d99aa86ac55da5e2add02e2882e44047b6264f93ade1b975a993/cryptography-50.0.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7d/47/5ecf1023850036e674c77ec4de86182d309ae344e39e7cba984b7df5d647/cffi-2.1.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cyclopts", "version": "4.25.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a9/cc/e879da3d54cf727f90e6d90118e132672c3913338b566740486f8797190d/cyclopts-4.25.3-py3-none-any.whl"}}, {"metadata": {"name": "rich-rst", "version": "2.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2a/68/1fc93dd759605b5d00fc98b50200739e41ed32bd22d6ba35ca6c3932371b/rich_rst-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "filelock", "version": "4.0.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/29/33/af0635ab07fe83b1788a1dbe370ff3e226062495a998335cb18a1cac81aa/filelock-4.0.1-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.9.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/6c/c0/a98505f18594f1bce828bb159cec0fcf9860562f1a2c85913409fc8f3d9e/fsspec-2026.9.0-py3-none-any.whl"}}, {"metadata": {"name": "genai-prices", "version": "0.1.7"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/d5/4a/9e04f3dca5ffe74133779ab5e9925ffb6411afbeac55d26fa0e148722599/genai_prices-0.1.7-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.58.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/59/13/477d90d09591b3938b45c4e11f4d8a51291682112cb5efcac961e815d562/google_auth-2.58.0-py3-none-any.whl"}}, {"metadata": {"name": "google-genai", "version": "2.24.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/84/5b/87913fe392ba7b6402577259289ed3740c577956554a674b191a2971d33e/google_genai-2.24.0-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0c/e8/f7dac2e980bacc92bdc26cebae4ae4d50cae5380732c50980598fc0bbae4/websockets-16.1.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "griffelib", "version": "2.3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/41/63/e876e789525063c840ccfa8857febdabd6523bcef9ce7eb979b9305ea895/griffelib-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "groq", "version": "1.7.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/3f/f6/c3d8ea3194d7d7d8292edd4dbb4b6832d29c2eab04887dda4a742e83902c/groq-1.7.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "joserfc", "version": "1.7.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/67/c5/82addfd375e5ee6520644e0553e4aadde92d668c4fc99cc716d337fe7bb3/joserfc-1.7.5-py3-none-any.whl"}}, {"metadata": {"name": "jsonref", "version": "1.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0c/ec/e1db9922bceb168197a558a2b8c03a7963f1afe93517ddd3cf99f202f996/jsonref-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-path", "version": "0.5.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/2c/9e69d73c4297508be9e3b64a970ea3971b3eb8db64ffc5802d40bd25981f/jsonschema_path-0.5.0-py3-none-any.whl"}}, {"metadata": {"name": "pathable", "version": "0.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a2/e8/6d75ffd9784bce2e93d1ae4415649427e39a53bb172d4672b2b59c6f0a7b/pathable-0.6.0-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "keyring", "version": "25.7.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/81/db/e655086b7f3a705df045bf0933bdd9c2f79bb3c97bfef1384598bb79a217/keyring-25.7.0-py3-none-any.whl"}}, {"metadata": {"name": "logfire", "version": "5.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cd/02/b32c3d5c298e4a9010694d261fb82c2c672747c0bf2b47bffda484aef349/logfire-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-exporter-otlp-proto-http", "version": "1.44.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cd/d0/fdeb1a98d8d3a6205f5f297c51b4a9bfe65126ab60339669bbe3dd54c2e2/opentelemetry_exporter_otlp_proto_http-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-exporter-otlp-proto-common", "version": "1.44.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/5e/71/65fd9d54c10b860f87c045ccee1264cab7011268895d3528818a29c1172a/opentelemetry_exporter_otlp_proto_common-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-proto", "version": "1.44.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/d1/7c/8be563d68e93bbefa5c8affb82ddcff91b3ad858ce49957ba7b16fd3e0ab/opentelemetry_proto-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "googleapis-common-protos", "version": "1.75.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/1a/7a/7d79170c6ce6f12e109df2b3879d6b934010cf4f99aea8de8b7e5408c174/googleapis_common_protos-1.75.3-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.44.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ca/6f/a04e900f465ff3221ccc395522503e2d10e79fa21f2723c8e177aae1e0d1/opentelemetry_api-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-sdk", "version": "1.44.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e7/23/ff077e61886ee020a17ce9c8b6fa11c601c8d8345b09ea24f605445df62a/opentelemetry_sdk-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-semantic-conventions", "version": "0.65b0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a6/0e/49df70d9b81fb5cbae4bbf2a49d865b09bcbcbc4eb53f5851b1027738d78/opentelemetry_semantic_conventions-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "executing", "version": "2.2.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "logfire-api", "version": "5.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2d/51/123dab197fb08c0892e3bea1c2266bff159aa2ee82ad43bef93505859705/logfire_api-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "mistralai", "version": "2.10.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ec/98/f64b54166a607ece4e5c8494c843ac1f9c7c0af6f1014272cc420fe1d519/mistralai-2.10.1-py3-none-any.whl"}}, {"metadata": {"name": "eval_type_backport", "version": "0.4.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/50/a7/bb99bf5e6f78736ddb53480f2c3ff3702ffe2196a7c5e1661c03081d398e/eval_type_backport-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonpath-python", "version": "1.1.6"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/55/8a/1270a6803bd821cbfcdda387eaa13cb41a7b1f7b9bd145979b3bfb9d6cb7/jsonpath_python-1.1.6-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "3.16.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/17/72/2b1fe3e303db76ab2ba0c2de2b57822869bcb588db82334d4ff3aea8acf2/openai-3.16.2-py3-none-any.whl"}}, {"metadata": {"name": "openapi-pydantic", "version": "0.5.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/12/cf/03675d8bd8ecbf4445504d8071adab19f5f993676795708e36402ab38263/openapi_pydantic-0.5.1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-instrumentation", "version": "0.65b0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/40/7b/85eab1215f72adf0e68d3dc4a679b9bff993fa679ff34cd8dd378e2659fd/opentelemetry_instrumentation-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "wrapt", "version": "2.4.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/72/26/7435de516099b528e2232770b459d6706002736f41d8f092bbb11ea01575/wrapt-2.4.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "opentelemetry-instrumentation-httpx", "version": "0.65b0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/9d/0f/c6144096b4914bbf44b43ba21c962e8f333ff045770b50a3e79ed8bd455f/opentelemetry_instrumentation_httpx-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-util-http", "version": "0.65b0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/23/3f/ab8d29df207ce5f470a07fa96ebb48af4e95b7fab7e7635311b9a32f2fab/opentelemetry_util_http-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "platformdirs", "version": "4.11.11"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/39/be/3ae887e84c38c4dd1c549cd5825adc93f48069a94fe1cb8ac52a9da16f15/platformdirs-4.11.11-py3-none-any.whl"}}, {"metadata": {"name": "prompt_toolkit", "version": "3.0.53"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/54/6f/84908cad2d6aa5144abcf7b42709fe4fdb459bc640ec7ac5786e7693dabc/prompt_toolkit-3.0.53-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/9a/3b/6163796d69c3977d1e4287bea4a6979161cbbdd170ebb430511e8e1999ce/pyasn1-0.6.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-handlebars", "version": "0.2.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/55/11/364bc401f1d8fdb3947079fc43ffdfbfc9132d065981a03a95d2e87440c4/pydantic_handlebars-0.2.1-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "email-validator", "version": "2.3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "dnspython", "version": "2.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.14.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/9c/97/672cb32ce0dfea44b740cb7b4f97038463b9cf7c0ead1aacf595572851d6/pyjwt-2.14.0-py3-none-any.whl"}}, {"metadata": {"name": "pyperclip", "version": "1.11.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/df/80/fc9d01d5ed37ba4c42ca2b55b4339ae6e200b456be3a1aaddf4a9fa99b8c/pyperclip-1.11.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e9/44/77bcb1168b33704908295533d27f10eb811e9e3e193e8993dc99572211d3/rpds_py-2026.6.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.11"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/98/6a/2ba3ed4a69babf3afdddf7d8314a48d87562c0a442206bbc2a1b50d5efc0/sse_starlette-3.4.11-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "temporalio", "version": "1.33.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/bd/64/b92769790411fa33ce2d037131f5bc856b90837ab1af3d093036f5144c15/temporalio-1.33.0.tar.gz"}}, {"metadata": {"name": "nexus-rpc", "version": "1.4.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/11/52/6327a5f4fda01207205038a106a99848a41c83e933cd23ea2cab3d2ebc6c/nexus_rpc-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "types-protobuf", "version": "7.35.1.20260906"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/44/4e/f63e826c68f77ef875506d72f225918800346545ee99847bc28f3394f18d/types_protobuf-7.35.1.20260906-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/79/29/46ad8061f57bd9f8b2ea0aa82bf574e0f2aa040b0857a1582adba9957899/tiktoken-0.14.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a7/03/921a3d3c75785aca9ebfbfcabfbc3a1be12e2ab5265deb026d55a5a3f83e/tqdm-4.70.1-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uncalled-for", "version": "0.4.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a2/40/97cec87c077eb3291fc7905e6633e08b7ca593c57d30238444bcb6bb3d53/uncalled_for-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.53.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/76/18/0eea75741ee812e9f598b687619ce2454f6c3a1c5cd21ea990ec6bd26f45/uvicorn-0.53.0-py3-none-any.whl"}}, {"metadata": {"name": "watchfiles", "version": "1.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/73/4e/9f7adf01754cbf81843722ccfec169d8f26c69778281a302855cecd2ee08/watchfiles-1.2.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/39/cc/9c0adc5861020de426ec71716b6c1bef8d90694b7d6d0a16202cdb1647f5/wcwidth-0.8.4-py3-none-any.whl"}}, {"metadata": {"name": "xai-sdk", "version": "1.19.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/bc/b5/6f6783b97fb3a5498eb852ccaa706e1a2c0de2409480e3c99428e85234fe/xai_sdk-1.19.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/9e/d8/8ec0e471248c500acdce2be3f46db8fb62b5eb60efef072529cc85ee1d26/aiohttp-3.14.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "grpcio", "version": "1.84.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/3f/4f/4435c0aae54657258d9cfcba78598f3d9e5fe4c82ff18d78558567b90faf/grpcio-1.84.0.tar.gz"}}, {"metadata": {"name": "multidict", "version": "6.9.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c8/65/fb3f5fc6d108dfd32660559d8247de0834a8654f7cd0506c27881dfd9709/multidict-6.9.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "25.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl"}}, {"metadata": {"name": "protobuf", "version": "6.33.6"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c4/72/02445137af02769918a93807b2b7890047c32bfb9f90371cbc12688819eb/protobuf-6.33.6-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.25.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/51/e2/9a6ce2e334ebf218a30335ae76fb1696459430d42f733b8cb0d7d65b84d3/yarl-1.25.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/eb/07/02196ae6320c110235bb343f90dbd34be41f8b8964a3ee30db84ec12579e/propcache-0.5.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "jaraco.classes", "version": "3.4.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7f/66/b15ce62552d84bbfcec9a4873ab79d993a1dd4edb922cbfccae192bd5b5f/jaraco.classes-3.4.0-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.context", "version": "6.1.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/f2/58/bc8954bda5fcda97bd7c19be11b85f91973d67a706ed4a3aec33e7de22db/jaraco_context-6.1.2-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.functools", "version": "4.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/02/36/ecc85bc96c273dc8a11273ed4782272975e6338d4a3e9228621175edf0e3/jaraco_functools-4.6.0-py3-none-any.whl"}}, {"metadata": {"name": "more-itertools", "version": "11.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e8/3d/1087453384dbde46a8c7f9356eead2c58be8a7bf156bca40243377c85715/more_itertools-11.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.9.10"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2b/d1/ee7662561735f90475443c3ca1977e5cecaeaa8f29620dec75580aebc839/regex-2026.9.10-cp314-cp314t-macosx_11_0_arm64.whl"}}], "install_targets_hash": "6ec32fccd93d0a92fa28c01474d3d311"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "anthropic", "version": "1.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c0/dc/74995efda028421917f4caabd24db1373ee0742573a2363fff1a21191441/anthropic-1.7.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/96/c1813dcca15c5a370145a448aaea7d1f83f6f0228a5f1130e79340ee385f/jiter-0.17.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/64/a4e536cb16d7f61a7fd3120b46c577fc7fa7325992f69c4f52bc786d77d8/pydantic_core-2.46.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}], "install_targets_hash": "6f39fdeb7a847546f5d772f520b3189f"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "Django", "version": "5.2.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/f8/ce120525ca78f12b07daf65786679c5d0b54a75285a8958d3ae55e39da35/django-5.2.17-py3-none-any.whl"}}, {"metadata": {"name": "asgiref", "version": "3.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c0/1b/54f4ad77cd8a584fa70746c47df988e002cf1ee1eba43364d46f87803647/asgiref-3.12.1-py3-none-any.whl"}}, {"metadata": {"name": "sqlparse", "version": "0.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d9/50/f00935da0ec7cbf325f8dc4f772ae46fbc7b672dd62876e73f0a94adda57/sqlparse-0.6.0-py3-none-any.whl"}}], "install_targets_hash": "6f59d0d75684e054fcd708cecf89c914"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "openai", "version": "2.54.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/a8/bb76c7356de8ad57f59d5ff993d434df0607f07f08bcc9c9a5c275e399c0/openai-2.54.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/6b/59127338b86d9fe4d99418f5a15118bea778103ee0fe9d9dd7e0af174e95/jiter-0.16.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "6fda56086ebf3b624c63bebeb605cd50"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "openai", "version": "3.17.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/57/bc/5b80a0ca4069a6b5ba6c7d48ae7a4f8176b2c0bde0bebccdb867472ec6f6/openai-3.17.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.17.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ac/4a/84a5ec271d09f7590b6073af5ee4abb44eab4ccace453b7e2c5ce45234ca/jiter-0.17.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c5/02/bc19b47a96c2d3109760711acf22369e56bd7e405ca52f7ade164d2ead57/pydantic_core-2.46.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "6fe5caedd83b044975e2a5e20436ed3f"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "openai-agents", "version": "0.18.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/7c/08b9929a15131081898e38c5612d44ee293851d5c80f31ca1153efe82143/openai_agents-0.18.3-py3-none-any.whl"}}, {"metadata": {"name": "griffelib", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/63/e876e789525063c840ccfa8857febdabd6523bcef9ce7eb979b9305ea895/griffelib-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "mcp", "version": "1.30.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f5/f4/e58bc33317c92a0203664daaf00bf6f41166cc0149e5d6870a03f7cd004a/mcp-1.30.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "2.54.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/a8/bb76c7356de8ad57f59d5ff993d434df0607f07f08bcc9c9a5c275e399c0/openai-2.54.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ac/4a/84a5ec271d09f7590b6073af5ee4abb44eab4ccace453b7e2c5ce45234ca/jiter-0.17.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/02/bc19b47a96c2d3109760711acf22369e56bd7e405ca52f7ade164d2ead57/pydantic_core-2.46.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1c/6c/c73fa9d5a85f6ab05395de61c5f6984e0a9ff40bb5ff888d46dff02526c6/charset_normalizer-3.5.1-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/e8/f7dac2e980bacc92bdc26cebae4ae4d50cae5380732c50980598fc0bbae4/websockets-16.1.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/97/672cb32ce0dfea44b740cb7b4f97038463b9cf7c0ead1aacf595572851d6/pyjwt-2.14.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/f0/424cb557d99aa86ac55da5e2add02e2882e44047b6264f93ade1b975a993/cryptography-50.0.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7d/47/5ecf1023850036e674c77ec4de86182d309ae344e39e7cba984b7df5d647/cffi-2.1.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/77bcb1168b33704908295533d27f10eb811e9e3e193e8993dc99572211d3/rpds_py-2026.6.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/6a/2ba3ed4a69babf3afdddf7d8314a48d87562c0a442206bbc2a1b50d5efc0/sse_starlette-3.4.11-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/03/921a3d3c75785aca9ebfbfcabfbc3a1be12e2ab5265deb026d55a5a3f83e/tqdm-4.70.1-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.52.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/79/4a20b54ab0491485ccd8c077db2d39187c7f12b3e15485d38a7be37c81b4/uvicorn-0.52.4-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "72e451893bc86523078d768ca9965660"} {"python_version": "3.14t", "dependencies": [{"metadata": {"name": "openai", "version": "2.54.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/a8/bb76c7356de8ad57f59d5ff993d434df0607f07f08bcc9c9a5c275e399c0/openai-2.54.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/6b/59127338b86d9fe4d99418f5a15118bea778103ee0fe9d9dd7e0af174e95/jiter-0.16.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "74376afb5a970b70b12c3903563ea5a0"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "openai", "version": "2.54.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/a8/bb76c7356de8ad57f59d5ff993d434df0607f07f08bcc9c9a5c275e399c0/openai-2.54.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/6b/59127338b86d9fe4d99418f5a15118bea778103ee0fe9d9dd7e0af174e95/jiter-0.16.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "74376afb5a970b70b12c3903563ea5a0"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "mcp", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/ff/8e7eade68b8a28f7da0ed1085544341b51f9c935dbf6b95c76b7edfea6a0/mcp-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mcp-types", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8f/d7/6ffba5d8cd5dd9b8a19478875c50e04945314ba5074e84d749283f27f62d/mcp_types-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/95/411ba65569158e862368917aaf56597f3e5fa3b91b0502919638465a08f3/httpx2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/74/d370e55600d9bcfa0d9794b0166126d49291a3d2b20c268fc98c453a4948/httpcore2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/6f/a04e900f465ff3221ccc395522503e2d10e79fa21f2723c8e177aae1e0d1/opentelemetry_api-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/02/bc19b47a96c2d3109760711acf22369e56bd7e405ca52f7ade164d2ead57/pydantic_core-2.46.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/97/672cb32ce0dfea44b740cb7b4f97038463b9cf7c0ead1aacf595572851d6/pyjwt-2.14.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/f0/424cb557d99aa86ac55da5e2add02e2882e44047b6264f93ade1b975a993/cryptography-50.0.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7d/47/5ecf1023850036e674c77ec4de86182d309ae344e39e7cba984b7df5d647/cffi-2.1.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/77bcb1168b33704908295533d27f10eb811e9e3e193e8993dc99572211d3/rpds_py-2026.6.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/6a/2ba3ed4a69babf3afdddf7d8314a48d87562c0a442206bbc2a1b50d5efc0/sse_starlette-3.4.11-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.53.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/76/18/0eea75741ee812e9f598b687619ce2454f6c3a1c5cd21ea990ec6bd26f45/uvicorn-0.53.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "753ede9e584170628cbda8efe3cce07d"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "rq", "version": "2.12.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a4/c2/995863e88669133a058c2a6a912b62d18a64fa7baaf78eb66aaa4350b48d/rq-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "redis", "version": "8.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/66/9d/c5731f6e3608663d4d3656fd8d3aecee8b509c3082818f5a13eae925baea/redis-8.1.0-py3-none-any.whl"}}, {"metadata": {"name": "croniter", "version": "6.2.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cd/ba/d678e5bd329646ca51d3c92addbc77804e86d21f4b6b6a027218e6abb010/croniter-6.2.4-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}], "install_targets_hash": "799909c84e212a340c7dd01c80a52fa3"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "gql", "version": "4.4.0b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/97/00105a44b645f2234e4540027d2ae4ea34b6a95d40e45f9f01c020d0f5b0/gql-4.4.0b0-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/d8/8ec0e471248c500acdce2be3f46db8fb62b5eb60efef072529cc85ee1d26/aiohttp-3.14.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.57"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/7a/1cfe9c296df0fa6e0143c8622b10f21fa8fb9cce25450e9a8e5cf6523e4b/botocore-1.43.57-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.3.0rc0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8c/89/efd877ac909125f050b9562afc1f4b1bc7c0a90bc2a03ed7b0cb21debca3/graphql_core-3.3.0rc0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/13/b8/cfd91c4ab9134d386d48f0b6ac662ff3d4be6efdee59ee1c67ebc3c0487c/httpx2-2.9.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9f/fb/46c52b781975c335a2bcf1072c7bbc007cbdc8d674217f5ee1daba2c848b/httpcore2-2.9.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/5e/17398df3a139985ba9d11ed072531986f408c8fca952835ef1ab1820c02b/charset_normalizer-3.4.9-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "15.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ff/0b/cfb76b7fe99686db264bff829779a539d923e7564ffd7ef18da6c54c3774/yarl-1.24.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "responses", "version": "0.26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/28/693e1d9ebf72baa062ded80d837a035b86ce75eda5a269379e9e2b1008a8/responses-0.26.2-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/73/daf935ea7048ddd7ec8eec5345b4a40b619d2d178b3c0a0900796bc3c794/propcache-0.5.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}], "install_targets_hash": "7d9f37badbb06455849b77944a0bd79e"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "gql", "version": "4.4.0b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/97/00105a44b645f2234e4540027d2ae4ea34b6a95d40e45f9f01c020d0f5b0/gql-4.4.0b0-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/d8/8ec0e471248c500acdce2be3f46db8fb62b5eb60efef072529cc85ee1d26/aiohttp-3.14.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.57"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/7a/1cfe9c296df0fa6e0143c8622b10f21fa8fb9cce25450e9a8e5cf6523e4b/botocore-1.43.57-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.3.0rc0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8c/89/efd877ac909125f050b9562afc1f4b1bc7c0a90bc2a03ed7b0cb21debca3/graphql_core-3.3.0rc0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/13/b8/cfd91c4ab9134d386d48f0b6ac662ff3d4be6efdee59ee1c67ebc3c0487c/httpx2-2.9.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9f/fb/46c52b781975c335a2bcf1072c7bbc007cbdc8d674217f5ee1daba2c848b/httpcore2-2.9.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/5e/17398df3a139985ba9d11ed072531986f408c8fca952835ef1ab1820c02b/charset_normalizer-3.4.9-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "15.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ff/0b/cfb76b7fe99686db264bff829779a539d923e7564ffd7ef18da6c54c3774/yarl-1.24.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "responses", "version": "0.26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/28/693e1d9ebf72baa062ded80d837a035b86ce75eda5a269379e9e2b1008a8/responses-0.26.2-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/73/daf935ea7048ddd7ec8eec5345b4a40b619d2d178b3c0a0900796bc3c794/propcache-0.5.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}], "install_targets_hash": "7d9f37badbb06455849b77944a0bd79e"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "gql", "version": "4.4.0b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/97/00105a44b645f2234e4540027d2ae4ea34b6a95d40e45f9f01c020d0f5b0/gql-4.4.0b0-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/d8/8ec0e471248c500acdce2be3f46db8fb62b5eb60efef072529cc85ee1d26/aiohttp-3.14.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.57"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/7a/1cfe9c296df0fa6e0143c8622b10f21fa8fb9cce25450e9a8e5cf6523e4b/botocore-1.43.57-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.3.0rc0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8c/89/efd877ac909125f050b9562afc1f4b1bc7c0a90bc2a03ed7b0cb21debca3/graphql_core-3.3.0rc0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/13/b8/cfd91c4ab9134d386d48f0b6ac662ff3d4be6efdee59ee1c67ebc3c0487c/httpx2-2.9.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9f/fb/46c52b781975c335a2bcf1072c7bbc007cbdc8d674217f5ee1daba2c848b/httpcore2-2.9.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/5e/17398df3a139985ba9d11ed072531986f408c8fca952835ef1ab1820c02b/charset_normalizer-3.4.9-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "15.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ff/0b/cfb76b7fe99686db264bff829779a539d923e7564ffd7ef18da6c54c3774/yarl-1.24.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "responses", "version": "0.26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/28/693e1d9ebf72baa062ded80d837a035b86ce75eda5a269379e9e2b1008a8/responses-0.26.2-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/73/daf935ea7048ddd7ec8eec5345b4a40b619d2d178b3c0a0900796bc3c794/propcache-0.5.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}], "install_targets_hash": "7d9f37badbb06455849b77944a0bd79e"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "gql", "version": "4.4.0b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/97/00105a44b645f2234e4540027d2ae4ea34b6a95d40e45f9f01c020d0f5b0/gql-4.4.0b0-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/d8/8ec0e471248c500acdce2be3f46db8fb62b5eb60efef072529cc85ee1d26/aiohttp-3.14.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.57"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/7a/1cfe9c296df0fa6e0143c8622b10f21fa8fb9cce25450e9a8e5cf6523e4b/botocore-1.43.57-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.3.0rc0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8c/89/efd877ac909125f050b9562afc1f4b1bc7c0a90bc2a03ed7b0cb21debca3/graphql_core-3.3.0rc0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/13/b8/cfd91c4ab9134d386d48f0b6ac662ff3d4be6efdee59ee1c67ebc3c0487c/httpx2-2.9.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9f/fb/46c52b781975c335a2bcf1072c7bbc007cbdc8d674217f5ee1daba2c848b/httpcore2-2.9.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/5e/17398df3a139985ba9d11ed072531986f408c8fca952835ef1ab1820c02b/charset_normalizer-3.4.9-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "15.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ff/0b/cfb76b7fe99686db264bff829779a539d923e7564ffd7ef18da6c54c3774/yarl-1.24.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "responses", "version": "0.26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/28/693e1d9ebf72baa062ded80d837a035b86ce75eda5a269379e9e2b1008a8/responses-0.26.2-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/73/daf935ea7048ddd7ec8eec5345b4a40b619d2d178b3c0a0900796bc3c794/propcache-0.5.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}], "install_targets_hash": "7d9f37badbb06455849b77944a0bd79e"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "gql", "version": "4.4.0b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/97/00105a44b645f2234e4540027d2ae4ea34b6a95d40e45f9f01c020d0f5b0/gql-4.4.0b0-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/d8/8ec0e471248c500acdce2be3f46db8fb62b5eb60efef072529cc85ee1d26/aiohttp-3.14.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.57"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/7a/1cfe9c296df0fa6e0143c8622b10f21fa8fb9cce25450e9a8e5cf6523e4b/botocore-1.43.57-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.3.0rc0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8c/89/efd877ac909125f050b9562afc1f4b1bc7c0a90bc2a03ed7b0cb21debca3/graphql_core-3.3.0rc0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/13/b8/cfd91c4ab9134d386d48f0b6ac662ff3d4be6efdee59ee1c67ebc3c0487c/httpx2-2.9.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9f/fb/46c52b781975c335a2bcf1072c7bbc007cbdc8d674217f5ee1daba2c848b/httpcore2-2.9.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/5e/17398df3a139985ba9d11ed072531986f408c8fca952835ef1ab1820c02b/charset_normalizer-3.4.9-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "15.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ff/0b/cfb76b7fe99686db264bff829779a539d923e7564ffd7ef18da6c54c3774/yarl-1.24.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "responses", "version": "0.26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/28/693e1d9ebf72baa062ded80d837a035b86ce75eda5a269379e9e2b1008a8/responses-0.26.2-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/73/daf935ea7048ddd7ec8eec5345b4a40b619d2d178b3c0a0900796bc3c794/propcache-0.5.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}], "install_targets_hash": "7d9f37badbb06455849b77944a0bd79e"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "gql", "version": "4.4.0b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/97/00105a44b645f2234e4540027d2ae4ea34b6a95d40e45f9f01c020d0f5b0/gql-4.4.0b0-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/d8/8ec0e471248c500acdce2be3f46db8fb62b5eb60efef072529cc85ee1d26/aiohttp-3.14.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.57"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/7a/1cfe9c296df0fa6e0143c8622b10f21fa8fb9cce25450e9a8e5cf6523e4b/botocore-1.43.57-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.3.0rc0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8c/89/efd877ac909125f050b9562afc1f4b1bc7c0a90bc2a03ed7b0cb21debca3/graphql_core-3.3.0rc0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/13/b8/cfd91c4ab9134d386d48f0b6ac662ff3d4be6efdee59ee1c67ebc3c0487c/httpx2-2.9.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9f/fb/46c52b781975c335a2bcf1072c7bbc007cbdc8d674217f5ee1daba2c848b/httpcore2-2.9.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/5e/17398df3a139985ba9d11ed072531986f408c8fca952835ef1ab1820c02b/charset_normalizer-3.4.9-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "15.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ff/0b/cfb76b7fe99686db264bff829779a539d923e7564ffd7ef18da6c54c3774/yarl-1.24.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "responses", "version": "0.26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/28/693e1d9ebf72baa062ded80d837a035b86ce75eda5a269379e9e2b1008a8/responses-0.26.2-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/73/daf935ea7048ddd7ec8eec5345b4a40b619d2d178b3c0a0900796bc3c794/propcache-0.5.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}], "install_targets_hash": "7d9f37badbb06455849b77944a0bd79e"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "gql", "version": "4.4.0b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/97/00105a44b645f2234e4540027d2ae4ea34b6a95d40e45f9f01c020d0f5b0/gql-4.4.0b0-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/d8/8ec0e471248c500acdce2be3f46db8fb62b5eb60efef072529cc85ee1d26/aiohttp-3.14.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.57"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/7a/1cfe9c296df0fa6e0143c8622b10f21fa8fb9cce25450e9a8e5cf6523e4b/botocore-1.43.57-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.3.0rc0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8c/89/efd877ac909125f050b9562afc1f4b1bc7c0a90bc2a03ed7b0cb21debca3/graphql_core-3.3.0rc0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/13/b8/cfd91c4ab9134d386d48f0b6ac662ff3d4be6efdee59ee1c67ebc3c0487c/httpx2-2.9.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9f/fb/46c52b781975c335a2bcf1072c7bbc007cbdc8d674217f5ee1daba2c848b/httpcore2-2.9.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/5e/17398df3a139985ba9d11ed072531986f408c8fca952835ef1ab1820c02b/charset_normalizer-3.4.9-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "15.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ff/0b/cfb76b7fe99686db264bff829779a539d923e7564ffd7ef18da6c54c3774/yarl-1.24.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "responses", "version": "0.26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/28/693e1d9ebf72baa062ded80d837a035b86ce75eda5a269379e9e2b1008a8/responses-0.26.2-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/73/daf935ea7048ddd7ec8eec5345b4a40b619d2d178b3c0a0900796bc3c794/propcache-0.5.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}], "install_targets_hash": "7d9f37badbb06455849b77944a0bd79e"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "gql", "version": "4.4.0b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/97/00105a44b645f2234e4540027d2ae4ea34b6a95d40e45f9f01c020d0f5b0/gql-4.4.0b0-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/d8/8ec0e471248c500acdce2be3f46db8fb62b5eb60efef072529cc85ee1d26/aiohttp-3.14.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.57"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/7a/1cfe9c296df0fa6e0143c8622b10f21fa8fb9cce25450e9a8e5cf6523e4b/botocore-1.43.57-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.3.0rc0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8c/89/efd877ac909125f050b9562afc1f4b1bc7c0a90bc2a03ed7b0cb21debca3/graphql_core-3.3.0rc0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/13/b8/cfd91c4ab9134d386d48f0b6ac662ff3d4be6efdee59ee1c67ebc3c0487c/httpx2-2.9.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9f/fb/46c52b781975c335a2bcf1072c7bbc007cbdc8d674217f5ee1daba2c848b/httpcore2-2.9.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/5e/17398df3a139985ba9d11ed072531986f408c8fca952835ef1ab1820c02b/charset_normalizer-3.4.9-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "15.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ff/0b/cfb76b7fe99686db264bff829779a539d923e7564ffd7ef18da6c54c3774/yarl-1.24.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "responses", "version": "0.26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/28/693e1d9ebf72baa062ded80d837a035b86ce75eda5a269379e9e2b1008a8/responses-0.26.2-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/73/daf935ea7048ddd7ec8eec5345b4a40b619d2d178b3c0a0900796bc3c794/propcache-0.5.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}], "install_targets_hash": "7d9f37badbb06455849b77944a0bd79e"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "gql", "version": "4.4.0b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/97/00105a44b645f2234e4540027d2ae4ea34b6a95d40e45f9f01c020d0f5b0/gql-4.4.0b0-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/d8/8ec0e471248c500acdce2be3f46db8fb62b5eb60efef072529cc85ee1d26/aiohttp-3.14.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.57"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/7a/1cfe9c296df0fa6e0143c8622b10f21fa8fb9cce25450e9a8e5cf6523e4b/botocore-1.43.57-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.3.0rc0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8c/89/efd877ac909125f050b9562afc1f4b1bc7c0a90bc2a03ed7b0cb21debca3/graphql_core-3.3.0rc0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/13/b8/cfd91c4ab9134d386d48f0b6ac662ff3d4be6efdee59ee1c67ebc3c0487c/httpx2-2.9.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9f/fb/46c52b781975c335a2bcf1072c7bbc007cbdc8d674217f5ee1daba2c848b/httpcore2-2.9.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/5e/17398df3a139985ba9d11ed072531986f408c8fca952835ef1ab1820c02b/charset_normalizer-3.4.9-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "15.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ff/0b/cfb76b7fe99686db264bff829779a539d923e7564ffd7ef18da6c54c3774/yarl-1.24.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "responses", "version": "0.26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/28/693e1d9ebf72baa062ded80d837a035b86ce75eda5a269379e9e2b1008a8/responses-0.26.2-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/73/daf935ea7048ddd7ec8eec5345b4a40b619d2d178b3c0a0900796bc3c794/propcache-0.5.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}], "install_targets_hash": "7d9f37badbb06455849b77944a0bd79e"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "gql", "version": "4.4.0b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/97/00105a44b645f2234e4540027d2ae4ea34b6a95d40e45f9f01c020d0f5b0/gql-4.4.0b0-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/d8/8ec0e471248c500acdce2be3f46db8fb62b5eb60efef072529cc85ee1d26/aiohttp-3.14.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.57"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/7a/1cfe9c296df0fa6e0143c8622b10f21fa8fb9cce25450e9a8e5cf6523e4b/botocore-1.43.57-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.3.0rc0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8c/89/efd877ac909125f050b9562afc1f4b1bc7c0a90bc2a03ed7b0cb21debca3/graphql_core-3.3.0rc0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/13/b8/cfd91c4ab9134d386d48f0b6ac662ff3d4be6efdee59ee1c67ebc3c0487c/httpx2-2.9.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9f/fb/46c52b781975c335a2bcf1072c7bbc007cbdc8d674217f5ee1daba2c848b/httpcore2-2.9.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/5e/17398df3a139985ba9d11ed072531986f408c8fca952835ef1ab1820c02b/charset_normalizer-3.4.9-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "15.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ff/0b/cfb76b7fe99686db264bff829779a539d923e7564ffd7ef18da6c54c3774/yarl-1.24.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "responses", "version": "0.26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/28/693e1d9ebf72baa062ded80d837a035b86ce75eda5a269379e9e2b1008a8/responses-0.26.2-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/73/daf935ea7048ddd7ec8eec5345b4a40b619d2d178b3c0a0900796bc3c794/propcache-0.5.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}], "install_targets_hash": "7d9f37badbb06455849b77944a0bd79e"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "gql", "version": "4.4.0b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/97/00105a44b645f2234e4540027d2ae4ea34b6a95d40e45f9f01c020d0f5b0/gql-4.4.0b0-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/d8/8ec0e471248c500acdce2be3f46db8fb62b5eb60efef072529cc85ee1d26/aiohttp-3.14.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.57"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/7a/1cfe9c296df0fa6e0143c8622b10f21fa8fb9cce25450e9a8e5cf6523e4b/botocore-1.43.57-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.3.0rc0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8c/89/efd877ac909125f050b9562afc1f4b1bc7c0a90bc2a03ed7b0cb21debca3/graphql_core-3.3.0rc0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/13/b8/cfd91c4ab9134d386d48f0b6ac662ff3d4be6efdee59ee1c67ebc3c0487c/httpx2-2.9.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9f/fb/46c52b781975c335a2bcf1072c7bbc007cbdc8d674217f5ee1daba2c848b/httpcore2-2.9.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/5e/17398df3a139985ba9d11ed072531986f408c8fca952835ef1ab1820c02b/charset_normalizer-3.4.9-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "15.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ff/0b/cfb76b7fe99686db264bff829779a539d923e7564ffd7ef18da6c54c3774/yarl-1.24.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "responses", "version": "0.26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/28/693e1d9ebf72baa062ded80d837a035b86ce75eda5a269379e9e2b1008a8/responses-0.26.2-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/73/daf935ea7048ddd7ec8eec5345b4a40b619d2d178b3c0a0900796bc3c794/propcache-0.5.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}], "install_targets_hash": "7d9f37badbb06455849b77944a0bd79e"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "gql", "version": "4.4.0b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/97/00105a44b645f2234e4540027d2ae4ea34b6a95d40e45f9f01c020d0f5b0/gql-4.4.0b0-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/d8/8ec0e471248c500acdce2be3f46db8fb62b5eb60efef072529cc85ee1d26/aiohttp-3.14.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.57"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/7a/1cfe9c296df0fa6e0143c8622b10f21fa8fb9cce25450e9a8e5cf6523e4b/botocore-1.43.57-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.3.0rc0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8c/89/efd877ac909125f050b9562afc1f4b1bc7c0a90bc2a03ed7b0cb21debca3/graphql_core-3.3.0rc0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/13/b8/cfd91c4ab9134d386d48f0b6ac662ff3d4be6efdee59ee1c67ebc3c0487c/httpx2-2.9.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9f/fb/46c52b781975c335a2bcf1072c7bbc007cbdc8d674217f5ee1daba2c848b/httpcore2-2.9.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/5e/17398df3a139985ba9d11ed072531986f408c8fca952835ef1ab1820c02b/charset_normalizer-3.4.9-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "15.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ff/0b/cfb76b7fe99686db264bff829779a539d923e7564ffd7ef18da6c54c3774/yarl-1.24.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "responses", "version": "0.26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/28/693e1d9ebf72baa062ded80d837a035b86ce75eda5a269379e9e2b1008a8/responses-0.26.2-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/73/daf935ea7048ddd7ec8eec5345b4a40b619d2d178b3c0a0900796bc3c794/propcache-0.5.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}], "install_targets_hash": "7d9f37badbb06455849b77944a0bd79e"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "gql", "version": "4.4.0b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/97/00105a44b645f2234e4540027d2ae4ea34b6a95d40e45f9f01c020d0f5b0/gql-4.4.0b0-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/d8/8ec0e471248c500acdce2be3f46db8fb62b5eb60efef072529cc85ee1d26/aiohttp-3.14.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.57"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/7a/1cfe9c296df0fa6e0143c8622b10f21fa8fb9cce25450e9a8e5cf6523e4b/botocore-1.43.57-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.3.0rc0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8c/89/efd877ac909125f050b9562afc1f4b1bc7c0a90bc2a03ed7b0cb21debca3/graphql_core-3.3.0rc0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/13/b8/cfd91c4ab9134d386d48f0b6ac662ff3d4be6efdee59ee1c67ebc3c0487c/httpx2-2.9.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9f/fb/46c52b781975c335a2bcf1072c7bbc007cbdc8d674217f5ee1daba2c848b/httpcore2-2.9.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/5e/17398df3a139985ba9d11ed072531986f408c8fca952835ef1ab1820c02b/charset_normalizer-3.4.9-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "15.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ff/0b/cfb76b7fe99686db264bff829779a539d923e7564ffd7ef18da6c54c3774/yarl-1.24.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "responses", "version": "0.26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/28/693e1d9ebf72baa062ded80d837a035b86ce75eda5a269379e9e2b1008a8/responses-0.26.2-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/73/daf935ea7048ddd7ec8eec5345b4a40b619d2d178b3c0a0900796bc3c794/propcache-0.5.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}], "install_targets_hash": "7d9f37badbb06455849b77944a0bd79e"} {"python_version": "3.14t", "dependencies": [{"metadata": {"name": "gql", "version": "4.4.0b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/97/00105a44b645f2234e4540027d2ae4ea34b6a95d40e45f9f01c020d0f5b0/gql-4.4.0b0-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/d8/8ec0e471248c500acdce2be3f46db8fb62b5eb60efef072529cc85ee1d26/aiohttp-3.14.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.57"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/7a/1cfe9c296df0fa6e0143c8622b10f21fa8fb9cce25450e9a8e5cf6523e4b/botocore-1.43.57-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.3.0rc0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8c/89/efd877ac909125f050b9562afc1f4b1bc7c0a90bc2a03ed7b0cb21debca3/graphql_core-3.3.0rc0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/13/b8/cfd91c4ab9134d386d48f0b6ac662ff3d4be6efdee59ee1c67ebc3c0487c/httpx2-2.9.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9f/fb/46c52b781975c335a2bcf1072c7bbc007cbdc8d674217f5ee1daba2c848b/httpcore2-2.9.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/5e/17398df3a139985ba9d11ed072531986f408c8fca952835ef1ab1820c02b/charset_normalizer-3.4.9-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "15.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ff/0b/cfb76b7fe99686db264bff829779a539d923e7564ffd7ef18da6c54c3774/yarl-1.24.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "responses", "version": "0.26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/28/693e1d9ebf72baa062ded80d837a035b86ce75eda5a269379e9e2b1008a8/responses-0.26.2-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/73/daf935ea7048ddd7ec8eec5345b4a40b619d2d178b3c0a0900796bc3c794/propcache-0.5.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}], "install_targets_hash": "7d9f37badbb06455849b77944a0bd79e"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "gql", "version": "4.4.0b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/97/00105a44b645f2234e4540027d2ae4ea34b6a95d40e45f9f01c020d0f5b0/gql-4.4.0b0-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/d8/8ec0e471248c500acdce2be3f46db8fb62b5eb60efef072529cc85ee1d26/aiohttp-3.14.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.57"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/7a/1cfe9c296df0fa6e0143c8622b10f21fa8fb9cce25450e9a8e5cf6523e4b/botocore-1.43.57-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.3.0rc0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8c/89/efd877ac909125f050b9562afc1f4b1bc7c0a90bc2a03ed7b0cb21debca3/graphql_core-3.3.0rc0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/13/b8/cfd91c4ab9134d386d48f0b6ac662ff3d4be6efdee59ee1c67ebc3c0487c/httpx2-2.9.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9f/fb/46c52b781975c335a2bcf1072c7bbc007cbdc8d674217f5ee1daba2c848b/httpcore2-2.9.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/5e/17398df3a139985ba9d11ed072531986f408c8fca952835ef1ab1820c02b/charset_normalizer-3.4.9-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "15.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ff/0b/cfb76b7fe99686db264bff829779a539d923e7564ffd7ef18da6c54c3774/yarl-1.24.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "responses", "version": "0.26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/28/693e1d9ebf72baa062ded80d837a035b86ce75eda5a269379e9e2b1008a8/responses-0.26.2-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/73/daf935ea7048ddd7ec8eec5345b4a40b619d2d178b3c0a0900796bc3c794/propcache-0.5.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}], "install_targets_hash": "7d9f37badbb06455849b77944a0bd79e"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "gql", "version": "4.4.0b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/97/00105a44b645f2234e4540027d2ae4ea34b6a95d40e45f9f01c020d0f5b0/gql-4.4.0b0-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/d8/8ec0e471248c500acdce2be3f46db8fb62b5eb60efef072529cc85ee1d26/aiohttp-3.14.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.57"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/7a/1cfe9c296df0fa6e0143c8622b10f21fa8fb9cce25450e9a8e5cf6523e4b/botocore-1.43.57-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.3.0rc0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8c/89/efd877ac909125f050b9562afc1f4b1bc7c0a90bc2a03ed7b0cb21debca3/graphql_core-3.3.0rc0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/13/b8/cfd91c4ab9134d386d48f0b6ac662ff3d4be6efdee59ee1c67ebc3c0487c/httpx2-2.9.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9f/fb/46c52b781975c335a2bcf1072c7bbc007cbdc8d674217f5ee1daba2c848b/httpcore2-2.9.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/5e/17398df3a139985ba9d11ed072531986f408c8fca952835ef1ab1820c02b/charset_normalizer-3.4.9-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "15.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ff/0b/cfb76b7fe99686db264bff829779a539d923e7564ffd7ef18da6c54c3774/yarl-1.24.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "responses", "version": "0.26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/28/693e1d9ebf72baa062ded80d837a035b86ce75eda5a269379e9e2b1008a8/responses-0.26.2-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/73/daf935ea7048ddd7ec8eec5345b4a40b619d2d178b3c0a0900796bc3c794/propcache-0.5.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}], "install_targets_hash": "7d9f37badbb06455849b77944a0bd79e"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "gql", "version": "4.4.0b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/97/00105a44b645f2234e4540027d2ae4ea34b6a95d40e45f9f01c020d0f5b0/gql-4.4.0b0-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/d8/8ec0e471248c500acdce2be3f46db8fb62b5eb60efef072529cc85ee1d26/aiohttp-3.14.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.57"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/7a/1cfe9c296df0fa6e0143c8622b10f21fa8fb9cce25450e9a8e5cf6523e4b/botocore-1.43.57-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.3.0rc0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8c/89/efd877ac909125f050b9562afc1f4b1bc7c0a90bc2a03ed7b0cb21debca3/graphql_core-3.3.0rc0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/13/b8/cfd91c4ab9134d386d48f0b6ac662ff3d4be6efdee59ee1c67ebc3c0487c/httpx2-2.9.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9f/fb/46c52b781975c335a2bcf1072c7bbc007cbdc8d674217f5ee1daba2c848b/httpcore2-2.9.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/5e/17398df3a139985ba9d11ed072531986f408c8fca952835ef1ab1820c02b/charset_normalizer-3.4.9-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "15.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ff/0b/cfb76b7fe99686db264bff829779a539d923e7564ffd7ef18da6c54c3774/yarl-1.24.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "responses", "version": "0.26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/28/693e1d9ebf72baa062ded80d837a035b86ce75eda5a269379e9e2b1008a8/responses-0.26.2-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/73/daf935ea7048ddd7ec8eec5345b4a40b619d2d178b3c0a0900796bc3c794/propcache-0.5.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}], "install_targets_hash": "7d9f37badbb06455849b77944a0bd79e"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "httpx2", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e6/a7/aea061b450d51cf448c1ccc8e1fc6f04c0d8fdc97c17524c7f835018bb92/httpx2-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2-pytest", "version": "1.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/46/ef/e9b6fb576f1f518f68e9f9cce9776870452ae2b8cfbba53b4127701b9a55/httpx2_pytest-1.0.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b7/76d6baa8c087cf5170f36dbeb92471e77c5c48f8f7ca8e5ba4ad613ea492/httpcore2-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}], "install_targets_hash": "81061e3f7fbd70089dc2dae262e96f28"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "httpx2", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e6/a7/aea061b450d51cf448c1ccc8e1fc6f04c0d8fdc97c17524c7f835018bb92/httpx2-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2-pytest", "version": "1.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/46/ef/e9b6fb576f1f518f68e9f9cce9776870452ae2b8cfbba53b4127701b9a55/httpx2_pytest-1.0.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b7/76d6baa8c087cf5170f36dbeb92471e77c5c48f8f7ca8e5ba4ad613ea492/httpcore2-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}], "install_targets_hash": "81061e3f7fbd70089dc2dae262e96f28"} {"python_version": "3.14t", "dependencies": [{"metadata": {"name": "httpx2", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e6/a7/aea061b450d51cf448c1ccc8e1fc6f04c0d8fdc97c17524c7f835018bb92/httpx2-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2-pytest", "version": "1.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/46/ef/e9b6fb576f1f518f68e9f9cce9776870452ae2b8cfbba53b4127701b9a55/httpx2_pytest-1.0.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b7/76d6baa8c087cf5170f36dbeb92471e77c5c48f8f7ca8e5ba4ad613ea492/httpcore2-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}], "install_targets_hash": "81061e3f7fbd70089dc2dae262e96f28"} {"python_version": "3.14t", "dependencies": [{"metadata": {"name": "mistralai", "version": "2.10.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/98/f64b54166a607ece4e5c8494c843ac1f9c7c0af6f1014272cc420fe1d519/mistralai-2.10.1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/6f/a04e900f465ff3221ccc395522503e2d10e79fa21f2723c8e177aae1e0d1/opentelemetry_api-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "eval_type_backport", "version": "0.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/a7/bb99bf5e6f78736ddb53480f2c3ff3702ffe2196a7c5e1661c03081d398e/eval_type_backport-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonpath-python", "version": "1.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/8a/1270a6803bd821cbfcdda387eaa13cb41a7b1f7b9bd145979b3bfb9d6cb7/jsonpath_python-1.1.6-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-semantic-conventions", "version": "0.65b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/0e/49df70d9b81fb5cbae4bbf2a49d865b09bcbcbc4eb53f5851b1027738d78/opentelemetry_semantic_conventions-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/02/bc19b47a96c2d3109760711acf22369e56bd7e405ca52f7ade164d2ead57/pydantic_core-2.46.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}], "install_targets_hash": "815ae8a75d9673398571743a7b3a35fa"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "openai", "version": "3.17.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/57/bc/5b80a0ca4069a6b5ba6c7d48ae7a4f8176b2c0bde0bebccdb867472ec6f6/openai-3.17.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.17.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ac/4a/84a5ec271d09f7590b6073af5ee4abb44eab4ccace453b7e2c5ce45234ca/jiter-0.17.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c5/02/bc19b47a96c2d3109760711acf22369e56bd7e405ca52f7ade164d2ead57/pydantic_core-2.46.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/79/29/46ad8061f57bd9f8b2ea0aa82bf574e0f2aa040b0857a1582adba9957899/tiktoken-0.14.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.9.10"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2b/d1/ee7662561735f90475443c3ca1977e5cecaeaa8f29620dec75580aebc839/regex-2026.9.10-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/1c/6c/c73fa9d5a85f6ab05395de61c5f6984e0a9ff40bb5ff888d46dff02526c6/charset_normalizer-3.5.1-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "urllib3", "version": "2.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "828f8978f312e7020633b81adf747d24"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "dramatiq", "version": "2.2.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/8c/13/0550ff585ade7b423e2ecaac29c4ab88673a58ae92ef25b6629089a2b92c/dramatiq-2.2.1-py3-none-any.whl"}}], "install_targets_hash": "83dfbbed9bd8bc2ec0e6747a01c98300"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "dramatiq", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8c/13/0550ff585ade7b423e2ecaac29c4ab88673a58ae92ef25b6629089a2b92c/dramatiq-2.2.1-py3-none-any.whl"}}], "install_targets_hash": "83dfbbed9bd8bc2ec0e6747a01c98300"} {"python_version": "3.14t", "dependencies": [{"metadata": {"name": "dramatiq", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8c/13/0550ff585ade7b423e2ecaac29c4ab88673a58ae92ef25b6629089a2b92c/dramatiq-2.2.1-py3-none-any.whl"}}], "install_targets_hash": "83dfbbed9bd8bc2ec0e6747a01c98300"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "httpx2", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e6/a7/aea061b450d51cf448c1ccc8e1fc6f04c0d8fdc97c17524c7f835018bb92/httpx2-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b7/76d6baa8c087cf5170f36dbeb92471e77c5c48f8f7ca8e5ba4ad613ea492/httpcore2-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}], "install_targets_hash": "86331d46691c7ca12c95f1cd84ede160"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "openai", "version": "3.17.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/57/bc/5b80a0ca4069a6b5ba6c7d48ae7a4f8176b2c0bde0bebccdb867472ec6f6/openai-3.17.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.17.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ac/4a/84a5ec271d09f7590b6073af5ee4abb44eab4ccace453b7e2c5ce45234ca/jiter-0.17.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c5/02/bc19b47a96c2d3109760711acf22369e56bd7e405ca52f7ade164d2ead57/pydantic_core-2.46.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "86e2b4eac10e4b825b8d9aaf885a8fec"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "celery", "version": "5.7.0a1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/de/bf/72703e2ac184cc9c4c641ba5abaec725cbdcf48755c7582f006005d38848/celery-5.7.0a1-py3-none-any.whl"}}, {"metadata": {"name": "billiard", "version": "4.3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/60/60/ade6d336983b82fbc330d0d0371f945249b448152852952f643787a3288d/billiard-4.3.0-py3-none-any.whl"}}, {"metadata": {"name": "click-repl", "version": "0.4.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e0/ae/63d94d251d2e1a7bf3794ea47cb1c99fe6de055b732ea79d7bcdabef8ff5/click_repl-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "vine", "version": "5.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/03/ff/7c0c86c43b3cbb927e0ccc0255cb4057ceba4799cd44ae95174ce8e8b5b2/vine-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "click-didyoumean", "version": "0.3.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/1b/5b/974430b5ffdb7a4f1941d13d83c64a0395114503cc357c6b9ae4ce5047ed/click_didyoumean-0.3.1-py3-none-any.whl"}}, {"metadata": {"name": "click-plugins", "version": "1.1.1.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/3d/9a/2abecb28ae875e39c8cad711eb1186d8d14eab564705325e77e4e6ab9ae5/click_plugins-1.1.1.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "kombu", "version": "5.7.0a1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b6/d9/1b98be4b45c3cb6737663ea5e7847fcc8f6c21de204a0411ae12874fbfc0/kombu-5.7.0a1-py3-none-any.whl"}}, {"metadata": {"name": "amqp", "version": "5.4.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/07/99/6b965aa99a32630c1c61ce57c9dcf81cec6fec354274a87f14525302b7f7/amqp-5.4.0-py3-none-any.whl"}}, {"metadata": {"name": "prompt_toolkit", "version": "3.0.53"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/54/6f/84908cad2d6aa5144abcf7b42709fe4fdb459bc640ec7ac5786e7693dabc/prompt_toolkit-3.0.53-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "tzdata", "version": "2026.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/f9/bc/8737e8d54cf51106118039b83f485a4783112fab49ea9d044b234978a46e/tzdata-2026.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/39/cc/9c0adc5861020de426ec71716b6c1bef8d90694b7d6d0a16202cdb1647f5/wcwidth-0.8.4-py3-none-any.whl"}}, {"metadata": {"name": "tzlocal", "version": "5.4.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/9e/a4/017a7a6cbe387d961a688ec31364ae60a5c4e22c96ae9921b79a947c855d/tzlocal-5.4.4-py3-none-any.whl"}}], "install_targets_hash": "87256d0835cc6f45dcbacae9a6963ceb"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "fastapi", "version": "0.141.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/03/10388a42375ee7e4ac9b94eb2c5c569c8b5795e377e701c9ac3ad63de890/fastapi-0.141.1-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}], "install_targets_hash": "8798f3fb9541cb70f8be77c65c082d34"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "google-genai", "version": "2.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/84/5b/87913fe392ba7b6402577259289ed3740c577956554a674b191a2971d33e/google_genai-2.24.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.58.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/59/13/477d90d09591b3938b45c4e11f4d8a51291682112cb5efcac961e815d562/google_auth-2.58.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/64/a4e536cb16d7f61a7fd3120b46c577fc7fa7325992f69c4f52bc786d77d8/pydantic_core-2.46.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/ee/e4e10a94d51cd1ee638aa7e00b65399e6b2a4e8376ab6d2eac9f95586671/charset_normalizer-3.5.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b2/39/26762f734113e22da2b942c3aca85798e0c0405d64c256549540ff31e5a1/websockets-16.1.1-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1a/01/0127d11a762b31a9ee0221894f540318761783f3fdc4bc5d057698caebd5/cryptography-50.0.1-cp314-cp314t-manylinux_2_34_x86_64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/95/eff5f0cee78d2eabc7eebffec40d3fc1876b5f3c95582e018bb4b99601f2/cffi-2.1.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/3b/6163796d69c3977d1e4287bea4a6979161cbbdd170ebb430511e8e1999ce/pyasn1-0.6.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "88119243985ed0f8d3d0e47569072da2"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "redis", "version": "8.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/66/9d/c5731f6e3608663d4d3656fd8d3aecee8b509c3082818f5a13eae925baea/redis-8.1.0-py3-none-any.whl"}}], "install_targets_hash": "893b65f9ebe606e765652cedded4338e"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "openai-agents", "version": "0.18.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e0/7c/08b9929a15131081898e38c5612d44ee293851d5c80f31ca1153efe82143/openai_agents-0.18.3-py3-none-any.whl"}}, {"metadata": {"name": "griffelib", "version": "2.3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/41/63/e876e789525063c840ccfa8857febdabd6523bcef9ce7eb979b9305ea895/griffelib-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "mcp", "version": "1.30.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/f5/f4/e58bc33317c92a0203664daaf00bf6f41166cc0149e5d6870a03f7cd004a/mcp-1.30.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "2.54.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/64/a8/bb76c7356de8ad57f59d5ff993d434df0607f07f08bcc9c9a5c275e399c0/openai-2.54.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.17.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ac/4a/84a5ec271d09f7590b6073af5ee4abb44eab4ccace453b7e2c5ce45234ca/jiter-0.17.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c5/02/bc19b47a96c2d3109760711acf22369e56bd7e405ca52f7ade164d2ead57/pydantic_core-2.46.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/1c/6c/c73fa9d5a85f6ab05395de61c5f6984e0a9ff40bb5ff888d46dff02526c6/charset_normalizer-3.5.1-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0c/e8/f7dac2e980bacc92bdc26cebae4ae4d50cae5380732c50980598fc0bbae4/websockets-16.1.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.14.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/9c/97/672cb32ce0dfea44b740cb7b4f97038463b9cf7c0ead1aacf595572851d6/pyjwt-2.14.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/5b/f0/424cb557d99aa86ac55da5e2add02e2882e44047b6264f93ade1b975a993/cryptography-50.0.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7d/47/5ecf1023850036e674c77ec4de86182d309ae344e39e7cba984b7df5d647/cffi-2.1.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e9/44/77bcb1168b33704908295533d27f10eb811e9e3e193e8993dc99572211d3/rpds_py-2026.6.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.11"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/98/6a/2ba3ed4a69babf3afdddf7d8314a48d87562c0a442206bbc2a1b50d5efc0/sse_starlette-3.4.11-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a7/03/921a3d3c75785aca9ebfbfcabfbc3a1be12e2ab5265deb026d55a5a3f83e/tqdm-4.70.1-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.53.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/76/18/0eea75741ee812e9f598b687619ce2454f6c3a1c5cd21ea990ec6bd26f45/uvicorn-0.53.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "8b55f0e85c19070da45e3021124eb34f"} {"python_version": "3.14t", "dependencies": [{"metadata": {"name": "huggingface_hub", "version": "1.32.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/cf/d98dd561d6d0d7b7d7a64d1563f8aaaa7c235daee41c1c9bcc3da62420ed/huggingface_hub-1.32.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d5/ee/7c0d7b6ab336167531b1c30af2af003f054af4c749becbd7209ae33a77c3/hf_xet-1.6.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "responses", "version": "0.26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6d/86/ca7958de70cb0752350575e98229368a3a2f746a2942034b3364e17312bb/responses-0.26.3-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/ee/e4e10a94d51cd1ee638aa7e00b65399e6b2a4e8376ab6d2eac9f95586671/charset_normalizer-3.5.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-httpx", "version": "0.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/55/1fa65f8e4fceb19dd6daa867c162ad845d547f6058cd92b4b02384a44777/pytest_httpx-0.36.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "filelock", "version": "4.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/29/33/af0635ab07fe83b1788a1dbe370ff3e226062495a998335cb18a1cac81aa/filelock-4.0.1-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6c/c0/a98505f18594f1bce828bb159cec0fcf9860562f1a2c85913409fc8f3d9e/fsspec-2026.9.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/03/921a3d3c75785aca9ebfbfcabfbc3a1be12e2ab5265deb026d55a5a3f83e/tqdm-4.70.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}], "install_targets_hash": "8d3f9781d86e000603a20c010acf0233"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "huggingface_hub", "version": "1.32.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/cf/d98dd561d6d0d7b7d7a64d1563f8aaaa7c235daee41c1c9bcc3da62420ed/huggingface_hub-1.32.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d5/ee/7c0d7b6ab336167531b1c30af2af003f054af4c749becbd7209ae33a77c3/hf_xet-1.6.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "responses", "version": "0.26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6d/86/ca7958de70cb0752350575e98229368a3a2f746a2942034b3364e17312bb/responses-0.26.3-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/ee/e4e10a94d51cd1ee638aa7e00b65399e6b2a4e8376ab6d2eac9f95586671/charset_normalizer-3.5.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-httpx", "version": "0.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/55/1fa65f8e4fceb19dd6daa867c162ad845d547f6058cd92b4b02384a44777/pytest_httpx-0.36.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "filelock", "version": "4.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/29/33/af0635ab07fe83b1788a1dbe370ff3e226062495a998335cb18a1cac81aa/filelock-4.0.1-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6c/c0/a98505f18594f1bce828bb159cec0fcf9860562f1a2c85913409fc8f3d9e/fsspec-2026.9.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/03/921a3d3c75785aca9ebfbfcabfbc3a1be12e2ab5265deb026d55a5a3f83e/tqdm-4.70.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}], "install_targets_hash": "8d3f9781d86e000603a20c010acf0233"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "typer", "version": "0.27.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/dc/bf/205d0004930ede8f542fb58f601526fccf4ae7626075ca1e6c4de5d3d652/typer-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "shellingham", "version": "1.5.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}], "install_targets_hash": "8ea02a85ddecd330a24e7e8daff773d1"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "typer", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/bf/205d0004930ede8f542fb58f601526fccf4ae7626075ca1e6c4de5d3d652/typer-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "shellingham", "version": "1.5.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}], "install_targets_hash": "8ea02a85ddecd330a24e7e8daff773d1"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "typer", "version": "0.27.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/dc/bf/205d0004930ede8f542fb58f601526fccf4ae7626075ca1e6c4de5d3d652/typer-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "shellingham", "version": "1.5.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}], "install_targets_hash": "8ea02a85ddecd330a24e7e8daff773d1"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "typer", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/bf/205d0004930ede8f542fb58f601526fccf4ae7626075ca1e6c4de5d3d652/typer-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "shellingham", "version": "1.5.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}], "install_targets_hash": "8ea02a85ddecd330a24e7e8daff773d1"} {"python_version": "3.14t", "dependencies": [{"metadata": {"name": "typer", "version": "0.27.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/dc/bf/205d0004930ede8f542fb58f601526fccf4ae7626075ca1e6c4de5d3d652/typer-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "shellingham", "version": "1.5.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}], "install_targets_hash": "8ea02a85ddecd330a24e7e8daff773d1"} {"python_version": "3.14t", "dependencies": [{"metadata": {"name": "typer", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/bf/205d0004930ede8f542fb58f601526fccf4ae7626075ca1e6c4de5d3d652/typer-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "shellingham", "version": "1.5.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}], "install_targets_hash": "8ea02a85ddecd330a24e7e8daff773d1"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "Quart", "version": "0.23.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/5c/c1/26dca56249da1a889ebb946000ab272712476209234f714ad3e8013ee005/quart-0.23.1-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "Hypercorn", "version": "0.18.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/93/35/850277d1b17b206bd10874c8a9a3f52e059452fb49bb0d22cbb908f6038b/hypercorn-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "h2", "version": "4.4.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/22/e85faf23bd72a92d1921e37d674ca56eb298a3c8be31fdecef0ff2b3aaac/h2-4.4.1-py3-none-any.whl"}}, {"metadata": {"name": "hpack", "version": "4.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/b4/4a9fcfb2aef6ba44d9073ecd301443aa00b3dac95de5619f2a7de7ec8a91/hpack-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "hyperframe", "version": "6.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/48/30/47d0bf6072f7252e6521f3447ccfa40b421b6824517f82854703d0f5a98b/hyperframe-6.1.0-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "wsproto", "version": "1.3.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a4/f5/10b68b7b1544245097b2a1b8238f66f2fc6dcaeb24ba5d917f52bd2eed4f/wsproto-1.3.2-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "priority", "version": "2.0.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/5e/5f/82c8074f7e84978129347c2c6ec8b6c59f3584ff1a20bc3c940a3e061790/priority-2.0.0-py3-none-any.whl"}}], "install_targets_hash": "9071d7bef95d0796e02e4622215f990f"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "Quart", "version": "0.23.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5c/c1/26dca56249da1a889ebb946000ab272712476209234f714ad3e8013ee005/quart-0.23.1-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "Hypercorn", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/35/850277d1b17b206bd10874c8a9a3f52e059452fb49bb0d22cbb908f6038b/hypercorn-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "h2", "version": "4.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/22/e85faf23bd72a92d1921e37d674ca56eb298a3c8be31fdecef0ff2b3aaac/h2-4.4.1-py3-none-any.whl"}}, {"metadata": {"name": "hpack", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/b4/4a9fcfb2aef6ba44d9073ecd301443aa00b3dac95de5619f2a7de7ec8a91/hpack-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "hyperframe", "version": "6.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/48/30/47d0bf6072f7252e6521f3447ccfa40b421b6824517f82854703d0f5a98b/hyperframe-6.1.0-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/09/c419f6f5a92e5fadde27efd190eca90f05e1261b10dbd8cbcb39cd8ea1dc/markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "wsproto", "version": "1.3.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a4/f5/10b68b7b1544245097b2a1b8238f66f2fc6dcaeb24ba5d917f52bd2eed4f/wsproto-1.3.2-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "priority", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5e/5f/82c8074f7e84978129347c2c6ec8b6c59f3584ff1a20bc3c940a3e061790/priority-2.0.0-py3-none-any.whl"}}], "install_targets_hash": "9071d7bef95d0796e02e4622215f990f"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "mcp", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/ff/8e7eade68b8a28f7da0ed1085544341b51f9c935dbf6b95c76b7edfea6a0/mcp-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mcp-types", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8f/d7/6ffba5d8cd5dd9b8a19478875c50e04945314ba5074e84d749283f27f62d/mcp_types-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/95/411ba65569158e862368917aaf56597f3e5fa3b91b0502919638465a08f3/httpx2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/74/d370e55600d9bcfa0d9794b0166126d49291a3d2b20c268fc98c453a4948/httpcore2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/6f/a04e900f465ff3221ccc395522503e2d10e79fa21f2723c8e177aae1e0d1/opentelemetry_api-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/02/bc19b47a96c2d3109760711acf22369e56bd7e405ca52f7ade164d2ead57/pydantic_core-2.46.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/97/672cb32ce0dfea44b740cb7b4f97038463b9cf7c0ead1aacf595572851d6/pyjwt-2.14.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/f0/424cb557d99aa86ac55da5e2add02e2882e44047b6264f93ade1b975a993/cryptography-50.0.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7d/47/5ecf1023850036e674c77ec4de86182d309ae344e39e7cba984b7df5d647/cffi-2.1.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/77bcb1168b33704908295533d27f10eb811e9e3e193e8993dc99572211d3/rpds_py-2026.6.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/6a/2ba3ed4a69babf3afdddf7d8314a48d87562c0a442206bbc2a1b50d5efc0/sse_starlette-3.4.11-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.53.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/76/18/0eea75741ee812e9f598b687619ce2454f6c3a1c5cd21ea990ec6bd26f45/uvicorn-0.53.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "92894b9de86e2bb0e11c5c76350def3a"} {"python_version": "3.14t", "dependencies": [{"metadata": {"name": "mcp", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/ff/8e7eade68b8a28f7da0ed1085544341b51f9c935dbf6b95c76b7edfea6a0/mcp-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mcp-types", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8f/d7/6ffba5d8cd5dd9b8a19478875c50e04945314ba5074e84d749283f27f62d/mcp_types-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/95/411ba65569158e862368917aaf56597f3e5fa3b91b0502919638465a08f3/httpx2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/74/d370e55600d9bcfa0d9794b0166126d49291a3d2b20c268fc98c453a4948/httpcore2-2.12.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/6f/a04e900f465ff3221ccc395522503e2d10e79fa21f2723c8e177aae1e0d1/opentelemetry_api-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/64/a4e536cb16d7f61a7fd3120b46c577fc7fa7325992f69c4f52bc786d77d8/pydantic_core-2.46.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/97/672cb32ce0dfea44b740cb7b4f97038463b9cf7c0ead1aacf595572851d6/pyjwt-2.14.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1a/01/0127d11a762b31a9ee0221894f540318761783f3fdc4bc5d057698caebd5/cryptography-50.0.1-cp314-cp314t-manylinux_2_34_x86_64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/95/eff5f0cee78d2eabc7eebffec40d3fc1876b5f3c95582e018bb4b99601f2/cffi-2.1.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8e/f4/b7ac49f30013aba8f7b9566b1dd07e81de95e708c1374b7bacc5b9bc5c9c/rpds_py-2026.6.3-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/6a/2ba3ed4a69babf3afdddf7d8314a48d87562c0a442206bbc2a1b50d5efc0/sse_starlette-3.4.11-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.52.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/79/4a20b54ab0491485ccd8c077db2d39187c7f12b3e15485d38a7be37c81b4/uvicorn-0.52.4-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "92894b9de86e2bb0e11c5c76350def3a"} {"python_version": "3.14t", "dependencies": [{"metadata": {"name": "Django", "version": "5.2.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/f8/ce120525ca78f12b07daf65786679c5d0b54a75285a8958d3ae55e39da35/django-5.2.17-py3-none-any.whl"}}, {"metadata": {"name": "coverage", "version": "7.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/d1/7f645fc2eccd318369a8a9948acc447bb7c1ade2911e31d3c5620544c22b/coverage-7.11.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "psycopg2-binary", "version": "2.9.12"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/60/a3624f79acea344c16fbef3a94d28b89a8042ddfb8f3e4ca83f538671409/psycopg2_binary-2.9.12.tar.gz"}}, {"metadata": {"name": "djangorestframework", "version": "3.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/d7/7461738e819b853275b35fd35712a85806c09a327e1fd5f8ff766bdd317e/djangorestframework-3.18.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-django", "version": "4.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/27/88/52db7a840fdbd74934f8df11b7450c9919ac00f61c02e88827f3d58180f7/pytest_django-4.13.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.7.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/18/f1/46d32fe4b9aae09fe397e768ff376d9b6bdbb4f11faaa727f163c3457b43/pytest_forked-1.7.5-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "channels", "version": "4.3.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/16/34/c32915288b7ef482377b6adc401192f98c6a99b3a145423d3b8aed807898/channels-4.3.2-py3-none-any.whl"}}, {"metadata": {"name": "asgiref", "version": "3.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c0/1b/54f4ad77cd8a584fa70746c47df988e002cf1ee1eba43364d46f87803647/asgiref-3.12.1-py3-none-any.whl"}}, {"metadata": {"name": "executing", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "daphne", "version": "4.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/0c/59e966c167880904f2e6a235c63169760dce58ba8062a7a153a6183539cc/daphne-4.2.3-py3-none-any.whl"}}, {"metadata": {"name": "autobahn", "version": "26.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/de/73/f109f563c27e048e45d135d81af19e6ca391e24905550b06bd1c9d674c57/autobahn-26.7.1.tar.gz"}}, {"metadata": {"name": "cbor2", "version": "6.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/41/3b28184154f6cbf7e47c1b7fb4a7a291c54f27a6f3a0a2f64b078c6a13e1/cbor2-6.1.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7d/47/5ecf1023850036e674c77ec4de86182d309ae344e39e7cba984b7df5d647/cffi-2.1.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c3/fb/951032a3bf22a5697c83183fb6294a4843772947a70e616c57b3ff5f522e/cryptography-50.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "hyperlink", "version": "21.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/aa/8caf6a0a3e62863cbb9dab27135660acba46903b703e224f14f447e57934/hyperlink-21.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "msgpack", "version": "1.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/74/0b797484013128837f3b1cbb6cea019277c4de4e377dc512b4d9a0f92940/msgpack-1.2.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "sqlparse", "version": "0.5.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/4b/359f28a903c13438ef59ebeee215fb25da53066db67b305c125f1c6d2a25/sqlparse-0.5.5-py3-none-any.whl"}}, {"metadata": {"name": "Twisted", "version": "26.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/57/bcf4e2370dd218c9aa68a9140a65d86729c73f1d529f7e94786c2766fc72/twisted-26.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "Automat", "version": "25.4.16"}, "download_info": {"url": "https://files.pythonhosted.org/packages/02/ff/1175b0b7371e46244032d43a56862d0af455823b5280a50c63d99cc50f18/automat-25.4.16-py3-none-any.whl"}}, {"metadata": {"name": "constantly", "version": "23.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b8/40/c199d095151addf69efdb4b9ca3a4f20f70e20508d6222bffb9b76f58573/constantly-23.10.4-py3-none-any.whl"}}, {"metadata": {"name": "Incremental", "version": "24.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1d/55/0f4df2a44053867ea9cbea73fc588b03c55605cd695cee0a3d86f0029cb2/incremental-24.11.0-py3-none-any.whl"}}, {"metadata": {"name": "pyOpenSSL", "version": "26.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ad/2cf6d3fa2fae5c79e1ed9960c0d42badd0f94d81dd12b50604cdc839e648/pyopenssl-26.4.0-py3-none-any.whl"}}, {"metadata": {"name": "service-identity", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/eb/2433e1af4ff903499144de4846569fb3300b816179ae99a03c2f011b666a/service_identity-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "txaio", "version": "26.6.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/91/68/075bf851e11c9ef65bd6a0426791f0d9a0c7dae0e7f6e0b16ca67334b456/txaio-26.6.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "5.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/e4/39862f0f7174ff07cfd1e2d0c9065ded34aeebdb7db8daf2f0e5bf89b46f/ujson-5.13.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "zope.interface", "version": "8.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f3/55/de0c3459ff717fce3342f9a29464c281fdeb0d36c3171ee88d119d5f0650/zope_interface-8.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "929f80d9f3977f1e1657f716043a13fa"} -{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "pydantic-ai", "version": "2.46.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/01/20a5fda50b3e30067450d43ecd7ac1ddf41055982540ee6a48626a4e748b/pydantic_ai-2.46.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-ai-slim", "version": "2.46.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8c/fc/6a28534bc4b27026225fec76b4a2cb97274a0bda601a90890676b09c5132/pydantic_ai_slim-2.46.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-evals", "version": "2.46.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/89/83921db264a4d76561c641dd785472e68877525848228876a949565dd6b2/pydantic_evals-2.46.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-graph", "version": "2.46.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8b/7d/711d5e3a1ca9f560a365080779858be76510ff615a5106121ba0430b5f55/pydantic_graph-2.46.0-py3-none-any.whl"}}, {"metadata": {"name": "fastmcp-slim", "version": "4.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ed/76/8dc551ef1f222bd146537ae100baf7441628aa1050494b567249ece997c2/fastmcp_slim-4.0.5-py3-none-any.whl"}}, {"metadata": {"name": "mcp", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/ff/8e7eade68b8a28f7da0ed1085544341b51f9c935dbf6b95c76b7edfea6a0/mcp-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mcp-types", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8f/d7/6ffba5d8cd5dd9b8a19478875c50e04945314ba5074e84d749283f27f62d/mcp_types-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "py-key-value-aio", "version": "0.4.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/46/12871550fb0613d149144bb9d41f22680d5f46717bc45a76eb5798c20c3f/py_key_value_aio-0.4.6-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofile", "version": "3.12.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/79/6e45e778c4c3cab39e0937b007b720c15f76c50c6453d153282d0fcc3588/aiofile-3.12.3-py3-none-any.whl"}}, {"metadata": {"name": "caio", "version": "0.12.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/25/81/6b86722be50975b80a636afebed5af1a6e6588afeff0ae1a0a7f8c262707/caio-0.12.4-cp314-cp314t-manylinux_2_34_x86_64.whl"}}, {"metadata": {"name": "anthropic", "version": "1.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c0/dc/74995efda028421917f4caabd24db1373ee0742573a2363fff1a21191441/anthropic-1.7.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/96/c1813dcca15c5a370145a448aaea7d1f83f6f0228a5f1130e79340ee385f/jiter-0.17.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/64/a4e536cb16d7f61a7fd3120b46c577fc7fa7325992f69c4f52bc786d77d8/pydantic_core-2.46.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "argcomplete", "version": "3.7.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/46/bd/551ee6af426af84ca33e02622be722925c196608e9127d731ef17c47f06e/argcomplete-3.7.2-py3-none-any.whl"}}, {"metadata": {"name": "Authlib", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b8/c6/6f124bcfbbfb20fba22c939b4e43a06dccfc0e1ca20e5634ca573cb1e271/authlib-1.8.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "beartype", "version": "0.22.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/cc/18245721fa7747065ab478316c7fea7c74777d07f37ae60db2e84f8172e8/beartype-0.22.9-py3-none-any.whl"}}, {"metadata": {"name": "cachetools", "version": "7.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cc/bb/1c6e7a89b11da19f137e4ef5a5c5fe47a5bb686449ba343944ccf8fb34b2/cachetools-7.2.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1a/01/0127d11a762b31a9ee0221894f540318761783f3fdc4bc5d057698caebd5/cryptography-50.0.1-cp314-cp314t-manylinux_2_34_x86_64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/95/eff5f0cee78d2eabc7eebffec40d3fc1876b5f3c95582e018bb4b99601f2/cffi-2.1.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "genai-prices", "version": "0.1.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d5/4a/9e04f3dca5ffe74133779ab5e9925ffb6411afbeac55d26fa0e148722599/genai_prices-0.1.7-py3-none-any.whl"}}, {"metadata": {"name": "google-genai", "version": "2.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/84/5b/87913fe392ba7b6402577259289ed3740c577956554a674b191a2971d33e/google_genai-2.24.0-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.58.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/59/13/477d90d09591b3938b45c4e11f4d8a51291682112cb5efcac961e815d562/google_auth-2.58.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/ee/e4e10a94d51cd1ee638aa7e00b65399e6b2a4e8376ab6d2eac9f95586671/charset_normalizer-3.5.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b2/39/26762f734113e22da2b942c3aca85798e0c0405d64c256549540ff31e5a1/websockets-16.1.1-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "griffelib", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/63/e876e789525063c840ccfa8857febdabd6523bcef9ce7eb979b9305ea895/griffelib-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "joserfc", "version": "1.7.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/c5/82addfd375e5ee6520644e0553e4aadde92d668c4fc99cc716d337fe7bb3/joserfc-1.7.5-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "keyring", "version": "25.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/db/e655086b7f3a705df045bf0933bdd9c2f79bb3c97bfef1384598bb79a217/keyring-25.7.0-py3-none-any.whl"}}, {"metadata": {"name": "jeepney", "version": "0.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b2/a3/e137168c9c44d18eff0376253da9f1e9234d0239e0ee230d2fee6cea8e55/jeepney-0.9.0-py3-none-any.whl"}}, {"metadata": {"name": "logfire", "version": "5.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cd/02/b32c3d5c298e4a9010694d261fb82c2c672747c0bf2b47bffda484aef349/logfire-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-exporter-otlp-proto-http", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cd/d0/fdeb1a98d8d3a6205f5f297c51b4a9bfe65126ab60339669bbe3dd54c2e2/opentelemetry_exporter_otlp_proto_http-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-exporter-otlp-proto-common", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5e/71/65fd9d54c10b860f87c045ccee1264cab7011268895d3528818a29c1172a/opentelemetry_exporter_otlp_proto_common-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-proto", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d1/7c/8be563d68e93bbefa5c8affb82ddcff91b3ad858ce49957ba7b16fd3e0ab/opentelemetry_proto-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "googleapis-common-protos", "version": "1.75.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1a/7a/7d79170c6ce6f12e109df2b3879d6b934010cf4f99aea8de8b7e5408c174/googleapis_common_protos-1.75.3-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/6f/a04e900f465ff3221ccc395522503e2d10e79fa21f2723c8e177aae1e0d1/opentelemetry_api-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-sdk", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e7/23/ff077e61886ee020a17ce9c8b6fa11c601c8d8345b09ea24f605445df62a/opentelemetry_sdk-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-semantic-conventions", "version": "0.65b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/0e/49df70d9b81fb5cbae4bbf2a49d865b09bcbcbc4eb53f5851b1027738d78/opentelemetry_semantic_conventions-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "protobuf", "version": "7.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e4/04/d52c7016b04b6c5108f26691f9d33ec82a9b65d041f1a9c771137693d618/protobuf-7.36.2-py3-none-any.whl"}}, {"metadata": {"name": "executing", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "logfire-api", "version": "5.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2d/51/123dab197fb08c0892e3bea1c2266bff159aa2ee82ad43bef93505859705/logfire_api-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "3.16.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/17/72/2b1fe3e303db76ab2ba0c2de2b57822869bcb588db82334d4ff3aea8acf2/openai-3.16.2-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-instrumentation", "version": "0.65b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/40/7b/85eab1215f72adf0e68d3dc4a679b9bff993fa679ff34cd8dd378e2659fd/opentelemetry_instrumentation-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "wrapt", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/a7/cca7fe0f26aa11cbbf09b2e6f4f774db167feeca43ad22fa1772afdccbad/wrapt-2.4.1-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl"}}, {"metadata": {"name": "opentelemetry-instrumentation-httpx", "version": "0.65b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/0f/c6144096b4914bbf44b43ba21c962e8f333ff045770b50a3e79ed8bd455f/opentelemetry_instrumentation_httpx-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-util-http", "version": "0.65b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/23/3f/ab8d29df207ce5f470a07fa96ebb48af4e95b7fab7e7635311b9a32f2fab/opentelemetry_util_http-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "platformdirs", "version": "4.11.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/39/be/3ae887e84c38c4dd1c549cd5825adc93f48069a94fe1cb8ac52a9da16f15/platformdirs-4.11.11-py3-none-any.whl"}}, {"metadata": {"name": "prompt_toolkit", "version": "3.0.53"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/6f/84908cad2d6aa5144abcf7b42709fe4fdb459bc640ec7ac5786e7693dabc/prompt_toolkit-3.0.53-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/3b/6163796d69c3977d1e4287bea4a6979161cbbdd170ebb430511e8e1999ce/pyasn1-0.6.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "email-validator", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "dnspython", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/97/672cb32ce0dfea44b740cb7b4f97038463b9cf7c0ead1aacf595572851d6/pyjwt-2.14.0-py3-none-any.whl"}}, {"metadata": {"name": "pyperclip", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/80/fc9d01d5ed37ba4c42ca2b55b4339ae6e200b456be3a1aaddf4a9fa99b8c/pyperclip-1.11.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8e/f4/b7ac49f30013aba8f7b9566b1dd07e81de95e708c1374b7bacc5b9bc5c9c/rpds_py-2026.6.3-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "SecretStorage", "version": "3.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/46/f5af3402b579fd5e11573ce652019a67074317e18c1935cc0b4ba9b35552/secretstorage-3.5.0-py3-none-any.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/6a/2ba3ed4a69babf3afdddf7d8314a48d87562c0a442206bbc2a1b50d5efc0/sse_starlette-3.4.11-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/e8/46de4400d5bf859f640feee85bd7e32235f68ddf25db53c63be78e581e3a/tiktoken-0.14.0-cp314-cp314t-manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.53.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/76/18/0eea75741ee812e9f598b687619ce2454f6c3a1c5cd21ea990ec6bd26f45/uvicorn-0.53.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/39/cc/9c0adc5861020de426ec71716b6c1bef8d90694b7d6d0a16202cdb1647f5/wcwidth-0.8.4-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.classes", "version": "3.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/66/b15ce62552d84bbfcec9a4873ab79d993a1dd4edb922cbfccae192bd5b5f/jaraco.classes-3.4.0-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.context", "version": "6.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f2/58/bc8954bda5fcda97bd7c19be11b85f91973d67a706ed4a3aec33e7de22db/jaraco_context-6.1.2-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.functools", "version": "4.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/02/36/ecc85bc96c273dc8a11273ed4782272975e6338d4a3e9228621175edf0e3/jaraco_functools-4.6.0-py3-none-any.whl"}}, {"metadata": {"name": "more-itertools", "version": "11.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/3d/1087453384dbde46a8c7f9356eead2c58be8a7bf156bca40243377c85715/more_itertools-11.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.9.10"}, "download_info": {"url": "https://files.pythonhosted.org/packages/86/38/49f8d6fd34fc1a9c75b5b96364ebdde702a8144e5ed63d2213c58d454c27/regex-2026.9.10-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}], "install_targets_hash": "99070e5a015df9ed8efe12e4aa3cf88a"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "Django", "version": "5.2.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/f8/ce120525ca78f12b07daf65786679c5d0b54a75285a8958d3ae55e39da35/django-5.2.17-py3-none-any.whl"}}, {"metadata": {"name": "coverage", "version": "7.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/d1/7f645fc2eccd318369a8a9948acc447bb7c1ade2911e31d3c5620544c22b/coverage-7.11.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "psycopg2-binary", "version": "2.9.12"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/60/a3624f79acea344c16fbef3a94d28b89a8042ddfb8f3e4ca83f538671409/psycopg2_binary-2.9.12.tar.gz"}}, {"metadata": {"name": "djangorestframework", "version": "3.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/d7/7461738e819b853275b35fd35712a85806c09a327e1fd5f8ff766bdd317e/djangorestframework-3.18.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-django", "version": "4.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/27/88/52db7a840fdbd74934f8df11b7450c9919ac00f61c02e88827f3d58180f7/pytest_django-4.13.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.7.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/18/f1/46d32fe4b9aae09fe397e768ff376d9b6bdbb4f11faaa727f163c3457b43/pytest_forked-1.7.5-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "channels", "version": "4.3.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/16/34/c32915288b7ef482377b6adc401192f98c6a99b3a145423d3b8aed807898/channels-4.3.2-py3-none-any.whl"}}, {"metadata": {"name": "asgiref", "version": "3.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c0/1b/54f4ad77cd8a584fa70746c47df988e002cf1ee1eba43364d46f87803647/asgiref-3.12.1-py3-none-any.whl"}}, {"metadata": {"name": "executing", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "daphne", "version": "4.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/0c/59e966c167880904f2e6a235c63169760dce58ba8062a7a153a6183539cc/daphne-4.2.3-py3-none-any.whl"}}, {"metadata": {"name": "autobahn", "version": "26.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/de/73/f109f563c27e048e45d135d81af19e6ca391e24905550b06bd1c9d674c57/autobahn-26.7.1.tar.gz"}}, {"metadata": {"name": "cbor2", "version": "6.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/41/3b28184154f6cbf7e47c1b7fb4a7a291c54f27a6f3a0a2f64b078c6a13e1/cbor2-6.1.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7d/47/5ecf1023850036e674c77ec4de86182d309ae344e39e7cba984b7df5d647/cffi-2.1.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c3/fb/951032a3bf22a5697c83183fb6294a4843772947a70e616c57b3ff5f522e/cryptography-50.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "hyperlink", "version": "21.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/aa/8caf6a0a3e62863cbb9dab27135660acba46903b703e224f14f447e57934/hyperlink-21.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "msgpack", "version": "1.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/74/0b797484013128837f3b1cbb6cea019277c4de4e377dc512b4d9a0f92940/msgpack-1.2.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "sqlparse", "version": "0.5.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/4b/359f28a903c13438ef59ebeee215fb25da53066db67b305c125f1c6d2a25/sqlparse-0.5.5-py3-none-any.whl"}}, {"metadata": {"name": "Twisted", "version": "26.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/57/bcf4e2370dd218c9aa68a9140a65d86729c73f1d529f7e94786c2766fc72/twisted-26.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "Automat", "version": "25.4.16"}, "download_info": {"url": "https://files.pythonhosted.org/packages/02/ff/1175b0b7371e46244032d43a56862d0af455823b5280a50c63d99cc50f18/automat-25.4.16-py3-none-any.whl"}}, {"metadata": {"name": "constantly", "version": "23.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b8/40/c199d095151addf69efdb4b9ca3a4f20f70e20508d6222bffb9b76f58573/constantly-23.10.4-py3-none-any.whl"}}, {"metadata": {"name": "Incremental", "version": "24.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1d/55/0f4df2a44053867ea9cbea73fc588b03c55605cd695cee0a3d86f0029cb2/incremental-24.11.0-py3-none-any.whl"}}, {"metadata": {"name": "pyOpenSSL", "version": "26.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ad/2cf6d3fa2fae5c79e1ed9960c0d42badd0f94d81dd12b50604cdc839e648/pyopenssl-26.4.0-py3-none-any.whl"}}, {"metadata": {"name": "service-identity", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/eb/2433e1af4ff903499144de4846569fb3300b816179ae99a03c2f011b666a/service_identity-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "txaio", "version": "26.6.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/91/68/075bf851e11c9ef65bd6a0426791f0d9a0c7dae0e7f6e0b16ca67334b456/txaio-26.6.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "5.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/e4/39862f0f7174ff07cfd1e2d0c9065ded34aeebdb7db8daf2f0e5bf89b46f/ujson-5.13.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "zope.interface", "version": "8.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f3/55/de0c3459ff717fce3342f9a29464c281fdeb0d36c3171ee88d119d5f0650/zope_interface-8.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "929f80d9f3977f1e1657f716043a13fa"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "Django", "version": "5.2.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/f8/ce120525ca78f12b07daf65786679c5d0b54a75285a8958d3ae55e39da35/django-5.2.17-py3-none-any.whl"}}, {"metadata": {"name": "coverage", "version": "7.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/d1/7f645fc2eccd318369a8a9948acc447bb7c1ade2911e31d3c5620544c22b/coverage-7.11.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "psycopg2-binary", "version": "2.9.12"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/60/a3624f79acea344c16fbef3a94d28b89a8042ddfb8f3e4ca83f538671409/psycopg2_binary-2.9.12.tar.gz"}}, {"metadata": {"name": "djangorestframework", "version": "3.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/d7/7461738e819b853275b35fd35712a85806c09a327e1fd5f8ff766bdd317e/djangorestframework-3.18.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-django", "version": "4.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/27/88/52db7a840fdbd74934f8df11b7450c9919ac00f61c02e88827f3d58180f7/pytest_django-4.13.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.7.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/18/f1/46d32fe4b9aae09fe397e768ff376d9b6bdbb4f11faaa727f163c3457b43/pytest_forked-1.7.5-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "channels", "version": "4.3.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/16/34/c32915288b7ef482377b6adc401192f98c6a99b3a145423d3b8aed807898/channels-4.3.2-py3-none-any.whl"}}, {"metadata": {"name": "asgiref", "version": "3.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c0/1b/54f4ad77cd8a584fa70746c47df988e002cf1ee1eba43364d46f87803647/asgiref-3.12.1-py3-none-any.whl"}}, {"metadata": {"name": "executing", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "daphne", "version": "4.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/0c/59e966c167880904f2e6a235c63169760dce58ba8062a7a153a6183539cc/daphne-4.2.3-py3-none-any.whl"}}, {"metadata": {"name": "autobahn", "version": "26.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/de/73/f109f563c27e048e45d135d81af19e6ca391e24905550b06bd1c9d674c57/autobahn-26.7.1.tar.gz"}}, {"metadata": {"name": "cbor2", "version": "6.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/41/3b28184154f6cbf7e47c1b7fb4a7a291c54f27a6f3a0a2f64b078c6a13e1/cbor2-6.1.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7d/47/5ecf1023850036e674c77ec4de86182d309ae344e39e7cba984b7df5d647/cffi-2.1.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c3/fb/951032a3bf22a5697c83183fb6294a4843772947a70e616c57b3ff5f522e/cryptography-50.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "hyperlink", "version": "21.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/aa/8caf6a0a3e62863cbb9dab27135660acba46903b703e224f14f447e57934/hyperlink-21.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "msgpack", "version": "1.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/74/0b797484013128837f3b1cbb6cea019277c4de4e377dc512b4d9a0f92940/msgpack-1.2.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "sqlparse", "version": "0.5.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/4b/359f28a903c13438ef59ebeee215fb25da53066db67b305c125f1c6d2a25/sqlparse-0.5.5-py3-none-any.whl"}}, {"metadata": {"name": "Twisted", "version": "26.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/57/bcf4e2370dd218c9aa68a9140a65d86729c73f1d529f7e94786c2766fc72/twisted-26.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "Automat", "version": "25.4.16"}, "download_info": {"url": "https://files.pythonhosted.org/packages/02/ff/1175b0b7371e46244032d43a56862d0af455823b5280a50c63d99cc50f18/automat-25.4.16-py3-none-any.whl"}}, {"metadata": {"name": "constantly", "version": "23.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b8/40/c199d095151addf69efdb4b9ca3a4f20f70e20508d6222bffb9b76f58573/constantly-23.10.4-py3-none-any.whl"}}, {"metadata": {"name": "Incremental", "version": "24.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1d/55/0f4df2a44053867ea9cbea73fc588b03c55605cd695cee0a3d86f0029cb2/incremental-24.11.0-py3-none-any.whl"}}, {"metadata": {"name": "pyOpenSSL", "version": "26.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ad/2cf6d3fa2fae5c79e1ed9960c0d42badd0f94d81dd12b50604cdc839e648/pyopenssl-26.4.0-py3-none-any.whl"}}, {"metadata": {"name": "service-identity", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/eb/2433e1af4ff903499144de4846569fb3300b816179ae99a03c2f011b666a/service_identity-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "txaio", "version": "26.6.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/91/68/075bf851e11c9ef65bd6a0426791f0d9a0c7dae0e7f6e0b16ca67334b456/txaio-26.6.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "5.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/e4/39862f0f7174ff07cfd1e2d0c9065ded34aeebdb7db8daf2f0e5bf89b46f/ujson-5.13.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "zope.interface", "version": "8.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f3/55/de0c3459ff717fce3342f9a29464c281fdeb0d36c3171ee88d119d5f0650/zope_interface-8.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "929f80d9f3977f1e1657f716043a13fa"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "google-genai", "version": "1.75.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2d/b6/552d40e96da22921eb1fead7c14b00b5b5473a20e45959488660fab35ee2/google_genai-1.75.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.55.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/1d/f6d3ca1ad0725f2e08a1c6915640748a52de2e66596160a4d53b010cccf0/google_auth-2.55.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/74/9b/6158d4e459b984f949dcbbb0c5d270154c7618e11c01029b9bbd1bb4c4f9/websockets-16.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/9e/db72b3ae7fc9cfad53e630e56c6ae83b9b6ff0bf3718ffb8012d20b3aabf/cryptography-49.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/a0/7d793dce3fa811fe047d6ae2431c672364b462850c6235ae306c0efd025f/pyasn1-0.6.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "a021ecf98104048960d17180bcdfc8fa"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "google-genai", "version": "1.75.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2d/b6/552d40e96da22921eb1fead7c14b00b5b5473a20e45959488660fab35ee2/google_genai-1.75.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.55.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/1d/f6d3ca1ad0725f2e08a1c6915640748a52de2e66596160a4d53b010cccf0/google_auth-2.55.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/74/9b/6158d4e459b984f949dcbbb0c5d270154c7618e11c01029b9bbd1bb4c4f9/websockets-16.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/9e/db72b3ae7fc9cfad53e630e56c6ae83b9b6ff0bf3718ffb8012d20b3aabf/cryptography-49.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/a0/7d793dce3fa811fe047d6ae2431c672364b462850c6235ae306c0efd025f/pyasn1-0.6.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "a021ecf98104048960d17180bcdfc8fa"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "google-genai", "version": "1.75.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2d/b6/552d40e96da22921eb1fead7c14b00b5b5473a20e45959488660fab35ee2/google_genai-1.75.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.55.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/1d/f6d3ca1ad0725f2e08a1c6915640748a52de2e66596160a4d53b010cccf0/google_auth-2.55.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/74/9b/6158d4e459b984f949dcbbb0c5d270154c7618e11c01029b9bbd1bb4c4f9/websockets-16.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/9e/db72b3ae7fc9cfad53e630e56c6ae83b9b6ff0bf3718ffb8012d20b3aabf/cryptography-49.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/a0/7d793dce3fa811fe047d6ae2431c672364b462850c6235ae306c0efd025f/pyasn1-0.6.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "a021ecf98104048960d17180bcdfc8fa"} {"python_version": "3.14t", "dependencies": [{"metadata": {"name": "google-genai", "version": "1.75.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2d/b6/552d40e96da22921eb1fead7c14b00b5b5473a20e45959488660fab35ee2/google_genai-1.75.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.55.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/1d/f6d3ca1ad0725f2e08a1c6915640748a52de2e66596160a4d53b010cccf0/google_auth-2.55.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/74/9b/6158d4e459b984f949dcbbb0c5d270154c7618e11c01029b9bbd1bb4c4f9/websockets-16.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/9e/db72b3ae7fc9cfad53e630e56c6ae83b9b6ff0bf3718ffb8012d20b3aabf/cryptography-49.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/a0/7d793dce3fa811fe047d6ae2431c672364b462850c6235ae306c0efd025f/pyasn1-0.6.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "a021ecf98104048960d17180bcdfc8fa"} -{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "openai", "version": "3.16.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/17/72/2b1fe3e303db76ab2ba0c2de2b57822869bcb588db82334d4ff3aea8acf2/openai-3.16.2-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/96/c1813dcca15c5a370145a448aaea7d1f83f6f0228a5f1130e79340ee385f/jiter-0.17.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/64/a4e536cb16d7f61a7fd3120b46c577fc7fa7325992f69c4f52bc786d77d8/pydantic_core-2.46.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/e8/46de4400d5bf859f640feee85bd7e32235f68ddf25db53c63be78e581e3a/tiktoken-0.14.0-cp314-cp314t-manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.9.10"}, "download_info": {"url": "https://files.pythonhosted.org/packages/86/38/49f8d6fd34fc1a9c75b5b96364ebdde702a8144e5ed63d2213c58d454c27/regex-2026.9.10-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/ee/e4e10a94d51cd1ee638aa7e00b65399e6b2a4e8376ab6d2eac9f95586671/charset_normalizer-3.5.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "urllib3", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "ac0b70b42bbda50724e182bcf918e944"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "google-genai", "version": "1.75.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2d/b6/552d40e96da22921eb1fead7c14b00b5b5473a20e45959488660fab35ee2/google_genai-1.75.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.55.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/1d/f6d3ca1ad0725f2e08a1c6915640748a52de2e66596160a4d53b010cccf0/google_auth-2.55.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/74/9b/6158d4e459b984f949dcbbb0c5d270154c7618e11c01029b9bbd1bb4c4f9/websockets-16.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/9e/db72b3ae7fc9cfad53e630e56c6ae83b9b6ff0bf3718ffb8012d20b3aabf/cryptography-49.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/a0/7d793dce3fa811fe047d6ae2431c672364b462850c6235ae306c0efd025f/pyasn1-0.6.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "a021ecf98104048960d17180bcdfc8fa"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "google-genai", "version": "1.75.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2d/b6/552d40e96da22921eb1fead7c14b00b5b5473a20e45959488660fab35ee2/google_genai-1.75.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.55.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/1d/f6d3ca1ad0725f2e08a1c6915640748a52de2e66596160a4d53b010cccf0/google_auth-2.55.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/74/9b/6158d4e459b984f949dcbbb0c5d270154c7618e11c01029b9bbd1bb4c4f9/websockets-16.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/9e/db72b3ae7fc9cfad53e630e56c6ae83b9b6ff0bf3718ffb8012d20b3aabf/cryptography-49.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/a0/7d793dce3fa811fe047d6ae2431c672364b462850c6235ae306c0efd025f/pyasn1-0.6.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "a021ecf98104048960d17180bcdfc8fa"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "google-genai", "version": "1.75.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2d/b6/552d40e96da22921eb1fead7c14b00b5b5473a20e45959488660fab35ee2/google_genai-1.75.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.55.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/1d/f6d3ca1ad0725f2e08a1c6915640748a52de2e66596160a4d53b010cccf0/google_auth-2.55.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/74/9b/6158d4e459b984f949dcbbb0c5d270154c7618e11c01029b9bbd1bb4c4f9/websockets-16.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/9e/db72b3ae7fc9cfad53e630e56c6ae83b9b6ff0bf3718ffb8012d20b3aabf/cryptography-49.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/a0/7d793dce3fa811fe047d6ae2431c672364b462850c6235ae306c0efd025f/pyasn1-0.6.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "a021ecf98104048960d17180bcdfc8fa"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "google-genai", "version": "1.75.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2d/b6/552d40e96da22921eb1fead7c14b00b5b5473a20e45959488660fab35ee2/google_genai-1.75.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.55.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/1d/f6d3ca1ad0725f2e08a1c6915640748a52de2e66596160a4d53b010cccf0/google_auth-2.55.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/74/9b/6158d4e459b984f949dcbbb0c5d270154c7618e11c01029b9bbd1bb4c4f9/websockets-16.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/9e/db72b3ae7fc9cfad53e630e56c6ae83b9b6ff0bf3718ffb8012d20b3aabf/cryptography-49.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/a0/7d793dce3fa811fe047d6ae2431c672364b462850c6235ae306c0efd025f/pyasn1-0.6.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "a021ecf98104048960d17180bcdfc8fa"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "google-genai", "version": "1.75.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2d/b6/552d40e96da22921eb1fead7c14b00b5b5473a20e45959488660fab35ee2/google_genai-1.75.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.55.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/1d/f6d3ca1ad0725f2e08a1c6915640748a52de2e66596160a4d53b010cccf0/google_auth-2.55.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/74/9b/6158d4e459b984f949dcbbb0c5d270154c7618e11c01029b9bbd1bb4c4f9/websockets-16.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/9e/db72b3ae7fc9cfad53e630e56c6ae83b9b6ff0bf3718ffb8012d20b3aabf/cryptography-49.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/a0/7d793dce3fa811fe047d6ae2431c672364b462850c6235ae306c0efd025f/pyasn1-0.6.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "a021ecf98104048960d17180bcdfc8fa"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "Django", "version": "6.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8d/ca/c1040a4fd15754ede7df15fd72fc2e123045b473b253ab5f5284e11c651e/django-6.1.1-py3-none-any.whl"}}, {"metadata": {"name": "asgiref", "version": "3.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c0/1b/54f4ad77cd8a584fa70746c47df988e002cf1ee1eba43364d46f87803647/asgiref-3.12.1-py3-none-any.whl"}}, {"metadata": {"name": "sqlparse", "version": "0.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d9/50/f00935da0ec7cbf325f8dc4f772ae46fbc7b672dd62876e73f0a94adda57/sqlparse-0.6.0-py3-none-any.whl"}}], "install_targets_hash": "a2d04aad7c78ba34e161b0d9df99ca52"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "cohere", "version": "7.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/4a/c3/064a44c498bf6ae8621caa14307d3ef5471157f149e33cfd64417c8e9ad3/cohere-7.1.1-py3-none-any.whl"}}, {"metadata": {"name": "fastavro", "version": "1.12.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/dd/8f/18f60329b627d2118a4a2b19e8741fbd807d60bf0470554e1bbfb7f1bca3/fastavro-1.12.2-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/1c/6c/c73fa9d5a85f6ab05395de61c5f6984e0a9ff40bb5ff888d46dff02526c6/charset_normalizer-3.5.1-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "tokenizers", "version": "0.23.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c1/60/21f715d9faba5f5407ff759472ade058ec4a507ad62bcea47cb847239a73/tokenizers-0.23.1.tar.gz"}}, {"metadata": {"name": "huggingface_hub", "version": "1.29.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/4e/a5/47c2ea9b228ccbcba8467e9a64823146e8ebbad29855e591d8f5eedcc9c7/huggingface_hub-1.29.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/bb/1e/c0ad437dd267a8e435bef594acf781bbc3874ff0b6435b4962d03ecf7cc4/hf_xet-1.6.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "types-requests", "version": "2.33.0.20260712"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/62/e7/010c87f559e216d83f9dc51e939633fd0d0ead3377340181ab0e223cd3b5/types_requests-2.33.0.20260712-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "filelock", "version": "3.32.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/36/d2/b70a31e13d04456d28493f31d2aa087e99eeb2767ef0293b2625727ccb8c/filelock-3.32.5-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.7.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/fd/3c/6a2bf344106328fd04963664a60b9bb6496fc25df8e962fcdc1367285fb9/fsspec-2026.7.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c5/02/bc19b47a96c2d3109760711acf22369e56bd7e405ca52f7ade164d2ead57/pydantic_core-2.46.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}], "install_targets_hash": "ab733f16537c82282cb23e3e0416c9fc"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "arq", "version": "0.28.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/48/32/66b616976c5058d434ca2017979bfffd784888177b16b5038abcec93954a/arq-0.28.0-py3-none-any.whl"}}, {"metadata": {"name": "redis", "version": "5.3.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7f/26/5c5fa0e83c3621db835cfc1f1d789b37e7fa99ed54423b5f519beb931aa7/redis-5.3.1-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "hiredis", "version": "3.4.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/69/be/327f1a953aefa5e0eaa8c7d6ed434cfc80e1906b96177eac7c86009395d2/hiredis-3.4.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.14.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/9c/97/672cb32ce0dfea44b740cb7b4f97038463b9cf7c0ead1aacf595572851d6/pyjwt-2.14.0-py3-none-any.whl"}}], "install_targets_hash": "ad9ed2e2d11b84f59088d48b987545ae"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "ariadne", "version": "1.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/f6/48/e0bd1918ef56b1a570dfc1882a036286bf4b3f13e5a659a8d9e16d888c69/ariadne-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.12"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/4e/b6/304c572e79b9e82982dbd5091e26a89f5018e565868091d804c2142f6ba5/graphql_core-3.2.12-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}], "install_targets_hash": "b09b43868333d163115ddb43082c46cd"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/d8/8ec0e471248c500acdce2be3f46db8fb62b5eb60efef072529cc85ee1d26/aiohttp-3.14.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ff/0b/cfb76b7fe99686db264bff829779a539d923e7564ffd7ef18da6c54c3774/yarl-1.24.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-aiohttp", "version": "1.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fa/b0/5056ed4c3f68a4db2b4a39fb0ec61b1e4cf1d89ee14effe5261cc587264c/pytest_aiohttp-1.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/73/daf935ea7048ddd7ec8eec5345b4a40b619d2d178b3c0a0900796bc3c794/propcache-0.5.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "b580cd1bfd98254876a1e968bf8d9af2"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/d8/8ec0e471248c500acdce2be3f46db8fb62b5eb60efef072529cc85ee1d26/aiohttp-3.14.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ff/0b/cfb76b7fe99686db264bff829779a539d923e7564ffd7ef18da6c54c3774/yarl-1.24.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-aiohttp", "version": "1.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fa/b0/5056ed4c3f68a4db2b4a39fb0ec61b1e4cf1d89ee14effe5261cc587264c/pytest_aiohttp-1.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/73/daf935ea7048ddd7ec8eec5345b4a40b619d2d178b3c0a0900796bc3c794/propcache-0.5.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "b580cd1bfd98254876a1e968bf8d9af2"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/d8/8ec0e471248c500acdce2be3f46db8fb62b5eb60efef072529cc85ee1d26/aiohttp-3.14.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ff/0b/cfb76b7fe99686db264bff829779a539d923e7564ffd7ef18da6c54c3774/yarl-1.24.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-aiohttp", "version": "1.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fa/b0/5056ed4c3f68a4db2b4a39fb0ec61b1e4cf1d89ee14effe5261cc587264c/pytest_aiohttp-1.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/73/daf935ea7048ddd7ec8eec5345b4a40b619d2d178b3c0a0900796bc3c794/propcache-0.5.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "b580cd1bfd98254876a1e968bf8d9af2"} {"python_version": "3.14t", "dependencies": [{"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/d8/8ec0e471248c500acdce2be3f46db8fb62b5eb60efef072529cc85ee1d26/aiohttp-3.14.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ff/0b/cfb76b7fe99686db264bff829779a539d923e7564ffd7ef18da6c54c3774/yarl-1.24.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-aiohttp", "version": "1.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fa/b0/5056ed4c3f68a4db2b4a39fb0ec61b1e4cf1d89ee14effe5261cc587264c/pytest_aiohttp-1.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/73/daf935ea7048ddd7ec8eec5345b4a40b619d2d178b3c0a0900796bc3c794/propcache-0.5.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "b580cd1bfd98254876a1e968bf8d9af2"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/d8/8ec0e471248c500acdce2be3f46db8fb62b5eb60efef072529cc85ee1d26/aiohttp-3.14.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ff/0b/cfb76b7fe99686db264bff829779a539d923e7564ffd7ef18da6c54c3774/yarl-1.24.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-aiohttp", "version": "1.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fa/b0/5056ed4c3f68a4db2b4a39fb0ec61b1e4cf1d89ee14effe5261cc587264c/pytest_aiohttp-1.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/73/daf935ea7048ddd7ec8eec5345b4a40b619d2d178b3c0a0900796bc3c794/propcache-0.5.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "b580cd1bfd98254876a1e968bf8d9af2"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/d8/8ec0e471248c500acdce2be3f46db8fb62b5eb60efef072529cc85ee1d26/aiohttp-3.14.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ff/0b/cfb76b7fe99686db264bff829779a539d923e7564ffd7ef18da6c54c3774/yarl-1.24.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-aiohttp", "version": "1.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fa/b0/5056ed4c3f68a4db2b4a39fb0ec61b1e4cf1d89ee14effe5261cc587264c/pytest_aiohttp-1.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/73/daf935ea7048ddd7ec8eec5345b4a40b619d2d178b3c0a0900796bc3c794/propcache-0.5.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "b580cd1bfd98254876a1e968bf8d9af2"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/d8/8ec0e471248c500acdce2be3f46db8fb62b5eb60efef072529cc85ee1d26/aiohttp-3.14.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ff/0b/cfb76b7fe99686db264bff829779a539d923e7564ffd7ef18da6c54c3774/yarl-1.24.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-aiohttp", "version": "1.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fa/b0/5056ed4c3f68a4db2b4a39fb0ec61b1e4cf1d89ee14effe5261cc587264c/pytest_aiohttp-1.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/73/daf935ea7048ddd7ec8eec5345b4a40b619d2d178b3c0a0900796bc3c794/propcache-0.5.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "b580cd1bfd98254876a1e968bf8d9af2"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "aiohttp", "version": "3.14.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/d8/8ec0e471248c500acdce2be3f46db8fb62b5eb60efef072529cc85ee1d26/aiohttp-3.14.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ff/0b/cfb76b7fe99686db264bff829779a539d923e7564ffd7ef18da6c54c3774/yarl-1.24.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-aiohttp", "version": "1.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fa/b0/5056ed4c3f68a4db2b4a39fb0ec61b1e4cf1d89ee14effe5261cc587264c/pytest_aiohttp-1.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/73/daf935ea7048ddd7ec8eec5345b4a40b619d2d178b3c0a0900796bc3c794/propcache-0.5.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "b580cd1bfd98254876a1e968bf8d9af2"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "huggingface_hub", "version": "1.32.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/cf/d98dd561d6d0d7b7d7a64d1563f8aaaa7c235daee41c1c9bcc3da62420ed/huggingface_hub-1.32.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d5/ee/7c0d7b6ab336167531b1c30af2af003f054af4c749becbd7209ae33a77c3/hf_xet-1.6.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "filelock", "version": "4.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/29/33/af0635ab07fe83b1788a1dbe370ff3e226062495a998335cb18a1cac81aa/filelock-4.0.1-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2026.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6c/c0/a98505f18594f1bce828bb159cec0fcf9860562f1a2c85913409fc8f3d9e/fsspec-2026.9.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/03/921a3d3c75785aca9ebfbfcabfbc3a1be12e2ab5265deb026d55a5a3f83e/tqdm-4.70.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}], "install_targets_hash": "b9b57b5ff4946cecf977840d5e2f8da1"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "anthropic", "version": "0.125.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2f/1a/b1bd30cda3790557e8791bec5922a6ec8fabb6fa8b008c76a39cf7be6152/anthropic-0.125.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/6b/59127338b86d9fe4d99418f5a15118bea778103ee0fe9d9dd7e0af174e95/jiter-0.16.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}], "install_targets_hash": "b9d5615a233ee3aa1b26a51b480fe0a3"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "sanic", "version": "25.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/91/5ecd9a91374a7b2831cf183357ceeb609fdfc8b390adb5cac90a261fe1f8/sanic-25.12.1-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/85/dc/549a807a53c13fd4a8dac286f117a7a71260defea9ec0c05d6027f2ae273/websockets-10.4.tar.gz"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/c8/14ce60ec31a2e5f5274bb17d383a6f7a3aabca31ac04eee05585bbadab16/aiohttp-3.14.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/b2/845cf2074a015e6fe0d0808cf1a2d9e868386c4220d657ebd8302b199043/yarl-1.24.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-testing", "version": "24.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/93/1d588f1cb9b710b9f22fa78b53d699a8062edc94204d50dd0d78c5f5b495/sanic_testing-24.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "html5tagger", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/12/2f5d43ee912ea14a6baba4b3db6d309b02d932e3b7074c3339b4aded98ff/html5tagger-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "httptools", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/b0/312a062ae741ae3e8baa8c8bf20be81b2e67337b259ab4349bebc7b6142e/httptools-0.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/73/daf935ea7048ddd7ec8eec5345b4a40b619d2d178b3c0a0900796bc3c794/propcache-0.5.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-routing", "version": "23.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/e3/3425c9a8773807ac2c01d6a56c8521733f09b627e5827e733c5cd36b9ac5/sanic_routing-23.12.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "83.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/40/e1e72872c6354b306daef1703549e8e83b4d43cfea356311bf722a043752/setuptools-83.0.0-py3-none-any.whl"}}, {"metadata": {"name": "tracerite", "version": "2.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b6/62/3f385a67ff3cc91209f107d20bbebdecf7a4e4aba55a43f9f71bddc424a9/tracerite-2.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "5.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/e4/39862f0f7174ff07cfd1e2d0c9065ded34aeebdb7db8daf2f0e5bf89b46f/ujson-5.13.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "uvloop", "version": "0.22.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/7b/b01414f31546caf0919da80ad57cbfe24c56b151d12af68cee1b04922ca8/uvloop-0.22.1-cp314-cp314t-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}], "install_targets_hash": "bdb1f2a8b2b051b4d694fd87001bee9b"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "sanic", "version": "25.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/91/5ecd9a91374a7b2831cf183357ceeb609fdfc8b390adb5cac90a261fe1f8/sanic-25.12.1-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/85/dc/549a807a53c13fd4a8dac286f117a7a71260defea9ec0c05d6027f2ae273/websockets-10.4.tar.gz"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/c8/14ce60ec31a2e5f5274bb17d383a6f7a3aabca31ac04eee05585bbadab16/aiohttp-3.14.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/b2/845cf2074a015e6fe0d0808cf1a2d9e868386c4220d657ebd8302b199043/yarl-1.24.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-testing", "version": "24.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/93/1d588f1cb9b710b9f22fa78b53d699a8062edc94204d50dd0d78c5f5b495/sanic_testing-24.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "html5tagger", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/12/2f5d43ee912ea14a6baba4b3db6d309b02d932e3b7074c3339b4aded98ff/html5tagger-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "httptools", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/b0/312a062ae741ae3e8baa8c8bf20be81b2e67337b259ab4349bebc7b6142e/httptools-0.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/73/daf935ea7048ddd7ec8eec5345b4a40b619d2d178b3c0a0900796bc3c794/propcache-0.5.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-routing", "version": "23.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/e3/3425c9a8773807ac2c01d6a56c8521733f09b627e5827e733c5cd36b9ac5/sanic_routing-23.12.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "83.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/40/e1e72872c6354b306daef1703549e8e83b4d43cfea356311bf722a043752/setuptools-83.0.0-py3-none-any.whl"}}, {"metadata": {"name": "tracerite", "version": "2.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b6/62/3f385a67ff3cc91209f107d20bbebdecf7a4e4aba55a43f9f71bddc424a9/tracerite-2.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "5.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/e4/39862f0f7174ff07cfd1e2d0c9065ded34aeebdb7db8daf2f0e5bf89b46f/ujson-5.13.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "uvloop", "version": "0.22.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/7b/b01414f31546caf0919da80ad57cbfe24c56b151d12af68cee1b04922ca8/uvloop-0.22.1-cp314-cp314t-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}], "install_targets_hash": "bdb1f2a8b2b051b4d694fd87001bee9b"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "sanic", "version": "25.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/91/5ecd9a91374a7b2831cf183357ceeb609fdfc8b390adb5cac90a261fe1f8/sanic-25.12.1-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/85/dc/549a807a53c13fd4a8dac286f117a7a71260defea9ec0c05d6027f2ae273/websockets-10.4.tar.gz"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/c8/14ce60ec31a2e5f5274bb17d383a6f7a3aabca31ac04eee05585bbadab16/aiohttp-3.14.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/b2/845cf2074a015e6fe0d0808cf1a2d9e868386c4220d657ebd8302b199043/yarl-1.24.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-testing", "version": "24.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/93/1d588f1cb9b710b9f22fa78b53d699a8062edc94204d50dd0d78c5f5b495/sanic_testing-24.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "html5tagger", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/12/2f5d43ee912ea14a6baba4b3db6d309b02d932e3b7074c3339b4aded98ff/html5tagger-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "httptools", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/b0/312a062ae741ae3e8baa8c8bf20be81b2e67337b259ab4349bebc7b6142e/httptools-0.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/73/daf935ea7048ddd7ec8eec5345b4a40b619d2d178b3c0a0900796bc3c794/propcache-0.5.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-routing", "version": "23.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/e3/3425c9a8773807ac2c01d6a56c8521733f09b627e5827e733c5cd36b9ac5/sanic_routing-23.12.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "83.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/40/e1e72872c6354b306daef1703549e8e83b4d43cfea356311bf722a043752/setuptools-83.0.0-py3-none-any.whl"}}, {"metadata": {"name": "tracerite", "version": "2.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b6/62/3f385a67ff3cc91209f107d20bbebdecf7a4e4aba55a43f9f71bddc424a9/tracerite-2.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "5.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/e4/39862f0f7174ff07cfd1e2d0c9065ded34aeebdb7db8daf2f0e5bf89b46f/ujson-5.13.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "uvloop", "version": "0.22.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/7b/b01414f31546caf0919da80ad57cbfe24c56b151d12af68cee1b04922ca8/uvloop-0.22.1-cp314-cp314t-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}], "install_targets_hash": "bdb1f2a8b2b051b4d694fd87001bee9b"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "sanic", "version": "25.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/91/5ecd9a91374a7b2831cf183357ceeb609fdfc8b390adb5cac90a261fe1f8/sanic-25.12.1-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/85/dc/549a807a53c13fd4a8dac286f117a7a71260defea9ec0c05d6027f2ae273/websockets-10.4.tar.gz"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/c8/14ce60ec31a2e5f5274bb17d383a6f7a3aabca31ac04eee05585bbadab16/aiohttp-3.14.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/b2/845cf2074a015e6fe0d0808cf1a2d9e868386c4220d657ebd8302b199043/yarl-1.24.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-testing", "version": "24.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/93/1d588f1cb9b710b9f22fa78b53d699a8062edc94204d50dd0d78c5f5b495/sanic_testing-24.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "html5tagger", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/12/2f5d43ee912ea14a6baba4b3db6d309b02d932e3b7074c3339b4aded98ff/html5tagger-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "httptools", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/b0/312a062ae741ae3e8baa8c8bf20be81b2e67337b259ab4349bebc7b6142e/httptools-0.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/73/daf935ea7048ddd7ec8eec5345b4a40b619d2d178b3c0a0900796bc3c794/propcache-0.5.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-routing", "version": "23.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/e3/3425c9a8773807ac2c01d6a56c8521733f09b627e5827e733c5cd36b9ac5/sanic_routing-23.12.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "83.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/40/e1e72872c6354b306daef1703549e8e83b4d43cfea356311bf722a043752/setuptools-83.0.0-py3-none-any.whl"}}, {"metadata": {"name": "tracerite", "version": "2.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b6/62/3f385a67ff3cc91209f107d20bbebdecf7a4e4aba55a43f9f71bddc424a9/tracerite-2.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "5.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/e4/39862f0f7174ff07cfd1e2d0c9065ded34aeebdb7db8daf2f0e5bf89b46f/ujson-5.13.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "uvloop", "version": "0.22.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/7b/b01414f31546caf0919da80ad57cbfe24c56b151d12af68cee1b04922ca8/uvloop-0.22.1-cp314-cp314t-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}], "install_targets_hash": "bdb1f2a8b2b051b4d694fd87001bee9b"} {"python_version": "3.14t", "dependencies": [{"metadata": {"name": "sanic", "version": "25.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/91/5ecd9a91374a7b2831cf183357ceeb609fdfc8b390adb5cac90a261fe1f8/sanic-25.12.1-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/85/dc/549a807a53c13fd4a8dac286f117a7a71260defea9ec0c05d6027f2ae273/websockets-10.4.tar.gz"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/c8/14ce60ec31a2e5f5274bb17d383a6f7a3aabca31ac04eee05585bbadab16/aiohttp-3.14.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/b2/845cf2074a015e6fe0d0808cf1a2d9e868386c4220d657ebd8302b199043/yarl-1.24.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-testing", "version": "24.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/93/1d588f1cb9b710b9f22fa78b53d699a8062edc94204d50dd0d78c5f5b495/sanic_testing-24.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "html5tagger", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/12/2f5d43ee912ea14a6baba4b3db6d309b02d932e3b7074c3339b4aded98ff/html5tagger-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "httptools", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/b0/312a062ae741ae3e8baa8c8bf20be81b2e67337b259ab4349bebc7b6142e/httptools-0.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/73/daf935ea7048ddd7ec8eec5345b4a40b619d2d178b3c0a0900796bc3c794/propcache-0.5.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-routing", "version": "23.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/e3/3425c9a8773807ac2c01d6a56c8521733f09b627e5827e733c5cd36b9ac5/sanic_routing-23.12.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "83.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/40/e1e72872c6354b306daef1703549e8e83b4d43cfea356311bf722a043752/setuptools-83.0.0-py3-none-any.whl"}}, {"metadata": {"name": "tracerite", "version": "2.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b6/62/3f385a67ff3cc91209f107d20bbebdecf7a4e4aba55a43f9f71bddc424a9/tracerite-2.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "5.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/e4/39862f0f7174ff07cfd1e2d0c9065ded34aeebdb7db8daf2f0e5bf89b46f/ujson-5.13.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "uvloop", "version": "0.22.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/7b/b01414f31546caf0919da80ad57cbfe24c56b151d12af68cee1b04922ca8/uvloop-0.22.1-cp314-cp314t-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}], "install_targets_hash": "bdb1f2a8b2b051b4d694fd87001bee9b"} -{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "mcp", "version": "1.30.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f5/f4/e58bc33317c92a0203664daaf00bf6f41166cc0149e5d6870a03f7cd004a/mcp-1.30.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/64/a4e536cb16d7f61a7fd3120b46c577fc7fa7325992f69c4f52bc786d77d8/pydantic_core-2.46.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/97/672cb32ce0dfea44b740cb7b4f97038463b9cf7c0ead1aacf595572851d6/pyjwt-2.14.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1a/01/0127d11a762b31a9ee0221894f540318761783f3fdc4bc5d057698caebd5/cryptography-50.0.1-cp314-cp314t-manylinux_2_34_x86_64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/95/eff5f0cee78d2eabc7eebffec40d3fc1876b5f3c95582e018bb4b99601f2/cffi-2.1.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8e/f4/b7ac49f30013aba8f7b9566b1dd07e81de95e708c1374b7bacc5b9bc5c9c/rpds_py-2026.6.3-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/6a/2ba3ed4a69babf3afdddf7d8314a48d87562c0a442206bbc2a1b50d5efc0/sse_starlette-3.4.11-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.52.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/79/4a20b54ab0491485ccd8c077db2d39187c7f12b3e15485d38a7be37c81b4/uvicorn-0.52.4-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "c22f32eaa2bf5c7f62806b63fcde2d83"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "sanic", "version": "25.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/91/5ecd9a91374a7b2831cf183357ceeb609fdfc8b390adb5cac90a261fe1f8/sanic-25.12.1-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/85/dc/549a807a53c13fd4a8dac286f117a7a71260defea9ec0c05d6027f2ae273/websockets-10.4.tar.gz"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/c8/14ce60ec31a2e5f5274bb17d383a6f7a3aabca31ac04eee05585bbadab16/aiohttp-3.14.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/b2/845cf2074a015e6fe0d0808cf1a2d9e868386c4220d657ebd8302b199043/yarl-1.24.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-testing", "version": "24.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/93/1d588f1cb9b710b9f22fa78b53d699a8062edc94204d50dd0d78c5f5b495/sanic_testing-24.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "html5tagger", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/12/2f5d43ee912ea14a6baba4b3db6d309b02d932e3b7074c3339b4aded98ff/html5tagger-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "httptools", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/b0/312a062ae741ae3e8baa8c8bf20be81b2e67337b259ab4349bebc7b6142e/httptools-0.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/73/daf935ea7048ddd7ec8eec5345b4a40b619d2d178b3c0a0900796bc3c794/propcache-0.5.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-routing", "version": "23.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/e3/3425c9a8773807ac2c01d6a56c8521733f09b627e5827e733c5cd36b9ac5/sanic_routing-23.12.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "83.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/40/e1e72872c6354b306daef1703549e8e83b4d43cfea356311bf722a043752/setuptools-83.0.0-py3-none-any.whl"}}, {"metadata": {"name": "tracerite", "version": "2.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b6/62/3f385a67ff3cc91209f107d20bbebdecf7a4e4aba55a43f9f71bddc424a9/tracerite-2.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "5.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/e4/39862f0f7174ff07cfd1e2d0c9065ded34aeebdb7db8daf2f0e5bf89b46f/ujson-5.13.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "uvloop", "version": "0.22.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/7b/b01414f31546caf0919da80ad57cbfe24c56b151d12af68cee1b04922ca8/uvloop-0.22.1-cp314-cp314t-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}], "install_targets_hash": "bdb1f2a8b2b051b4d694fd87001bee9b"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "sanic", "version": "25.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/91/5ecd9a91374a7b2831cf183357ceeb609fdfc8b390adb5cac90a261fe1f8/sanic-25.12.1-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/85/dc/549a807a53c13fd4a8dac286f117a7a71260defea9ec0c05d6027f2ae273/websockets-10.4.tar.gz"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/c8/14ce60ec31a2e5f5274bb17d383a6f7a3aabca31ac04eee05585bbadab16/aiohttp-3.14.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/b2/845cf2074a015e6fe0d0808cf1a2d9e868386c4220d657ebd8302b199043/yarl-1.24.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-testing", "version": "24.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/93/1d588f1cb9b710b9f22fa78b53d699a8062edc94204d50dd0d78c5f5b495/sanic_testing-24.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "html5tagger", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/12/2f5d43ee912ea14a6baba4b3db6d309b02d932e3b7074c3339b4aded98ff/html5tagger-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "httptools", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/b0/312a062ae741ae3e8baa8c8bf20be81b2e67337b259ab4349bebc7b6142e/httptools-0.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/73/daf935ea7048ddd7ec8eec5345b4a40b619d2d178b3c0a0900796bc3c794/propcache-0.5.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-routing", "version": "23.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/e3/3425c9a8773807ac2c01d6a56c8521733f09b627e5827e733c5cd36b9ac5/sanic_routing-23.12.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "83.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/40/e1e72872c6354b306daef1703549e8e83b4d43cfea356311bf722a043752/setuptools-83.0.0-py3-none-any.whl"}}, {"metadata": {"name": "tracerite", "version": "2.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b6/62/3f385a67ff3cc91209f107d20bbebdecf7a4e4aba55a43f9f71bddc424a9/tracerite-2.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "5.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/e4/39862f0f7174ff07cfd1e2d0c9065ded34aeebdb7db8daf2f0e5bf89b46f/ujson-5.13.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "uvloop", "version": "0.22.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/7b/b01414f31546caf0919da80ad57cbfe24c56b151d12af68cee1b04922ca8/uvloop-0.22.1-cp314-cp314t-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}], "install_targets_hash": "bdb1f2a8b2b051b4d694fd87001bee9b"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "sanic", "version": "25.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/91/5ecd9a91374a7b2831cf183357ceeb609fdfc8b390adb5cac90a261fe1f8/sanic-25.12.1-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/85/dc/549a807a53c13fd4a8dac286f117a7a71260defea9ec0c05d6027f2ae273/websockets-10.4.tar.gz"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/c8/14ce60ec31a2e5f5274bb17d383a6f7a3aabca31ac04eee05585bbadab16/aiohttp-3.14.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/b2/845cf2074a015e6fe0d0808cf1a2d9e868386c4220d657ebd8302b199043/yarl-1.24.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-testing", "version": "24.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/93/1d588f1cb9b710b9f22fa78b53d699a8062edc94204d50dd0d78c5f5b495/sanic_testing-24.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "html5tagger", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/12/2f5d43ee912ea14a6baba4b3db6d309b02d932e3b7074c3339b4aded98ff/html5tagger-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "httptools", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/b0/312a062ae741ae3e8baa8c8bf20be81b2e67337b259ab4349bebc7b6142e/httptools-0.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/73/daf935ea7048ddd7ec8eec5345b4a40b619d2d178b3c0a0900796bc3c794/propcache-0.5.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-routing", "version": "23.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/e3/3425c9a8773807ac2c01d6a56c8521733f09b627e5827e733c5cd36b9ac5/sanic_routing-23.12.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "83.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/40/e1e72872c6354b306daef1703549e8e83b4d43cfea356311bf722a043752/setuptools-83.0.0-py3-none-any.whl"}}, {"metadata": {"name": "tracerite", "version": "2.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b6/62/3f385a67ff3cc91209f107d20bbebdecf7a4e4aba55a43f9f71bddc424a9/tracerite-2.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "5.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/e4/39862f0f7174ff07cfd1e2d0c9065ded34aeebdb7db8daf2f0e5bf89b46f/ujson-5.13.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "uvloop", "version": "0.22.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/7b/b01414f31546caf0919da80ad57cbfe24c56b151d12af68cee1b04922ca8/uvloop-0.22.1-cp314-cp314t-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}], "install_targets_hash": "bdb1f2a8b2b051b4d694fd87001bee9b"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "sanic", "version": "25.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/91/5ecd9a91374a7b2831cf183357ceeb609fdfc8b390adb5cac90a261fe1f8/sanic-25.12.1-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/85/dc/549a807a53c13fd4a8dac286f117a7a71260defea9ec0c05d6027f2ae273/websockets-10.4.tar.gz"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/c8/14ce60ec31a2e5f5274bb17d383a6f7a3aabca31ac04eee05585bbadab16/aiohttp-3.14.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/b2/845cf2074a015e6fe0d0808cf1a2d9e868386c4220d657ebd8302b199043/yarl-1.24.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-testing", "version": "24.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/93/1d588f1cb9b710b9f22fa78b53d699a8062edc94204d50dd0d78c5f5b495/sanic_testing-24.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "html5tagger", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/12/2f5d43ee912ea14a6baba4b3db6d309b02d932e3b7074c3339b4aded98ff/html5tagger-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "httptools", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/b0/312a062ae741ae3e8baa8c8bf20be81b2e67337b259ab4349bebc7b6142e/httptools-0.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/73/daf935ea7048ddd7ec8eec5345b4a40b619d2d178b3c0a0900796bc3c794/propcache-0.5.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-routing", "version": "23.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/e3/3425c9a8773807ac2c01d6a56c8521733f09b627e5827e733c5cd36b9ac5/sanic_routing-23.12.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "83.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/40/e1e72872c6354b306daef1703549e8e83b4d43cfea356311bf722a043752/setuptools-83.0.0-py3-none-any.whl"}}, {"metadata": {"name": "tracerite", "version": "2.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b6/62/3f385a67ff3cc91209f107d20bbebdecf7a4e4aba55a43f9f71bddc424a9/tracerite-2.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "5.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/e4/39862f0f7174ff07cfd1e2d0c9065ded34aeebdb7db8daf2f0e5bf89b46f/ujson-5.13.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "uvloop", "version": "0.22.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/7b/b01414f31546caf0919da80ad57cbfe24c56b151d12af68cee1b04922ca8/uvloop-0.22.1-cp314-cp314t-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}], "install_targets_hash": "bdb1f2a8b2b051b4d694fd87001bee9b"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "sanic", "version": "25.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/91/5ecd9a91374a7b2831cf183357ceeb609fdfc8b390adb5cac90a261fe1f8/sanic-25.12.1-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/85/dc/549a807a53c13fd4a8dac286f117a7a71260defea9ec0c05d6027f2ae273/websockets-10.4.tar.gz"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/c8/14ce60ec31a2e5f5274bb17d383a6f7a3aabca31ac04eee05585bbadab16/aiohttp-3.14.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/b2/845cf2074a015e6fe0d0808cf1a2d9e868386c4220d657ebd8302b199043/yarl-1.24.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-testing", "version": "24.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/93/1d588f1cb9b710b9f22fa78b53d699a8062edc94204d50dd0d78c5f5b495/sanic_testing-24.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "html5tagger", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/12/2f5d43ee912ea14a6baba4b3db6d309b02d932e3b7074c3339b4aded98ff/html5tagger-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "httptools", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/b0/312a062ae741ae3e8baa8c8bf20be81b2e67337b259ab4349bebc7b6142e/httptools-0.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/73/daf935ea7048ddd7ec8eec5345b4a40b619d2d178b3c0a0900796bc3c794/propcache-0.5.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-routing", "version": "23.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/e3/3425c9a8773807ac2c01d6a56c8521733f09b627e5827e733c5cd36b9ac5/sanic_routing-23.12.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "83.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/40/e1e72872c6354b306daef1703549e8e83b4d43cfea356311bf722a043752/setuptools-83.0.0-py3-none-any.whl"}}, {"metadata": {"name": "tracerite", "version": "2.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b6/62/3f385a67ff3cc91209f107d20bbebdecf7a4e4aba55a43f9f71bddc424a9/tracerite-2.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "5.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/e4/39862f0f7174ff07cfd1e2d0c9065ded34aeebdb7db8daf2f0e5bf89b46f/ujson-5.13.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "uvloop", "version": "0.22.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/7b/b01414f31546caf0919da80ad57cbfe24c56b151d12af68cee1b04922ca8/uvloop-0.22.1-cp314-cp314t-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}], "install_targets_hash": "bdb1f2a8b2b051b4d694fd87001bee9b"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "sanic", "version": "25.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/91/5ecd9a91374a7b2831cf183357ceeb609fdfc8b390adb5cac90a261fe1f8/sanic-25.12.1-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/85/dc/549a807a53c13fd4a8dac286f117a7a71260defea9ec0c05d6027f2ae273/websockets-10.4.tar.gz"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/c8/14ce60ec31a2e5f5274bb17d383a6f7a3aabca31ac04eee05585bbadab16/aiohttp-3.14.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/b2/845cf2074a015e6fe0d0808cf1a2d9e868386c4220d657ebd8302b199043/yarl-1.24.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-testing", "version": "24.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/93/1d588f1cb9b710b9f22fa78b53d699a8062edc94204d50dd0d78c5f5b495/sanic_testing-24.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "html5tagger", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/12/2f5d43ee912ea14a6baba4b3db6d309b02d932e3b7074c3339b4aded98ff/html5tagger-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "httptools", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/b0/312a062ae741ae3e8baa8c8bf20be81b2e67337b259ab4349bebc7b6142e/httptools-0.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/73/daf935ea7048ddd7ec8eec5345b4a40b619d2d178b3c0a0900796bc3c794/propcache-0.5.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-routing", "version": "23.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/e3/3425c9a8773807ac2c01d6a56c8521733f09b627e5827e733c5cd36b9ac5/sanic_routing-23.12.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "83.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/40/e1e72872c6354b306daef1703549e8e83b4d43cfea356311bf722a043752/setuptools-83.0.0-py3-none-any.whl"}}, {"metadata": {"name": "tracerite", "version": "2.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b6/62/3f385a67ff3cc91209f107d20bbebdecf7a4e4aba55a43f9f71bddc424a9/tracerite-2.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "5.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/e4/39862f0f7174ff07cfd1e2d0c9065ded34aeebdb7db8daf2f0e5bf89b46f/ujson-5.13.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "uvloop", "version": "0.22.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/7b/b01414f31546caf0919da80ad57cbfe24c56b151d12af68cee1b04922ca8/uvloop-0.22.1-cp314-cp314t-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}], "install_targets_hash": "bdb1f2a8b2b051b4d694fd87001bee9b"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "sanic", "version": "25.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/91/5ecd9a91374a7b2831cf183357ceeb609fdfc8b390adb5cac90a261fe1f8/sanic-25.12.1-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/85/dc/549a807a53c13fd4a8dac286f117a7a71260defea9ec0c05d6027f2ae273/websockets-10.4.tar.gz"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/c8/14ce60ec31a2e5f5274bb17d383a6f7a3aabca31ac04eee05585bbadab16/aiohttp-3.14.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/b2/845cf2074a015e6fe0d0808cf1a2d9e868386c4220d657ebd8302b199043/yarl-1.24.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-testing", "version": "24.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/93/1d588f1cb9b710b9f22fa78b53d699a8062edc94204d50dd0d78c5f5b495/sanic_testing-24.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "html5tagger", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/12/2f5d43ee912ea14a6baba4b3db6d309b02d932e3b7074c3339b4aded98ff/html5tagger-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "httptools", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/b0/312a062ae741ae3e8baa8c8bf20be81b2e67337b259ab4349bebc7b6142e/httptools-0.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/73/daf935ea7048ddd7ec8eec5345b4a40b619d2d178b3c0a0900796bc3c794/propcache-0.5.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-routing", "version": "23.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/e3/3425c9a8773807ac2c01d6a56c8521733f09b627e5827e733c5cd36b9ac5/sanic_routing-23.12.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "83.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/40/e1e72872c6354b306daef1703549e8e83b4d43cfea356311bf722a043752/setuptools-83.0.0-py3-none-any.whl"}}, {"metadata": {"name": "tracerite", "version": "2.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b6/62/3f385a67ff3cc91209f107d20bbebdecf7a4e4aba55a43f9f71bddc424a9/tracerite-2.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "5.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/e4/39862f0f7174ff07cfd1e2d0c9065ded34aeebdb7db8daf2f0e5bf89b46f/ujson-5.13.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "uvloop", "version": "0.22.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/7b/b01414f31546caf0919da80ad57cbfe24c56b151d12af68cee1b04922ca8/uvloop-0.22.1-cp314-cp314t-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}], "install_targets_hash": "bdb1f2a8b2b051b4d694fd87001bee9b"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "sanic", "version": "25.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/91/5ecd9a91374a7b2831cf183357ceeb609fdfc8b390adb5cac90a261fe1f8/sanic-25.12.1-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/85/dc/549a807a53c13fd4a8dac286f117a7a71260defea9ec0c05d6027f2ae273/websockets-10.4.tar.gz"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/c8/14ce60ec31a2e5f5274bb17d383a6f7a3aabca31ac04eee05585bbadab16/aiohttp-3.14.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/b2/845cf2074a015e6fe0d0808cf1a2d9e868386c4220d657ebd8302b199043/yarl-1.24.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-testing", "version": "24.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/93/1d588f1cb9b710b9f22fa78b53d699a8062edc94204d50dd0d78c5f5b495/sanic_testing-24.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "html5tagger", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/12/2f5d43ee912ea14a6baba4b3db6d309b02d932e3b7074c3339b4aded98ff/html5tagger-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "httptools", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/b0/312a062ae741ae3e8baa8c8bf20be81b2e67337b259ab4349bebc7b6142e/httptools-0.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/73/daf935ea7048ddd7ec8eec5345b4a40b619d2d178b3c0a0900796bc3c794/propcache-0.5.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-routing", "version": "23.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/e3/3425c9a8773807ac2c01d6a56c8521733f09b627e5827e733c5cd36b9ac5/sanic_routing-23.12.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "83.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/40/e1e72872c6354b306daef1703549e8e83b4d43cfea356311bf722a043752/setuptools-83.0.0-py3-none-any.whl"}}, {"metadata": {"name": "tracerite", "version": "2.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b6/62/3f385a67ff3cc91209f107d20bbebdecf7a4e4aba55a43f9f71bddc424a9/tracerite-2.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "5.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/e4/39862f0f7174ff07cfd1e2d0c9065ded34aeebdb7db8daf2f0e5bf89b46f/ujson-5.13.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "uvloop", "version": "0.22.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/7b/b01414f31546caf0919da80ad57cbfe24c56b151d12af68cee1b04922ca8/uvloop-0.22.1-cp314-cp314t-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}], "install_targets_hash": "bdb1f2a8b2b051b4d694fd87001bee9b"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "sanic", "version": "25.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/91/5ecd9a91374a7b2831cf183357ceeb609fdfc8b390adb5cac90a261fe1f8/sanic-25.12.1-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/85/dc/549a807a53c13fd4a8dac286f117a7a71260defea9ec0c05d6027f2ae273/websockets-10.4.tar.gz"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/c8/14ce60ec31a2e5f5274bb17d383a6f7a3aabca31ac04eee05585bbadab16/aiohttp-3.14.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/b2/845cf2074a015e6fe0d0808cf1a2d9e868386c4220d657ebd8302b199043/yarl-1.24.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-testing", "version": "24.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/93/1d588f1cb9b710b9f22fa78b53d699a8062edc94204d50dd0d78c5f5b495/sanic_testing-24.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "html5tagger", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/12/2f5d43ee912ea14a6baba4b3db6d309b02d932e3b7074c3339b4aded98ff/html5tagger-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "httptools", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/b0/312a062ae741ae3e8baa8c8bf20be81b2e67337b259ab4349bebc7b6142e/httptools-0.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/73/daf935ea7048ddd7ec8eec5345b4a40b619d2d178b3c0a0900796bc3c794/propcache-0.5.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-routing", "version": "23.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/e3/3425c9a8773807ac2c01d6a56c8521733f09b627e5827e733c5cd36b9ac5/sanic_routing-23.12.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "83.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/40/e1e72872c6354b306daef1703549e8e83b4d43cfea356311bf722a043752/setuptools-83.0.0-py3-none-any.whl"}}, {"metadata": {"name": "tracerite", "version": "2.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b6/62/3f385a67ff3cc91209f107d20bbebdecf7a4e4aba55a43f9f71bddc424a9/tracerite-2.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "5.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/e4/39862f0f7174ff07cfd1e2d0c9065ded34aeebdb7db8daf2f0e5bf89b46f/ujson-5.13.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "uvloop", "version": "0.22.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/7b/b01414f31546caf0919da80ad57cbfe24c56b151d12af68cee1b04922ca8/uvloop-0.22.1-cp314-cp314t-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}], "install_targets_hash": "bdb1f2a8b2b051b4d694fd87001bee9b"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "sanic", "version": "25.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/91/5ecd9a91374a7b2831cf183357ceeb609fdfc8b390adb5cac90a261fe1f8/sanic-25.12.1-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/85/dc/549a807a53c13fd4a8dac286f117a7a71260defea9ec0c05d6027f2ae273/websockets-10.4.tar.gz"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/c8/14ce60ec31a2e5f5274bb17d383a6f7a3aabca31ac04eee05585bbadab16/aiohttp-3.14.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "yarl", "version": "1.24.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/b2/845cf2074a015e6fe0d0808cf1a2d9e868386c4220d657ebd8302b199043/yarl-1.24.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-testing", "version": "24.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/93/1d588f1cb9b710b9f22fa78b53d699a8062edc94204d50dd0d78c5f5b495/sanic_testing-24.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "html5tagger", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/12/2f5d43ee912ea14a6baba4b3db6d309b02d932e3b7074c3339b4aded98ff/html5tagger-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "httptools", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/b0/312a062ae741ae3e8baa8c8bf20be81b2e67337b259ab4349bebc7b6142e/httptools-0.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/73/daf935ea7048ddd7ec8eec5345b4a40b619d2d178b3c0a0900796bc3c794/propcache-0.5.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-routing", "version": "23.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/e3/3425c9a8773807ac2c01d6a56c8521733f09b627e5827e733c5cd36b9ac5/sanic_routing-23.12.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "83.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/40/e1e72872c6354b306daef1703549e8e83b4d43cfea356311bf722a043752/setuptools-83.0.0-py3-none-any.whl"}}, {"metadata": {"name": "tracerite", "version": "2.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b6/62/3f385a67ff3cc91209f107d20bbebdecf7a4e4aba55a43f9f71bddc424a9/tracerite-2.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "5.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/e4/39862f0f7174ff07cfd1e2d0c9065ded34aeebdb7db8daf2f0e5bf89b46f/ujson-5.13.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "uvloop", "version": "0.22.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/7b/b01414f31546caf0919da80ad57cbfe24c56b151d12af68cee1b04922ca8/uvloop-0.22.1-cp314-cp314t-macosx_10_13_universal2.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}], "install_targets_hash": "bdb1f2a8b2b051b4d694fd87001bee9b"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "chalice", "version": "1.33.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/ed/c721931d966d135387ab2d5404a026ca0ae205325fbac4b8f9ac91a45186/chalice-1.33.0-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.43.78"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/5b/b7c5c22767c0e8eb4bb2bd0a972d77bd0be3dd9908e15d4487094a31fa4b/botocore-1.43.78-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "inquirer", "version": "3.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f0/fd/7c404169a3e04a908df0644893a331f253a7f221961f2b6c0cf44430ae5a/inquirer-3.4.1-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pip", "version": "26.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/95/6b5cb3461ea5673ba0995989746db58eb18b91b54dbf331e72f569540946/pip-26.1.2-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "blessed", "version": "1.48.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/3e/6e6ba6c809688332d2f8450371e672c76f7e8e73574aba9dfe89b55eb900/blessed-1.48.0-py3-none-any.whl"}}, {"metadata": {"name": "jinxed", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/1d/0a6be99b69bb448448403a45a241aff0dca751832ae54f027ed940d2eb52/jinxed-2.1.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "editor", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/b8/6648cadf38b61045262bf2a534e526f04eb833275ad1fc77a2026e9f7e3a/editor-1.8.0-py3-none-any.whl"}}, {"metadata": {"name": "readchar", "version": "4.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/ca/36133653e00939922dd1416f4c56177361289172a30563fcb9552c9ccde4/readchar-4.2.2-py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl"}}, {"metadata": {"name": "runs", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/b6/049c75d399ccf6e25abea0652b85bf7e7e101e0300aa9c1d284ad7061c0b/runs-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "84.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/9c/c510029fc6ef33a6275cd2c5d3cecd6613dfd6aa401d57c54f1c18852ccf/setuptools-84.0.0-py3-none-any.whl"}}, {"metadata": {"name": "wheel", "version": "0.48.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2e/29/69cfbb602cd91690c55d38ba9fe53e6a7e76a6fa647bf38f19c138d25449/wheel-0.48.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "xmod", "version": "1.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/e9/c362d47ed2b1928d65d61888c1419fae8ef69417fba2067d2fd3da1d400b/xmod-1.10.0-py3-none-any.whl"}}], "install_targets_hash": "bea3b0d953db88b05dda600ccc5aaab5"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "pydantic-ai", "version": "2.47.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/12/1a/a46dad48b18c004eb686596d360d2310fc9c928b5b9b31341c03c6c813f1/pydantic_ai-2.47.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-ai-slim", "version": "2.47.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/eb/94/5d8a27dbe4a9e27378698c31c5848310d7a7727e22e1334f683dfbe5397d/pydantic_ai_slim-2.47.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-evals", "version": "2.47.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a9/81/34504d9426f420cc3ea05eb5d3f387a17f14d5ea678b6ced18d6f4be9da4/pydantic_evals-2.47.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-graph", "version": "2.47.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/3c/b0/4630a964201fb04dba730cbe54b7941309d97d59c01537465b075c26cae7/pydantic_graph-2.47.0-py3-none-any.whl"}}, {"metadata": {"name": "fastmcp-slim", "version": "4.0.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ed/76/8dc551ef1f222bd146537ae100baf7441628aa1050494b567249ece997c2/fastmcp_slim-4.0.5-py3-none-any.whl"}}, {"metadata": {"name": "mcp", "version": "2.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/1b/ff/8e7eade68b8a28f7da0ed1085544341b51f9c935dbf6b95c76b7edfea6a0/mcp-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mcp-types", "version": "2.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/8f/d7/6ffba5d8cd5dd9b8a19478875c50e04945314ba5074e84d749283f27f62d/mcp_types-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "py-key-value-aio", "version": "0.4.6"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/9a/46/12871550fb0613d149144bb9d41f22680d5f46717bc45a76eb5798c20c3f/py_key_value_aio-0.4.6-py3-none-any.whl"}}, {"metadata": {"name": "aiofile", "version": "3.12.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/4e/79/6e45e778c4c3cab39e0937b007b720c15f76c50c6453d153282d0fcc3588/aiofile-3.12.3-py3-none-any.whl"}}, {"metadata": {"name": "caio", "version": "0.12.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/d3/f4/c39ed874d420bb2719d52932d763953c28371c536d6bf264de1febeb27d5/caio-0.12.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anthropic", "version": "1.7.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c0/dc/74995efda028421917f4caabd24db1373ee0742573a2363fff1a21191441/anthropic-1.7.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.17.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ac/4a/84a5ec271d09f7590b6073af5ee4abb44eab4ccace453b7e2c5ce45234ca/jiter-0.17.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c5/02/bc19b47a96c2d3109760711acf22369e56bd7e405ca52f7ade164d2ead57/pydantic_core-2.46.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "argcomplete", "version": "3.7.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/46/bd/551ee6af426af84ca33e02622be722925c196608e9127d731ef17c47f06e/argcomplete-3.7.2-py3-none-any.whl"}}, {"metadata": {"name": "Authlib", "version": "1.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b8/c6/6f124bcfbbfb20fba22c939b4e43a06dccfc0e1ca20e5634ca573cb1e271/authlib-1.8.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "beartype", "version": "0.22.9"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/cc/18245721fa7747065ab478316c7fea7c74777d07f37ae60db2e84f8172e8/beartype-0.22.9-py3-none-any.whl"}}, {"metadata": {"name": "cachetools", "version": "7.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cc/bb/1c6e7a89b11da19f137e4ef5a5c5fe47a5bb686449ba343944ccf8fb34b2/cachetools-7.2.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/5b/f0/424cb557d99aa86ac55da5e2add02e2882e44047b6264f93ade1b975a993/cryptography-50.0.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7d/47/5ecf1023850036e674c77ec4de86182d309ae344e39e7cba984b7df5d647/cffi-2.1.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "genai-prices", "version": "0.1.7"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/d5/4a/9e04f3dca5ffe74133779ab5e9925ffb6411afbeac55d26fa0e148722599/genai_prices-0.1.7-py3-none-any.whl"}}, {"metadata": {"name": "google-genai", "version": "2.24.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/84/5b/87913fe392ba7b6402577259289ed3740c577956554a674b191a2971d33e/google_genai-2.24.0-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.58.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/59/13/477d90d09591b3938b45c4e11f4d8a51291682112cb5efcac961e815d562/google_auth-2.58.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/1c/6c/c73fa9d5a85f6ab05395de61c5f6984e0a9ff40bb5ff888d46dff02526c6/charset_normalizer-3.5.1-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0c/e8/f7dac2e980bacc92bdc26cebae4ae4d50cae5380732c50980598fc0bbae4/websockets-16.1.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "griffelib", "version": "2.3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/41/63/e876e789525063c840ccfa8857febdabd6523bcef9ce7eb979b9305ea895/griffelib-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "joserfc", "version": "1.7.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/67/c5/82addfd375e5ee6520644e0553e4aadde92d668c4fc99cc716d337fe7bb3/joserfc-1.7.5-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "keyring", "version": "25.7.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/81/db/e655086b7f3a705df045bf0933bdd9c2f79bb3c97bfef1384598bb79a217/keyring-25.7.0-py3-none-any.whl"}}, {"metadata": {"name": "logfire", "version": "5.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cd/02/b32c3d5c298e4a9010694d261fb82c2c672747c0bf2b47bffda484aef349/logfire-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-exporter-otlp-proto-http", "version": "1.44.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cd/d0/fdeb1a98d8d3a6205f5f297c51b4a9bfe65126ab60339669bbe3dd54c2e2/opentelemetry_exporter_otlp_proto_http-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-exporter-otlp-proto-common", "version": "1.44.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/5e/71/65fd9d54c10b860f87c045ccee1264cab7011268895d3528818a29c1172a/opentelemetry_exporter_otlp_proto_common-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-proto", "version": "1.44.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/d1/7c/8be563d68e93bbefa5c8affb82ddcff91b3ad858ce49957ba7b16fd3e0ab/opentelemetry_proto-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "googleapis-common-protos", "version": "1.75.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/1a/7a/7d79170c6ce6f12e109df2b3879d6b934010cf4f99aea8de8b7e5408c174/googleapis_common_protos-1.75.3-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.44.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ca/6f/a04e900f465ff3221ccc395522503e2d10e79fa21f2723c8e177aae1e0d1/opentelemetry_api-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-sdk", "version": "1.44.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e7/23/ff077e61886ee020a17ce9c8b6fa11c601c8d8345b09ea24f605445df62a/opentelemetry_sdk-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-semantic-conventions", "version": "0.65b0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a6/0e/49df70d9b81fb5cbae4bbf2a49d865b09bcbcbc4eb53f5851b1027738d78/opentelemetry_semantic_conventions-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "protobuf", "version": "7.36.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e4/04/d52c7016b04b6c5108f26691f9d33ec82a9b65d041f1a9c771137693d618/protobuf-7.36.2-py3-none-any.whl"}}, {"metadata": {"name": "executing", "version": "2.2.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "logfire-api", "version": "5.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2d/51/123dab197fb08c0892e3bea1c2266bff159aa2ee82ad43bef93505859705/logfire_api-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "3.17.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/57/bc/5b80a0ca4069a6b5ba6c7d48ae7a4f8176b2c0bde0bebccdb867472ec6f6/openai-3.17.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-instrumentation", "version": "0.65b0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/40/7b/85eab1215f72adf0e68d3dc4a679b9bff993fa679ff34cd8dd378e2659fd/opentelemetry_instrumentation-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "wrapt", "version": "2.4.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/72/26/7435de516099b528e2232770b459d6706002736f41d8f092bbb11ea01575/wrapt-2.4.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "opentelemetry-instrumentation-httpx", "version": "0.65b0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/9d/0f/c6144096b4914bbf44b43ba21c962e8f333ff045770b50a3e79ed8bd455f/opentelemetry_instrumentation_httpx-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-util-http", "version": "0.65b0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/23/3f/ab8d29df207ce5f470a07fa96ebb48af4e95b7fab7e7635311b9a32f2fab/opentelemetry_util_http-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "platformdirs", "version": "4.11.12"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ec/2b/69de6317fbf48865bb12aa56c9cfcfff46b3add0cd45250725d96146dce0/platformdirs-4.11.12-py3-none-any.whl"}}, {"metadata": {"name": "prompt_toolkit", "version": "3.0.53"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/54/6f/84908cad2d6aa5144abcf7b42709fe4fdb459bc640ec7ac5786e7693dabc/prompt_toolkit-3.0.53-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/9a/3b/6163796d69c3977d1e4287bea4a6979161cbbdd170ebb430511e8e1999ce/pyasn1-0.6.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "email-validator", "version": "2.3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "dnspython", "version": "2.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.14.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/9c/97/672cb32ce0dfea44b740cb7b4f97038463b9cf7c0ead1aacf595572851d6/pyjwt-2.14.0-py3-none-any.whl"}}, {"metadata": {"name": "pyperclip", "version": "1.11.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/df/80/fc9d01d5ed37ba4c42ca2b55b4339ae6e200b456be3a1aaddf4a9fa99b8c/pyperclip-1.11.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e9/44/77bcb1168b33704908295533d27f10eb811e9e3e193e8993dc99572211d3/rpds_py-2026.6.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.11"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/98/6a/2ba3ed4a69babf3afdddf7d8314a48d87562c0a442206bbc2a1b50d5efc0/sse_starlette-3.4.11-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/79/29/46ad8061f57bd9f8b2ea0aa82bf574e0f2aa040b0857a1582adba9957899/tiktoken-0.14.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.53.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/76/18/0eea75741ee812e9f598b687619ce2454f6c3a1c5cd21ea990ec6bd26f45/uvicorn-0.53.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/39/cc/9c0adc5861020de426ec71716b6c1bef8d90694b7d6d0a16202cdb1647f5/wcwidth-0.8.4-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.classes", "version": "3.4.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7f/66/b15ce62552d84bbfcec9a4873ab79d993a1dd4edb922cbfccae192bd5b5f/jaraco.classes-3.4.0-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.context", "version": "6.1.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/f2/58/bc8954bda5fcda97bd7c19be11b85f91973d67a706ed4a3aec33e7de22db/jaraco_context-6.1.2-py3-none-any.whl"}}, {"metadata": {"name": "jaraco.functools", "version": "4.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/02/36/ecc85bc96c273dc8a11273ed4782272975e6338d4a3e9228621175edf0e3/jaraco_functools-4.6.0-py3-none-any.whl"}}, {"metadata": {"name": "more-itertools", "version": "11.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e8/3d/1087453384dbde46a8c7f9356eead2c58be8a7bf156bca40243377c85715/more_itertools-11.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.9.10"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2b/d1/ee7662561735f90475443c3ca1977e5cecaeaa8f29620dec75580aebc839/regex-2026.9.10-cp314-cp314t-macosx_11_0_arm64.whl"}}], "install_targets_hash": "c00e0595631e41d50bde5c20d0890a90"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "pyramid", "version": "2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1f/d4/03a8f9b60b8f2a9198c962d08fd9b657c1c0797cbbde3793babbad200845/pyramid-2.1-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "81.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/e3/c164c88b2e5ce7b24d667b9bd83589cf4f3520d97cad01534cd3c4f55fdb/setuptools-81.0.0-py3-none-any.whl"}}, {"metadata": {"name": "hupper", "version": "1.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/86/7d/3888833e4f5ea56af4a9935066ec09a83228e533d7b8877f65889d706ee4/hupper-1.12.1-py3-none-any.whl"}}, {"metadata": {"name": "translationstring", "version": "1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3b/98/36187601a15e3d37e9bfcf0e0e1055532b39d044353b06861c3a519737a9/translationstring-1.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "venusian", "version": "3.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5a/4b/34d926eba40db81b204066a60b4efdc5d8867a8efcbfe44d69b634b1c907/venusian-3.1.1-py3-none-any.whl"}}, {"metadata": {"name": "WebOb", "version": "1.8.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/71/370a65bc7726a1cbf478445c898c7affe907aa42e2e9e5bb38319db74115/webob-1.8.11-py2.py3-none-any.whl"}}, {"metadata": {"name": "legacy-cgi", "version": "2.6.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8c/7e/e7394eeb49a41cc514b3eb49020223666cbf40d86f5721c2f07871e6d84a/legacy_cgi-2.6.4-py3-none-any.whl"}}, {"metadata": {"name": "zope.deprecation", "version": "6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/ed/da7f8b1c73caf989a0ff7096cc73c59e6c36f35a8f967c51104098602e2d/zope_deprecation-6.0-py3-none-any.whl"}}, {"metadata": {"name": "zope.interface", "version": "8.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/c1/889dc114e9a9e8d59fec53facb71dd26345f60c504ad20fd17121af0449c/zope_interface-8.6-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "plaster", "version": "1.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e7/8b/3f98db1448e3b4d2d142716874a7e02f6101685fdaa0f55a8668e9ffa048/plaster-1.1.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "plaster-pastedeploy", "version": "1.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/30/2d4cf89035c22a89bf0e34dbc50fdc07c42c9bdc90fd972d495257ad2b6e/plaster_pastedeploy-1.0.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "PasteDeploy", "version": "3.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/85/30/cdddd9a88969683a59222a6d61cd6dce923977f2e9f9ffba38e1324149cd/PasteDeploy-3.1.0-py3-none-any.whl"}}], "install_targets_hash": "c072f65486df4079e926fa917e25937b"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}], "install_targets_hash": "c4e67585767bde6ea034db94a448f267"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "litestar", "version": "2.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/ce/4697b547790f23d2fcc37a928d48c38140cf86360e4041ca8177e3367c14/litestar-2.24.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "litestar-htmx", "version": "0.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f2/24/8d99982f0aa9c1cd82073c6232b54a0dbe6797c7d63c0583a6c68ee3ddf2/litestar_htmx-0.5.0-py3-none-any.whl"}}, {"metadata": {"name": "msgspec", "version": "0.21.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/70/9b/ce0cca6d2d87fcd4b6ff97600790494e64f26a2c55d61507cd2755c16193/msgspec-0.21.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multipart", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/dd/feb9c23d5c5a382194a9f86b02e98b8724d745e1a1cf4ecb1a5c0f884aa1/multipart-2.0.0-py3-none-any.whl"}}, {"metadata": {"name": "polyfactory", "version": "3.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/34/b6f19941adcdaf415b5e8a8d577499f5b6a76b59cbae37f9b125a9ffe9f2/polyfactory-3.3.0-py3-none-any.whl"}}, {"metadata": {"name": "Faker", "version": "40.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/22/bf589b6b2c7527047f55450358fbe5961aeaadf168d6b51a1a1c67da497f/faker-40.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "rich-click", "version": "1.9.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6d/97/a87901aef6b7e7e4a34c6dd6cc17dca8594a592ef9d9dd765fca2b7facf7/rich_click-1.9.8-py3-none-any.whl"}}], "install_targets_hash": "c80ead0cffe16af0e68d3fc9cf7d4d03"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "openai-agents", "version": "0.10.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e2/07/ad27018fb42d6f1e70f471a5ca3f6398a2159575b623edf86e1ddde66ce4/openai_agents-0.10.5-py3-none-any.whl"}}, {"metadata": {"name": "griffe", "version": "1.15.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/9c/83/3b1d03d36f224edded98e9affd0467630fc09d766c0e56fb1498cbb04a9b/griffe-1.15.0-py3-none-any.whl"}}, {"metadata": {"name": "mcp", "version": "1.30.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/f5/f4/e58bc33317c92a0203664daaf00bf6f41166cc0149e5d6870a03f7cd004a/mcp-1.30.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "2.54.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/64/a8/bb76c7356de8ad57f59d5ff993d434df0607f07f08bcc9c9a5c275e399c0/openai-2.54.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.17.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ac/4a/84a5ec271d09f7590b6073af5ee4abb44eab4ccace453b7e2c5ce45234ca/jiter-0.17.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c5/02/bc19b47a96c2d3109760711acf22369e56bd7e405ca52f7ade164d2ead57/pydantic_core-2.46.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/1c/6c/c73fa9d5a85f6ab05395de61c5f6984e0a9ff40bb5ff888d46dff02526c6/charset_normalizer-3.5.1-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "types-requests", "version": "2.33.0.20260906"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/60/4c/51ec821d22a45b4162fa3f3e9e94ea4c0f8c49e82363b10955baa5438391/types_requests-2.33.0.20260906-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "colorama", "version": "0.4.6"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.14.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/9c/97/672cb32ce0dfea44b740cb7b4f97038463b9cf7c0ead1aacf595572851d6/pyjwt-2.14.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/5b/f0/424cb557d99aa86ac55da5e2add02e2882e44047b6264f93ade1b975a993/cryptography-50.0.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7d/47/5ecf1023850036e674c77ec4de86182d309ae344e39e7cba984b7df5d647/cffi-2.1.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e9/44/77bcb1168b33704908295533d27f10eb811e9e3e193e8993dc99572211d3/rpds_py-2026.6.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.11"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/98/6a/2ba3ed4a69babf3afdddf7d8314a48d87562c0a442206bbc2a1b50d5efc0/sse_starlette-3.4.11-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a7/03/921a3d3c75785aca9ebfbfcabfbc3a1be12e2ab5265deb026d55a5a3f83e/tqdm-4.70.1-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.53.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/76/18/0eea75741ee812e9f598b687619ce2454f6c3a1c5cd21ea990ec6bd26f45/uvicorn-0.53.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "c9908704a7a657a79faaab8ba9d390db"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "mcp", "version": "2.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/75/20/312acf5fd37b90589269349b2c4d5c056b4603c964d181e91f9bf4a79f97/mcp-2.0.1-py3-none-any.whl"}}, {"metadata": {"name": "mcp-types", "version": "2.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b6/49/37a1f580d94ee0f16c1f3d1c6e32bbb264e607f1739a4c0cb9232619dfd9/mcp_types-2.0.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/6f/a04e900f465ff3221ccc395522503e2d10e79fa21f2723c8e177aae1e0d1/opentelemetry_api-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/02/bc19b47a96c2d3109760711acf22369e56bd7e405ca52f7ade164d2ead57/pydantic_core-2.46.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/97/672cb32ce0dfea44b740cb7b4f97038463b9cf7c0ead1aacf595572851d6/pyjwt-2.14.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/f0/424cb557d99aa86ac55da5e2add02e2882e44047b6264f93ade1b975a993/cryptography-50.0.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7d/47/5ecf1023850036e674c77ec4de86182d309ae344e39e7cba984b7df5d647/cffi-2.1.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/77bcb1168b33704908295533d27f10eb811e9e3e193e8993dc99572211d3/rpds_py-2026.6.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/6a/2ba3ed4a69babf3afdddf7d8314a48d87562c0a442206bbc2a1b50d5efc0/sse_starlette-3.4.11-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.53.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/76/18/0eea75741ee812e9f598b687619ce2454f6c3a1c5cd21ea990ec6bd26f45/uvicorn-0.53.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "cce7f3c3feff18eeb00efa85d75073cb"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "strawberry-graphql", "version": "0.327.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/09/e0deac5d4f466f6ecae1b91a91d1a291aad1890960a5d891bb80bda3425c/strawberry_graphql-0.327.7-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.12"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/b6/304c572e79b9e82982dbd5091e26a89f5018e565868091d804c2142f6ba5/graphql_core-3.2.12-py3-none-any.whl"}}, {"metadata": {"name": "cross-web", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7a/4a/78b52ec2edcbd9b123638f4e0421fd8699ebe653ebf63ac5f82abd2665bc/cross_web-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "fastapi", "version": "0.141.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/03/10388a42375ee7e4ac9b94eb2c5c569c8b5795e377e701c9ac3ad63de890/fastapi-0.141.1-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/09/c419f6f5a92e5fadde27efd190eca90f05e1261b10dbd8cbcb39cd8ea1dc/markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/64/a4e536cb16d7f61a7fd3120b46c577fc7fa7325992f69c4f52bc786d77d8/pydantic_core-2.46.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}], "install_targets_hash": "cfc1e9957ab373475c45bbd06bbcbe92"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "starlette", "version": "0.52.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/0d/13d1d239a25cbfb19e740db83143e95c772a1fe10202dda4b76792b114dd/starlette-0.52.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}], "install_targets_hash": "d03821fdac2b71f13fa91b761150981c"} {"python_version": "3.14t", "dependencies": [{"metadata": {"name": "google-genai", "version": "2.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/84/5b/87913fe392ba7b6402577259289ed3740c577956554a674b191a2971d33e/google_genai-2.24.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.58.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/59/13/477d90d09591b3938b45c4e11f4d8a51291682112cb5efcac961e815d562/google_auth-2.58.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/64/a4e536cb16d7f61a7fd3120b46c577fc7fa7325992f69c4f52bc786d77d8/pydantic_core-2.46.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/ee/e4e10a94d51cd1ee638aa7e00b65399e6b2a4e8376ab6d2eac9f95586671/charset_normalizer-3.5.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b2/39/26762f734113e22da2b942c3aca85798e0c0405d64c256549540ff31e5a1/websockets-16.1.1-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1a/01/0127d11a762b31a9ee0221894f540318761783f3fdc4bc5d057698caebd5/cryptography-50.0.1-cp314-cp314t-manylinux_2_34_x86_64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/95/eff5f0cee78d2eabc7eebffec40d3fc1876b5f3c95582e018bb4b99601f2/cffi-2.1.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/3b/6163796d69c3977d1e4287bea4a6979161cbbdd170ebb430511e8e1999ce/pyasn1-0.6.4-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "d5f17eff9efc836f1883edb6f7bfdfbc"} {"python_version": "3.14t", "dependencies": [{"metadata": {"name": "launchdarkly-server-sdk", "version": "9.17.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c1/58/bcede9c0f11b5c37b492ea993ed0599099e15f803b9fe98452558cfd6e96/launchdarkly_server_sdk-9.17.0-py3-none-any.whl"}}, {"metadata": {"name": "launchdarkly-eventsource", "version": "1.7.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/49/8592c1d9c156d3c2d3f8c02e1c00260c3e0a7a10bcb50c942bd80c285c62/launchdarkly_eventsource-1.7.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "expiringdict", "version": "1.2.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cb/84/a04c59324445f4bcc98dc05b39a1cd07c242dde643c1a3c21e4f7beaf2f2/expiringdict-1.2.2-py3-none-any.whl"}}, {"metadata": {"name": "pyRFC3339", "version": "2.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/34/90/0200184d2124484f918054751ef997ed6409cb05b7e8dcbf5a22da4c4748/pyrfc3339-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "semver", "version": "3.0.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a6/24/4d91e05817e92e3a61c8a21e08fd0f390f5301f1c448b137c57c4bc6e543/semver-3.0.4-py3-none-any.whl"}}], "install_targets_hash": "e039dc9ecf1b28450bdeec6c73e7b68c"} {"python_version": "3.14t", "dependencies": [{"metadata": {"name": "launchdarkly-server-sdk", "version": "9.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/58/bcede9c0f11b5c37b492ea993ed0599099e15f803b9fe98452558cfd6e96/launchdarkly_server_sdk-9.17.0-py3-none-any.whl"}}, {"metadata": {"name": "launchdarkly-eventsource", "version": "1.7.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/49/8592c1d9c156d3c2d3f8c02e1c00260c3e0a7a10bcb50c942bd80c285c62/launchdarkly_eventsource-1.7.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "expiringdict", "version": "1.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/84/a04c59324445f4bcc98dc05b39a1cd07c242dde643c1a3c21e4f7beaf2f2/expiringdict-1.2.2-py3-none-any.whl"}}, {"metadata": {"name": "pyRFC3339", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/34/90/0200184d2124484f918054751ef997ed6409cb05b7e8dcbf5a22da4c4748/pyrfc3339-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "semver", "version": "3.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/24/4d91e05817e92e3a61c8a21e08fd0f390f5301f1c448b137c57c4bc6e543/semver-3.0.4-py3-none-any.whl"}}], "install_targets_hash": "e039dc9ecf1b28450bdeec6c73e7b68c"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "launchdarkly-server-sdk", "version": "9.17.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c1/58/bcede9c0f11b5c37b492ea993ed0599099e15f803b9fe98452558cfd6e96/launchdarkly_server_sdk-9.17.0-py3-none-any.whl"}}, {"metadata": {"name": "launchdarkly-eventsource", "version": "1.7.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/49/8592c1d9c156d3c2d3f8c02e1c00260c3e0a7a10bcb50c942bd80c285c62/launchdarkly_eventsource-1.7.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "expiringdict", "version": "1.2.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cb/84/a04c59324445f4bcc98dc05b39a1cd07c242dde643c1a3c21e4f7beaf2f2/expiringdict-1.2.2-py3-none-any.whl"}}, {"metadata": {"name": "pyRFC3339", "version": "2.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/34/90/0200184d2124484f918054751ef997ed6409cb05b7e8dcbf5a22da4c4748/pyrfc3339-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "semver", "version": "3.0.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a6/24/4d91e05817e92e3a61c8a21e08fd0f390f5301f1c448b137c57c4bc6e543/semver-3.0.4-py3-none-any.whl"}}], "install_targets_hash": "e039dc9ecf1b28450bdeec6c73e7b68c"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "launchdarkly-server-sdk", "version": "9.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/58/bcede9c0f11b5c37b492ea993ed0599099e15f803b9fe98452558cfd6e96/launchdarkly_server_sdk-9.17.0-py3-none-any.whl"}}, {"metadata": {"name": "launchdarkly-eventsource", "version": "1.7.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/49/8592c1d9c156d3c2d3f8c02e1c00260c3e0a7a10bcb50c942bd80c285c62/launchdarkly_eventsource-1.7.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "expiringdict", "version": "1.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/84/a04c59324445f4bcc98dc05b39a1cd07c242dde643c1a3c21e4f7beaf2f2/expiringdict-1.2.2-py3-none-any.whl"}}, {"metadata": {"name": "pyRFC3339", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/34/90/0200184d2124484f918054751ef997ed6409cb05b7e8dcbf5a22da4c4748/pyrfc3339-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "semver", "version": "3.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/24/4d91e05817e92e3a61c8a21e08fd0f390f5301f1c448b137c57c4bc6e543/semver-3.0.4-py3-none-any.whl"}}], "install_targets_hash": "e039dc9ecf1b28450bdeec6c73e7b68c"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "openai-agents", "version": "0.14.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/af/6e/1e9adcedcde7b163579b88a68f765a4915be4ead0713270386d9432cfd2f/openai_agents-0.14.8-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "2.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ae/f4/561ed79fd94876160018a5e75254cfcb9b0e62d4dded9dcb20072e86d623/openai-2.44.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "griffelib", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/63/e876e789525063c840ccfa8857febdabd6523bcef9ce7eb979b9305ea895/griffelib-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ac/4a/84a5ec271d09f7590b6073af5ee4abb44eab4ccace453b7e2c5ce45234ca/jiter-0.17.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "mcp", "version": "1.30.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f5/f4/e58bc33317c92a0203664daaf00bf6f41166cc0149e5d6870a03f7cd004a/mcp-1.30.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/02/bc19b47a96c2d3109760711acf22369e56bd7e405ca52f7ade164d2ead57/pydantic_core-2.46.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1c/6c/c73fa9d5a85f6ab05395de61c5f6984e0a9ff40bb5ff888d46dff02526c6/charset_normalizer-3.5.1-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "types-requests", "version": "2.33.0.20260906"}, "download_info": {"url": "https://files.pythonhosted.org/packages/60/4c/51ec821d22a45b4162fa3f3e9e94ea4c0f8c49e82363b10955baa5438391/types_requests-2.33.0.20260906-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/e8/f7dac2e980bacc92bdc26cebae4ae4d50cae5380732c50980598fc0bbae4/websockets-16.1.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/97/672cb32ce0dfea44b740cb7b4f97038463b9cf7c0ead1aacf595572851d6/pyjwt-2.14.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/f0/424cb557d99aa86ac55da5e2add02e2882e44047b6264f93ade1b975a993/cryptography-50.0.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7d/47/5ecf1023850036e674c77ec4de86182d309ae344e39e7cba984b7df5d647/cffi-2.1.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/77bcb1168b33704908295533d27f10eb811e9e3e193e8993dc99572211d3/rpds_py-2026.6.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/6a/2ba3ed4a69babf3afdddf7d8314a48d87562c0a442206bbc2a1b50d5efc0/sse_starlette-3.4.11-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/03/921a3d3c75785aca9ebfbfcabfbc3a1be12e2ab5265deb026d55a5a3f83e/tqdm-4.70.1-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.52.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/79/4a20b54ab0491485ccd8c077db2d39187c7f12b3e15485d38a7be37c81b4/uvicorn-0.52.4-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "e39da8a431d3f40f0c1638f060e9b600"} {"python_version": "3.14t", "dependencies": [{"metadata": {"name": "openai-agents", "version": "0.14.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/af/6e/1e9adcedcde7b163579b88a68f765a4915be4ead0713270386d9432cfd2f/openai_agents-0.14.8-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "2.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ae/f4/561ed79fd94876160018a5e75254cfcb9b0e62d4dded9dcb20072e86d623/openai-2.44.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "griffelib", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/b6/f65ac785d4ac90dcf7c831ac6256f5dd4a19780f4e1575b2c0d6eeebe319/griffelib-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/6b/59127338b86d9fe4d99418f5a15118bea778103ee0fe9d9dd7e0af174e95/jiter-0.16.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "mcp", "version": "1.29.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/c8/248b201f6d753d69fd5d6506011abbb35a946d9142b2ae311a948fd0be3d/mcp-1.29.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1c/6c/c73fa9d5a85f6ab05395de61c5f6984e0a9ff40bb5ff888d46dff02526c6/charset_normalizer-3.5.1-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "types-requests", "version": "2.33.0.20260712"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/e7/010c87f559e216d83f9dc51e939633fd0d0ead3377340181ab0e223cd3b5/types_requests-2.33.0.20260712-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/e8/f7dac2e980bacc92bdc26cebae4ae4d50cae5380732c50980598fc0bbae4/websockets-16.1.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c3/fb/951032a3bf22a5697c83183fb6294a4843772947a70e616c57b3ff5f522e/cryptography-50.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7d/47/5ecf1023850036e674c77ec4de86182d309ae344e39e7cba984b7df5d647/cffi-2.1.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/77bcb1168b33704908295533d27f10eb811e9e3e193e8993dc99572211d3/rpds_py-2026.6.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/3a/764912c58293d95b6dcdf4cc255f9d10de310580ced547b082eb9d72018c/sse_starlette-3.4.8-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.52.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/79/4a20b54ab0491485ccd8c077db2d39187c7f12b3e15485d38a7be37c81b4/uvicorn-0.52.4-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "e39da8a431d3f40f0c1638f060e9b600"} {"python_version": "3.14t", "dependencies": [{"metadata": {"name": "openai-agents", "version": "0.14.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/af/6e/1e9adcedcde7b163579b88a68f765a4915be4ead0713270386d9432cfd2f/openai_agents-0.14.8-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "2.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ae/f4/561ed79fd94876160018a5e75254cfcb9b0e62d4dded9dcb20072e86d623/openai-2.44.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "griffelib", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/b6/f65ac785d4ac90dcf7c831ac6256f5dd4a19780f4e1575b2c0d6eeebe319/griffelib-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/81/6b/59127338b86d9fe4d99418f5a15118bea778103ee0fe9d9dd7e0af174e95/jiter-0.16.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "mcp", "version": "1.29.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/c8/248b201f6d753d69fd5d6506011abbb35a946d9142b2ae311a948fd0be3d/mcp-1.29.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1c/6c/c73fa9d5a85f6ab05395de61c5f6984e0a9ff40bb5ff888d46dff02526c6/charset_normalizer-3.5.1-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "types-requests", "version": "2.33.0.20260712"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/e7/010c87f559e216d83f9dc51e939633fd0d0ead3377340181ab0e223cd3b5/types_requests-2.33.0.20260712-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/e8/f7dac2e980bacc92bdc26cebae4ae4d50cae5380732c50980598fc0bbae4/websockets-16.1.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c3/fb/951032a3bf22a5697c83183fb6294a4843772947a70e616c57b3ff5f522e/cryptography-50.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7d/47/5ecf1023850036e674c77ec4de86182d309ae344e39e7cba984b7df5d647/cffi-2.1.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/77bcb1168b33704908295533d27f10eb811e9e3e193e8993dc99572211d3/rpds_py-2026.6.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/3a/764912c58293d95b6dcdf4cc255f9d10de310580ced547b082eb9d72018c/sse_starlette-3.4.8-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.52.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/79/4a20b54ab0491485ccd8c077db2d39187c7f12b3e15485d38a7be37c81b4/uvicorn-0.52.4-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "e39da8a431d3f40f0c1638f060e9b600"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "redis", "version": "7.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4a/2e/2677f3f93dae0497e7e33b6637302e7f3744efc553f34231183e32584885/redis-7.4.1-py3-none-any.whl"}}], "install_targets_hash": "e7a5d4bd46a49db6ccfdd2e16c07f1d1"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "redis", "version": "7.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4a/2e/2677f3f93dae0497e7e33b6637302e7f3744efc553f34231183e32584885/redis-7.4.1-py3-none-any.whl"}}], "install_targets_hash": "e7a5d4bd46a49db6ccfdd2e16c07f1d1"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}], "install_targets_hash": "ec8576124014b08444bda36a1922532d"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}], "install_targets_hash": "ec8576124014b08444bda36a1922532d"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "mcp", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/af/8644cc5fa26a59afd2df2e98eeb19e72926887fa4b7441aba4ff661140db/mcp-2.1.1-py3-none-any.whl"}}, {"metadata": {"name": "mcp-types", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/d0/242e63c510f4a17381f55b1549a3f94f5687a0595984febd2b6f87a687a0/mcp_types-2.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/6f/a04e900f465ff3221ccc395522503e2d10e79fa21f2723c8e177aae1e0d1/opentelemetry_api-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/02/bc19b47a96c2d3109760711acf22369e56bd7e405ca52f7ade164d2ead57/pydantic_core-2.46.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/97/672cb32ce0dfea44b740cb7b4f97038463b9cf7c0ead1aacf595572851d6/pyjwt-2.14.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/f0/424cb557d99aa86ac55da5e2add02e2882e44047b6264f93ade1b975a993/cryptography-50.0.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7d/47/5ecf1023850036e674c77ec4de86182d309ae344e39e7cba984b7df5d647/cffi-2.1.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/77bcb1168b33704908295533d27f10eb811e9e3e193e8993dc99572211d3/rpds_py-2026.6.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/6a/2ba3ed4a69babf3afdddf7d8314a48d87562c0a442206bbc2a1b50d5efc0/sse_starlette-3.4.11-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.53.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/76/18/0eea75741ee812e9f598b687619ce2454f6c3a1c5cd21ea990ec6bd26f45/uvicorn-0.53.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "f0d2472e8e45f37ecbb75fd658385dd5"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "pure_eval", "version": "0.2.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6d/18/83376915176eb058cb86470eb7396388a13350b09a8f233a79303bbcbc5b/pure_eval-0.2.4-py3-none-any.whl"}}], "install_targets_hash": "f57089decb29d6779c0a7d039d6126c1"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "langchain", "version": "1.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/85/86/cc13651cfda820d96ca8c612538166334935e8cf4331a31f5dd369d27760/langchain-1.4.2-py3-none-any.whl"}}, {"metadata": {"name": "langchain-core", "version": "1.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e6/18/cf18cfec118b02e003f35300b54d6a1173dc6e4905cffdf5ea49e390a7f9/langchain_core-1.6.3-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "jsonpatch", "version": "1.33"}, "download_info": {"url": "https://files.pythonhosted.org/packages/73/07/02e16ed01e04a374e644b575638ec7987ae846d25ad97bcc9945a3ee4b0e/jsonpatch-1.33-py2.py3-none-any.whl"}}, {"metadata": {"name": "langgraph", "version": "1.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0a/7f/c5c30e4be99ff821029c7ac872a480676bb179c9f3df85ea3f38d13f86d4/langgraph-1.2.11-py3-none-any.whl"}}, {"metadata": {"name": "langgraph-checkpoint", "version": "4.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/71/3b475f09bd57d3a5649792c66353312b4432afd843f301739dfcebd157f0/langgraph_checkpoint-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "langgraph-prebuilt", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/43/3fe1a700b8490ed02679cdbbc8c915eb23a092faf496c9c1118abcd10be3/langgraph_prebuilt-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "langgraph-sdk", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/43/d5/2ad7f3a835c6fcebf58b6669552536ecd52d2dfe4cf49c6c36648fd83572/langgraph_sdk-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "langsmith", "version": "0.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/51/892ff5a2efc8e222ca114dd0e19b56978f78a5ee62d3b33783588dd8e6d4/langsmith-0.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/64/a4e536cb16d7f61a7fd3120b46c577fc7fa7325992f69c4f52bc786d77d8/pydantic_core-2.46.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "uuid_utils", "version": "0.17.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/33/11/a2ef25dc4a3dcae5ddf8a7c2debc0d10719a991e327e43913605fd3b9c90/uuid_utils-0.17.1-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "websockets", "version": "16.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b2/39/26762f734113e22da2b942c3aca85798e0c0405d64c256549540ff31e5a1/websockets-16.1.1-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "jsonpointer", "version": "3.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/6a/a83720e953b1682d2d109d3c2dbb0bc9bf28cc1cbc205be4ef4be5da709d/jsonpointer-3.1.1-py3-none-any.whl"}}, {"metadata": {"name": "langchain-protocol", "version": "0.0.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/80/c9/f6cbf357d48ccbd18bb394433b1fd7ad9be004eed9377ad08bb85777e5e6/langchain_protocol-0.0.19-py3-none-any.whl"}}, {"metadata": {"name": "orjson", "version": "3.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0f/f3/742fb1f62b825f2c010697eaf4e828004bc2a81e7e806666989c132c7c42/orjson-3.12.0.tar.gz"}}, {"metadata": {"name": "ormsgpack", "version": "1.12.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/87/4c/27a95466354606b256f24fad464d7c97ab62bce6cc529dd4673e1179b8fb/ormsgpack-1.12.2-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/ee/e4e10a94d51cd1ee638aa7e00b65399e6b2a4e8376ab6d2eac9f95586671/charset_normalizer-3.5.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "urllib3", "version": "2.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "xxhash", "version": "4.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/0c/16b5e419f24e59507ee05626d2bb0deafdb03f9f27783bc0785a9849602e/xxhash-4.0.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "zstandard", "version": "0.25.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/aa/3e0508d5a5dd96529cdc5a97011299056e14c6505b678fd58938792794b1/zstandard-0.25.0.tar.gz"}}], "install_targets_hash": "f6f70b07098b8c82c22d548106cfcc40"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "asyncpg", "version": "0.31.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6a/81/e6be6e37e560bd91e6c23ea8a6138a04fd057b08cf63d3c5055c98e81c1d/asyncpg-0.31.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "f737563b075b37dba35f4a4e7631e9cd"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "asyncpg", "version": "0.31.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6a/81/e6be6e37e560bd91e6c23ea8a6138a04fd057b08cf63d3c5055c98e81c1d/asyncpg-0.31.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "f737563b075b37dba35f4a4e7631e9cd"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "asyncpg", "version": "0.31.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6a/81/e6be6e37e560bd91e6c23ea8a6138a04fd057b08cf63d3c5055c98e81c1d/asyncpg-0.31.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "f737563b075b37dba35f4a4e7631e9cd"} {"python_version": "3.14t", "dependencies": [{"metadata": {"name": "asyncpg", "version": "0.31.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6a/81/e6be6e37e560bd91e6c23ea8a6138a04fd057b08cf63d3c5055c98e81c1d/asyncpg-0.31.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "f737563b075b37dba35f4a4e7631e9cd"} {"python_version": "3.14t", "dependencies": [{"metadata": {"name": "asyncpg", "version": "0.31.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6a/81/e6be6e37e560bd91e6c23ea8a6138a04fd057b08cf63d3c5055c98e81c1d/asyncpg-0.31.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "f737563b075b37dba35f4a4e7631e9cd"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "asyncpg", "version": "0.31.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6a/81/e6be6e37e560bd91e6c23ea8a6138a04fd057b08cf63d3c5055c98e81c1d/asyncpg-0.31.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "f737563b075b37dba35f4a4e7631e9cd"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "asyncpg", "version": "0.31.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6a/81/e6be6e37e560bd91e6c23ea8a6138a04fd057b08cf63d3c5055c98e81c1d/asyncpg-0.31.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "f737563b075b37dba35f4a4e7631e9cd"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "asyncpg", "version": "0.31.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6a/81/e6be6e37e560bd91e6c23ea8a6138a04fd057b08cf63d3c5055c98e81c1d/asyncpg-0.31.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "f737563b075b37dba35f4a4e7631e9cd"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "asyncpg", "version": "0.31.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6a/81/e6be6e37e560bd91e6c23ea8a6138a04fd057b08cf63d3c5055c98e81c1d/asyncpg-0.31.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "f737563b075b37dba35f4a4e7631e9cd"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "asyncpg", "version": "0.31.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6a/81/e6be6e37e560bd91e6c23ea8a6138a04fd057b08cf63d3c5055c98e81c1d/asyncpg-0.31.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "f737563b075b37dba35f4a4e7631e9cd"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "asyncpg", "version": "0.31.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6a/81/e6be6e37e560bd91e6c23ea8a6138a04fd057b08cf63d3c5055c98e81c1d/asyncpg-0.31.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "f737563b075b37dba35f4a4e7631e9cd"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "asyncpg", "version": "0.31.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6a/81/e6be6e37e560bd91e6c23ea8a6138a04fd057b08cf63d3c5055c98e81c1d/asyncpg-0.31.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "f737563b075b37dba35f4a4e7631e9cd"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "asyncpg", "version": "0.31.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6a/81/e6be6e37e560bd91e6c23ea8a6138a04fd057b08cf63d3c5055c98e81c1d/asyncpg-0.31.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "f737563b075b37dba35f4a4e7631e9cd"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "asyncpg", "version": "0.31.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6a/81/e6be6e37e560bd91e6c23ea8a6138a04fd057b08cf63d3c5055c98e81c1d/asyncpg-0.31.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "f737563b075b37dba35f4a4e7631e9cd"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "asyncpg", "version": "0.31.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6a/81/e6be6e37e560bd91e6c23ea8a6138a04fd057b08cf63d3c5055c98e81c1d/asyncpg-0.31.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "f737563b075b37dba35f4a4e7631e9cd"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "asyncpg", "version": "0.31.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6a/81/e6be6e37e560bd91e6c23ea8a6138a04fd057b08cf63d3c5055c98e81c1d/asyncpg-0.31.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "f737563b075b37dba35f4a4e7631e9cd"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "asyncpg", "version": "0.31.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6a/81/e6be6e37e560bd91e6c23ea8a6138a04fd057b08cf63d3c5055c98e81c1d/asyncpg-0.31.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "f737563b075b37dba35f4a4e7631e9cd"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "asyncpg", "version": "0.31.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6a/81/e6be6e37e560bd91e6c23ea8a6138a04fd057b08cf63d3c5055c98e81c1d/asyncpg-0.31.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "f737563b075b37dba35f4a4e7631e9cd"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "asyncpg", "version": "0.31.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6a/81/e6be6e37e560bd91e6c23ea8a6138a04fd057b08cf63d3c5055c98e81c1d/asyncpg-0.31.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}], "install_targets_hash": "f737563b075b37dba35f4a4e7631e9cd"} +{"python_version": "3.14t", "dependencies": [{"metadata": {"name": "fastapi", "version": "0.123.10"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/d7/f0/7cb92c4a720def85240fd63fbbcf147ce19e7a731c8e1032376bb5a486ac/fastapi-0.123.10-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c5/02/bc19b47a96c2d3109760711acf22369e56bd7e405ca52f7ade164d2ead57/pydantic_core-2.46.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "starlette", "version": "0.50.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/d9/52/1064f510b141bd54025f9b55105e26d1fa970b9be67ad766380a3c9b74b0/starlette-0.50.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}], "install_targets_hash": "fd80cd7f13ecac6f1ce29c0a9f4eb166"} +{"python_version": "3.15", "dependencies": [{"metadata": {"name": "openfeature_sdk", "version": "0.7.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/9b/20/cb043f54b11505d993e4dd84652cfc44c1260dc94b7f41aa35489af58277/openfeature_sdk-0.7.5-py3-none-any.whl"}}], "install_targets_hash": "1014994e190575f0710da79951d7f561"} {"python_version": "3.15", "dependencies": [{"metadata": {"name": "openfeature_sdk", "version": "0.7.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/9b/20/cb043f54b11505d993e4dd84652cfc44c1260dc94b7f41aa35489af58277/openfeature_sdk-0.7.5-py3-none-any.whl"}}], "install_targets_hash": "1014994e190575f0710da79951d7f561"} -{"python_version": "3.15", "dependencies": [{"metadata": {"name": "fastmcp", "version": "1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b9/bf/0a77688242f30f81e3633d3765289966d9c7e408f9dcb4928a85852b9fde/fastmcp-1.0-py3-none-any.whl"}}, {"metadata": {"name": "mcp", "version": "1.29.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0b/04/d6b4fb82eefe9e81807aabca1ac98f460ae0883974b83a997aaa20c52545/mcp-1.29.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/af/f9/8a06bea35ef8daf588f707784c973a7046e0034c8d8cfb08828eeffb8b75/pydantic_core-2.46.5.tar.gz"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.13.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ba/19/797e2aaac9df6a66f1550f49979dc1b1e39ecd2077501c30efa81e8d5d67/cryptography-50.0.1-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0c/75/2f5207ff6d1a613133b23a5203cc0c2a628313b5eb3974d7956ae3c57950/cffi-2.1.1-cp315-cp315-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c3/63/e7b3a1a5358dd32c930a1062d8e15b67fd6e8922e81df9e91706d66ee5c8/rpds_py-2026.6.3-cp315-cp315-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.8"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/dd/3a/764912c58293d95b6dcdf4cc255f9d10de310580ced547b082eb9d72018c/sse_starlette-3.4.8-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "typer", "version": "0.27.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/dc/bf/205d0004930ede8f542fb58f601526fccf4ae7626075ca1e6c4de5d3d652/typer-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "shellingham", "version": "1.5.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.52.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/f1/79/4a20b54ab0491485ccd8c077db2d39187c7f12b3e15485d38a7be37c81b4/uvicorn-0.52.4-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "20723503fc47693dca3f6601f6cab1ee"} {"python_version": "3.15", "dependencies": [{"metadata": {"name": "mistralai", "version": "2.3.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/83/e0/9f246d18f8fe6e815f7cae88c437c986b342d3ff568607c8e0d53f4710d0/mistralai-2.3.2-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-semantic-conventions", "version": "0.60b1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7a/5e/5958555e09635d09b75de3c4f8b9cae7335ca545d77392ffe7331534c402/opentelemetry_semantic_conventions-0.60b1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.39.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/df/d3f1ddf4bb4cb50ed9b1139cc7b1c54c34a1e7ce8fd1b9a37c0d1551a6bd/opentelemetry_api-1.39.1-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fa/5e/f8e9a1d23b9c20a551a8a02ea3637b4642e22c2626e3a13a9a29cdea99eb/importlib_metadata-8.7.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "eval_type_backport", "version": "0.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/a7/bb99bf5e6f78736ddb53480f2c3ff3702ffe2196a7c5e1661c03081d398e/eval_type_backport-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonpath-python", "version": "1.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/8a/1270a6803bd821cbfcdda387eaa13cb41a7b1f7b9bd145979b3bfb9d6cb7/jsonpath_python-1.1.6-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/af/f9/8a06bea35ef8daf588f707784c973a7046e0034c8d8cfb08828eeffb8b75/pydantic_core-2.46.5.tar.gz"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "zipp", "version": "4.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}], "install_targets_hash": "220b48fa30e6d4e6ee437946e03f7dfd"} {"python_version": "3.15", "dependencies": [{"metadata": {"name": "Flask", "version": "2.3.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/fd/56/26f0be8adc2b4257df20c1c4260ddd0aa396cf8e75d90ab2f7ff99bc34f9/flask-2.3.3-py3-none-any.whl"}}, {"metadata": {"name": "Flask-Login", "version": "0.6.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/59/f5/67e9cc5c2036f58115f9fe0f00d203cf6780c3ff8ae0e705e7a9d9e8ff9e/Flask_Login-0.6.3-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz"}}], "install_targets_hash": "26b4bd6a717ed504426367c6af492c2d"} +{"python_version": "3.15", "dependencies": [{"metadata": {"name": "SQLAlchemy", "version": "2.1.0rc2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/38/91/659dd0375c1c5a65c22f500e9c6de7e391754024dc5950cc0a468fabfd49/sqlalchemy-2.1.0rc2-cp315-cp315t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}], "install_targets_hash": "3f216279dfc7a16b8b146f00ed33cb9a"} {"python_version": "3.15", "dependencies": [{"metadata": {"name": "SQLAlchemy", "version": "2.1.0rc2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/8b/bd6da96cb82fb4d41a7cbfbef3fed1320d9802c4fdfefc438375f4bdc6ab/sqlalchemy-2.1.0rc2-cp315-cp315-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}], "install_targets_hash": "3f216279dfc7a16b8b146f00ed33cb9a"} {"python_version": "3.15", "dependencies": [{"metadata": {"name": "huey", "version": "3.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/31/cee585bd4d1e39947a426a6736f4e17d22b454952370fb9cf48eb3103085/huey-3.4.0-py3-none-any.whl"}}], "install_targets_hash": "40f9e0b7b0afb09fe34d19285f3f89c9"} -{"python_version": "3.15", "dependencies": [{"metadata": {"name": "fastmcp", "version": "0.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/f5/07/bc69e65b45d638822190bce0defb497a50d240291b8467cb79078d0064b7/fastmcp-0.1.0-py3-none-any.whl"}}, {"metadata": {"name": "mcp", "version": "1.29.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0b/04/d6b4fb82eefe9e81807aabca1ac98f460ae0883974b83a997aaa20c52545/mcp-1.29.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/af/f9/8a06bea35ef8daf588f707784c973a7046e0034c8d8cfb08828eeffb8b75/pydantic_core-2.46.5.tar.gz"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.13.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ba/19/797e2aaac9df6a66f1550f49979dc1b1e39ecd2077501c30efa81e8d5d67/cryptography-50.0.1-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0c/75/2f5207ff6d1a613133b23a5203cc0c2a628313b5eb3974d7956ae3c57950/cffi-2.1.1-cp315-cp315-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c3/63/e7b3a1a5358dd32c930a1062d8e15b67fd6e8922e81df9e91706d66ee5c8/rpds_py-2026.6.3-cp315-cp315-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.8"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/dd/3a/764912c58293d95b6dcdf4cc255f9d10de310580ced547b082eb9d72018c/sse_starlette-3.4.8-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "typer", "version": "0.27.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/dc/bf/205d0004930ede8f542fb58f601526fccf4ae7626075ca1e6c4de5d3d652/typer-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "shellingham", "version": "1.5.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.52.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/f1/79/4a20b54ab0491485ccd8c077db2d39187c7f12b3e15485d38a7be37c81b4/uvicorn-0.52.4-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "4ef5d5161db3a01ccf52260b7895e529"} +{"python_version": "3.15", "dependencies": [{"metadata": {"name": "huey", "version": "3.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/31/cee585bd4d1e39947a426a6736f4e17d22b454952370fb9cf48eb3103085/huey-3.4.0-py3-none-any.whl"}}], "install_targets_hash": "40f9e0b7b0afb09fe34d19285f3f89c9"} {"python_version": "3.15", "dependencies": [{"metadata": {"name": "mistralai", "version": "2.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e3/d5/6b9c08ab9b5b890970e8949bf00a9f8f82653826de5cc5ad506fe1c1fb73/mistralai-2.6.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-semantic-conventions", "version": "0.60b1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7a/5e/5958555e09635d09b75de3c4f8b9cae7335ca545d77392ffe7331534c402/opentelemetry_semantic_conventions-0.60b1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.39.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/df/d3f1ddf4bb4cb50ed9b1139cc7b1c54c34a1e7ce8fd1b9a37c0d1551a6bd/opentelemetry_api-1.39.1-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fa/5e/f8e9a1d23b9c20a551a8a02ea3637b4642e22c2626e3a13a9a29cdea99eb/importlib_metadata-8.7.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "eval_type_backport", "version": "0.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/a7/bb99bf5e6f78736ddb53480f2c3ff3702ffe2196a7c5e1661c03081d398e/eval_type_backport-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonpath-python", "version": "1.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/8a/1270a6803bd821cbfcdda387eaa13cb41a7b1f7b9bd145979b3bfb9d6cb7/jsonpath_python-1.1.6-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/af/f9/8a06bea35ef8daf588f707784c973a7046e0034c8d8cfb08828eeffb8b75/pydantic_core-2.46.5.tar.gz"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "zipp", "version": "4.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}], "install_targets_hash": "4f94c708225730a84d6fdb55c929ba1b"} {"python_version": "3.15", "dependencies": [{"metadata": {"name": "SQLAlchemy", "version": "2.0.54"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/a1/bd5e3e99bc9c8863b51ac5b9b03008a7f2da8c6b59695992f5c654e1265b/sqlalchemy-2.0.54-py3-none-any.whl"}}, {"metadata": {"name": "greenlet", "version": "3.5.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/16/ac9e547b611539aaed1870eb1d6ddc57abdd5924b3a99bb9b5f0b44176b8/greenlet-3.5.6-cp315-cp315-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}], "install_targets_hash": "5f2fe90c79dc2d3da3f52a628b506ec0"} {"python_version": "3.15", "dependencies": [{"metadata": {"name": "Quart", "version": "0.23.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/5c/c1/26dca56249da1a889ebb946000ab272712476209234f714ad3e8013ee005/quart-0.23.1-py3-none-any.whl"}}, {"metadata": {"name": "quart-auth", "version": "0.12.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ce/6b/e902def52a0c1c32bf872d87eb76cf4bf6109d015ac8c9e6768894676c8d/quart_auth-0.12.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.7.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/18/f1/46d32fe4b9aae09fe397e768ff376d9b6bdbb4f11faaa727f163c3457b43/pytest_forked-1.7.5-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "Hypercorn", "version": "0.18.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/93/35/850277d1b17b206bd10874c8a9a3f52e059452fb49bb0d22cbb908f6038b/hypercorn-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "h2", "version": "4.4.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/22/e85faf23bd72a92d1921e37d674ca56eb298a3c8be31fdecef0ff2b3aaac/h2-4.4.1-py3-none-any.whl"}}, {"metadata": {"name": "hpack", "version": "4.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/b4/4a9fcfb2aef6ba44d9073ecd301443aa00b3dac95de5619f2a7de7ec8a91/hpack-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "hyperframe", "version": "6.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/48/30/47d0bf6072f7252e6521f3447ccfa40b421b6824517f82854703d0f5a98b/hyperframe-6.1.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "wsproto", "version": "1.3.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a4/f5/10b68b7b1544245097b2a1b8238f66f2fc6dcaeb24ba5d917f52bd2eed4f/wsproto-1.3.2-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "priority", "version": "2.0.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/5e/5f/82c8074f7e84978129347c2c6ec8b6c59f3584ff1a20bc3c940a3e061790/priority-2.0.0-py3-none-any.whl"}}], "install_targets_hash": "8466032de3e88e282989c969ffd1cb35"} +{"python_version": "3.15", "dependencies": [{"metadata": {"name": "Quart", "version": "0.23.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/5c/c1/26dca56249da1a889ebb946000ab272712476209234f714ad3e8013ee005/quart-0.23.1-py3-none-any.whl"}}, {"metadata": {"name": "quart-auth", "version": "0.12.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ce/6b/e902def52a0c1c32bf872d87eb76cf4bf6109d015ac8c9e6768894676c8d/quart_auth-0.12.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.7.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/18/f1/46d32fe4b9aae09fe397e768ff376d9b6bdbb4f11faaa727f163c3457b43/pytest_forked-1.7.5-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "Hypercorn", "version": "0.18.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/93/35/850277d1b17b206bd10874c8a9a3f52e059452fb49bb0d22cbb908f6038b/hypercorn-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "h2", "version": "4.4.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/22/e85faf23bd72a92d1921e37d674ca56eb298a3c8be31fdecef0ff2b3aaac/h2-4.4.1-py3-none-any.whl"}}, {"metadata": {"name": "hpack", "version": "4.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/b4/4a9fcfb2aef6ba44d9073ecd301443aa00b3dac95de5619f2a7de7ec8a91/hpack-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "hyperframe", "version": "6.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/48/30/47d0bf6072f7252e6521f3447ccfa40b421b6824517f82854703d0f5a98b/hyperframe-6.1.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "wsproto", "version": "1.3.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a4/f5/10b68b7b1544245097b2a1b8238f66f2fc6dcaeb24ba5d917f52bd2eed4f/wsproto-1.3.2-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "priority", "version": "2.0.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/5e/5f/82c8074f7e84978129347c2c6ec8b6c59f3584ff1a20bc3c940a3e061790/priority-2.0.0-py3-none-any.whl"}}], "install_targets_hash": "8466032de3e88e282989c969ffd1cb35"} +{"python_version": "3.15", "dependencies": [{"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "Flask-Login", "version": "0.6.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/59/f5/67e9cc5c2036f58115f9fe0f00d203cf6780c3ff8ae0e705e7a9d9e8ff9e/Flask_Login-0.6.3-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz"}}], "install_targets_hash": "8e9f2612223a3ea6906a34018db168cd"} {"python_version": "3.15", "dependencies": [{"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "Flask-Login", "version": "0.6.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/59/f5/67e9cc5c2036f58115f9fe0f00d203cf6780c3ff8ae0e705e7a9d9e8ff9e/Flask_Login-0.6.3-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz"}}], "install_targets_hash": "8e9f2612223a3ea6906a34018db168cd"} {"python_version": "3.15", "dependencies": [{"metadata": {"name": "strawberry-graphql", "version": "0.327.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/09/e0deac5d4f466f6ecae1b91a91d1a291aad1890960a5d891bb80bda3425c/strawberry_graphql-0.327.7-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.12"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/b6/304c572e79b9e82982dbd5091e26a89f5018e565868091d804c2142f6ba5/graphql_core-3.2.12-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "cross-web", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7a/4a/78b52ec2edcbd9b123638f4e0421fd8699ebe653ebf63ac5f82abd2665bc/cross_web-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "fastapi", "version": "0.141.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/03/10388a42375ee7e4ac9b94eb2c5c569c8b5795e377e701c9ac3ad63de890/fastapi-0.141.1-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/af/f9/8a06bea35ef8daf588f707784c973a7046e0034c8d8cfb08828eeffb8b75/pydantic_core-2.46.5.tar.gz"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}], "install_targets_hash": "973f4a5847325907761d52b88b87e613"} +{"python_version": "3.15", "dependencies": [{"metadata": {"name": "strawberry-graphql", "version": "0.327.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/09/e0deac5d4f466f6ecae1b91a91d1a291aad1890960a5d891bb80bda3425c/strawberry_graphql-0.327.7-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.12"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/b6/304c572e79b9e82982dbd5091e26a89f5018e565868091d804c2142f6ba5/graphql_core-3.2.12-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "cross-web", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7a/4a/78b52ec2edcbd9b123638f4e0421fd8699ebe653ebf63ac5f82abd2665bc/cross_web-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "fastapi", "version": "0.141.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/03/10388a42375ee7e4ac9b94eb2c5c569c8b5795e377e701c9ac3ad63de890/fastapi-0.141.1-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/af/f9/8a06bea35ef8daf588f707784c973a7046e0034c8d8cfb08828eeffb8b75/pydantic_core-2.46.5.tar.gz"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}], "install_targets_hash": "973f4a5847325907761d52b88b87e613"} {"python_version": "3.15", "dependencies": [{"metadata": {"name": "mistralai", "version": "2.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c0/ab/a565e4bec9b5496eb3b44b8799b6ad8378b2cd0be4cd5e6b7d098e8cedcc/mistralai-2.0.5-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-semantic-conventions", "version": "0.60b1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7a/5e/5958555e09635d09b75de3c4f8b9cae7335ca545d77392ffe7331534c402/opentelemetry_semantic_conventions-0.60b1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.39.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/df/d3f1ddf4bb4cb50ed9b1139cc7b1c54c34a1e7ce8fd1b9a37c0d1551a6bd/opentelemetry_api-1.39.1-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fa/5e/f8e9a1d23b9c20a551a8a02ea3637b4642e22c2626e3a13a9a29cdea99eb/importlib_metadata-8.7.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "eval_type_backport", "version": "0.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/a7/bb99bf5e6f78736ddb53480f2c3ff3702ffe2196a7c5e1661c03081d398e/eval_type_backport-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/af/f9/8a06bea35ef8daf588f707784c973a7046e0034c8d8cfb08828eeffb8b75/pydantic_core-2.46.5.tar.gz"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "zipp", "version": "4.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}], "install_targets_hash": "994d711e6ebda622f4cced8803ee9a73"} {"python_version": "3.15", "dependencies": [{"metadata": {"name": "trytond", "version": "8.0.10"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/db/57a3be9504273276216dde241d3bc3602c9cae62f60afb1944cf651fe638/trytond-8.0.10-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "lxml", "version": "6.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/70/c5/b71ffb289b15e2642e2a3cf6d468c44da39ea119061a99e5b05e3d10f217/lxml-6.1.3-cp315-cp315-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz"}}, {"metadata": {"name": "pwdlib", "version": "0.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6b/2e/51979293b2337f508597d13ee20db1ac1d43e48086b2ed7de6da213ed46b/pwdlib-0.3.1-py3-none-any.whl"}}, {"metadata": {"name": "argon2-cffi", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/d3/a8b22fa575b297cd6e3e3b0155c7e25db170edf1c74783d6a31a2490b8d9/argon2_cffi-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "python-sql", "version": "1.8.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/77/ac/3603bbdde340f7354c975431c94b70ef3e99966c5b170fa121f8e64d269e/python_sql-1.8.1-py3-none-any.whl"}}, {"metadata": {"name": "relatorio", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/74/eb/798c426ebd54f52c27aed6593eaf96ed07dca3ca1d084822cc34f0db5159/relatorio-1.0.0-py3-none-any.whl"}}, {"metadata": {"name": "Genshi", "version": "0.7.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/27/503016bc329720ba2856eb4831d6ba36089cd6f15bc4fe85db69fea5b563/genshi-0.7.11-py3-none-any.whl"}}, {"metadata": {"name": "argon2-cffi-bindings", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6f/86/5363df11b86d02cf3662208e7406496327649cc90eb365bf6f4e8a54a41f/argon2_cffi_bindings-26.1.0-cp310-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/44/16/29e6d01b388bef055ecd6ca8244b3f4d336bd09e92d5d892187b9601084e/cffi-2.1.1-cp315-cp315-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "defusedxml", "version": "0.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "polib", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6b/99/45bb1f9926efe370c6dbe324741c749658e44cb060124f28dad201202274/polib-1.2.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "puremagic", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/81/314320aeffd88dadeac553ff9eb10f54507ab41deccd0c69f6221d254a0a/puremagic-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "simpleeval", "version": "1.0.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/33/d1ecd9f4f5f272b36ad7b268e307ba0a59c109d8ad134a231cda780baac9/simpleeval-1.0.8-py3-none-any.whl"}}], "install_targets_hash": "ab391832abd062e60ebbad762fe1f443"} +{"python_version": "3.15", "dependencies": [{"metadata": {"name": "grpcio", "version": "1.84.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/4f/4435c0aae54657258d9cfcba78598f3d9e5fe4c82ff18d78558567b90faf/grpcio-1.84.0.tar.gz"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "protobuf", "version": "7.36.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/39/ca/c47f91d3cab175b01fd8c4f0d80fdf8613be876cc616e66ad281a59c5ddf/protobuf-7.36.1-py3-none-any.whl"}}, {"metadata": {"name": "mypy-protobuf", "version": "5.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/ec/5ffcf8f5f53757e01afdece10c664e694ac60d2f17c2036811b85b842a5b/mypy_protobuf-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "types-protobuf", "version": "7.35.1.20260906"}, "download_info": {"url": "https://files.pythonhosted.org/packages/44/4e/f63e826c68f77ef875506d72f225918800346545ee99847bc28f3394f18d/types_protobuf-7.35.1.20260906-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.7.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/18/f1/46d32fe4b9aae09fe397e768ff376d9b6bdbb4f11faaa727f163c3457b43/pytest_forked-1.7.5-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}], "install_targets_hash": "b000c682d30e09087f05bd957ebe7664"} {"python_version": "3.15", "dependencies": [{"metadata": {"name": "grpcio", "version": "1.84.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0e/9e/799d4c45db91bbdcd8c54b3982932dbcf3d059f7ce67dca3e8540faa1ece/grpcio-1.84.0-cp315-cp315-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "protobuf", "version": "7.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/db/f3/3996583dd2906297a637af12114deddf7658af6e683fedb83be061983fb5/protobuf-7.36.2-cp310-abi3-manylinux2014_x86_64.whl"}}, {"metadata": {"name": "mypy-protobuf", "version": "5.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/ec/5ffcf8f5f53757e01afdece10c664e694ac60d2f17c2036811b85b842a5b/mypy_protobuf-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "types-protobuf", "version": "7.35.1.20260906"}, "download_info": {"url": "https://files.pythonhosted.org/packages/44/4e/f63e826c68f77ef875506d72f225918800346545ee99847bc28f3394f18d/types_protobuf-7.35.1.20260906-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.7.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/18/f1/46d32fe4b9aae09fe397e768ff376d9b6bdbb4f11faaa727f163c3457b43/pytest_forked-1.7.5-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}], "install_targets_hash": "b000c682d30e09087f05bd957ebe7664"} +{"python_version": "3.15", "dependencies": [{"metadata": {"name": "tornado", "version": "6.6a1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/6d/a5/8d2a0673aa45376dc0d16a593abee707313ff919a22c10b33d02a7347e8b/tornado-6.6a1-cp311-abi3-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}], "install_targets_hash": "b883316dda3824a719a7fb8ca38112ff"} +{"python_version": "3.15", "dependencies": [{"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/4a/4e/8544831ef59d8f27ce92c80871380fdacc8076a8a56ed62f82e54f991333/charset_normalizer-3.5.1-cp315-cp315-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}], "install_targets_hash": "c4e67585767bde6ea034db94a448f267"} {"python_version": "3.15", "dependencies": [{"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/4a/4e/8544831ef59d8f27ce92c80871380fdacc8076a8a56ed62f82e54f991333/charset_normalizer-3.5.1-cp315-cp315-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}], "install_targets_hash": "c4e67585767bde6ea034db94a448f267"} -{"python_version": "3.15", "dependencies": [{"metadata": {"name": "fastmcp", "version": "0.4.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/79/0b/008a340435fe8f0879e9d608f48af2737ad48440e09bd33b83b3fd03798b/fastmcp-0.4.1-py3-none-any.whl"}}, {"metadata": {"name": "mcp", "version": "1.29.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0b/04/d6b4fb82eefe9e81807aabca1ac98f460ae0883974b83a997aaa20c52545/mcp-1.29.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/af/f9/8a06bea35ef8daf588f707784c973a7046e0034c8d8cfb08828eeffb8b75/pydantic_core-2.46.5.tar.gz"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.13.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ba/19/797e2aaac9df6a66f1550f49979dc1b1e39ecd2077501c30efa81e8d5d67/cryptography-50.0.1-cp311-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0c/75/2f5207ff6d1a613133b23a5203cc0c2a628313b5eb3974d7956ae3c57950/cffi-2.1.1-cp315-cp315-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c3/63/e7b3a1a5358dd32c930a1062d8e15b67fd6e8922e81df9e91706d66ee5c8/rpds_py-2026.6.3-cp315-cp315-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.8"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/dd/3a/764912c58293d95b6dcdf4cc255f9d10de310580ced547b082eb9d72018c/sse_starlette-3.4.8-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "typer", "version": "0.27.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/dc/bf/205d0004930ede8f542fb58f601526fccf4ae7626075ca1e6c4de5d3d652/typer-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "shellingham", "version": "1.5.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.52.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/f1/79/4a20b54ab0491485ccd8c077db2d39187c7f12b3e15485d38a7be37c81b4/uvicorn-0.52.4-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "d3ba412b13e2cfc8f79cd31c37175dca"} {"python_version": "3.15", "dependencies": [{"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2-pytest", "version": "1.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/46/ef/e9b6fb576f1f518f68e9f9cce9776870452ae2b8cfbba53b4127701b9a55/httpx2_pytest-1.0.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}], "install_targets_hash": "d6da1d54536a49d0f25beda4d7a148f5"} {"python_version": "3.15", "dependencies": [{"metadata": {"name": "pure_eval", "version": "0.2.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6d/18/83376915176eb058cb86470eb7396388a13350b09a8f233a79303bbcbc5b/pure_eval-0.2.4-py3-none-any.whl"}}, {"metadata": {"name": "asttokens", "version": "3.0.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d4/2b/04b8a15f3a1c77bc79ddf5c73875327f34b4fa75982df2b76e45e402d364/asttokens-3.0.2-py3-none-any.whl"}}, {"metadata": {"name": "executing", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl"}}], "install_targets_hash": "ef91391ff2fb8720438fb9fbd1e2fc94"} +{"python_version": "3.15", "dependencies": [{"metadata": {"name": "pure_eval", "version": "0.2.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6d/18/83376915176eb058cb86470eb7396388a13350b09a8f233a79303bbcbc5b/pure_eval-0.2.4-py3-none-any.whl"}}, {"metadata": {"name": "asttokens", "version": "3.0.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d4/2b/04b8a15f3a1c77bc79ddf5c73875327f34b4fa75982df2b76e45e402d364/asttokens-3.0.2-py3-none-any.whl"}}, {"metadata": {"name": "executing", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl"}}], "install_targets_hash": "ef91391ff2fb8720438fb9fbd1e2fc94"} {"python_version": "3.15", "dependencies": [{"metadata": {"name": "mistralai", "version": "2.10.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/98/f64b54166a607ece4e5c8494c843ac1f9c7c0af6f1014272cc420fe1d519/mistralai-2.10.1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/6f/a04e900f465ff3221ccc395522503e2d10e79fa21f2723c8e177aae1e0d1/opentelemetry_api-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "eval_type_backport", "version": "0.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/a7/bb99bf5e6f78736ddb53480f2c3ff3702ffe2196a7c5e1661c03081d398e/eval_type_backport-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonpath-python", "version": "1.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/8a/1270a6803bd821cbfcdda387eaa13cb41a7b1f7b9bd145979b3bfb9d6cb7/jsonpath_python-1.1.6-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-semantic-conventions", "version": "0.65b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/0e/49df70d9b81fb5cbae4bbf2a49d865b09bcbcbc4eb53f5851b1027738d78/opentelemetry_semantic_conventions-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/af/f9/8a06bea35ef8daf588f707784c973a7046e0034c8d8cfb08828eeffb8b75/pydantic_core-2.46.5.tar.gz"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}], "install_targets_hash": "f60e32909a4363f0d8cc05916d4da67a"} {"python_version": "3.15t", "dependencies": [{"metadata": {"name": "mistralai", "version": "2.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c0/ab/a565e4bec9b5496eb3b44b8799b6ad8378b2cd0be4cd5e6b7d098e8cedcc/mistralai-2.0.5-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-semantic-conventions", "version": "0.60b1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7a/5e/5958555e09635d09b75de3c4f8b9cae7335ca545d77392ffe7331534c402/opentelemetry_semantic_conventions-0.60b1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.39.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/df/d3f1ddf4bb4cb50ed9b1139cc7b1c54c34a1e7ce8fd1b9a37c0d1551a6bd/opentelemetry_api-1.39.1-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fa/5e/f8e9a1d23b9c20a551a8a02ea3637b4642e22c2626e3a13a9a29cdea99eb/importlib_metadata-8.7.1-py3-none-any.whl"}}, {"metadata": {"name": "eval_type_backport", "version": "0.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/a7/bb99bf5e6f78736ddb53480f2c3ff3702ffe2196a7c5e1661c03081d398e/eval_type_backport-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/af/f9/8a06bea35ef8daf588f707784c973a7046e0034c8d8cfb08828eeffb8b75/pydantic_core-2.46.5.tar.gz"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "zipp", "version": "4.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}], "install_targets_hash": "09f62d5b2b308b2b3cee9c7a73dc8d2c"} {"python_version": "3.15t", "dependencies": [{"metadata": {"name": "openfeature_sdk", "version": "0.7.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/9b/20/cb043f54b11505d993e4dd84652cfc44c1260dc94b7f41aa35489af58277/openfeature_sdk-0.7.5-py3-none-any.whl"}}], "install_targets_hash": "1014994e190575f0710da79951d7f561"} +{"python_version": "3.15t", "dependencies": [{"metadata": {"name": "openfeature_sdk", "version": "0.7.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/9b/20/cb043f54b11505d993e4dd84652cfc44c1260dc94b7f41aa35489af58277/openfeature_sdk-0.7.5-py3-none-any.whl"}}], "install_targets_hash": "1014994e190575f0710da79951d7f561"} +{"python_version": "3.15t", "dependencies": [{"metadata": {"name": "openfeature_sdk", "version": "0.7.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/9b/20/cb043f54b11505d993e4dd84652cfc44c1260dc94b7f41aa35489af58277/openfeature_sdk-0.7.5-py3-none-any.whl"}}], "install_targets_hash": "1014994e190575f0710da79951d7f561"} {"python_version": "3.15t", "dependencies": [{"metadata": {"name": "mistralai", "version": "2.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e3/d5/6b9c08ab9b5b890970e8949bf00a9f8f82653826de5cc5ad506fe1c1fb73/mistralai-2.6.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-semantic-conventions", "version": "0.60b1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7a/5e/5958555e09635d09b75de3c4f8b9cae7335ca545d77392ffe7331534c402/opentelemetry_semantic_conventions-0.60b1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.39.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/df/d3f1ddf4bb4cb50ed9b1139cc7b1c54c34a1e7ce8fd1b9a37c0d1551a6bd/opentelemetry_api-1.39.1-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fa/5e/f8e9a1d23b9c20a551a8a02ea3637b4642e22c2626e3a13a9a29cdea99eb/importlib_metadata-8.7.1-py3-none-any.whl"}}, {"metadata": {"name": "eval_type_backport", "version": "0.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/a7/bb99bf5e6f78736ddb53480f2c3ff3702ffe2196a7c5e1661c03081d398e/eval_type_backport-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonpath-python", "version": "1.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/8a/1270a6803bd821cbfcdda387eaa13cb41a7b1f7b9bd145979b3bfb9d6cb7/jsonpath_python-1.1.6-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/af/f9/8a06bea35ef8daf588f707784c973a7046e0034c8d8cfb08828eeffb8b75/pydantic_core-2.46.5.tar.gz"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "zipp", "version": "4.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}], "install_targets_hash": "18668385af67bc3f77e3be8664774dca"} -{"python_version": "3.15t", "dependencies": [{"metadata": {"name": "fastmcp", "version": "1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b9/bf/0a77688242f30f81e3633d3765289966d9c7e408f9dcb4928a85852b9fde/fastmcp-1.0-py3-none-any.whl"}}, {"metadata": {"name": "mcp", "version": "1.29.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0b/04/d6b4fb82eefe9e81807aabca1ac98f460ae0883974b83a997aaa20c52545/mcp-1.29.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/af/f9/8a06bea35ef8daf588f707784c973a7046e0034c8d8cfb08828eeffb8b75/pydantic_core-2.46.5.tar.gz"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.13.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/bb/ad/5d6702db60b1e40b41ef513b6967ff5848f307d50f8449baf1634f5908f1/cryptography-50.0.1.tar.gz"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/ae/a56fa8c4686ad50e148fcbc8d3ae0d03915ff5c30d795058988c24118cef/cffi-2.1.1-cp315-cp315t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/9d/29/9907bdf1c5346763cf10b7f6852aad86652168c259def904cbe0082c5864/rpds_py-2026.6.3-cp315-cp315t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.8"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/dd/3a/764912c58293d95b6dcdf4cc255f9d10de310580ced547b082eb9d72018c/sse_starlette-3.4.8-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "typer", "version": "0.27.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/dc/bf/205d0004930ede8f542fb58f601526fccf4ae7626075ca1e6c4de5d3d652/typer-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "shellingham", "version": "1.5.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.52.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/f1/79/4a20b54ab0491485ccd8c077db2d39187c7f12b3e15485d38a7be37c81b4/uvicorn-0.52.4-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "20723503fc47693dca3f6601f6cab1ee"} +{"python_version": "3.15t", "dependencies": [{"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}], "install_targets_hash": "1e45025f67a3d865a4071044e1969927"} {"python_version": "3.15t", "dependencies": [{"metadata": {"name": "mistralai", "version": "2.3.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/83/e0/9f246d18f8fe6e815f7cae88c437c986b342d3ff568607c8e0d53f4710d0/mistralai-2.3.2-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-semantic-conventions", "version": "0.60b1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7a/5e/5958555e09635d09b75de3c4f8b9cae7335ca545d77392ffe7331534c402/opentelemetry_semantic_conventions-0.60b1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.39.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/df/d3f1ddf4bb4cb50ed9b1139cc7b1c54c34a1e7ce8fd1b9a37c0d1551a6bd/opentelemetry_api-1.39.1-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fa/5e/f8e9a1d23b9c20a551a8a02ea3637b4642e22c2626e3a13a9a29cdea99eb/importlib_metadata-8.7.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "eval_type_backport", "version": "0.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/a7/bb99bf5e6f78736ddb53480f2c3ff3702ffe2196a7c5e1661c03081d398e/eval_type_backport-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonpath-python", "version": "1.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/8a/1270a6803bd821cbfcdda387eaa13cb41a7b1f7b9bd145979b3bfb9d6cb7/jsonpath_python-1.1.6-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/af/f9/8a06bea35ef8daf588f707784c973a7046e0034c8d8cfb08828eeffb8b75/pydantic_core-2.46.5.tar.gz"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "zipp", "version": "4.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}], "install_targets_hash": "220b48fa30e6d4e6ee437946e03f7dfd"} {"python_version": "3.15t", "dependencies": [{"metadata": {"name": "mistralai", "version": "2.3.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/83/e0/9f246d18f8fe6e815f7cae88c437c986b342d3ff568607c8e0d53f4710d0/mistralai-2.3.2-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-semantic-conventions", "version": "0.60b1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7a/5e/5958555e09635d09b75de3c4f8b9cae7335ca545d77392ffe7331534c402/opentelemetry_semantic_conventions-0.60b1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.39.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/df/d3f1ddf4bb4cb50ed9b1139cc7b1c54c34a1e7ce8fd1b9a37c0d1551a6bd/opentelemetry_api-1.39.1-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fa/5e/f8e9a1d23b9c20a551a8a02ea3637b4642e22c2626e3a13a9a29cdea99eb/importlib_metadata-8.7.1-py3-none-any.whl"}}, {"metadata": {"name": "eval_type_backport", "version": "0.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/a7/bb99bf5e6f78736ddb53480f2c3ff3702ffe2196a7c5e1661c03081d398e/eval_type_backport-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonpath-python", "version": "1.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/8a/1270a6803bd821cbfcdda387eaa13cb41a7b1f7b9bd145979b3bfb9d6cb7/jsonpath_python-1.1.6-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/af/f9/8a06bea35ef8daf588f707784c973a7046e0034c8d8cfb08828eeffb8b75/pydantic_core-2.46.5.tar.gz"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "zipp", "version": "4.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}], "install_targets_hash": "249823eb259de4caefbecfd82d608107"} +{"python_version": "3.15t", "dependencies": [{"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}], "install_targets_hash": "2544ffc140307d915c4ba79d5aafc0dd"} +{"python_version": "3.15t", "dependencies": [{"metadata": {"name": "Flask", "version": "2.3.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/fd/56/26f0be8adc2b4257df20c1c4260ddd0aa396cf8e75d90ab2f7ff99bc34f9/flask-2.3.3-py3-none-any.whl"}}, {"metadata": {"name": "Flask-Login", "version": "0.6.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/59/f5/67e9cc5c2036f58115f9fe0f00d203cf6780c3ff8ae0e705e7a9d9e8ff9e/Flask_Login-0.6.3-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz"}}], "install_targets_hash": "26b4bd6a717ed504426367c6af492c2d"} {"python_version": "3.15t", "dependencies": [{"metadata": {"name": "Flask", "version": "2.3.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/fd/56/26f0be8adc2b4257df20c1c4260ddd0aa396cf8e75d90ab2f7ff99bc34f9/flask-2.3.3-py3-none-any.whl"}}, {"metadata": {"name": "Flask-Login", "version": "0.6.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/59/f5/67e9cc5c2036f58115f9fe0f00d203cf6780c3ff8ae0e705e7a9d9e8ff9e/Flask_Login-0.6.3-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz"}}], "install_targets_hash": "26b4bd6a717ed504426367c6af492c2d"} +{"python_version": "3.15t", "dependencies": [{"metadata": {"name": "Flask", "version": "2.3.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/fd/56/26f0be8adc2b4257df20c1c4260ddd0aa396cf8e75d90ab2f7ff99bc34f9/flask-2.3.3-py3-none-any.whl"}}, {"metadata": {"name": "Flask-Login", "version": "0.6.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/59/f5/67e9cc5c2036f58115f9fe0f00d203cf6780c3ff8ae0e705e7a9d9e8ff9e/Flask_Login-0.6.3-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz"}}], "install_targets_hash": "26b4bd6a717ed504426367c6af492c2d"} +{"python_version": "3.15t", "dependencies": [{"metadata": {"name": "Flask", "version": "2.3.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/fd/56/26f0be8adc2b4257df20c1c4260ddd0aa396cf8e75d90ab2f7ff99bc34f9/flask-2.3.3-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}], "install_targets_hash": "3d3346a121c9335e59917ef88d9c8e69"} +{"python_version": "3.15t", "dependencies": [{"metadata": {"name": "SQLAlchemy", "version": "2.1.0rc2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/38/91/659dd0375c1c5a65c22f500e9c6de7e391754024dc5950cc0a468fabfd49/sqlalchemy-2.1.0rc2-cp315-cp315t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}], "install_targets_hash": "3f216279dfc7a16b8b146f00ed33cb9a"} +{"python_version": "3.15t", "dependencies": [{"metadata": {"name": "SQLAlchemy", "version": "2.1.0rc2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/0f/cfbbed86e295d6aecbfbf84a72b4f21ee012a71c31e362c062dece98a8cf/sqlalchemy-2.1.0rc2-cp315-cp315t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}], "install_targets_hash": "3f216279dfc7a16b8b146f00ed33cb9a"} {"python_version": "3.15t", "dependencies": [{"metadata": {"name": "SQLAlchemy", "version": "2.1.0rc2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/0f/cfbbed86e295d6aecbfbf84a72b4f21ee012a71c31e362c062dece98a8cf/sqlalchemy-2.1.0rc2-cp315-cp315t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}], "install_targets_hash": "3f216279dfc7a16b8b146f00ed33cb9a"} {"python_version": "3.15t", "dependencies": [{"metadata": {"name": "huey", "version": "3.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/31/cee585bd4d1e39947a426a6736f4e17d22b454952370fb9cf48eb3103085/huey-3.4.0-py3-none-any.whl"}}], "install_targets_hash": "40f9e0b7b0afb09fe34d19285f3f89c9"} -{"python_version": "3.15t", "dependencies": [{"metadata": {"name": "fastmcp", "version": "0.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/f5/07/bc69e65b45d638822190bce0defb497a50d240291b8467cb79078d0064b7/fastmcp-0.1.0-py3-none-any.whl"}}, {"metadata": {"name": "mcp", "version": "1.29.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0b/04/d6b4fb82eefe9e81807aabca1ac98f460ae0883974b83a997aaa20c52545/mcp-1.29.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/af/f9/8a06bea35ef8daf588f707784c973a7046e0034c8d8cfb08828eeffb8b75/pydantic_core-2.46.5.tar.gz"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.13.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/bb/ad/5d6702db60b1e40b41ef513b6967ff5848f307d50f8449baf1634f5908f1/cryptography-50.0.1.tar.gz"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/ae/a56fa8c4686ad50e148fcbc8d3ae0d03915ff5c30d795058988c24118cef/cffi-2.1.1-cp315-cp315t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/9d/29/9907bdf1c5346763cf10b7f6852aad86652168c259def904cbe0082c5864/rpds_py-2026.6.3-cp315-cp315t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.8"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/dd/3a/764912c58293d95b6dcdf4cc255f9d10de310580ced547b082eb9d72018c/sse_starlette-3.4.8-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "typer", "version": "0.27.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/dc/bf/205d0004930ede8f542fb58f601526fccf4ae7626075ca1e6c4de5d3d652/typer-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "shellingham", "version": "1.5.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.52.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/f1/79/4a20b54ab0491485ccd8c077db2d39187c7f12b3e15485d38a7be37c81b4/uvicorn-0.52.4-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "4ef5d5161db3a01ccf52260b7895e529"} +{"python_version": "3.15t", "dependencies": [{"metadata": {"name": "huey", "version": "3.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/31/cee585bd4d1e39947a426a6736f4e17d22b454952370fb9cf48eb3103085/huey-3.4.0-py3-none-any.whl"}}], "install_targets_hash": "40f9e0b7b0afb09fe34d19285f3f89c9"} +{"python_version": "3.15t", "dependencies": [{"metadata": {"name": "huey", "version": "3.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/31/cee585bd4d1e39947a426a6736f4e17d22b454952370fb9cf48eb3103085/huey-3.4.0-py3-none-any.whl"}}], "install_targets_hash": "40f9e0b7b0afb09fe34d19285f3f89c9"} {"python_version": "3.15t", "dependencies": [{"metadata": {"name": "mistralai", "version": "2.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e3/d5/6b9c08ab9b5b890970e8949bf00a9f8f82653826de5cc5ad506fe1c1fb73/mistralai-2.6.0-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-semantic-conventions", "version": "0.60b1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7a/5e/5958555e09635d09b75de3c4f8b9cae7335ca545d77392ffe7331534c402/opentelemetry_semantic_conventions-0.60b1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.39.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/df/d3f1ddf4bb4cb50ed9b1139cc7b1c54c34a1e7ce8fd1b9a37c0d1551a6bd/opentelemetry_api-1.39.1-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fa/5e/f8e9a1d23b9c20a551a8a02ea3637b4642e22c2626e3a13a9a29cdea99eb/importlib_metadata-8.7.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "eval_type_backport", "version": "0.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/a7/bb99bf5e6f78736ddb53480f2c3ff3702ffe2196a7c5e1661c03081d398e/eval_type_backport-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonpath-python", "version": "1.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/8a/1270a6803bd821cbfcdda387eaa13cb41a7b1f7b9bd145979b3bfb9d6cb7/jsonpath_python-1.1.6-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/af/f9/8a06bea35ef8daf588f707784c973a7046e0034c8d8cfb08828eeffb8b75/pydantic_core-2.46.5.tar.gz"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "zipp", "version": "4.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}], "install_targets_hash": "4f94c708225730a84d6fdb55c929ba1b"} {"python_version": "3.15t", "dependencies": [{"metadata": {"name": "SQLAlchemy", "version": "2.0.54"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/a1/bd5e3e99bc9c8863b51ac5b9b03008a7f2da8c6b59695992f5c654e1265b/sqlalchemy-2.0.54-py3-none-any.whl"}}, {"metadata": {"name": "greenlet", "version": "3.5.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/19/00e1bee5d2af890dc8f400b54d0b0f9b489965f92bc12b407ff72cc6f469/greenlet-3.5.6-cp315-cp315t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}], "install_targets_hash": "5f2fe90c79dc2d3da3f52a628b506ec0"} +{"python_version": "3.15t", "dependencies": [{"metadata": {"name": "trytond", "version": "8.0.10"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/94/db/57a3be9504273276216dde241d3bc3602c9cae62f60afb1944cf651fe638/trytond-8.0.10-py3-none-any.whl"}}, {"metadata": {"name": "lxml", "version": "6.1.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/8f/c6/7465ffd9c43883526a382df6fa4846c9d8d419214f7effbf65270e795471/lxml-6.1.3-cp315-cp315t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "pwdlib", "version": "0.3.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/6b/2e/51979293b2337f508597d13ee20db1ac1d43e48086b2ed7de6da213ed46b/pwdlib-0.3.1-py3-none-any.whl"}}, {"metadata": {"name": "argon2-cffi", "version": "25.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/4f/d3/a8b22fa575b297cd6e3e3b0155c7e25db170edf1c74783d6a31a2490b8d9/argon2_cffi-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "python-sql", "version": "1.8.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/77/ac/3603bbdde340f7354c975431c94b70ef3e99966c5b170fa121f8e64d269e/python_sql-1.8.1-py3-none-any.whl"}}, {"metadata": {"name": "relatorio", "version": "1.0.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/74/eb/798c426ebd54f52c27aed6593eaf96ed07dca3ca1d084822cc34f0db5159/relatorio-1.0.0-py3-none-any.whl"}}, {"metadata": {"name": "Genshi", "version": "0.7.11"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b7/27/503016bc329720ba2856eb4831d6ba36089cd6f15bc4fe85db69fea5b563/genshi-0.7.11-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz"}}, {"metadata": {"name": "argon2-cffi-bindings", "version": "26.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/66/cb/214092c39c4dbcb72cf98b12234ddac2221f8fe2c0acf29c6a70fa83be53/argon2_cffi_bindings-26.1.0-cp315-cp315t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/ae/a56fa8c4686ad50e148fcbc8d3ae0d03915ff5c30d795058988c24118cef/cffi-2.1.1-cp315-cp315t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "defusedxml", "version": "0.7.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "polib", "version": "1.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/6b/99/45bb1f9926efe370c6dbe324741c749658e44cb060124f28dad201202274/polib-1.2.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "puremagic", "version": "2.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/95/81/314320aeffd88dadeac553ff9eb10f54507ab41deccd0c69f6221d254a0a/puremagic-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "simpleeval", "version": "1.0.8"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/12/33/d1ecd9f4f5f272b36ad7b268e307ba0a59c109d8ad134a231cda780baac9/simpleeval-1.0.8-py3-none-any.whl"}}], "install_targets_hash": "62a0dc5ad5a6cf00b6e38ecd95dcba64"} {"python_version": "3.15t", "dependencies": [{"metadata": {"name": "mistralai", "version": "2.10.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/98/f64b54166a607ece4e5c8494c843ac1f9c7c0af6f1014272cc420fe1d519/mistralai-2.10.1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/6f/a04e900f465ff3221ccc395522503e2d10e79fa21f2723c8e177aae1e0d1/opentelemetry_api-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "eval_type_backport", "version": "0.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/a7/bb99bf5e6f78736ddb53480f2c3ff3702ffe2196a7c5e1661c03081d398e/eval_type_backport-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonpath-python", "version": "1.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/8a/1270a6803bd821cbfcdda387eaa13cb41a7b1f7b9bd145979b3bfb9d6cb7/jsonpath_python-1.1.6-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-semantic-conventions", "version": "0.65b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/0e/49df70d9b81fb5cbae4bbf2a49d865b09bcbcbc4eb53f5851b1027738d78/opentelemetry_semantic_conventions-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/af/f9/8a06bea35ef8daf588f707784c973a7046e0034c8d8cfb08828eeffb8b75/pydantic_core-2.46.5.tar.gz"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}], "install_targets_hash": "815ae8a75d9673398571743a7b3a35fa"} {"python_version": "3.15t", "dependencies": [{"metadata": {"name": "Quart", "version": "0.23.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/5c/c1/26dca56249da1a889ebb946000ab272712476209234f714ad3e8013ee005/quart-0.23.1-py3-none-any.whl"}}, {"metadata": {"name": "quart-auth", "version": "0.12.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ce/6b/e902def52a0c1c32bf872d87eb76cf4bf6109d015ac8c9e6768894676c8d/quart_auth-0.12.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.7.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/18/f1/46d32fe4b9aae09fe397e768ff376d9b6bdbb4f11faaa727f163c3457b43/pytest_forked-1.7.5-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "Hypercorn", "version": "0.18.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/93/35/850277d1b17b206bd10874c8a9a3f52e059452fb49bb0d22cbb908f6038b/hypercorn-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "h2", "version": "4.4.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/22/e85faf23bd72a92d1921e37d674ca56eb298a3c8be31fdecef0ff2b3aaac/h2-4.4.1-py3-none-any.whl"}}, {"metadata": {"name": "hpack", "version": "4.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/b4/4a9fcfb2aef6ba44d9073ecd301443aa00b3dac95de5619f2a7de7ec8a91/hpack-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "hyperframe", "version": "6.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/48/30/47d0bf6072f7252e6521f3447ccfa40b421b6824517f82854703d0f5a98b/hyperframe-6.1.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "wsproto", "version": "1.3.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a4/f5/10b68b7b1544245097b2a1b8238f66f2fc6dcaeb24ba5d917f52bd2eed4f/wsproto-1.3.2-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "priority", "version": "2.0.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/5e/5f/82c8074f7e84978129347c2c6ec8b6c59f3584ff1a20bc3c940a3e061790/priority-2.0.0-py3-none-any.whl"}}], "install_targets_hash": "8466032de3e88e282989c969ffd1cb35"} {"python_version": "3.15t", "dependencies": [{"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "Flask-Login", "version": "0.6.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/59/f5/67e9cc5c2036f58115f9fe0f00d203cf6780c3ff8ae0e705e7a9d9e8ff9e/Flask_Login-0.6.3-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz"}}], "install_targets_hash": "8e9f2612223a3ea6906a34018db168cd"} +{"python_version": "3.15t", "dependencies": [{"metadata": {"name": "Quart", "version": "0.23.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/5c/c1/26dca56249da1a889ebb946000ab272712476209234f714ad3e8013ee005/quart-0.23.1-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "Hypercorn", "version": "0.18.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/93/35/850277d1b17b206bd10874c8a9a3f52e059452fb49bb0d22cbb908f6038b/hypercorn-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "h2", "version": "4.4.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/22/e85faf23bd72a92d1921e37d674ca56eb298a3c8be31fdecef0ff2b3aaac/h2-4.4.1-py3-none-any.whl"}}, {"metadata": {"name": "hpack", "version": "4.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/b4/4a9fcfb2aef6ba44d9073ecd301443aa00b3dac95de5619f2a7de7ec8a91/hpack-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "hyperframe", "version": "6.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/48/30/47d0bf6072f7252e6521f3447ccfa40b421b6824517f82854703d0f5a98b/hyperframe-6.1.0-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "wsproto", "version": "1.3.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a4/f5/10b68b7b1544245097b2a1b8238f66f2fc6dcaeb24ba5d917f52bd2eed4f/wsproto-1.3.2-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "priority", "version": "2.0.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/5e/5f/82c8074f7e84978129347c2c6ec8b6c59f3584ff1a20bc3c940a3e061790/priority-2.0.0-py3-none-any.whl"}}], "install_targets_hash": "9071d7bef95d0796e02e4622215f990f"} {"python_version": "3.15t", "dependencies": [{"metadata": {"name": "strawberry-graphql", "version": "0.327.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/09/e0deac5d4f466f6ecae1b91a91d1a291aad1890960a5d891bb80bda3425c/strawberry_graphql-0.327.7-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.12"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/b6/304c572e79b9e82982dbd5091e26a89f5018e565868091d804c2142f6ba5/graphql_core-3.2.12-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "cross-web", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7a/4a/78b52ec2edcbd9b123638f4e0421fd8699ebe653ebf63ac5f82abd2665bc/cross_web-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "fastapi", "version": "0.141.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/03/10388a42375ee7e4ac9b94eb2c5c569c8b5795e377e701c9ac3ad63de890/fastapi-0.141.1-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/af/f9/8a06bea35ef8daf588f707784c973a7046e0034c8d8cfb08828eeffb8b75/pydantic_core-2.46.5.tar.gz"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}], "install_targets_hash": "973f4a5847325907761d52b88b87e613"} {"python_version": "3.15t", "dependencies": [{"metadata": {"name": "mistralai", "version": "2.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c0/ab/a565e4bec9b5496eb3b44b8799b6ad8378b2cd0be4cd5e6b7d098e8cedcc/mistralai-2.0.5-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-semantic-conventions", "version": "0.60b1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7a/5e/5958555e09635d09b75de3c4f8b9cae7335ca545d77392ffe7331534c402/opentelemetry_semantic_conventions-0.60b1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.39.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/df/d3f1ddf4bb4cb50ed9b1139cc7b1c54c34a1e7ce8fd1b9a37c0d1551a6bd/opentelemetry_api-1.39.1-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fa/5e/f8e9a1d23b9c20a551a8a02ea3637b4642e22c2626e3a13a9a29cdea99eb/importlib_metadata-8.7.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "eval_type_backport", "version": "0.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/a7/bb99bf5e6f78736ddb53480f2c3ff3702ffe2196a7c5e1661c03081d398e/eval_type_backport-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/af/f9/8a06bea35ef8daf588f707784c973a7046e0034c8d8cfb08828eeffb8b75/pydantic_core-2.46.5.tar.gz"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "zipp", "version": "4.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}], "install_targets_hash": "994d711e6ebda622f4cced8803ee9a73"} {"python_version": "3.15t", "dependencies": [{"metadata": {"name": "trytond", "version": "8.0.10"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/db/57a3be9504273276216dde241d3bc3602c9cae62f60afb1944cf651fe638/trytond-8.0.10-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "lxml", "version": "6.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/90/73675f3f4141350ed65d6fec533b107d4e802c5caa340cf111771edd86e0/lxml-6.1.3-cp315-cp315t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz"}}, {"metadata": {"name": "pwdlib", "version": "0.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6b/2e/51979293b2337f508597d13ee20db1ac1d43e48086b2ed7de6da213ed46b/pwdlib-0.3.1-py3-none-any.whl"}}, {"metadata": {"name": "argon2-cffi", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/d3/a8b22fa575b297cd6e3e3b0155c7e25db170edf1c74783d6a31a2490b8d9/argon2_cffi-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "python-sql", "version": "1.8.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/77/ac/3603bbdde340f7354c975431c94b70ef3e99966c5b170fa121f8e64d269e/python_sql-1.8.1-py3-none-any.whl"}}, {"metadata": {"name": "relatorio", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/74/eb/798c426ebd54f52c27aed6593eaf96ed07dca3ca1d084822cc34f0db5159/relatorio-1.0.0-py3-none-any.whl"}}, {"metadata": {"name": "Genshi", "version": "0.7.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/27/503016bc329720ba2856eb4831d6ba36089cd6f15bc4fe85db69fea5b563/genshi-0.7.11-py3-none-any.whl"}}, {"metadata": {"name": "argon2-cffi-bindings", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c3/4a/85e612787d0796878b3b4f6bd53dcd5484b6fe7b64cc6fc7b6e6a04cf835/argon2_cffi_bindings-26.1.0-cp315-cp315t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/52/86/2976131c639aead931c5bee5aba67e4b09fbeb8018b6f282f70803f923a7/cffi-2.1.1-cp315-cp315t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "defusedxml", "version": "0.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "polib", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6b/99/45bb1f9926efe370c6dbe324741c749658e44cb060124f28dad201202274/polib-1.2.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "puremagic", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/81/314320aeffd88dadeac553ff9eb10f54507ab41deccd0c69f6221d254a0a/puremagic-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "simpleeval", "version": "1.0.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/33/d1ecd9f4f5f272b36ad7b268e307ba0a59c109d8ad134a231cda780baac9/simpleeval-1.0.8-py3-none-any.whl"}}], "install_targets_hash": "ab391832abd062e60ebbad762fe1f443"} +{"python_version": "3.15t", "dependencies": [{"metadata": {"name": "tornado", "version": "6.6a1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/ae/5a/aa24542dd04286abf95e6e22627b97f2a2a2d99d37103a333ae57ac8f25c/tornado-6.6a1-cp315-cp315t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}], "install_targets_hash": "b883316dda3824a719a7fb8ca38112ff"} {"python_version": "3.15t", "dependencies": [{"metadata": {"name": "requests", "version": "2.34.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/3b/32/9b8929bf384061ee1fe5d9c27c6f9776d3d824039ad4e14c88ec00c7808e/charset_normalizer-3.5.1-cp315-cp315t-macosx_10_15_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.7.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}], "install_targets_hash": "c4e67585767bde6ea034db94a448f267"} -{"python_version": "3.15t", "dependencies": [{"metadata": {"name": "fastmcp", "version": "0.4.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/79/0b/008a340435fe8f0879e9d608f48af2737ad48440e09bd33b83b3fd03798b/fastmcp-0.4.1-py3-none-any.whl"}}, {"metadata": {"name": "mcp", "version": "1.29.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0b/04/d6b4fb82eefe9e81807aabca1ac98f460ae0883974b83a997aaa20c52545/mcp-1.29.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/af/f9/8a06bea35ef8daf588f707784c973a7046e0034c8d8cfb08828eeffb8b75/pydantic_core-2.46.5.tar.gz"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.14.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.26.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.15.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/30/a4/2bffa9f8e804325a09867f0e9d30795c80ea9f8d62560bd1b6ad6220eb2f/pydantic_settings-2.15.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.13.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/bb/ad/5d6702db60b1e40b41ef513b6967ff5848f307d50f8449baf1634f5908f1/cryptography-50.0.1.tar.gz"}}, {"metadata": {"name": "cffi", "version": "2.1.1"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/7e/ae/a56fa8c4686ad50e148fcbc8d3ae0d03915ff5c30d795058988c24118cef/cffi-2.1.1-cp315-cp315t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.37.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "2026.6.3"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/9d/29/9907bdf1c5346763cf10b7f6852aad86652168c259def904cbe0082c5864/rpds_py-2026.6.3-cp315-cp315t-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sse-starlette", "version": "3.4.8"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/dd/3a/764912c58293d95b6dcdf4cc255f9d10de310580ced547b082eb9d72018c/sse_starlette-3.4.8-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "typer", "version": "0.27.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/dc/bf/205d0004930ede8f542fb58f601526fccf4ae7626075ca1e6c4de5d3d652/typer-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "4.2.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "shellingham", "version": "1.5.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "uvicorn", "version": "0.52.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/f1/79/4a20b54ab0491485ccd8c077db2d39187c7f12b3e15485d38a7be37c81b4/uvicorn-0.52.4-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "3.0"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}], "install_targets_hash": "d3ba412b13e2cfc8f79cd31c37175dca"} +{"python_version": "3.15t", "dependencies": [{"metadata": {"name": "strawberry-graphql", "version": "0.327.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/09/e0deac5d4f466f6ecae1b91a91d1a291aad1890960a5d891bb80bda3425c/strawberry_graphql-0.327.7-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.12"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/b6/304c572e79b9e82982dbd5091e26a89f5018e565868091d804c2142f6ba5/graphql_core-3.2.12-py3-none-any.whl"}}, {"metadata": {"name": "cross-web", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7a/4a/78b52ec2edcbd9b123638f4e0421fd8699ebe653ebf63ac5f82abd2665bc/cross_web-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "fastapi", "version": "0.141.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/03/10388a42375ee7e4ac9b94eb2c5c569c8b5795e377e701c9ac3ad63de890/fastapi-0.141.1-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/af/f9/8a06bea35ef8daf588f707784c973a7046e0034c8d8cfb08828eeffb8b75/pydantic_core-2.46.5.tar.gz"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.32"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/cb/6a6a47d5b464bd08695d254f3da6e7986cc70c9fa5d778eda57538edfe56/starlette-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}], "install_targets_hash": "cfc1e9957ab373475c45bbd06bbcbe92"} {"python_version": "3.15t", "dependencies": [{"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2-pytest", "version": "1.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/46/ef/e9b6fb576f1f518f68e9f9cce9776870452ae2b8cfbba53b4127701b9a55/httpx2_pytest-1.0.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}], "install_targets_hash": "d6da1d54536a49d0f25beda4d7a148f5"} +{"python_version": "3.15t", "dependencies": [{"metadata": {"name": "httpx2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/d1/a0c72b0e006df654709fbc366cc5bcb53e5aee13e1e3395152c6dd293376/httpx2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx2-pytest", "version": "1.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/46/ef/e9b6fb576f1f518f68e9f9cce9776870452ae2b8cfbba53b4127701b9a55/httpx2_pytest-1.0.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore2", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/0d/117a771a2bb91df334b66bf4da14cd02f21aefbcfe53180f336ce55e8f90/httpcore2-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "truststore", "version": "0.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl"}}], "install_targets_hash": "d6da1d54536a49d0f25beda4d7a148f5"} +{"python_version": "3.15t", "dependencies": [{"metadata": {"name": "pure_eval", "version": "0.2.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6d/18/83376915176eb058cb86470eb7396388a13350b09a8f233a79303bbcbc5b/pure_eval-0.2.4-py3-none-any.whl"}}, {"metadata": {"name": "asttokens", "version": "3.0.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d4/2b/04b8a15f3a1c77bc79ddf5c73875327f34b4fa75982df2b76e45e402d364/asttokens-3.0.2-py3-none-any.whl"}}, {"metadata": {"name": "executing", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl"}}], "install_targets_hash": "ef91391ff2fb8720438fb9fbd1e2fc94"} {"python_version": "3.15t", "dependencies": [{"metadata": {"name": "pure_eval", "version": "0.2.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6d/18/83376915176eb058cb86470eb7396388a13350b09a8f233a79303bbcbc5b/pure_eval-0.2.4-py3-none-any.whl"}}, {"metadata": {"name": "asttokens", "version": "3.0.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d4/2b/04b8a15f3a1c77bc79ddf5c73875327f34b4fa75982df2b76e45e402d364/asttokens-3.0.2-py3-none-any.whl"}}, {"metadata": {"name": "executing", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl"}}], "install_targets_hash": "ef91391ff2fb8720438fb9fbd1e2fc94"} +{"python_version": "3.15t", "dependencies": [{"metadata": {"name": "pure_eval", "version": "0.2.4"}, "download_info": {"url": "https://sfw.security.sentry.io/pypi/packages/6d/18/83376915176eb058cb86470eb7396388a13350b09a8f233a79303bbcbc5b/pure_eval-0.2.4-py3-none-any.whl"}}], "install_targets_hash": "f57089decb29d6779c0a7d039d6126c1"} {"python_version": "3.15t", "dependencies": [{"metadata": {"name": "mistralai", "version": "2.10.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/98/f64b54166a607ece4e5c8494c843ac1f9c7c0af6f1014272cc420fe1d519/mistralai-2.10.1-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-api", "version": "1.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/6f/a04e900f465ff3221ccc395522503e2d10e79fa21f2723c8e177aae1e0d1/opentelemetry_api-1.44.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "9.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "eval_type_backport", "version": "0.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/a7/bb99bf5e6f78736ddb53480f2c3ff3702ffe2196a7c5e1661c03081d398e/eval_type_backport-0.4.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonpath-python", "version": "1.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/8a/1270a6803bd821cbfcdda387eaa13cb41a7b1f7b9bd145979b3bfb9d6cb7/jsonpath_python-1.1.6-py3-none-any.whl"}}, {"metadata": {"name": "opentelemetry-semantic-conventions", "version": "0.65b0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/0e/49df70d9b81fb5cbae4bbf2a49d865b09bcbcbc4eb53f5851b1027738d78/opentelemetry_semantic_conventions-0.65b0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/47/c95ffc2009878c7aac0c5e08528022dcb885933252a88b5f170058014464/pydantic-2.13.5-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/af/f9/8a06bea35ef8daf588f707784c973a7046e0034c8d8cfb08828eeffb8b75/pydantic_core-2.46.5.tar.gz"}}, {"metadata": {"name": "annotated-types", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}], "install_targets_hash": "f60e32909a4363f0d8cc05916d4da67a"} {"python_version": "3.8", "dependencies": [{"metadata": {"name": "litestar", "version": "2.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/ce/4697b547790f23d2fcc37a928d48c38140cf86360e4041ca8177e3367c14/litestar-2.24.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/31/6607dab48616902f76885dfcf62c08d929796fc3b2d2318faf9fd54dbed9/pytest_asyncio-0.24.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/45/58/38b5afbc1a800eeea951b9285d3912613f2603bdf897a4ab0f4bd7f405fc/python_multipart-0.0.20-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.32.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "47.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/34/a4fae8ae7c3bc227460c9ae43f56abf1b911da0ec29e0ebac53bb0a4b6b7/cryptography-47.0.0-cp38-abi3-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/b4/f7e396030e3b11394436358ca258a81d6010106582422f23443c16ca1873/anyio-4.5.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "1.17.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/46/fce169ad09419b8e8a5a81db61e08cd7b9fd31332221b84bd176fe0a3136/charset_normalizer-3.4.7-cp38-cp38-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.15"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/23/408243171aa9aaba178d3e2559159c24c1171a641aa83b67bdd3394ead8e/idna-3.15-py3-none-any.whl"}}, {"metadata": {"name": "importlib_resources", "version": "6.4.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/6a/4604f9ae2fa62ef47b9de2fa5ad599589d28c9fd1d335f32759813dfa91e/importlib_resources-6.4.5-py3-none-any.whl"}}, {"metadata": {"name": "litestar-htmx", "version": "0.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/99/3ea64a79a2f4fea5225ccd0128201a3b8eab5e216b8fba8b778b8c462f29/litestar_htmx-0.4.1-py3-none-any.whl"}}, {"metadata": {"name": "msgspec", "version": "0.18.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/86/6f/1da53a2ba5f312c3dca9e5f38912732e77f996a22945c8d62df7617c4733/msgspec-0.18.6-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/7f/5d1ce7f47d44393d429922910afbe88fcd29ee3069babbb47507a4c3a7ea/multidict-6.1.0-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multipart", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/ed/e1f03200ee1f0bf4a2b9b72709afefbf5319b68df654e0b84b35c65613ee/multipart-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "polyfactory", "version": "2.22.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/11/87/6cd69c43e86bc5863f93dba3c9fb42ee4fda36a0fe5aa3cbd25001fb26f8/polyfactory-2.22.5-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "8.3.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "14.3.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/76/6d163cfac87b632216f71879e6b2cf17163f773ff59c00b5ff4900a80fa3/rich-14.3.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.13.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ce/d9/5f4c13cecde62396b0d3fe530a50ccea91e7dfc1ccf0e09c228841bb5ba8/urllib3-2.2.3-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/d9/a1e041c5e7caa9a05c925f4bdbdfb7f006d1f74996af53467bc394c97be7/importlib_metadata-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz"}}, {"metadata": {"name": "rich-click", "version": "1.9.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6d/97/a87901aef6b7e7e4a34c6dd6cc17dca8594a592ef9d9dd765fca2b7facf7/rich_click-1.9.8-py3-none-any.whl"}}, {"metadata": {"name": "Faker", "version": "35.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/18/f70c67c9d3a71f1749faa027dad3cd626c728df5682458091d73c69ed9a9/Faker-35.2.2-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "3.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.19.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "zipp", "version": "3.20.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/8b/5ba542fa83c90e09eac972fc9baca7a88e7e7ca4b221a89251954019308b/zipp-3.20.2-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "2.23"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}], "install_targets_hash": "030c889f2cc15fac775b2cc21c8d01e4"} -{"python_version": "3.8", "dependencies": [{"metadata": {"name": "fastapi", "version": "0.121.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/b6/4f620d7720fc0a754c8c1b7501d73777f6ba43b57c8ab99671f4d7441eb8/fastapi-0.121.3-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/31/6607dab48616902f76885dfcf62c08d929796fc3b2d2318faf9fd54dbed9/pytest_asyncio-0.24.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/45/58/38b5afbc1a800eeea951b9285d3912613f2603bdf897a4ab0f4bd7f405fc/python_multipart-0.0.20-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.32.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/b4/f7e396030e3b11394436358ca258a81d6010106582422f23443c16ca1873/anyio-4.5.2-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/2b/f97f1c193fb855c345d678f5077d6926034db0722df74c8f057020e05a25/charset_normalizer-3.4.9-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.15"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/23/408243171aa9aaba178d3e2559159c24c1171a641aa83b67bdd3394ead8e/idna-3.15-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "2.1.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c7/bd/50319665ce81bb10e90d1cf76f9e1aa269ea6f7fa30ab4521f14d122a3df/MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.10.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/3c/8cc1cc84deffa6e25d2d0c688ebb80635dfdbf1dbea3e30c541c8cf4d860/pydantic-2.10.6-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f7/a3/5f19bc495793546825ab160e530330c2afcee2281c02b5ffafd0b32ac05e/pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"metadata": {"name": "pytest", "version": "8.3.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "0.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b6/c5/7ae467eeddb57260c8ce17a3a09f9f5edba35820fc022d7c55b7decd5d3a/starlette-0.44.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.13.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ce/d9/5f4c13cecde62396b0d3fe530a50ccea91e7dfc1ccf0e09c228841bb5ba8/urllib3-2.2.3-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}], "install_targets_hash": "07dedda23092a79cd219b98e946eb134"} +{"python_version": "3.8", "dependencies": [{"metadata": {"name": "litestar", "version": "2.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/ce/4697b547790f23d2fcc37a928d48c38140cf86360e4041ca8177e3367c14/litestar-2.24.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/31/6607dab48616902f76885dfcf62c08d929796fc3b2d2318faf9fd54dbed9/pytest_asyncio-0.24.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/45/58/38b5afbc1a800eeea951b9285d3912613f2603bdf897a4ab0f4bd7f405fc/python_multipart-0.0.20-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.32.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "47.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/34/a4fae8ae7c3bc227460c9ae43f56abf1b911da0ec29e0ebac53bb0a4b6b7/cryptography-47.0.0-cp38-abi3-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/b4/f7e396030e3b11394436358ca258a81d6010106582422f23443c16ca1873/anyio-4.5.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "1.17.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/46/fce169ad09419b8e8a5a81db61e08cd7b9fd31332221b84bd176fe0a3136/charset_normalizer-3.4.7-cp38-cp38-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.15"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/23/408243171aa9aaba178d3e2559159c24c1171a641aa83b67bdd3394ead8e/idna-3.15-py3-none-any.whl"}}, {"metadata": {"name": "importlib_resources", "version": "6.4.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/6a/4604f9ae2fa62ef47b9de2fa5ad599589d28c9fd1d335f32759813dfa91e/importlib_resources-6.4.5-py3-none-any.whl"}}, {"metadata": {"name": "litestar-htmx", "version": "0.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/99/3ea64a79a2f4fea5225ccd0128201a3b8eab5e216b8fba8b778b8c462f29/litestar_htmx-0.4.1-py3-none-any.whl"}}, {"metadata": {"name": "msgspec", "version": "0.18.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/86/6f/1da53a2ba5f312c3dca9e5f38912732e77f996a22945c8d62df7617c4733/msgspec-0.18.6-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/7f/5d1ce7f47d44393d429922910afbe88fcd29ee3069babbb47507a4c3a7ea/multidict-6.1.0-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multipart", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/ed/e1f03200ee1f0bf4a2b9b72709afefbf5319b68df654e0b84b35c65613ee/multipart-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "polyfactory", "version": "2.22.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/11/87/6cd69c43e86bc5863f93dba3c9fb42ee4fda36a0fe5aa3cbd25001fb26f8/polyfactory-2.22.5-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "8.3.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "14.3.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/76/6d163cfac87b632216f71879e6b2cf17163f773ff59c00b5ff4900a80fa3/rich-14.3.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.13.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ce/d9/5f4c13cecde62396b0d3fe530a50ccea91e7dfc1ccf0e09c228841bb5ba8/urllib3-2.2.3-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/d9/a1e041c5e7caa9a05c925f4bdbdfb7f006d1f74996af53467bc394c97be7/importlib_metadata-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz"}}, {"metadata": {"name": "rich-click", "version": "1.9.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6d/97/a87901aef6b7e7e4a34c6dd6cc17dca8594a592ef9d9dd765fca2b7facf7/rich_click-1.9.8-py3-none-any.whl"}}, {"metadata": {"name": "Faker", "version": "35.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/18/f70c67c9d3a71f1749faa027dad3cd626c728df5682458091d73c69ed9a9/Faker-35.2.2-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "3.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.19.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "zipp", "version": "3.20.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/8b/5ba542fa83c90e09eac972fc9baca7a88e7e7ca4b221a89251954019308b/zipp-3.20.2-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "2.23"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}], "install_targets_hash": "030c889f2cc15fac775b2cc21c8d01e4"} +{"python_version": "3.8", "dependencies": [{"metadata": {"name": "litestar", "version": "2.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/ce/4697b547790f23d2fcc37a928d48c38140cf86360e4041ca8177e3367c14/litestar-2.24.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/31/6607dab48616902f76885dfcf62c08d929796fc3b2d2318faf9fd54dbed9/pytest_asyncio-0.24.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/45/58/38b5afbc1a800eeea951b9285d3912613f2603bdf897a4ab0f4bd7f405fc/python_multipart-0.0.20-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.32.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "47.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/34/a4fae8ae7c3bc227460c9ae43f56abf1b911da0ec29e0ebac53bb0a4b6b7/cryptography-47.0.0-cp38-abi3-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/b4/f7e396030e3b11394436358ca258a81d6010106582422f23443c16ca1873/anyio-4.5.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "1.17.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/46/fce169ad09419b8e8a5a81db61e08cd7b9fd31332221b84bd176fe0a3136/charset_normalizer-3.4.7-cp38-cp38-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.15"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/23/408243171aa9aaba178d3e2559159c24c1171a641aa83b67bdd3394ead8e/idna-3.15-py3-none-any.whl"}}, {"metadata": {"name": "importlib_resources", "version": "6.4.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/6a/4604f9ae2fa62ef47b9de2fa5ad599589d28c9fd1d335f32759813dfa91e/importlib_resources-6.4.5-py3-none-any.whl"}}, {"metadata": {"name": "litestar-htmx", "version": "0.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/99/3ea64a79a2f4fea5225ccd0128201a3b8eab5e216b8fba8b778b8c462f29/litestar_htmx-0.4.1-py3-none-any.whl"}}, {"metadata": {"name": "msgspec", "version": "0.18.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/86/6f/1da53a2ba5f312c3dca9e5f38912732e77f996a22945c8d62df7617c4733/msgspec-0.18.6-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/7f/5d1ce7f47d44393d429922910afbe88fcd29ee3069babbb47507a4c3a7ea/multidict-6.1.0-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multipart", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/ed/e1f03200ee1f0bf4a2b9b72709afefbf5319b68df654e0b84b35c65613ee/multipart-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "polyfactory", "version": "2.22.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/11/87/6cd69c43e86bc5863f93dba3c9fb42ee4fda36a0fe5aa3cbd25001fb26f8/polyfactory-2.22.5-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "8.3.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "14.3.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/76/6d163cfac87b632216f71879e6b2cf17163f773ff59c00b5ff4900a80fa3/rich-14.3.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.13.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ce/d9/5f4c13cecde62396b0d3fe530a50ccea91e7dfc1ccf0e09c228841bb5ba8/urllib3-2.2.3-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/d9/a1e041c5e7caa9a05c925f4bdbdfb7f006d1f74996af53467bc394c97be7/importlib_metadata-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz"}}, {"metadata": {"name": "rich-click", "version": "1.9.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6d/97/a87901aef6b7e7e4a34c6dd6cc17dca8594a592ef9d9dd765fca2b7facf7/rich_click-1.9.8-py3-none-any.whl"}}, {"metadata": {"name": "Faker", "version": "35.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/18/f70c67c9d3a71f1749faa027dad3cd626c728df5682458091d73c69ed9a9/Faker-35.2.2-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "3.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.19.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "zipp", "version": "3.20.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/8b/5ba542fa83c90e09eac972fc9baca7a88e7e7ca4b221a89251954019308b/zipp-3.20.2-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "2.23"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}], "install_targets_hash": "030c889f2cc15fac775b2cc21c8d01e4"} +{"python_version": "3.8", "dependencies": [{"metadata": {"name": "litestar", "version": "2.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/ce/4697b547790f23d2fcc37a928d48c38140cf86360e4041ca8177e3367c14/litestar-2.24.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/31/6607dab48616902f76885dfcf62c08d929796fc3b2d2318faf9fd54dbed9/pytest_asyncio-0.24.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/45/58/38b5afbc1a800eeea951b9285d3912613f2603bdf897a4ab0f4bd7f405fc/python_multipart-0.0.20-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.32.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "47.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/34/a4fae8ae7c3bc227460c9ae43f56abf1b911da0ec29e0ebac53bb0a4b6b7/cryptography-47.0.0-cp38-abi3-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/b4/f7e396030e3b11394436358ca258a81d6010106582422f23443c16ca1873/anyio-4.5.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "1.17.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/46/fce169ad09419b8e8a5a81db61e08cd7b9fd31332221b84bd176fe0a3136/charset_normalizer-3.4.7-cp38-cp38-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.15"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/23/408243171aa9aaba178d3e2559159c24c1171a641aa83b67bdd3394ead8e/idna-3.15-py3-none-any.whl"}}, {"metadata": {"name": "importlib_resources", "version": "6.4.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/6a/4604f9ae2fa62ef47b9de2fa5ad599589d28c9fd1d335f32759813dfa91e/importlib_resources-6.4.5-py3-none-any.whl"}}, {"metadata": {"name": "litestar-htmx", "version": "0.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/99/3ea64a79a2f4fea5225ccd0128201a3b8eab5e216b8fba8b778b8c462f29/litestar_htmx-0.4.1-py3-none-any.whl"}}, {"metadata": {"name": "msgspec", "version": "0.18.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/86/6f/1da53a2ba5f312c3dca9e5f38912732e77f996a22945c8d62df7617c4733/msgspec-0.18.6-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/7f/5d1ce7f47d44393d429922910afbe88fcd29ee3069babbb47507a4c3a7ea/multidict-6.1.0-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multipart", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/ed/e1f03200ee1f0bf4a2b9b72709afefbf5319b68df654e0b84b35c65613ee/multipart-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "polyfactory", "version": "2.22.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/11/87/6cd69c43e86bc5863f93dba3c9fb42ee4fda36a0fe5aa3cbd25001fb26f8/polyfactory-2.22.5-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "8.3.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "14.3.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/76/6d163cfac87b632216f71879e6b2cf17163f773ff59c00b5ff4900a80fa3/rich-14.3.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.13.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ce/d9/5f4c13cecde62396b0d3fe530a50ccea91e7dfc1ccf0e09c228841bb5ba8/urllib3-2.2.3-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/d9/a1e041c5e7caa9a05c925f4bdbdfb7f006d1f74996af53467bc394c97be7/importlib_metadata-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz"}}, {"metadata": {"name": "rich-click", "version": "1.9.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6d/97/a87901aef6b7e7e4a34c6dd6cc17dca8594a592ef9d9dd765fca2b7facf7/rich_click-1.9.8-py3-none-any.whl"}}, {"metadata": {"name": "Faker", "version": "35.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/18/f70c67c9d3a71f1749faa027dad3cd626c728df5682458091d73c69ed9a9/Faker-35.2.2-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "3.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.19.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "zipp", "version": "3.20.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/8b/5ba542fa83c90e09eac972fc9baca7a88e7e7ca4b221a89251954019308b/zipp-3.20.2-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "2.23"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}], "install_targets_hash": "030c889f2cc15fac775b2cc21c8d01e4"} +{"python_version": "3.8", "dependencies": [{"metadata": {"name": "litestar", "version": "2.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/ce/4697b547790f23d2fcc37a928d48c38140cf86360e4041ca8177e3367c14/litestar-2.24.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/31/6607dab48616902f76885dfcf62c08d929796fc3b2d2318faf9fd54dbed9/pytest_asyncio-0.24.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/45/58/38b5afbc1a800eeea951b9285d3912613f2603bdf897a4ab0f4bd7f405fc/python_multipart-0.0.20-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.32.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "47.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/34/a4fae8ae7c3bc227460c9ae43f56abf1b911da0ec29e0ebac53bb0a4b6b7/cryptography-47.0.0-cp38-abi3-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/b4/f7e396030e3b11394436358ca258a81d6010106582422f23443c16ca1873/anyio-4.5.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "1.17.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/46/fce169ad09419b8e8a5a81db61e08cd7b9fd31332221b84bd176fe0a3136/charset_normalizer-3.4.7-cp38-cp38-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.15"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/23/408243171aa9aaba178d3e2559159c24c1171a641aa83b67bdd3394ead8e/idna-3.15-py3-none-any.whl"}}, {"metadata": {"name": "importlib_resources", "version": "6.4.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/6a/4604f9ae2fa62ef47b9de2fa5ad599589d28c9fd1d335f32759813dfa91e/importlib_resources-6.4.5-py3-none-any.whl"}}, {"metadata": {"name": "litestar-htmx", "version": "0.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/99/3ea64a79a2f4fea5225ccd0128201a3b8eab5e216b8fba8b778b8c462f29/litestar_htmx-0.4.1-py3-none-any.whl"}}, {"metadata": {"name": "msgspec", "version": "0.18.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/86/6f/1da53a2ba5f312c3dca9e5f38912732e77f996a22945c8d62df7617c4733/msgspec-0.18.6-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/7f/5d1ce7f47d44393d429922910afbe88fcd29ee3069babbb47507a4c3a7ea/multidict-6.1.0-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multipart", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/ed/e1f03200ee1f0bf4a2b9b72709afefbf5319b68df654e0b84b35c65613ee/multipart-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "polyfactory", "version": "2.22.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/11/87/6cd69c43e86bc5863f93dba3c9fb42ee4fda36a0fe5aa3cbd25001fb26f8/polyfactory-2.22.5-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "8.3.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "14.3.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/76/6d163cfac87b632216f71879e6b2cf17163f773ff59c00b5ff4900a80fa3/rich-14.3.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.13.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ce/d9/5f4c13cecde62396b0d3fe530a50ccea91e7dfc1ccf0e09c228841bb5ba8/urllib3-2.2.3-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/d9/a1e041c5e7caa9a05c925f4bdbdfb7f006d1f74996af53467bc394c97be7/importlib_metadata-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz"}}, {"metadata": {"name": "rich-click", "version": "1.9.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6d/97/a87901aef6b7e7e4a34c6dd6cc17dca8594a592ef9d9dd765fca2b7facf7/rich_click-1.9.8-py3-none-any.whl"}}, {"metadata": {"name": "Faker", "version": "35.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/18/f70c67c9d3a71f1749faa027dad3cd626c728df5682458091d73c69ed9a9/Faker-35.2.2-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "3.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.19.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "zipp", "version": "3.20.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/8b/5ba542fa83c90e09eac972fc9baca7a88e7e7ca4b221a89251954019308b/zipp-3.20.2-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "2.23"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}], "install_targets_hash": "030c889f2cc15fac775b2cc21c8d01e4"} +{"python_version": "3.8", "dependencies": [{"metadata": {"name": "litestar", "version": "2.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/ce/4697b547790f23d2fcc37a928d48c38140cf86360e4041ca8177e3367c14/litestar-2.24.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/31/6607dab48616902f76885dfcf62c08d929796fc3b2d2318faf9fd54dbed9/pytest_asyncio-0.24.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/45/58/38b5afbc1a800eeea951b9285d3912613f2603bdf897a4ab0f4bd7f405fc/python_multipart-0.0.20-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.32.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "47.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/34/a4fae8ae7c3bc227460c9ae43f56abf1b911da0ec29e0ebac53bb0a4b6b7/cryptography-47.0.0-cp38-abi3-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/b4/f7e396030e3b11394436358ca258a81d6010106582422f23443c16ca1873/anyio-4.5.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "1.17.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/46/fce169ad09419b8e8a5a81db61e08cd7b9fd31332221b84bd176fe0a3136/charset_normalizer-3.4.7-cp38-cp38-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.15"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/23/408243171aa9aaba178d3e2559159c24c1171a641aa83b67bdd3394ead8e/idna-3.15-py3-none-any.whl"}}, {"metadata": {"name": "importlib_resources", "version": "6.4.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/6a/4604f9ae2fa62ef47b9de2fa5ad599589d28c9fd1d335f32759813dfa91e/importlib_resources-6.4.5-py3-none-any.whl"}}, {"metadata": {"name": "litestar-htmx", "version": "0.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/99/3ea64a79a2f4fea5225ccd0128201a3b8eab5e216b8fba8b778b8c462f29/litestar_htmx-0.4.1-py3-none-any.whl"}}, {"metadata": {"name": "msgspec", "version": "0.18.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/86/6f/1da53a2ba5f312c3dca9e5f38912732e77f996a22945c8d62df7617c4733/msgspec-0.18.6-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/7f/5d1ce7f47d44393d429922910afbe88fcd29ee3069babbb47507a4c3a7ea/multidict-6.1.0-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multipart", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/ed/e1f03200ee1f0bf4a2b9b72709afefbf5319b68df654e0b84b35c65613ee/multipart-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "polyfactory", "version": "2.22.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/11/87/6cd69c43e86bc5863f93dba3c9fb42ee4fda36a0fe5aa3cbd25001fb26f8/polyfactory-2.22.5-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "8.3.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "14.3.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/76/6d163cfac87b632216f71879e6b2cf17163f773ff59c00b5ff4900a80fa3/rich-14.3.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.13.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ce/d9/5f4c13cecde62396b0d3fe530a50ccea91e7dfc1ccf0e09c228841bb5ba8/urllib3-2.2.3-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/d9/a1e041c5e7caa9a05c925f4bdbdfb7f006d1f74996af53467bc394c97be7/importlib_metadata-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz"}}, {"metadata": {"name": "rich-click", "version": "1.9.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6d/97/a87901aef6b7e7e4a34c6dd6cc17dca8594a592ef9d9dd765fca2b7facf7/rich_click-1.9.8-py3-none-any.whl"}}, {"metadata": {"name": "Faker", "version": "35.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/18/f70c67c9d3a71f1749faa027dad3cd626c728df5682458091d73c69ed9a9/Faker-35.2.2-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "3.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.19.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "zipp", "version": "3.20.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/8b/5ba542fa83c90e09eac972fc9baca7a88e7e7ca4b221a89251954019308b/zipp-3.20.2-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "2.23"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}], "install_targets_hash": "030c889f2cc15fac775b2cc21c8d01e4"} +{"python_version": "3.8", "dependencies": [{"metadata": {"name": "litestar", "version": "2.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/ce/4697b547790f23d2fcc37a928d48c38140cf86360e4041ca8177e3367c14/litestar-2.24.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/31/6607dab48616902f76885dfcf62c08d929796fc3b2d2318faf9fd54dbed9/pytest_asyncio-0.24.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/45/58/38b5afbc1a800eeea951b9285d3912613f2603bdf897a4ab0f4bd7f405fc/python_multipart-0.0.20-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.32.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "47.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/34/a4fae8ae7c3bc227460c9ae43f56abf1b911da0ec29e0ebac53bb0a4b6b7/cryptography-47.0.0-cp38-abi3-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/b4/f7e396030e3b11394436358ca258a81d6010106582422f23443c16ca1873/anyio-4.5.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "1.17.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/46/fce169ad09419b8e8a5a81db61e08cd7b9fd31332221b84bd176fe0a3136/charset_normalizer-3.4.7-cp38-cp38-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.15"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/23/408243171aa9aaba178d3e2559159c24c1171a641aa83b67bdd3394ead8e/idna-3.15-py3-none-any.whl"}}, {"metadata": {"name": "importlib_resources", "version": "6.4.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/6a/4604f9ae2fa62ef47b9de2fa5ad599589d28c9fd1d335f32759813dfa91e/importlib_resources-6.4.5-py3-none-any.whl"}}, {"metadata": {"name": "litestar-htmx", "version": "0.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/99/3ea64a79a2f4fea5225ccd0128201a3b8eab5e216b8fba8b778b8c462f29/litestar_htmx-0.4.1-py3-none-any.whl"}}, {"metadata": {"name": "msgspec", "version": "0.18.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/86/6f/1da53a2ba5f312c3dca9e5f38912732e77f996a22945c8d62df7617c4733/msgspec-0.18.6-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/7f/5d1ce7f47d44393d429922910afbe88fcd29ee3069babbb47507a4c3a7ea/multidict-6.1.0-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multipart", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/ed/e1f03200ee1f0bf4a2b9b72709afefbf5319b68df654e0b84b35c65613ee/multipart-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "polyfactory", "version": "2.22.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/11/87/6cd69c43e86bc5863f93dba3c9fb42ee4fda36a0fe5aa3cbd25001fb26f8/polyfactory-2.22.5-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "8.3.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "14.3.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/76/6d163cfac87b632216f71879e6b2cf17163f773ff59c00b5ff4900a80fa3/rich-14.3.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.13.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ce/d9/5f4c13cecde62396b0d3fe530a50ccea91e7dfc1ccf0e09c228841bb5ba8/urllib3-2.2.3-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/d9/a1e041c5e7caa9a05c925f4bdbdfb7f006d1f74996af53467bc394c97be7/importlib_metadata-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz"}}, {"metadata": {"name": "rich-click", "version": "1.9.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6d/97/a87901aef6b7e7e4a34c6dd6cc17dca8594a592ef9d9dd765fca2b7facf7/rich_click-1.9.8-py3-none-any.whl"}}, {"metadata": {"name": "Faker", "version": "35.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/18/f70c67c9d3a71f1749faa027dad3cd626c728df5682458091d73c69ed9a9/Faker-35.2.2-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "3.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.19.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "zipp", "version": "3.20.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/8b/5ba542fa83c90e09eac972fc9baca7a88e7e7ca4b221a89251954019308b/zipp-3.20.2-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "2.23"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}], "install_targets_hash": "030c889f2cc15fac775b2cc21c8d01e4"} +{"python_version": "3.8", "dependencies": [{"metadata": {"name": "litestar", "version": "2.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/ce/4697b547790f23d2fcc37a928d48c38140cf86360e4041ca8177e3367c14/litestar-2.24.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/31/6607dab48616902f76885dfcf62c08d929796fc3b2d2318faf9fd54dbed9/pytest_asyncio-0.24.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/45/58/38b5afbc1a800eeea951b9285d3912613f2603bdf897a4ab0f4bd7f405fc/python_multipart-0.0.20-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.32.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "47.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/34/a4fae8ae7c3bc227460c9ae43f56abf1b911da0ec29e0ebac53bb0a4b6b7/cryptography-47.0.0-cp38-abi3-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/b4/f7e396030e3b11394436358ca258a81d6010106582422f23443c16ca1873/anyio-4.5.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "1.17.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/46/fce169ad09419b8e8a5a81db61e08cd7b9fd31332221b84bd176fe0a3136/charset_normalizer-3.4.7-cp38-cp38-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.15"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/23/408243171aa9aaba178d3e2559159c24c1171a641aa83b67bdd3394ead8e/idna-3.15-py3-none-any.whl"}}, {"metadata": {"name": "importlib_resources", "version": "6.4.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/6a/4604f9ae2fa62ef47b9de2fa5ad599589d28c9fd1d335f32759813dfa91e/importlib_resources-6.4.5-py3-none-any.whl"}}, {"metadata": {"name": "litestar-htmx", "version": "0.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/99/3ea64a79a2f4fea5225ccd0128201a3b8eab5e216b8fba8b778b8c462f29/litestar_htmx-0.4.1-py3-none-any.whl"}}, {"metadata": {"name": "msgspec", "version": "0.18.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/86/6f/1da53a2ba5f312c3dca9e5f38912732e77f996a22945c8d62df7617c4733/msgspec-0.18.6-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/7f/5d1ce7f47d44393d429922910afbe88fcd29ee3069babbb47507a4c3a7ea/multidict-6.1.0-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multipart", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/ed/e1f03200ee1f0bf4a2b9b72709afefbf5319b68df654e0b84b35c65613ee/multipart-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "polyfactory", "version": "2.22.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/11/87/6cd69c43e86bc5863f93dba3c9fb42ee4fda36a0fe5aa3cbd25001fb26f8/polyfactory-2.22.5-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "8.3.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "14.3.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/76/6d163cfac87b632216f71879e6b2cf17163f773ff59c00b5ff4900a80fa3/rich-14.3.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.13.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ce/d9/5f4c13cecde62396b0d3fe530a50ccea91e7dfc1ccf0e09c228841bb5ba8/urllib3-2.2.3-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/d9/a1e041c5e7caa9a05c925f4bdbdfb7f006d1f74996af53467bc394c97be7/importlib_metadata-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz"}}, {"metadata": {"name": "rich-click", "version": "1.9.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6d/97/a87901aef6b7e7e4a34c6dd6cc17dca8594a592ef9d9dd765fca2b7facf7/rich_click-1.9.8-py3-none-any.whl"}}, {"metadata": {"name": "Faker", "version": "35.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/18/f70c67c9d3a71f1749faa027dad3cd626c728df5682458091d73c69ed9a9/Faker-35.2.2-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "3.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.19.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "zipp", "version": "3.20.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/8b/5ba542fa83c90e09eac972fc9baca7a88e7e7ca4b221a89251954019308b/zipp-3.20.2-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "2.23"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}], "install_targets_hash": "030c889f2cc15fac775b2cc21c8d01e4"} +{"python_version": "3.8", "dependencies": [{"metadata": {"name": "litestar", "version": "2.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/ce/4697b547790f23d2fcc37a928d48c38140cf86360e4041ca8177e3367c14/litestar-2.24.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/31/6607dab48616902f76885dfcf62c08d929796fc3b2d2318faf9fd54dbed9/pytest_asyncio-0.24.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/45/58/38b5afbc1a800eeea951b9285d3912613f2603bdf897a4ab0f4bd7f405fc/python_multipart-0.0.20-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.32.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "47.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/34/a4fae8ae7c3bc227460c9ae43f56abf1b911da0ec29e0ebac53bb0a4b6b7/cryptography-47.0.0-cp38-abi3-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/b4/f7e396030e3b11394436358ca258a81d6010106582422f23443c16ca1873/anyio-4.5.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "1.17.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/46/fce169ad09419b8e8a5a81db61e08cd7b9fd31332221b84bd176fe0a3136/charset_normalizer-3.4.7-cp38-cp38-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.15"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/23/408243171aa9aaba178d3e2559159c24c1171a641aa83b67bdd3394ead8e/idna-3.15-py3-none-any.whl"}}, {"metadata": {"name": "importlib_resources", "version": "6.4.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/6a/4604f9ae2fa62ef47b9de2fa5ad599589d28c9fd1d335f32759813dfa91e/importlib_resources-6.4.5-py3-none-any.whl"}}, {"metadata": {"name": "litestar-htmx", "version": "0.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/99/3ea64a79a2f4fea5225ccd0128201a3b8eab5e216b8fba8b778b8c462f29/litestar_htmx-0.4.1-py3-none-any.whl"}}, {"metadata": {"name": "msgspec", "version": "0.18.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/86/6f/1da53a2ba5f312c3dca9e5f38912732e77f996a22945c8d62df7617c4733/msgspec-0.18.6-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/7f/5d1ce7f47d44393d429922910afbe88fcd29ee3069babbb47507a4c3a7ea/multidict-6.1.0-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multipart", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/ed/e1f03200ee1f0bf4a2b9b72709afefbf5319b68df654e0b84b35c65613ee/multipart-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "polyfactory", "version": "2.22.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/11/87/6cd69c43e86bc5863f93dba3c9fb42ee4fda36a0fe5aa3cbd25001fb26f8/polyfactory-2.22.5-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "8.3.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "14.3.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/76/6d163cfac87b632216f71879e6b2cf17163f773ff59c00b5ff4900a80fa3/rich-14.3.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.13.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ce/d9/5f4c13cecde62396b0d3fe530a50ccea91e7dfc1ccf0e09c228841bb5ba8/urllib3-2.2.3-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/d9/a1e041c5e7caa9a05c925f4bdbdfb7f006d1f74996af53467bc394c97be7/importlib_metadata-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz"}}, {"metadata": {"name": "rich-click", "version": "1.9.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6d/97/a87901aef6b7e7e4a34c6dd6cc17dca8594a592ef9d9dd765fca2b7facf7/rich_click-1.9.8-py3-none-any.whl"}}, {"metadata": {"name": "Faker", "version": "35.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/18/f70c67c9d3a71f1749faa027dad3cd626c728df5682458091d73c69ed9a9/Faker-35.2.2-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "3.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.19.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "zipp", "version": "3.20.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/8b/5ba542fa83c90e09eac972fc9baca7a88e7e7ca4b221a89251954019308b/zipp-3.20.2-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "2.23"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}], "install_targets_hash": "030c889f2cc15fac775b2cc21c8d01e4"} +{"python_version": "3.8", "dependencies": [{"metadata": {"name": "litestar", "version": "2.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/ce/4697b547790f23d2fcc37a928d48c38140cf86360e4041ca8177e3367c14/litestar-2.24.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/31/6607dab48616902f76885dfcf62c08d929796fc3b2d2318faf9fd54dbed9/pytest_asyncio-0.24.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/45/58/38b5afbc1a800eeea951b9285d3912613f2603bdf897a4ab0f4bd7f405fc/python_multipart-0.0.20-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.32.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "47.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/34/a4fae8ae7c3bc227460c9ae43f56abf1b911da0ec29e0ebac53bb0a4b6b7/cryptography-47.0.0-cp38-abi3-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/b4/f7e396030e3b11394436358ca258a81d6010106582422f23443c16ca1873/anyio-4.5.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "1.17.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/46/fce169ad09419b8e8a5a81db61e08cd7b9fd31332221b84bd176fe0a3136/charset_normalizer-3.4.7-cp38-cp38-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.15"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/23/408243171aa9aaba178d3e2559159c24c1171a641aa83b67bdd3394ead8e/idna-3.15-py3-none-any.whl"}}, {"metadata": {"name": "importlib_resources", "version": "6.4.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/6a/4604f9ae2fa62ef47b9de2fa5ad599589d28c9fd1d335f32759813dfa91e/importlib_resources-6.4.5-py3-none-any.whl"}}, {"metadata": {"name": "litestar-htmx", "version": "0.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/99/3ea64a79a2f4fea5225ccd0128201a3b8eab5e216b8fba8b778b8c462f29/litestar_htmx-0.4.1-py3-none-any.whl"}}, {"metadata": {"name": "msgspec", "version": "0.18.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/86/6f/1da53a2ba5f312c3dca9e5f38912732e77f996a22945c8d62df7617c4733/msgspec-0.18.6-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/7f/5d1ce7f47d44393d429922910afbe88fcd29ee3069babbb47507a4c3a7ea/multidict-6.1.0-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multipart", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/ed/e1f03200ee1f0bf4a2b9b72709afefbf5319b68df654e0b84b35c65613ee/multipart-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "polyfactory", "version": "2.22.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/11/87/6cd69c43e86bc5863f93dba3c9fb42ee4fda36a0fe5aa3cbd25001fb26f8/polyfactory-2.22.5-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "8.3.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "14.3.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/76/6d163cfac87b632216f71879e6b2cf17163f773ff59c00b5ff4900a80fa3/rich-14.3.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.13.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ce/d9/5f4c13cecde62396b0d3fe530a50ccea91e7dfc1ccf0e09c228841bb5ba8/urllib3-2.2.3-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/d9/a1e041c5e7caa9a05c925f4bdbdfb7f006d1f74996af53467bc394c97be7/importlib_metadata-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz"}}, {"metadata": {"name": "rich-click", "version": "1.9.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6d/97/a87901aef6b7e7e4a34c6dd6cc17dca8594a592ef9d9dd765fca2b7facf7/rich_click-1.9.8-py3-none-any.whl"}}, {"metadata": {"name": "Faker", "version": "35.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/18/f70c67c9d3a71f1749faa027dad3cd626c728df5682458091d73c69ed9a9/Faker-35.2.2-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "3.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.19.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "zipp", "version": "3.20.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/8b/5ba542fa83c90e09eac972fc9baca7a88e7e7ca4b221a89251954019308b/zipp-3.20.2-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "2.23"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}], "install_targets_hash": "030c889f2cc15fac775b2cc21c8d01e4"} +{"python_version": "3.8", "dependencies": [{"metadata": {"name": "litestar", "version": "2.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/ce/4697b547790f23d2fcc37a928d48c38140cf86360e4041ca8177e3367c14/litestar-2.24.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/31/6607dab48616902f76885dfcf62c08d929796fc3b2d2318faf9fd54dbed9/pytest_asyncio-0.24.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/45/58/38b5afbc1a800eeea951b9285d3912613f2603bdf897a4ab0f4bd7f405fc/python_multipart-0.0.20-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.32.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "47.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/34/a4fae8ae7c3bc227460c9ae43f56abf1b911da0ec29e0ebac53bb0a4b6b7/cryptography-47.0.0-cp38-abi3-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/b4/f7e396030e3b11394436358ca258a81d6010106582422f23443c16ca1873/anyio-4.5.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "1.17.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/46/fce169ad09419b8e8a5a81db61e08cd7b9fd31332221b84bd176fe0a3136/charset_normalizer-3.4.7-cp38-cp38-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.15"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/23/408243171aa9aaba178d3e2559159c24c1171a641aa83b67bdd3394ead8e/idna-3.15-py3-none-any.whl"}}, {"metadata": {"name": "importlib_resources", "version": "6.4.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/6a/4604f9ae2fa62ef47b9de2fa5ad599589d28c9fd1d335f32759813dfa91e/importlib_resources-6.4.5-py3-none-any.whl"}}, {"metadata": {"name": "litestar-htmx", "version": "0.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/99/3ea64a79a2f4fea5225ccd0128201a3b8eab5e216b8fba8b778b8c462f29/litestar_htmx-0.4.1-py3-none-any.whl"}}, {"metadata": {"name": "msgspec", "version": "0.18.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/86/6f/1da53a2ba5f312c3dca9e5f38912732e77f996a22945c8d62df7617c4733/msgspec-0.18.6-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/7f/5d1ce7f47d44393d429922910afbe88fcd29ee3069babbb47507a4c3a7ea/multidict-6.1.0-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multipart", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/ed/e1f03200ee1f0bf4a2b9b72709afefbf5319b68df654e0b84b35c65613ee/multipart-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "polyfactory", "version": "2.22.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/11/87/6cd69c43e86bc5863f93dba3c9fb42ee4fda36a0fe5aa3cbd25001fb26f8/polyfactory-2.22.5-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "8.3.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "14.3.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/76/6d163cfac87b632216f71879e6b2cf17163f773ff59c00b5ff4900a80fa3/rich-14.3.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.13.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ce/d9/5f4c13cecde62396b0d3fe530a50ccea91e7dfc1ccf0e09c228841bb5ba8/urllib3-2.2.3-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/d9/a1e041c5e7caa9a05c925f4bdbdfb7f006d1f74996af53467bc394c97be7/importlib_metadata-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz"}}, {"metadata": {"name": "rich-click", "version": "1.9.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6d/97/a87901aef6b7e7e4a34c6dd6cc17dca8594a592ef9d9dd765fca2b7facf7/rich_click-1.9.8-py3-none-any.whl"}}, {"metadata": {"name": "Faker", "version": "35.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/18/f70c67c9d3a71f1749faa027dad3cd626c728df5682458091d73c69ed9a9/Faker-35.2.2-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "3.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.19.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "zipp", "version": "3.20.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/8b/5ba542fa83c90e09eac972fc9baca7a88e7e7ca4b221a89251954019308b/zipp-3.20.2-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "2.23"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}], "install_targets_hash": "030c889f2cc15fac775b2cc21c8d01e4"} +{"python_version": "3.8", "dependencies": [{"metadata": {"name": "litestar", "version": "2.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/ce/4697b547790f23d2fcc37a928d48c38140cf86360e4041ca8177e3367c14/litestar-2.24.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/31/6607dab48616902f76885dfcf62c08d929796fc3b2d2318faf9fd54dbed9/pytest_asyncio-0.24.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/45/58/38b5afbc1a800eeea951b9285d3912613f2603bdf897a4ab0f4bd7f405fc/python_multipart-0.0.20-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.32.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "47.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/34/a4fae8ae7c3bc227460c9ae43f56abf1b911da0ec29e0ebac53bb0a4b6b7/cryptography-47.0.0-cp38-abi3-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/b4/f7e396030e3b11394436358ca258a81d6010106582422f23443c16ca1873/anyio-4.5.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "1.17.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/46/fce169ad09419b8e8a5a81db61e08cd7b9fd31332221b84bd176fe0a3136/charset_normalizer-3.4.7-cp38-cp38-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.15"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/23/408243171aa9aaba178d3e2559159c24c1171a641aa83b67bdd3394ead8e/idna-3.15-py3-none-any.whl"}}, {"metadata": {"name": "importlib_resources", "version": "6.4.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/6a/4604f9ae2fa62ef47b9de2fa5ad599589d28c9fd1d335f32759813dfa91e/importlib_resources-6.4.5-py3-none-any.whl"}}, {"metadata": {"name": "litestar-htmx", "version": "0.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/99/3ea64a79a2f4fea5225ccd0128201a3b8eab5e216b8fba8b778b8c462f29/litestar_htmx-0.4.1-py3-none-any.whl"}}, {"metadata": {"name": "msgspec", "version": "0.18.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/86/6f/1da53a2ba5f312c3dca9e5f38912732e77f996a22945c8d62df7617c4733/msgspec-0.18.6-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/7f/5d1ce7f47d44393d429922910afbe88fcd29ee3069babbb47507a4c3a7ea/multidict-6.1.0-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multipart", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/ed/e1f03200ee1f0bf4a2b9b72709afefbf5319b68df654e0b84b35c65613ee/multipart-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "polyfactory", "version": "2.22.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/11/87/6cd69c43e86bc5863f93dba3c9fb42ee4fda36a0fe5aa3cbd25001fb26f8/polyfactory-2.22.5-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "8.3.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "14.3.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/76/6d163cfac87b632216f71879e6b2cf17163f773ff59c00b5ff4900a80fa3/rich-14.3.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.13.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ce/d9/5f4c13cecde62396b0d3fe530a50ccea91e7dfc1ccf0e09c228841bb5ba8/urllib3-2.2.3-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/d9/a1e041c5e7caa9a05c925f4bdbdfb7f006d1f74996af53467bc394c97be7/importlib_metadata-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz"}}, {"metadata": {"name": "rich-click", "version": "1.9.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6d/97/a87901aef6b7e7e4a34c6dd6cc17dca8594a592ef9d9dd765fca2b7facf7/rich_click-1.9.8-py3-none-any.whl"}}, {"metadata": {"name": "Faker", "version": "35.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/18/f70c67c9d3a71f1749faa027dad3cd626c728df5682458091d73c69ed9a9/Faker-35.2.2-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "3.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.19.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "zipp", "version": "3.20.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/8b/5ba542fa83c90e09eac972fc9baca7a88e7e7ca4b221a89251954019308b/zipp-3.20.2-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "2.23"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}], "install_targets_hash": "030c889f2cc15fac775b2cc21c8d01e4"} {"python_version": "3.8", "dependencies": [{"metadata": {"name": "openfeature_sdk", "version": "0.7.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/20/cb043f54b11505d993e4dd84652cfc44c1260dc94b7f41aa35489af58277/openfeature_sdk-0.7.5-py3-none-any.whl"}}], "install_targets_hash": "1014994e190575f0710da79951d7f561"} +{"python_version": "3.8", "dependencies": [{"metadata": {"name": "fastapi", "version": "0.123.10"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/f0/7cb92c4a720def85240fd63fbbcf147ce19e7a731c8e1032376bb5a486ac/fastapi-0.123.10-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/31/6607dab48616902f76885dfcf62c08d929796fc3b2d2318faf9fd54dbed9/pytest_asyncio-0.24.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/45/58/38b5afbc1a800eeea951b9285d3912613f2603bdf897a4ab0f4bd7f405fc/python_multipart-0.0.20-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.32.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/b4/f7e396030e3b11394436358ca258a81d6010106582422f23443c16ca1873/anyio-4.5.2-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/2b/f97f1c193fb855c345d678f5077d6926034db0722df74c8f057020e05a25/charset_normalizer-3.4.9-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.15"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/23/408243171aa9aaba178d3e2559159c24c1171a641aa83b67bdd3394ead8e/idna-3.15-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "2.1.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f8/ff/2c942a82c35a49df5de3a630ce0a8456ac2969691b230e530ac12314364c/MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "pydantic", "version": "2.10.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/3c/8cc1cc84deffa6e25d2d0c688ebb80635dfdbf1dbea3e30c541c8cf4d860/pydantic-2.10.6-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/20/26c549249769ed84877f862f7bb93f89a6ee08b4bee1ed8781616b7fbb5e/pydantic_core-2.27.2-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "8.3.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "0.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b6/c5/7ae467eeddb57260c8ce17a3a09f9f5edba35820fc022d7c55b7decd5d3a/starlette-0.44.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.13.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ce/d9/5f4c13cecde62396b0d3fe530a50ccea91e7dfc1ccf0e09c228841bb5ba8/urllib3-2.2.3-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}], "install_targets_hash": "11d8ddfacb08ef9d446aa4936e0d4ecd"} {"python_version": "3.8", "dependencies": [{"metadata": {"name": "openai", "version": "1.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/94/99a674bd1dd3a74d5b679bfdd9e1396f08407f933eb15672207e5a8abf1d/openai-1.0.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/31/6607dab48616902f76885dfcf62c08d929796fc3b2d2318faf9fd54dbed9/pytest_asyncio-0.24.0-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e6/04/9a2b978beea18ef8916319e51f6d079c804062df80c63f0392202e5ddf10/tiktoken-0.7.0-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.15"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/23/408243171aa9aaba178d3e2559159c24c1171a641aa83b67bdd3394ead8e/idna-3.15-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.10.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/3c/8cc1cc84deffa6e25d2d0c688ebb80635dfdbf1dbea3e30c541c8cf4d860/pydantic-2.10.6-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/20/26c549249769ed84877f862f7bb93f89a6ee08b4bee1ed8781616b7fbb5e/pydantic_core-2.27.2-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "8.3.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2024.11.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/08/92/9df786fad8a4e0766bfc9a2e334c5f0757356070c9639b2ec776b8cdef3d/regex-2024.11.6-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.32.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.13.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/97/fb4e82231aba271ffd775a1b4993b0defc4e3059f286ae41d9433409fe85/charset_normalizer-3.5.1-cp37-abi3-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ce/d9/5f4c13cecde62396b0d3fe530a50ccea91e7dfc1ccf0e09c228841bb5ba8/urllib3-2.2.3-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}], "install_targets_hash": "12df249d83810baf33b2334b64611de2"} +{"python_version": "3.8", "dependencies": [{"metadata": {"name": "openai", "version": "1.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/94/99a674bd1dd3a74d5b679bfdd9e1396f08407f933eb15672207e5a8abf1d/openai-1.0.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/31/6607dab48616902f76885dfcf62c08d929796fc3b2d2318faf9fd54dbed9/pytest_asyncio-0.24.0-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e6/04/9a2b978beea18ef8916319e51f6d079c804062df80c63f0392202e5ddf10/tiktoken-0.7.0-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.15"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/23/408243171aa9aaba178d3e2559159c24c1171a641aa83b67bdd3394ead8e/idna-3.15-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.10.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/3c/8cc1cc84deffa6e25d2d0c688ebb80635dfdbf1dbea3e30c541c8cf4d860/pydantic-2.10.6-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/20/26c549249769ed84877f862f7bb93f89a6ee08b4bee1ed8781616b7fbb5e/pydantic_core-2.27.2-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "8.3.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2024.11.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/08/92/9df786fad8a4e0766bfc9a2e334c5f0757356070c9639b2ec776b8cdef3d/regex-2024.11.6-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.32.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.13.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/97/fb4e82231aba271ffd775a1b4993b0defc4e3059f286ae41d9433409fe85/charset_normalizer-3.5.1-cp37-abi3-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ce/d9/5f4c13cecde62396b0d3fe530a50ccea91e7dfc1ccf0e09c228841bb5ba8/urllib3-2.2.3-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}], "install_targets_hash": "12df249d83810baf33b2334b64611de2"} +{"python_version": "3.8", "dependencies": [{"metadata": {"name": "fastapi", "version": "0.104.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f3/4f/0ce34195b63240b6693086496c9bab4ef23999112184399a3e88854c7674/fastapi-0.104.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/31/6607dab48616902f76885dfcf62c08d929796fc3b2d2318faf9fd54dbed9/pytest_asyncio-0.24.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/45/58/38b5afbc1a800eeea951b9285d3912613f2603bdf897a4ab0f4bd7f405fc/python_multipart-0.0.20-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.32.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/2b/f97f1c193fb855c345d678f5077d6926034db0722df74c8f057020e05a25/charset_normalizer-3.4.9-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.15"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/23/408243171aa9aaba178d3e2559159c24c1171a641aa83b67bdd3394ead8e/idna-3.15-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "2.1.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f8/ff/2c942a82c35a49df5de3a630ce0a8456ac2969691b230e530ac12314364c/MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "pydantic", "version": "2.10.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/3c/8cc1cc84deffa6e25d2d0c688ebb80635dfdbf1dbea3e30c541c8cf4d860/pydantic-2.10.6-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/20/26c549249769ed84877f862f7bb93f89a6ee08b4bee1ed8781616b7fbb5e/pydantic_core-2.27.2-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "8.3.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "0.27.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/f8/e2cca22387965584a409795913b774235752be4176d276714e15e1a58884/starlette-0.27.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.13.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ce/d9/5f4c13cecde62396b0d3fe530a50ccea91e7dfc1ccf0e09c228841bb5ba8/urllib3-2.2.3-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}], "install_targets_hash": "169e3a84c7fb134352fce11f7e68103c"} +{"python_version": "3.8", "dependencies": [{"metadata": {"name": "pyspark", "version": "3.5.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/ce/81e53e729790556e3983e95de1a7d5df91a34adfcd34b5a5ab0e0c6e9b33/pyspark-3.5.9.tar.gz"}}, {"metadata": {"name": "py4j", "version": "0.10.9.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/db/ea0203e495be491c85af87b66e37acfd3bf756fd985f87e46fc5e3bf022c/py4j-0.10.9.9-py2.py3-none-any.whl"}}], "install_targets_hash": "1a79880f834ae1c486d6aca78b08c546"} {"python_version": "3.8", "dependencies": [{"metadata": {"name": "pyspark", "version": "3.5.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/ce/81e53e729790556e3983e95de1a7d5df91a34adfcd34b5a5ab0e0c6e9b33/pyspark-3.5.9.tar.gz"}}, {"metadata": {"name": "py4j", "version": "0.10.9.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/db/ea0203e495be491c85af87b66e37acfd3bf756fd985f87e46fc5e3bf022c/py4j-0.10.9.9-py2.py3-none-any.whl"}}], "install_targets_hash": "1a79880f834ae1c486d6aca78b08c546"} +{"python_version": "3.8", "dependencies": [{"metadata": {"name": "pyspark", "version": "3.5.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/ce/81e53e729790556e3983e95de1a7d5df91a34adfcd34b5a5ab0e0c6e9b33/pyspark-3.5.9.tar.gz"}}, {"metadata": {"name": "py4j", "version": "0.10.9.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/db/ea0203e495be491c85af87b66e37acfd3bf756fd985f87e46fc5e3bf022c/py4j-0.10.9.9-py2.py3-none-any.whl"}}], "install_targets_hash": "1a79880f834ae1c486d6aca78b08c546"} +{"python_version": "3.8", "dependencies": [{"metadata": {"name": "grpcio", "version": "1.32.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0e/5f/eeb402746a65839acdec78b7e757635f5e446138cc1d68589dfa32cba593/grpcio-1.32.0.tar.gz"}}, {"metadata": {"name": "protobuf", "version": "5.29.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/06/db/49b05966fd208ae3f44dcd33837b6243b4915c57561d730a43f881f24dea/protobuf-5.29.6-cp38-abi3-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "mypy-protobuf", "version": "5.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/ec/5ffcf8f5f53757e01afdece10c664e694ac60d2f17c2036811b85b842a5b/mypy_protobuf-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "types-protobuf", "version": "5.29.1.20241207"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/6e/cdf152187019d6f6d04066b23e48659d961b527e9c6d43b48459d160e332/types_protobuf-5.29.1.20241207-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/31/6607dab48616902f76885dfcf62c08d929796fc3b2d2318faf9fd54dbed9/pytest_asyncio-0.24.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/af/9c0bda43e486a3c9bf1e0f876d0f241bc3f229d7d65d09331a0868db9629/pytest_forked-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "8.3.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "py", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.13.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl"}}], "install_targets_hash": "1c17d25272b4c49ed5b60742f972a614"} {"python_version": "3.8", "dependencies": [{"metadata": {"name": "grpcio", "version": "1.32.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0e/5f/eeb402746a65839acdec78b7e757635f5e446138cc1d68589dfa32cba593/grpcio-1.32.0.tar.gz"}}, {"metadata": {"name": "protobuf", "version": "5.29.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/06/db/49b05966fd208ae3f44dcd33837b6243b4915c57561d730a43f881f24dea/protobuf-5.29.6-cp38-abi3-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "mypy-protobuf", "version": "5.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/ec/5ffcf8f5f53757e01afdece10c664e694ac60d2f17c2036811b85b842a5b/mypy_protobuf-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "types-protobuf", "version": "5.29.1.20241207"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/6e/cdf152187019d6f6d04066b23e48659d961b527e9c6d43b48459d160e332/types_protobuf-5.29.1.20241207-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/31/6607dab48616902f76885dfcf62c08d929796fc3b2d2318faf9fd54dbed9/pytest_asyncio-0.24.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/af/9c0bda43e486a3c9bf1e0f876d0f241bc3f229d7d65d09331a0868db9629/pytest_forked-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "8.3.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "py", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.13.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl"}}], "install_targets_hash": "1c17d25272b4c49ed5b60742f972a614"} +{"python_version": "3.8", "dependencies": [{"metadata": {"name": "grpcio", "version": "1.32.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0e/5f/eeb402746a65839acdec78b7e757635f5e446138cc1d68589dfa32cba593/grpcio-1.32.0.tar.gz"}}, {"metadata": {"name": "protobuf", "version": "5.29.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/06/db/49b05966fd208ae3f44dcd33837b6243b4915c57561d730a43f881f24dea/protobuf-5.29.6-cp38-abi3-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "mypy-protobuf", "version": "5.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/ec/5ffcf8f5f53757e01afdece10c664e694ac60d2f17c2036811b85b842a5b/mypy_protobuf-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "types-protobuf", "version": "5.29.1.20241207"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/6e/cdf152187019d6f6d04066b23e48659d961b527e9c6d43b48459d160e332/types_protobuf-5.29.1.20241207-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/31/6607dab48616902f76885dfcf62c08d929796fc3b2d2318faf9fd54dbed9/pytest_asyncio-0.24.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/af/9c0bda43e486a3c9bf1e0f876d0f241bc3f229d7d65d09331a0868db9629/pytest_forked-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "8.3.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "py", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.13.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl"}}], "install_targets_hash": "1c17d25272b4c49ed5b60742f972a614"} +{"python_version": "3.8", "dependencies": [{"metadata": {"name": "anthropic", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/b4/0f37ca7ba43ec390f363fac20ae04c53b5db23a153e08251f214ac8eda7a/anthropic-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/31/6607dab48616902f76885dfcf62c08d929796fc3b2d2318faf9fd54dbed9/pytest_asyncio-0.24.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "tokenizers", "version": "0.20.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/83/a620059226e5c864c02d133510927cf64d649887469025de6caef15acd42/tokenizers-0.20.3-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anyio", "version": "4.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/b4/f7e396030e3b11394436358ca258a81d6010106582422f23443c16ca1873/anyio-4.5.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "huggingface_hub", "version": "0.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/af/48ac8483240de756d2438c380746e7130d1c6f75802ef22f3c6d49982787/huggingface_hub-0.36.2-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.15"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/23/408243171aa9aaba178d3e2559159c24c1171a641aa83b67bdd3394ead8e/idna-3.15-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.10.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/3c/8cc1cc84deffa6e25d2d0c688ebb80635dfdbf1dbea3e30c541c8cf4d860/pydantic-2.10.6-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/20/26c549249769ed84877f862f7bb93f89a6ee08b4bee1ed8781616b7fbb5e/pydantic_core-2.27.2-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "8.3.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.13.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2025.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/53/eb690efa8513166adef3e0669afd31e95ffde69fb3c52ec2ac7223ed6018/fsspec-2025.3.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/69/55b8dcf636142ae660fec1869fcac14c4da2e8412e14d6eee1523be77e9f/hf_xet-1.6.0-cp38-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "filelock", "version": "3.16.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/f8/feced7779d755758a52d1f6635d990b8d98dc0a29fa568bbe0625f18fdf3/filelock-3.16.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.32.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/97/fb4e82231aba271ffd775a1b4993b0defc4e3059f286ae41d9433409fe85/charset_normalizer-3.5.1-cp37-abi3-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "urllib3", "version": "2.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ce/d9/5f4c13cecde62396b0d3fe530a50ccea91e7dfc1ccf0e09c228841bb5ba8/urllib3-2.2.3-py3-none-any.whl"}}], "install_targets_hash": "2290509248c7cfdb460d103d3b5f31ec"} {"python_version": "3.8", "dependencies": [{"metadata": {"name": "anthropic", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/b4/0f37ca7ba43ec390f363fac20ae04c53b5db23a153e08251f214ac8eda7a/anthropic-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/31/6607dab48616902f76885dfcf62c08d929796fc3b2d2318faf9fd54dbed9/pytest_asyncio-0.24.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "tokenizers", "version": "0.20.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/83/a620059226e5c864c02d133510927cf64d649887469025de6caef15acd42/tokenizers-0.20.3-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anyio", "version": "4.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/b4/f7e396030e3b11394436358ca258a81d6010106582422f23443c16ca1873/anyio-4.5.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "huggingface_hub", "version": "0.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/af/48ac8483240de756d2438c380746e7130d1c6f75802ef22f3c6d49982787/huggingface_hub-0.36.2-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.15"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/23/408243171aa9aaba178d3e2559159c24c1171a641aa83b67bdd3394ead8e/idna-3.15-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.10.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/3c/8cc1cc84deffa6e25d2d0c688ebb80635dfdbf1dbea3e30c541c8cf4d860/pydantic-2.10.6-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/20/26c549249769ed84877f862f7bb93f89a6ee08b4bee1ed8781616b7fbb5e/pydantic_core-2.27.2-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "8.3.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.13.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2025.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/53/eb690efa8513166adef3e0669afd31e95ffde69fb3c52ec2ac7223ed6018/fsspec-2025.3.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/69/55b8dcf636142ae660fec1869fcac14c4da2e8412e14d6eee1523be77e9f/hf_xet-1.6.0-cp38-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "filelock", "version": "3.16.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/f8/feced7779d755758a52d1f6635d990b8d98dc0a29fa568bbe0625f18fdf3/filelock-3.16.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.32.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/97/fb4e82231aba271ffd775a1b4993b0defc4e3059f286ae41d9433409fe85/charset_normalizer-3.5.1-cp37-abi3-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "urllib3", "version": "2.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ce/d9/5f4c13cecde62396b0d3fe530a50ccea91e7dfc1ccf0e09c228841bb5ba8/urllib3-2.2.3-py3-none-any.whl"}}], "install_targets_hash": "2290509248c7cfdb460d103d3b5f31ec"} +{"python_version": "3.8", "dependencies": [{"metadata": {"name": "aiohttp", "version": "3.9.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/37/ca379996ae72e7795d5b3f6bd13c0b24ad8641d11d02732606fd363b7bed/aiohttp-3.9.5-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-aiohttp", "version": "1.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/a7/6e50ba2c0a27a34859a952162e63362a13142ce3c646e925b76de440e102/pytest_aiohttp-1.0.5-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/31/6607dab48616902f76885dfcf62c08d929796fc3b2d2318faf9fd54dbed9/pytest_asyncio-0.24.0-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/76/ac/a7305707cb852b7e16ff80eaf5692309bde30e2b1100a1fcacdc8f731d97/aiosignal-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "async-timeout", "version": "4.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/fa/e01228c2938de91d47b307831c62ab9e4001e747789d0b05baf779a6488c/async_timeout-4.0.3-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "25.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/77/06/bb80f5f86020c4551da315d78b3ab75e8228f89f0162f2c3a819e407941a/attrs-25.3.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/76/a3/c08322a91e73d1199901a77ce73971cffa06d3c74974270ff97aed6e152a/frozenlist-1.5.0-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/7f/5d1ce7f47d44393d429922910afbe88fcd29ee3069babbb47507a4c3a7ea/multidict-6.1.0-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "8.3.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.15.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/34/ede8d8ed7350b4b21e33fc4eff71e08de31da697034969b41190132d421f/yarl-1.15.2-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.15"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/23/408243171aa9aaba178d3e2559159c24c1171a641aa83b67bdd3394ead8e/idna-3.15-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/80/ef/18af27caaae5589c08bb5a461cfa136b83b7e7983be604f2140d91f92b97/propcache-0.2.0-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.13.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}], "install_targets_hash": "233113f80ecbd02cde8c7f1f523c1af4"} {"python_version": "3.8", "dependencies": [{"metadata": {"name": "asyncpg", "version": "0.23.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/97/b0/acacd8496670b24bad90b92c105fd2f66e83051bf5e23b978a059e5f9608/asyncpg-0.23.0.tar.gz"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/31/6607dab48616902f76885dfcf62c08d929796fc3b2d2318faf9fd54dbed9/pytest_asyncio-0.24.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "8.3.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.13.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl"}}], "install_targets_hash": "258979437b2e8714e61c32eff07271c3"} {"python_version": "3.8", "dependencies": [{"metadata": {"name": "Flask", "version": "2.3.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/56/26f0be8adc2b4257df20c1c4260ddd0aa396cf8e75d90ab2f7ff99bc34f9/flask-2.3.3-py3-none-any.whl"}}, {"metadata": {"name": "Flask-Login", "version": "0.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/59/f5/67e9cc5c2036f58115f9fe0f00d203cf6780c3ff8ae0e705e7a9d9e8ff9e/Flask_Login-0.6.3-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.0.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6c/69/05837f91dfe42109203ffa3e488214ff86a6d68b2ed6c167da6cdc42349b/werkzeug-3.0.6-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bb/2a/10164ed1f31196a2f7f3799368a821765c62851ead0e630ab52b8e14b4d0/blinker-1.8.2-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/d9/a1e041c5e7caa9a05c925f4bdbdfb7f006d1f74996af53467bc394c97be7/importlib_metadata-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "2.1.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f8/ff/2c942a82c35a49df5de3a630ce0a8456ac2969691b230e530ac12314364c/MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "zipp", "version": "3.20.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/8b/5ba542fa83c90e09eac972fc9baca7a88e7e7ca4b221a89251954019308b/zipp-3.20.2-py3-none-any.whl"}}], "install_targets_hash": "26b4bd6a717ed504426367c6af492c2d"} +{"python_version": "3.8", "dependencies": [{"metadata": {"name": "falcon", "version": "3.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/22/6a9009c53ad78e65d88a44db8eccc7f39c6f54fc05fb43b1e9cbbc481d06/falcon-3.0.1.tar.gz"}}], "install_targets_hash": "2963e8711ff6a3e310e62912cd678f80"} {"python_version": "3.8", "dependencies": [{"metadata": {"name": "aiohttp", "version": "3.7.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7a/95/eb60aaad7943e18c9d091de93c9b0b5ed40aa67c7d5e3c5ee9b36f100a38/aiohttp-3.7.4.tar.gz"}}, {"metadata": {"name": "pytest-aiohttp", "version": "0.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c9/2f/34f8581a799d1e58f0b64d9eb4aa0864b53f520d160281c2eb692340fefc/pytest_aiohttp-0.3.0-py3-none-any.whl"}}, {"metadata": {"name": "async-timeout", "version": "3.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/1e/5a4441be21b0726c4464f3f23c8b19628372f606755a9d2e46c187e65ec4/async_timeout-3.0.1-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "25.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/77/06/bb80f5f86020c4551da315d78b3ab75e8228f89f0162f2c3a819e407941a/attrs-25.3.0-py3-none-any.whl"}}, {"metadata": {"name": "chardet", "version": "3.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/a9/01ffebfb562e4274b6487b4bb1ddec7ca55ec7510b22e4c51f14098443b8/chardet-3.0.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/7f/5d1ce7f47d44393d429922910afbe88fcd29ee3069babbb47507a4c3a7ea/multidict-6.1.0-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.13.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.15.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/34/ede8d8ed7350b4b21e33fc4eff71e08de31da697034969b41190132d421f/yarl-1.15.2-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "8.3.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.15"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/23/408243171aa9aaba178d3e2559159c24c1171a641aa83b67bdd3394ead8e/idna-3.15-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/80/ef/18af27caaae5589c08bb5a461cfa136b83b7e7983be604f2140d91f92b97/propcache-0.2.0-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}], "install_targets_hash": "297ddb3a2529f85d96683b8bc493a96d"} +{"python_version": "3.8", "dependencies": [{"metadata": {"name": "redis", "version": "5.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/26/5c5fa0e83c3621db835cfc1f1d789b37e7fa99ed54423b5f519beb931aa7/redis-5.3.1-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.25.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/ae/0a522205b23e2f3d2d67c69114baee9381873849f676de221267f3ad759e/fakeredis-2.25.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "7.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ff/f6e8b8f39e08547faece4bd80f89d5a8de68a38b2d179cc1c4490ffa3286/pytest-7.4.4-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.23.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ee/82/62e2d63639ecb0fbe8a7ee59ef0bc69a4669ec50f6d3459f74ad4e4189a2/pytest_asyncio-0.23.8-py3-none-any.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/84/0fdf9b18ba31d69877bd39c9cd6052b47f3761e9910c15de788e519f079f/PyJWT-2.9.0-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.13.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}], "install_targets_hash": "30dbe57b1c71e4ba515bb4fc9cd2328b"} +{"python_version": "3.8", "dependencies": [{"metadata": {"name": "Quart", "version": "0.19.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/01/e5d6127f6304c7e596e5c8eec5accdec0f698ec65fe342d8474ad5223717/quart-0.19.9-py3-none-any.whl"}}, {"metadata": {"name": "taskgroup", "version": "0.0.0a4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e5/0f8dac3d9e6314f60a725cdc9ec01f45591ddd720e59f6a4ff8bdcdf82cd/taskgroup-0.0.0a4-py2.py3-none-any.whl"}}, {"metadata": {"name": "quart-auth", "version": "0.10.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/f7/ea7eb12f2461de11ade546353546f386c27ce1b99a8ec247625d2c73fe91/quart_auth-0.10.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/31/6607dab48616902f76885dfcf62c08d929796fc3b2d2318faf9fd54dbed9/pytest_asyncio-0.24.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/af/9c0bda43e486a3c9bf1e0f876d0f241bc3f229d7d65d09331a0868db9629/pytest_forked-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.0.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6c/69/05837f91dfe42109203ffa3e488214ff86a6d68b2ed6c167da6cdc42349b/werkzeug-3.0.6-py3-none-any.whl"}}, {"metadata": {"name": "quart-flask-patch", "version": "0.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/ce/ad2b19e3a26d2c611aa883b8500e8b4eb08f8a2d1595e28c37864e54e99c/quart_flask_patch-0.3.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bb/2a/10164ed1f31196a2f7f3799368a821765c62851ead0e630ab52b8e14b4d0/blinker-1.8.2-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/61/80/ffe1da13ad9300f87c93af113edd0638c75138c42a0994becfacac078c06/flask-3.0.3-py3-none-any.whl"}}, {"metadata": {"name": "Hypercorn", "version": "0.17.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0e/3b/dfa13a8d96aa24e40ea74a975a9906cfdc2ab2f4e3b498862a57052f04eb/hypercorn-0.17.3-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/d9/a1e041c5e7caa9a05c925f4bdbdfb7f006d1f74996af53467bc394c97be7/importlib_metadata-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "2.1.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f8/ff/2c942a82c35a49df5de3a630ce0a8456ac2969691b230e530ac12314364c/MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "pytest", "version": "8.3.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.13.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "24.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a5/45/30bb92d442636f570cb5651bc661f52b610e2eec3f891a5dc3a4c3667db0/aiofiles-24.1.0-py3-none-any.whl"}}, {"metadata": {"name": "py", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "h2", "version": "4.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/e5/db6d438da759efbb488c4f3fbdab7764492ff3c3f953132efa6b9f0e9e53/h2-4.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "wsproto", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/58/e860788190eba3bcce367f74d29c4675466ce8dddfba85f7827588416f01/wsproto-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "zipp", "version": "3.20.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/8b/5ba542fa83c90e09eac972fc9baca7a88e7e7ca4b221a89251954019308b/zipp-3.20.2-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "priority", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5e/5f/82c8074f7e84978129347c2c6ec8b6c59f3584ff1a20bc3c940a3e061790/priority-2.0.0-py3-none-any.whl"}}, {"metadata": {"name": "hpack", "version": "4.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d5/34/e8b383f35b77c402d28563d2b8f83159319b509bc5f760b15d60b0abf165/hpack-4.0.0-py3-none-any.whl"}}, {"metadata": {"name": "hyperframe", "version": "6.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/de/85a784bcc4a3779d1753a7ec2dee5de90e18c7bcf402e71b51fcf150b129/hyperframe-6.0.1-py3-none-any.whl"}}], "install_targets_hash": "318ae1241bbed77c30cfd07b4ce80bd0"} {"python_version": "3.8", "dependencies": [{"metadata": {"name": "starlite", "version": "1.51.16"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f3/02/664dda98e4f715ef0cba583f53dabddb3f42667d464d38156e1837ed4ce2/starlite-1.51.16-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/31/6607dab48616902f76885dfcf62c08d929796fc3b2d2318faf9fd54dbed9/pytest_asyncio-0.24.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/45/58/38b5afbc1a800eeea951b9285d3912613f2603bdf897a4ab0f4bd7f405fc/python_multipart-0.0.20-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.32.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "47.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/34/a4fae8ae7c3bc227460c9ae43f56abf1b911da0ec29e0ebac53bb0a4b6b7/cryptography-47.0.0-cp38-abi3-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "pydantic", "version": "1.10.26"}, "download_info": {"url": "https://files.pythonhosted.org/packages/85/15/b2304a2f8206880b0a85dbe6593736c59bf0b676d57ad9338312f1369805/pydantic-1.10.26-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "1.17.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/46/fce169ad09419b8e8a5a81db61e08cd7b9fd31332221b84bd176fe0a3136/charset_normalizer-3.4.7-cp38-cp38-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.15"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/23/408243171aa9aaba178d3e2559159c24c1171a641aa83b67bdd3394ead8e/idna-3.15-py3-none-any.whl"}}, {"metadata": {"name": "Mako", "version": "1.3.12"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/b1/a0ec7a5a9db730a08daef1fdfb8090435b82465abbf758a596f0ea88727e/mako-1.3.12-py3-none-any.whl"}}, {"metadata": {"name": "msgspec", "version": "0.18.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/86/6f/1da53a2ba5f312c3dca9e5f38912732e77f996a22945c8d62df7617c4733/msgspec-0.18.6-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/7f/5d1ce7f47d44393d429922910afbe88fcd29ee3069babbb47507a4c3a7ea/multidict-6.1.0-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic-openapi-schema", "version": "1.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bb/a1/9b906584055e2a9ee48368e2ad7148625e06594fb0f81f8656c6e71eb672/pydantic_openapi_schema-1.5.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "8.3.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.13.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ce/d9/5f4c13cecde62396b0d3fe530a50ccea91e7dfc1ccf0e09c228841bb5ba8/urllib3-2.2.3-py3-none-any.whl"}}, {"metadata": {"name": "fast-query-parsers", "version": "1.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/21/c8c160f61a740efc4577079eb5747a6b2cb8d1168a84a0bfda6044113768/fast_query_parsers-1.0.3-cp38-abi3-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/d9/a1e041c5e7caa9a05c925f4bdbdfb7f006d1f74996af53467bc394c97be7/importlib_metadata-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic-factories", "version": "1.17.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/40/49/81bbfccaf7174e7a94be1fa95d9ed46da6663372b2a7cd597c1c6fdfcabe/pydantic_factories-1.17.3-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "2.1.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f8/ff/2c942a82c35a49df5de3a630ce0a8456ac2969691b230e530ac12314364c/MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "pluggy", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "zipp", "version": "3.20.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/8b/5ba542fa83c90e09eac972fc9baca7a88e7e7ca4b221a89251954019308b/zipp-3.20.2-py3-none-any.whl"}}, {"metadata": {"name": "email-validator", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "Faker", "version": "35.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/18/f70c67c9d3a71f1749faa027dad3cd626c728df5682458091d73c69ed9a9/Faker-35.2.2-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "2.23"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl"}}, {"metadata": {"name": "dnspython", "version": "2.6.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/87/a1/8c5287991ddb8d3e4662f71356d9656d91ab3a36618c3dd11b280df0d255/dnspython-2.6.1-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}], "install_targets_hash": "33d6741d45d5018c097d63500582c5d9"} {"python_version": "3.8", "dependencies": [{"metadata": {"name": "asyncpg", "version": "0.29.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/bd/29e0d546a2cd4e22f8dda2fbeaae73978af2058059c93527237a1e6da855/asyncpg-0.29.0-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/31/6607dab48616902f76885dfcf62c08d929796fc3b2d2318faf9fd54dbed9/pytest_asyncio-0.24.0-py3-none-any.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "8.3.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.13.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl"}}], "install_targets_hash": "37b71e639b9f2205d095eed9add52c09"} -{"python_version": "3.8", "dependencies": [{"metadata": {"name": "aiohttp", "version": "3.10.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/31/bb/2890a3c77126758ef58536ca9f7476a12ba2021e0cd074108fb99b8c8747/aiohttp-3.10.11-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-aiohttp", "version": "1.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/a7/6e50ba2c0a27a34859a952162e63362a13142ce3c646e925b76de440e102/pytest_aiohttp-1.0.5-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/31/6607dab48616902f76885dfcf62c08d929796fc3b2d2318faf9fd54dbed9/pytest_asyncio-0.24.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/74/fbb6559de3607b3300b9be3cc64e97548d55678e44623db17820dbd20002/aiohappyeyeballs-2.4.4-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/76/ac/a7305707cb852b7e16ff80eaf5692309bde30e2b1100a1fcacdc8f731d97/aiosignal-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "25.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/77/06/bb80f5f86020c4551da315d78b3ab75e8228f89f0162f2c3a819e407941a/attrs-25.3.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/76/a3/c08322a91e73d1199901a77ce73971cffa06d3c74974270ff97aed6e152a/frozenlist-1.5.0-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/7f/5d1ce7f47d44393d429922910afbe88fcd29ee3069babbb47507a4c3a7ea/multidict-6.1.0-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "8.3.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.15.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/34/ede8d8ed7350b4b21e33fc4eff71e08de31da697034969b41190132d421f/yarl-1.15.2-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.15"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/23/408243171aa9aaba178d3e2559159c24c1171a641aa83b67bdd3394ead8e/idna-3.15-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/80/ef/18af27caaae5589c08bb5a461cfa136b83b7e7983be604f2140d91f92b97/propcache-0.2.0-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.13.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}], "install_targets_hash": "38bb936208e4e77b6875b0856d10553a"} {"python_version": "3.8", "dependencies": [{"metadata": {"name": "starlite", "version": "1.48.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/46/84/fdfb336bf788e52a5fead1e9e302ac5a0b8a5a0094bdd2c491d6162cd147/starlite-1.48.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/31/6607dab48616902f76885dfcf62c08d929796fc3b2d2318faf9fd54dbed9/pytest_asyncio-0.24.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/45/58/38b5afbc1a800eeea951b9285d3912613f2603bdf897a4ab0f4bd7f405fc/python_multipart-0.0.20-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.32.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "47.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/34/a4fae8ae7c3bc227460c9ae43f56abf1b911da0ec29e0ebac53bb0a4b6b7/cryptography-47.0.0-cp38-abi3-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "pydantic", "version": "1.10.26"}, "download_info": {"url": "https://files.pythonhosted.org/packages/85/15/b2304a2f8206880b0a85dbe6593736c59bf0b676d57ad9338312f1369805/pydantic-1.10.26-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/b4/f7e396030e3b11394436358ca258a81d6010106582422f23443c16ca1873/anyio-4.5.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "1.17.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/46/fce169ad09419b8e8a5a81db61e08cd7b9fd31332221b84bd176fe0a3136/charset_normalizer-3.4.7-cp38-cp38-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.15"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/23/408243171aa9aaba178d3e2559159c24c1171a641aa83b67bdd3394ead8e/idna-3.15-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/d9/a1e041c5e7caa9a05c925f4bdbdfb7f006d1f74996af53467bc394c97be7/importlib_metadata-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "Mako", "version": "1.3.12"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/b1/a0ec7a5a9db730a08daef1fdfb8090435b82465abbf758a596f0ea88727e/mako-1.3.12-py3-none-any.whl"}}, {"metadata": {"name": "msgspec", "version": "0.18.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/86/6f/1da53a2ba5f312c3dca9e5f38912732e77f996a22945c8d62df7617c4733/msgspec-0.18.6-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/7f/5d1ce7f47d44393d429922910afbe88fcd29ee3069babbb47507a4c3a7ea/multidict-6.1.0-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic-openapi-schema", "version": "1.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bb/a1/9b906584055e2a9ee48368e2ad7148625e06594fb0f81f8656c6e71eb672/pydantic_openapi_schema-1.5.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "8.3.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.13.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ce/d9/5f4c13cecde62396b0d3fe530a50ccea91e7dfc1ccf0e09c228841bb5ba8/urllib3-2.2.3-py3-none-any.whl"}}, {"metadata": {"name": "fast-query-parsers", "version": "1.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/21/c8c160f61a740efc4577079eb5747a6b2cb8d1168a84a0bfda6044113768/fast_query_parsers-1.0.3-cp38-abi3-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl"}}, {"metadata": {"name": "pydantic-factories", "version": "1.17.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/40/49/81bbfccaf7174e7a94be1fa95d9ed46da6663372b2a7cd597c1c6fdfcabe/pydantic_factories-1.17.3-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "2.1.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f8/ff/2c942a82c35a49df5de3a630ce0a8456ac2969691b230e530ac12314364c/MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "pluggy", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "zipp", "version": "3.20.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/8b/5ba542fa83c90e09eac972fc9baca7a88e7e7ca4b221a89251954019308b/zipp-3.20.2-py3-none-any.whl"}}, {"metadata": {"name": "email-validator", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl"}}, {"metadata": {"name": "Faker", "version": "35.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/18/f70c67c9d3a71f1749faa027dad3cd626c728df5682458091d73c69ed9a9/Faker-35.2.2-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "2.23"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl"}}, {"metadata": {"name": "dnspython", "version": "2.6.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/87/a1/8c5287991ddb8d3e4662f71356d9656d91ab3a36618c3dd11b280df0d255/dnspython-2.6.1-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}], "install_targets_hash": "3907d2f6a755b140082148b91c7e757f"} {"python_version": "3.8", "dependencies": [{"metadata": {"name": "launchdarkly-server-sdk", "version": "9.8.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/aa/b7/e5eed9ec95341d2fe8f9c78377b951045dd8afc9dcdb4f0c9391be02a030/launchdarkly_server_sdk-9.8.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "expiringdict", "version": "1.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/84/a04c59324445f4bcc98dc05b39a1cd07c242dde643c1a3c21e4f7beaf2f2/expiringdict-1.2.2-py3-none-any.whl"}}, {"metadata": {"name": "launchdarkly-eventsource", "version": "1.2.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/80/af/2002e5ee6343f44a416d4d092a0c0b9076c90ada4e772e5ee263b3d76f15/launchdarkly_eventsource-1.2.4-py3-none-any.whl"}}, {"metadata": {"name": "pyRFC3339", "version": "2.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dd/ba/d778be0f6d8d583307b47ba481c95f88a59d5c6dfd5d136bc56656d1d17f/pyRFC3339-2.0.1-py3-none-any.whl"}}, {"metadata": {"name": "semver", "version": "3.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/24/4d91e05817e92e3a61c8a21e08fd0f390f5301f1c448b137c57c4bc6e543/semver-3.0.4-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ce/d9/5f4c13cecde62396b0d3fe530a50ccea91e7dfc1ccf0e09c228841bb5ba8/urllib3-2.2.3-py3-none-any.whl"}}], "install_targets_hash": "39e38f320060d087837513360056dd40"} {"python_version": "3.8", "dependencies": [{"metadata": {"name": "Django", "version": "2.2.28"}, "download_info": {"url": "https://files.pythonhosted.org/packages/43/69/eaac9a827335898d626066989865974fa48bfc23efd1b34628d64543b2d9/Django-2.2.28-py3-none-any.whl"}}, {"metadata": {"name": "psycopg2-binary", "version": "2.9.10"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/0e/bdc8274dc0585090b4e3432267d7be4dfbfd8971c0fa59167c711105a6bf/psycopg2-binary-2.9.10.tar.gz"}}, {"metadata": {"name": "djangorestframework", "version": "3.13.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/45/2588c7c5a01a7da6822c6ffbc9a731d498c318a803a29ae780ec635ea41d/djangorestframework-3.13.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-django", "version": "3.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/5d/c43af4d29cd0380cfac100c86f9496f6a2fc2c5864ca40ce64575a634e65/pytest_django-3.10.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/af/9c0bda43e486a3c9bf1e0f876d0f241bc3f229d7d65d09331a0868db9629/pytest_forked-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "2.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/f3/22afbdb20cc4654b10c98043414a14057cd27fdba9d4ae61cea596000ba2/Werkzeug-2.0.3-py3-none-any.whl"}}, {"metadata": {"name": "executing", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "asgiref", "version": "3.8.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/39/e3/893e8757be2612e6c266d9bb58ad2e3651524b5b40cf56761e985a28b13e/asgiref-3.8.1-py3-none-any.whl"}}, {"metadata": {"name": "daphne", "version": "3.0.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5c/a3/52d62474eae7f665837434c2685d1b7ec55d1c0336ea84e1cd5693699554/daphne-3.0.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "8.3.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl"}}, {"metadata": {"name": "sqlparse", "version": "0.5.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/4b/359f28a903c13438ef59ebeee215fb25da53066db67b305c125f1c6d2a25/sqlparse-0.5.5-py3-none-any.whl"}}, {"metadata": {"name": "channels", "version": "3.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/45/31031f6b405b41fdc5f5d9f2b1fc1ddf5717a23bb2c64d62838cdc63ce5c/channels-3.0.5-py3-none-any.whl"}}, {"metadata": {"name": "py", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "pytz", "version": "2026.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/dd/96da98f892250475bdf2328112d7468abdd4acc7b902b6af23f4ed958ea0/pytz-2026.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "autobahn", "version": "23.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/53/99/b6e0ffa0e8bafe9dfae1c9ab46d44d07317cbf297fbf8f07aff8a80e5bd8/autobahn-23.1.2.tar.gz"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "Twisted", "version": "25.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/66/ab7efd8941f0bc7b2bd555b0f0471bff77df4c88e0cc31120c82737fec77/twisted-25.5.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.13.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "25.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/77/06/bb80f5f86020c4551da315d78b3ab75e8228f89f0162f2c3a819e407941a/attrs-25.3.0-py3-none-any.whl"}}, {"metadata": {"name": "Automat", "version": "24.8.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/af/cc/55a32a2c98022d88812b5986d2a92c4ff3ee087e83b712ebc703bba452bf/Automat-24.8.1-py3-none-any.whl"}}, {"metadata": {"name": "constantly", "version": "23.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b8/40/c199d095151addf69efdb4b9ca3a4f20f70e20508d6222bffb9b76f58573/constantly-23.10.4-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "47.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/34/a4fae8ae7c3bc227460c9ae43f56abf1b911da0ec29e0ebac53bb0a4b6b7/cryptography-47.0.0-cp38-abi3-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "hyperlink", "version": "21.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/aa/8caf6a0a3e62863cbb9dab27135660acba46903b703e224f14f447e57934/hyperlink-21.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.15"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/23/408243171aa9aaba178d3e2559159c24c1171a641aa83b67bdd3394ead8e/idna-3.15-py3-none-any.whl"}}, {"metadata": {"name": "Incremental", "version": "24.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1d/55/0f4df2a44053867ea9cbea73fc588b03c55605cd695cee0a3d86f0029cb2/incremental-24.11.0-py3-none-any.whl"}}, {"metadata": {"name": "pyOpenSSL", "version": "26.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/73/b8/a0e2790ae249d6f38c9f66de7a211621a7ab2650217bcd04e1262f578a56/pyopenssl-26.2.0-py3-none-any.whl"}}, {"metadata": {"name": "service-identity", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/eb/2433e1af4ff903499144de4846569fb3300b816179ae99a03c2f011b666a/service_identity-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "txaio", "version": "23.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7d/6c/a53cc9a97c2da76d9cd83c03f377468599a28f2d4ad9fc71c3b99640e71e/txaio-23.1.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "zope.interface", "version": "7.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f5/8c/49548aaa4f691615d703b5bee88ea67f68eac8f94c9fb6f1b2f4ae631354/zope.interface-7.2-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "setuptools", "version": "75.3.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cd/b1/961ba076c7d3732e3a97e6681c55ef647afb795fe8bfcd27becec8a762ce/setuptools-75.3.4-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "1.17.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz"}}, {"metadata": {"name": "pycparser", "version": "2.23"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl"}}], "install_targets_hash": "3c126f25877b64fcb94712f28ab545f3"} @@ -498,9 +1111,7 @@ {"python_version": "3.8", "dependencies": [{"metadata": {"name": "trytond", "version": "6.8.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4f/13/b994f377d1896f70ca6edbfb0c068f8f9739fe706485b2d0759d96c798d1/trytond-6.8.17-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.0.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6c/69/05837f91dfe42109203ffa3e488214ff86a6d68b2ed6c167da6cdc42349b/werkzeug-3.0.6-py3-none-any.whl"}}, {"metadata": {"name": "lxml", "version": "6.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/3b/aab6728cae887456f409b4d75e8a01856e4f04bd510de38052a47768b680/lxml-6.1.1.tar.gz"}}, {"metadata": {"name": "MarkupSafe", "version": "2.1.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f8/ff/2c942a82c35a49df5de3a630ce0a8456ac2969691b230e530ac12314364c/MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "passlib", "version": "1.7.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3b/a4/ab6b7589382ca3df236e03faa71deac88cae040af60c071a78d254a62172/passlib-1.7.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "python-sql", "version": "1.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8f/3c/b69e5623a52a2a31c9f60a200c4e713cf30349c9b641fdaa4a2b3aeff2d7/python_sql-1.7.0-py3-none-any.whl"}}, {"metadata": {"name": "relatorio", "version": "0.11.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c6/45/ad7ecd947845a145b2813efdb48be5a7df880c13835066213fb6ae38c3ba/relatorio-0.11.1-py3-none-any.whl"}}, {"metadata": {"name": "Genshi", "version": "0.7.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/27/503016bc329720ba2856eb4831d6ba36089cd6f15bc4fe85db69fea5b563/genshi-0.7.11-py3-none-any.whl"}}, {"metadata": {"name": "defusedxml", "version": "0.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "polib", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6b/99/45bb1f9926efe370c6dbe324741c749658e44cb060124f28dad201202274/polib-1.2.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "pytz", "version": "2026.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/dd/96da98f892250475bdf2328112d7468abdd4acc7b902b6af23f4ed958ea0/pytz-2026.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "importlib_resources", "version": "6.4.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/6a/4604f9ae2fa62ef47b9de2fa5ad599589d28c9fd1d335f32759813dfa91e/importlib_resources-6.4.5-py3-none-any.whl"}}, {"metadata": {"name": "python-magic", "version": "0.4.27"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6c/73/9f872cb81fc5c3bb48f7227872c28975f998f3e7c2b1c16e95e6432bbb90/python_magic-0.4.27-py2.py3-none-any.whl"}}, {"metadata": {"name": "zipp", "version": "3.20.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/8b/5ba542fa83c90e09eac972fc9baca7a88e7e7ca4b221a89251954019308b/zipp-3.20.2-py3-none-any.whl"}}], "install_targets_hash": "4a8a27395c61752c0a56a6636507732c"} {"python_version": "3.8", "dependencies": [{"metadata": {"name": "tornado", "version": "6.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/84/119a46d494f008969bf0c775cb2c6b3579d3c4cc1bb1b41a022aa93ee242/tornado-6.0.4.tar.gz"}}, {"metadata": {"name": "pytest", "version": "8.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f0/d7/a812a0bd0f5160823e647524488cc9734f93782f2c273b8f77e8afc60a37/pytest-8.1.2-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.13.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl"}}], "install_targets_hash": "4f7b0f975f9c9c5c5420cd63a5bdbd01"} {"python_version": "3.8", "dependencies": [{"metadata": {"name": "openai", "version": "1.109.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1d/2a/7dd3d207ec669cacc1f186fd856a0f61dbc255d24f6fdc1a6715d6051b0f/openai-1.109.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/31/6607dab48616902f76885dfcf62c08d929796fc3b2d2318faf9fd54dbed9/pytest_asyncio-0.24.0-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e6/04/9a2b978beea18ef8916319e51f6d079c804062df80c63f0392202e5ddf10/tiktoken-0.7.0-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/b4/f7e396030e3b11394436358ca258a81d6010106582422f23443c16ca1873/anyio-4.5.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.15"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/23/408243171aa9aaba178d3e2559159c24c1171a641aa83b67bdd3394ead8e/idna-3.15-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/d9/3a6300309e312f8ed529ae57d565f69abdb520e4f12460cefa7996d0716c/jiter-0.9.1-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.10.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/3c/8cc1cc84deffa6e25d2d0c688ebb80635dfdbf1dbea3e30c541c8cf4d860/pydantic-2.10.6-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/20/26c549249769ed84877f862f7bb93f89a6ee08b4bee1ed8781616b7fbb5e/pydantic_core-2.27.2-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "8.3.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2024.11.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/08/92/9df786fad8a4e0766bfc9a2e334c5f0757356070c9639b2ec776b8cdef3d/regex-2024.11.6-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.32.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.13.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5b/97/fb4e82231aba271ffd775a1b4993b0defc4e3059f286ae41d9433409fe85/charset_normalizer-3.5.1-cp37-abi3-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ce/d9/5f4c13cecde62396b0d3fe530a50ccea91e7dfc1ccf0e09c228841bb5ba8/urllib3-2.2.3-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}], "install_targets_hash": "5c15f7294f49ccda5d519b89114a1254"} -{"python_version": "3.8", "dependencies": [{"metadata": {"name": "SQLAlchemy", "version": "1.2.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/67/d07cf7ac7e6dd0bc55ba62816753f86d7c558107104ca915e730c9ec2512/SQLAlchemy-1.2.19.tar.gz"}}], "install_targets_hash": "6367cf90dccc4dd9cc10d0a07a7946da"} -{"python_version": "3.8", "dependencies": [{"metadata": {"name": "pyramid", "version": "1.10.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3c/0b/6a56fe7dd5ccb1dc9188c3f337c776d7bc6d3f2fc6044c458b0799d37b0d/pyramid-1.10.8-py2.py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "2.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/f3/22afbdb20cc4654b10c98043414a14057cd27fdba9d4ae61cea596000ba2/Werkzeug-2.0.3-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "75.3.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cd/b1/961ba076c7d3732e3a97e6681c55ef647afb795fe8bfcd27becec8a762ce/setuptools-75.3.4-py3-none-any.whl"}}, {"metadata": {"name": "hupper", "version": "1.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/86/7d/3888833e4f5ea56af4a9935066ec09a83228e533d7b8877f65889d706ee4/hupper-1.12.1-py3-none-any.whl"}}, {"metadata": {"name": "translationstring", "version": "1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3b/98/36187601a15e3d37e9bfcf0e0e1055532b39d044353b06861c3a519737a9/translationstring-1.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "venusian", "version": "3.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5a/4b/34d926eba40db81b204066a60b4efdc5d8867a8efcbfe44d69b634b1c907/venusian-3.1.1-py3-none-any.whl"}}, {"metadata": {"name": "WebOb", "version": "1.8.10"}, "download_info": {"url": "https://files.pythonhosted.org/packages/83/21/fce134877fb6fc6ad3c464e4a07ede0ee9219f705d26a981ae58ea36ca13/webob-1.8.10-py2.py3-none-any.whl"}}, {"metadata": {"name": "zope.deprecation", "version": "5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/7d/24a23d4d6d93744babfb99266eeb97a25ceae58c0f841a872b51c45ee214/zope.deprecation-5.0-py3-none-any.whl"}}, {"metadata": {"name": "zope.interface", "version": "7.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f5/8c/49548aaa4f691615d703b5bee88ea67f68eac8f94c9fb6f1b2f4ae631354/zope.interface-7.2-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "plaster", "version": "1.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e7/8b/3f98db1448e3b4d2d142716874a7e02f6101685fdaa0f55a8668e9ffa048/plaster-1.1.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "plaster-pastedeploy", "version": "1.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/30/2d4cf89035c22a89bf0e34dbc50fdc07c42c9bdc90fd972d495257ad2b6e/plaster_pastedeploy-1.0.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "PasteDeploy", "version": "3.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/85/30/cdddd9a88969683a59222a6d61cd6dce923977f2e9f9ffba38e1324149cd/PasteDeploy-3.1.0-py3-none-any.whl"}}], "install_targets_hash": "67c9f9c2d02d8933f4796a9f37629c55"} -{"python_version": "3.8", "dependencies": [{"metadata": {"name": "Flask", "version": "1.1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/6d/994208daa354f68fd89a34a8bafbeaab26fda84e7af1e35bdaed02b667e6/Flask-1.1.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "Flask-Login", "version": "0.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/59/f5/67e9cc5c2036f58115f9fe0f00d203cf6780c3ff8ae0e705e7a9d9e8ff9e/Flask_Login-0.6.3-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "1.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cc/94/5f7079a0e00bd6863ef8f1da638721e9da21e5bacee597595b318f71d62e/Werkzeug-1.0.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bb/2a/10164ed1f31196a2f7f3799368a821765c62851ead0e630ab52b8e14b4d0/blinker-1.8.2-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "1.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/2e/64db92e53b86efccfaea71321f597fa2e1b2bd3853d8ce658568f7a13094/MarkupSafe-1.1.1.tar.gz"}}, {"metadata": {"name": "itsdangerous", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/76/ae/44b03b253d6fade317f32c24d100b3b35c2239807046a4c953c7b89fa49e/itsdangerous-1.1.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "2.11.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/c2/1eece8c95ddbc9b1aeb64f5783a9e07a286de42191b7204d67b7496ddf35/Jinja2-2.11.3-py2.py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "7.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/3d/fa76db83bf75c4f8d338c2fd15c8d33fdd7ad23a9b5e57eb6c5de26b430e/click-7.1.2-py2.py3-none-any.whl"}}], "install_targets_hash": "7b7072a0c1b1b8bbc67223696ff5cca5"} +{"python_version": "3.8", "dependencies": [{"metadata": {"name": "celery", "version": "5.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/90/c4/6a4d3772e5407622feb93dd25c86ce3c0fee746fa822a777a627d56b4f2a/celery-5.4.0-py3-none-any.whl"}}, {"metadata": {"name": "newrelic", "version": "10.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d4/71/07c41fd5e8c94e95216b000d00c3cf735f769cb406c0f33c6ff83b7b7418/newrelic-10.16.0.tar.gz"}}, {"metadata": {"name": "redis", "version": "6.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c2/cd/29503c609186104c363ef1f38d6e752e7d91ef387fc90aa165e96d69f446/redis-6.1.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/af/9c0bda43e486a3c9bf1e0f876d0f241bc3f229d7d65d09331a0868db9629/pytest_forked-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "backports.zoneinfo", "version": "0.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/85/475e514c3140937cf435954f78dedea1861aeab7662d11de232bdaa90655/backports.zoneinfo-0.2.1.tar.gz"}}, {"metadata": {"name": "billiard", "version": "4.2.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/87/8bab77b323f16d67be364031220069f79159117dd5e43eeb4be2fef1ac9b/billiard-4.2.4-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl"}}, {"metadata": {"name": "click-didyoumean", "version": "0.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/5b/974430b5ffdb7a4f1941d13d83c64a0395114503cc357c6b9ae4ce5047ed/click_didyoumean-0.3.1-py3-none-any.whl"}}, {"metadata": {"name": "click-plugins", "version": "1.1.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/9a/2abecb28ae875e39c8cad711eb1186d8d14eab564705325e77e4e6ab9ae5/click_plugins-1.1.1.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "click-repl", "version": "0.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/52/40/9d857001228658f0d59e97ebd4c346fe73e138c6de1bce61dc568a57c7f8/click_repl-0.3.0-py3-none-any.whl"}}, {"metadata": {"name": "kombu", "version": "5.5.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/70/a07dcf4f62598c8ad579df241af55ced65bed76e42e45d3c368a6d82dbc1/kombu-5.5.4-py3-none-any.whl"}}, {"metadata": {"name": "vine", "version": "5.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/ff/7c0c86c43b3cbb927e0ccc0255cb4057ceba4799cd44ae95174ce8e8b5b2/vine-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "8.3.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tzdata", "version": "2026.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e5/6d/b53b99a9f2766d095985947a5782f1702cabb129a34f7a802d7197af832f/tzdata-2026.3-py2.py3-none-any.whl"}}, {"metadata": {"name": "py", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "amqp", "version": "5.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/26/99/fc813cd978842c26c82534010ea849eee9ab3a13ea2b74e95cb9c99e747b/amqp-5.3.1-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl"}}, {"metadata": {"name": "prompt_toolkit", "version": "3.0.52"}, "download_info": {"url": "https://files.pythonhosted.org/packages/84/03/0d3ce49e2505ae70cf43bc5bb3033955d2fc9f932163e84dc0779cc47f48/prompt_toolkit-3.0.52-py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.13.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl"}}], "install_targets_hash": "7bc432e5912a9b6ade7f1ac7ce46a30a"} {"python_version": "3.8", "dependencies": [{"metadata": {"name": "UnleashClient", "version": "6.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f3/52/2f9da0f81dba2323409e291dc32975bf20d245d493e22c8295461d8025e3/unleashclient-6.8.0-py3-none-any.whl"}}, {"metadata": {"name": "APScheduler", "version": "3.11.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/42/c9/8638db32514dbb9157b3d82680c6faea89283523edf9ed2415ea3884f2ae/apscheduler-3.11.3-py3-none-any.whl"}}, {"metadata": {"name": "semver", "version": "3.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/24/4d91e05817e92e3a61c8a21e08fd0f390f5301f1c448b137c57c4bc6e543/semver-3.0.4-py3-none-any.whl"}}, {"metadata": {"name": "yggdrasil-engine", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/d5/8fb96f4a7fc9c299d4191f769bab8679207b9079e987b39d20ceef4c6282/yggdrasil_engine-1.3.1-cp38-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "fcache", "version": "0.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/af/9456f42b1fa74a44b9ac7c34c3cf4b4598a6e2eb2e996871b13f679ea431/fcache-0.5.2-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/d9/a1e041c5e7caa9a05c925f4bdbdfb7f006d1f74996af53467bc394c97be7/importlib_metadata-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "launchdarkly-eventsource", "version": "1.2.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/80/af/2002e5ee6343f44a416d4d092a0c0b9076c90ada4e772e5ee263b3d76f15/launchdarkly_eventsource-1.2.4-py3-none-any.whl"}}, {"metadata": {"name": "mmh3", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/b2/54dfe64837623d1cf739561e261f6688c32f481f3bc9d7211826d21f8c30/mmh3-5.0.1-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.32.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/98/2b/f97f1c193fb855c345d678f5077d6926034db0722df74c8f057020e05a25/charset_normalizer-3.4.9-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.15"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/23/408243171aa9aaba178d3e2559159c24c1171a641aa83b67bdd3394ead8e/idna-3.15-py3-none-any.whl"}}, {"metadata": {"name": "platformdirs", "version": "3.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/29/3ec311dc18804409ecf0d2b09caa976f3ae6215559306b5b530004e11156/platformdirs-3.11.0-py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tzlocal", "version": "5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/97/3f/c4c51c55ff8487f2e6d0e618dba917e3c3ee2caae6cf0fbb59c9b1876f2e/tzlocal-5.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ce/d9/5f4c13cecde62396b0d3fe530a50ccea91e7dfc1ccf0e09c228841bb5ba8/urllib3-2.2.3-py3-none-any.whl"}}, {"metadata": {"name": "zipp", "version": "3.20.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/8b/5ba542fa83c90e09eac972fc9baca7a88e7e7ca4b221a89251954019308b/zipp-3.20.2-py3-none-any.whl"}}, {"metadata": {"name": "backports.zoneinfo", "version": "0.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/85/475e514c3140937cf435954f78dedea1861aeab7662d11de232bdaa90655/backports.zoneinfo-0.2.1.tar.gz"}}], "install_targets_hash": "80f0bee8c3b3234399e0317b74ba4c5a"} {"python_version": "3.8", "dependencies": [{"metadata": {"name": "grpcio", "version": "1.66.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/41/484d4c377d7fe1b1ce58f29d58a6e07941ad2805ea149617cf43e4c26efd/grpcio-1.66.2-cp38-cp38-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "protobuf", "version": "5.29.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/06/db/49b05966fd208ae3f44dcd33837b6243b4915c57561d730a43f881f24dea/protobuf-5.29.6-cp38-abi3-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "mypy-protobuf", "version": "5.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/ec/5ffcf8f5f53757e01afdece10c664e694ac60d2f17c2036811b85b842a5b/mypy_protobuf-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "types-protobuf", "version": "5.29.1.20241207"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/6e/cdf152187019d6f6d04066b23e48659d961b527e9c6d43b48459d160e332/types_protobuf-5.29.1.20241207-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/31/6607dab48616902f76885dfcf62c08d929796fc3b2d2318faf9fd54dbed9/pytest_asyncio-0.24.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/af/9c0bda43e486a3c9bf1e0f876d0f241bc3f229d7d65d09331a0868db9629/pytest_forked-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "8.3.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl"}}, {"metadata": {"name": "py", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.13.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl"}}], "install_targets_hash": "9664bc6c25b7664cbf0e53ad567cc109"} {"python_version": "3.8", "dependencies": [{"metadata": {"name": "strawberry-graphql", "version": "0.209.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f5/2a/0ff66cce0fbd42e232486f4e4d8ffa39395b7ce0086b06b02a5742f923b1/strawberry_graphql-0.209.8-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.10.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/3c/8cc1cc84deffa6e25d2d0c688ebb80635dfdbf1dbea3e30c541c8cf4d860/pydantic-2.10.6-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/20/26c549249769ed84877f862f7bb93f89a6ee08b4bee1ed8781616b7fbb5e/pydantic_core-2.27.2-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "astunparse", "version": "1.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2b/03/13dde6512ad7b4557eb792fbcf0c653af6076b81e5941d36ec61f7ce6028/astunparse-1.6.3-py2.py3-none-any.whl"}}, {"metadata": {"name": "fastapi", "version": "0.124.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/57/aa70121b5008f44031be645a61a7c4abc24e0e888ad3fc8fda916f4d188e/fastapi-0.124.4-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/61/80/ffe1da13ad9300f87c93af113edd0638c75138c42a0994becfacac078c06/flask-3.0.3-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/15/b92b4e1d88d02c6eff9733c9eea21846ab435cc4d813d84ccc5d335955df/graphql_core-3.2.11-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b4/ff/b1e11d8bffb5e0e1b6d27f402eeedbeb9be6df2cdbc09356a1ae49806dbf/python_multipart-0.0.6-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.13.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/b4/f7e396030e3b11394436358ca258a81d6010106582422f23443c16ca1873/anyio-4.5.2-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.15"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/23/408243171aa9aaba178d3e2559159c24c1171a641aa83b67bdd3394ead8e/idna-3.15-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bb/2a/10164ed1f31196a2f7f3799368a821765c62851ead0e630ab52b8e14b4d0/blinker-1.8.2-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/d9/a1e041c5e7caa9a05c925f4bdbdfb7f006d1f74996af53467bc394c97be7/importlib_metadata-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "0.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b6/c5/7ae467eeddb57260c8ce17a3a09f9f5edba35820fc022d7c55b7decd5d3a/starlette-0.44.0-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.0.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6c/69/05837f91dfe42109203ffa3e488214ff86a6d68b2ed6c167da6cdc42349b/werkzeug-3.0.6-py3-none-any.whl"}}, {"metadata": {"name": "wheel", "version": "0.45.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/2c/87f3254fd8ffd29e4c02732eee68a83a1d3c346ae39bc6822dcbcb697f2b/wheel-0.45.1-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "2.1.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f8/ff/2c942a82c35a49df5de3a630ce0a8456ac2969691b230e530ac12314364c/MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "zipp", "version": "3.20.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/8b/5ba542fa83c90e09eac972fc9baca7a88e7e7ca4b221a89251954019308b/zipp-3.20.2-py3-none-any.whl"}}], "install_targets_hash": "9a43a190bf43b9eff8ea17e64ecb9b7f"} @@ -508,7 +1119,6 @@ {"python_version": "3.8", "dependencies": [{"metadata": {"name": "huggingface-hub", "version": "0.24.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/28/a0b0dd3cca63908045edc300360d6cd8758d4d86eee3fd2b08f00c5a41c4/huggingface_hub-0.24.7-py3-none-any.whl"}}, {"metadata": {"name": "responses", "version": "0.26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/28/693e1d9ebf72baa062ded80d837a035b86ce75eda5a269379e9e2b1008a8/responses-0.26.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest-httpx", "version": "0.22.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/23/a8438a0e11bc159d922a62c868593088b78285628e61f01c78bc1f1251e4/pytest_httpx-0.22.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.24.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/91/e41f64f03d2a13aee7e8c819d82ee3aa7cdc484d18c0ae859742597d5aa0/httpx-0.24.1-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2025.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/53/eb690efa8513166adef3e0669afd31e95ffde69fb3c52ec2ac7223ed6018/fsspec-2025.3.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "7.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ff/f6e8b8f39e08547faece4bd80f89d5a8de68a38b2d179cc1c4490ffa3286/pytest-7.4.4-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz"}}, {"metadata": {"name": "requests", "version": "2.32.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.68.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d8/8e/bb97bb0c71802080bfc8952937d174e49cfc50de5c951dd47b2496f0dcdb/tqdm-4.68.3-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.13.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ce/d9/5f4c13cecde62396b0d3fe530a50ccea91e7dfc1ccf0e09c228841bb5ba8/urllib3-2.2.3-py3-none-any.whl"}}, {"metadata": {"name": "filelock", "version": "3.16.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/f8/feced7779d755758a52d1f6635d990b8d98dc0a29fa568bbe0625f18fdf3/filelock-3.16.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/46/fce169ad09419b8e8a5a81db61e08cd7b9fd31332221b84bd176fe0a3136/charset_normalizer-3.4.7-cp38-cp38-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "0.17.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/2c/2bde7ff8dd2064395555220cbf7cba79991172bf5315a07eb3ac7688d9f1/httpcore-0.17.3-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.15"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/23/408243171aa9aaba178d3e2559159c24c1171a641aa83b67bdd3394ead8e/idna-3.15-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/b4/f7e396030e3b11394436358ca258a81d6010106582422f23443c16ca1873/anyio-4.5.2-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/04/ff642e65ad6b90db43e668d70ffb6736436c7ce41fcc549f4e9472234127/h11-0.14.0-py3-none-any.whl"}}], "install_targets_hash": "a5a1524ef8f136e98c6e71cf45c35bd4"} {"python_version": "3.8", "dependencies": [{"metadata": {"name": "trytond", "version": "5.8.16"}, "download_info": {"url": "https://files.pythonhosted.org/packages/45/02/f8e8b02cceceab86afed9e8303185c06d3d1828f769ba04da7498c9ebf6f/trytond-5.8.16-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "1.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cc/94/5f7079a0e00bd6863ef8f1da638721e9da21e5bacee597595b318f71d62e/Werkzeug-1.0.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "lxml", "version": "6.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/3b/aab6728cae887456f409b4d75e8a01856e4f04bd510de38052a47768b680/lxml-6.1.1.tar.gz"}}, {"metadata": {"name": "passlib", "version": "1.7.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3b/a4/ab6b7589382ca3df236e03faa71deac88cae040af60c071a78d254a62172/passlib-1.7.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "python-sql", "version": "1.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8f/3c/b69e5623a52a2a31c9f60a200c4e713cf30349c9b641fdaa4a2b3aeff2d7/python_sql-1.7.0-py3-none-any.whl"}}, {"metadata": {"name": "relatorio", "version": "0.11.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c6/45/ad7ecd947845a145b2813efdb48be5a7df880c13835066213fb6ae38c3ba/relatorio-0.11.1-py3-none-any.whl"}}, {"metadata": {"name": "Genshi", "version": "0.7.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/27/503016bc329720ba2856eb4831d6ba36089cd6f15bc4fe85db69fea5b563/genshi-0.7.11-py3-none-any.whl"}}, {"metadata": {"name": "polib", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6b/99/45bb1f9926efe370c6dbe324741c749658e44cb060124f28dad201202274/polib-1.2.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "wrapt", "version": "2.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6b/7b/56bf38c8bd5e8a48749f1a13c743eddcbd7a616da342b4877f79ec3e7087/wrapt-2.0.1-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "importlib_resources", "version": "6.4.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/6a/4604f9ae2fa62ef47b9de2fa5ad599589d28c9fd1d335f32759813dfa91e/importlib_resources-6.4.5-py3-none-any.whl"}}, {"metadata": {"name": "python-magic", "version": "0.4.27"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6c/73/9f872cb81fc5c3bb48f7227872c28975f998f3e7c2b1c16e95e6432bbb90/python_magic-0.4.27-py2.py3-none-any.whl"}}, {"metadata": {"name": "zipp", "version": "3.20.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/8b/5ba542fa83c90e09eac972fc9baca7a88e7e7ca4b221a89251954019308b/zipp-3.20.2-py3-none-any.whl"}}], "install_targets_hash": "a92ecc801394b38bdbca0234abddc3cb"} {"python_version": "3.8", "dependencies": [{"metadata": {"name": "litestar", "version": "2.8.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/e7/3d7ca62d6c48ff4c8162e2f03264c3202d8a76cb6a4987eac67f27af1de5/litestar-2.8.3-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/31/6607dab48616902f76885dfcf62c08d929796fc3b2d2318faf9fd54dbed9/pytest_asyncio-0.24.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/45/58/38b5afbc1a800eeea951b9285d3912613f2603bdf897a4ab0f4bd7f405fc/python_multipart-0.0.20-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.32.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "47.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/34/a4fae8ae7c3bc227460c9ae43f56abf1b911da0ec29e0ebac53bb0a4b6b7/cryptography-47.0.0-cp38-abi3-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/b4/f7e396030e3b11394436358ca258a81d6010106582422f23443c16ca1873/anyio-4.5.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "1.17.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/46/fce169ad09419b8e8a5a81db61e08cd7b9fd31332221b84bd176fe0a3136/charset_normalizer-3.4.7-cp38-cp38-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.15"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/23/408243171aa9aaba178d3e2559159c24c1171a641aa83b67bdd3394ead8e/idna-3.15-py3-none-any.whl"}}, {"metadata": {"name": "importlib_resources", "version": "6.4.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/6a/4604f9ae2fa62ef47b9de2fa5ad599589d28c9fd1d335f32759813dfa91e/importlib_resources-6.4.5-py3-none-any.whl"}}, {"metadata": {"name": "msgspec", "version": "0.18.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/86/6f/1da53a2ba5f312c3dca9e5f38912732e77f996a22945c8d62df7617c4733/msgspec-0.18.6-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/7f/5d1ce7f47d44393d429922910afbe88fcd29ee3069babbb47507a4c3a7ea/multidict-6.1.0-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "polyfactory", "version": "2.22.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/11/87/6cd69c43e86bc5863f93dba3c9fb42ee4fda36a0fe5aa3cbd25001fb26f8/polyfactory-2.22.5-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "8.3.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "14.3.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/76/6d163cfac87b632216f71879e6b2cf17163f773ff59c00b5ff4900a80fa3/rich-14.3.4-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.13.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ce/d9/5f4c13cecde62396b0d3fe530a50ccea91e7dfc1ccf0e09c228841bb5ba8/urllib3-2.2.3-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/d9/a1e041c5e7caa9a05c925f4bdbdfb7f006d1f74996af53467bc394c97be7/importlib_metadata-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz"}}, {"metadata": {"name": "rich-click", "version": "1.9.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6d/97/a87901aef6b7e7e4a34c6dd6cc17dca8594a592ef9d9dd765fca2b7facf7/rich_click-1.9.8-py3-none-any.whl"}}, {"metadata": {"name": "Faker", "version": "35.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/18/f70c67c9d3a71f1749faa027dad3cd626c728df5682458091d73c69ed9a9/Faker-35.2.2-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "3.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.19.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "zipp", "version": "3.20.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/8b/5ba542fa83c90e09eac972fc9baca7a88e7e7ca4b221a89251954019308b/zipp-3.20.2-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "2.23"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}], "install_targets_hash": "aad339208686a05fcf6dfa07b8c6ba47"} -{"python_version": "3.8", "dependencies": [{"metadata": {"name": "redis-py-cluster", "version": "2.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b2/96/153bbcf5dee29b52b2674e77a87ce864d381f72151737317529b7de4f337/redis_py_cluster-2.1.3-py2.py3-none-any.whl"}}, {"metadata": {"name": "redis", "version": "3.5.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/7c/24fb0511df653cf1a5d938d8f5d19802a88cef255706fdda242ff97e91b7/redis-3.5.3-py2.py3-none-any.whl"}}], "install_targets_hash": "af5a3f3b7d55e7250be5ffa435e2dd86"} {"python_version": "3.8", "dependencies": [{"metadata": {"name": "Django", "version": "4.2.30"}, "download_info": {"url": "https://files.pythonhosted.org/packages/39/b7/a7c96f239cf91313a6589233fed55111c7063b26683b226802732c455dbc/django-4.2.30-py3-none-any.whl"}}, {"metadata": {"name": "psycopg2-binary", "version": "2.9.10"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/0e/bdc8274dc0585090b4e3432267d7be4dfbfd8971c0fa59167c711105a6bf/psycopg2-binary-2.9.10.tar.gz"}}, {"metadata": {"name": "djangorestframework", "version": "3.15.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/b6/fa99d8f05eff3a9310286ae84c4059b08c301ae4ab33ae32e46e8ef76491/djangorestframework-3.15.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest-django", "version": "4.11.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/be/ac/bd0608d229ec808e51a21044f3f2f27b9a37e7a0ebaca7247882e67876af/pytest_django-4.11.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/af/9c0bda43e486a3c9bf1e0f876d0f241bc3f229d7d65d09331a0868db9629/pytest_forked-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.0.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6c/69/05837f91dfe42109203ffa3e488214ff86a6d68b2ed6c167da6cdc42349b/werkzeug-3.0.6-py3-none-any.whl"}}, {"metadata": {"name": "executing", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/31/6607dab48616902f76885dfcf62c08d929796fc3b2d2318faf9fd54dbed9/pytest_asyncio-0.24.0-py3-none-any.whl"}}, {"metadata": {"name": "asgiref", "version": "3.8.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/39/e3/893e8757be2612e6c266d9bb58ad2e3651524b5b40cf56761e985a28b13e/asgiref-3.8.1-py3-none-any.whl"}}, {"metadata": {"name": "daphne", "version": "4.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ab/d6/466f9219281472ecc269ab1d351c5b22a3cfca2d52f72881917949e414df/daphne-4.1.2-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "2.1.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f8/ff/2c942a82c35a49df5de3a630ce0a8456ac2969691b230e530ac12314364c/MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "pytest", "version": "8.3.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl"}}, {"metadata": {"name": "sqlparse", "version": "0.5.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/4b/359f28a903c13438ef59ebeee215fb25da53066db67b305c125f1c6d2a25/sqlparse-0.5.5-py3-none-any.whl"}}, {"metadata": {"name": "backports.zoneinfo", "version": "0.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ad/85/475e514c3140937cf435954f78dedea1861aeab7662d11de232bdaa90655/backports.zoneinfo-0.2.1.tar.gz"}}, {"metadata": {"name": "channels", "version": "4.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cc/bf/4799809715225d19928147d59fda0d3a4129da055b59a9b3e35aa6223f52/channels-4.2.2-py3-none-any.whl"}}, {"metadata": {"name": "py", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "autobahn", "version": "23.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/53/99/b6e0ffa0e8bafe9dfae1c9ab46d44d07317cbf297fbf8f07aff8a80e5bd8/autobahn-23.1.2.tar.gz"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "Twisted", "version": "25.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/66/ab7efd8941f0bc7b2bd555b0f0471bff77df4c88e0cc31120c82737fec77/twisted-25.5.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.13.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "25.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/77/06/bb80f5f86020c4551da315d78b3ab75e8228f89f0162f2c3a819e407941a/attrs-25.3.0-py3-none-any.whl"}}, {"metadata": {"name": "Automat", "version": "24.8.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/af/cc/55a32a2c98022d88812b5986d2a92c4ff3ee087e83b712ebc703bba452bf/Automat-24.8.1-py3-none-any.whl"}}, {"metadata": {"name": "constantly", "version": "23.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b8/40/c199d095151addf69efdb4b9ca3a4f20f70e20508d6222bffb9b76f58573/constantly-23.10.4-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "47.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/34/a4fae8ae7c3bc227460c9ae43f56abf1b911da0ec29e0ebac53bb0a4b6b7/cryptography-47.0.0-cp38-abi3-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "hyperlink", "version": "21.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/aa/8caf6a0a3e62863cbb9dab27135660acba46903b703e224f14f447e57934/hyperlink-21.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.15"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/23/408243171aa9aaba178d3e2559159c24c1171a641aa83b67bdd3394ead8e/idna-3.15-py3-none-any.whl"}}, {"metadata": {"name": "Incremental", "version": "24.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1d/55/0f4df2a44053867ea9cbea73fc588b03c55605cd695cee0a3d86f0029cb2/incremental-24.11.0-py3-none-any.whl"}}, {"metadata": {"name": "pyOpenSSL", "version": "26.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/73/b8/a0e2790ae249d6f38c9f66de7a211621a7ab2650217bcd04e1262f578a56/pyopenssl-26.2.0-py3-none-any.whl"}}, {"metadata": {"name": "service-identity", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/eb/2433e1af4ff903499144de4846569fb3300b816179ae99a03c2f011b666a/service_identity-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "txaio", "version": "23.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7d/6c/a53cc9a97c2da76d9cd83c03f377468599a28f2d4ad9fc71c3b99640e71e/txaio-23.1.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "zope.interface", "version": "7.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f5/8c/49548aaa4f691615d703b5bee88ea67f68eac8f94c9fb6f1b2f4ae631354/zope.interface-7.2-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "setuptools", "version": "75.3.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cd/b1/961ba076c7d3732e3a97e6681c55ef647afb795fe8bfcd27becec8a762ce/setuptools-75.3.4-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "1.17.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz"}}, {"metadata": {"name": "pycparser", "version": "2.23"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl"}}], "install_targets_hash": "b0d4ec08daf07a9aba63eb1306f8fbf7"} {"python_version": "3.8", "dependencies": [{"metadata": {"name": "httpx", "version": "0.16.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2d/c6/59aa4188e7eddb9e89ec67a51598ca6bfc09f1b38c9b45f7ee45af7a4df4/httpx-0.16.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-httpx", "version": "0.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5f/c2/5afbb915233722136b1acaa019b4a3eeb220135376e89adcda4a46ba9413/pytest_httpx-0.10.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "0.12.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/ce/544244e2145075896d38f7db3e822c24d1be9f7966ed3d83f158e388d195/httpcore-0.12.3-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "6.2.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/40/76/86f886e750b81a4357b6ed606b2bcf0ce6d6c27ad3c09ebf63ed674fc86e/pytest-6.2.5-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.20.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/45/74/9421cfde8def10c265b4f9ae19c95b8f4dc227f639cb8b89287d4946ac97/pytest_asyncio-0.20.3-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.15"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/23/408243171aa9aaba178d3e2559159c24c1171a641aa83b67bdd3394ead8e/idna-3.15-py3-none-any.whl"}}, {"metadata": {"name": "rfc3986", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c4/e5/63ca2c4edf4e00657584608bee1001302bbf8c5f569340b78304f2f446cb/rfc3986-1.5.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "25.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/77/06/bb80f5f86020c4551da315d78b3ab75e8228f89f0162f2c3a819e407941a/attrs-25.3.0-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl"}}, {"metadata": {"name": "py", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.13.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "toml", "version": "0.10.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/44/6f/7120676b6d73228c96e17f1f794d8ab046fc910d781c8d151120c3f1569e/toml-0.10.2-py2.py3-none-any.whl"}}], "install_targets_hash": "b3e4935a42940aab9f3a4cc71bd17b0b"} {"python_version": "3.8", "dependencies": [{"metadata": {"name": "ariadne", "version": "0.20.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e4/7c/6ca01607e6dc23472ab599507af67e9b4db9868e4baf8477fcafe958af00/ariadne-0.20.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "fastapi", "version": "0.124.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/57/aa70121b5008f44031be645a61a7c4abc24e0e888ad3fc8fda916f4d188e/fastapi-0.124.4-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/61/80/ffe1da13ad9300f87c93af113edd0638c75138c42a0994becfacac078c06/flask-3.0.3-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bb/2a/10164ed1f31196a2f7f3799368a821765c62851ead0e630ab52b8e14b4d0/blinker-1.8.2-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/15/b92b4e1d88d02c6eff9733c9eea21846ab435cc4d813d84ccc5d335955df/graphql_core-3.2.11-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/d9/a1e041c5e7caa9a05c925f4bdbdfb7f006d1f74996af53467bc394c97be7/importlib_metadata-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.10.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/3c/8cc1cc84deffa6e25d2d0c688ebb80635dfdbf1dbea3e30c541c8cf4d860/pydantic-2.10.6-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/20/26c549249769ed84877f862f7bb93f89a6ee08b4bee1ed8781616b7fbb5e/pydantic_core-2.27.2-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "starlette", "version": "0.44.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b6/c5/7ae467eeddb57260c8ce17a3a09f9f5edba35820fc022d7c55b7decd5d3a/starlette-0.44.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/b4/f7e396030e3b11394436358ca258a81d6010106582422f23443c16ca1873/anyio-4.5.2-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.15"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/23/408243171aa9aaba178d3e2559159c24c1171a641aa83b67bdd3394ead8e/idna-3.15-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.13.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.0.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6c/69/05837f91dfe42109203ffa3e488214ff86a6d68b2ed6c167da6cdc42349b/werkzeug-3.0.6-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "2.1.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f8/ff/2c942a82c35a49df5de3a630ce0a8456ac2969691b230e530ac12314364c/MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "zipp", "version": "3.20.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/8b/5ba542fa83c90e09eac972fc9baca7a88e7e7ca4b221a89251954019308b/zipp-3.20.2-py3-none-any.whl"}}], "install_targets_hash": "ba34689285beeef10583bc1d6faea8b5"} @@ -518,52 +1128,68 @@ {"python_version": "3.8", "dependencies": [{"metadata": {"name": "boto3", "version": "1.16.63"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c3/db/a7e290eb77632c9d25247977bbfc99aef9cd59f7c13eea69f8fea44404af/boto3-1.16.63-py2.py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "1.26.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/33/cf/8435d5a7159e2a9c83a95896ed596f68cf798005fe107cc655b5c5c14704/urllib3-1.26.20-py2.py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.19.63"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/05/0a955f0c92bec7da076fbbc73926dfb13fab8e2b88de7f8eb17c443f28f0/botocore-1.19.63-py2.py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "0.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/07/cb/5f001272b6faeb23c1c9e0acc04d48eaaf5c862c17709d20e3469c6e0139/jmespath-0.10.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "s3transfer", "version": "0.3.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/89/0cb4e92c239e6425b9b0035227b8cdf9d3d098a5c9e95632c3815df63a09/s3transfer-0.3.7-py2.py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}], "install_targets_hash": "cda6046ab83b870609fc0dd0e89ecd6b"} {"python_version": "3.8", "dependencies": [{"metadata": {"name": "pyspark", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/15/4ee019bfbf9e3e7af2c8e94a900f17c079bc39eafe0868b1b50bcade77de/pyspark-3.0.3.tar.gz"}}, {"metadata": {"name": "py4j", "version": "0.10.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/b6/6a4fb90cd235dc8e265a6a2067f2a2c99f0d91787f06aca4bcf7c23f3f80/py4j-0.10.9-py2.py3-none-any.whl"}}], "install_targets_hash": "d73494848bf6993086fc370f2ab4fb6d"} {"python_version": "3.8", "dependencies": [{"metadata": {"name": "openai", "version": "1.109.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1d/2a/7dd3d207ec669cacc1f186fd856a0f61dbc255d24f6fdc1a6715d6051b0f/openai-1.109.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/31/6607dab48616902f76885dfcf62c08d929796fc3b2d2318faf9fd54dbed9/pytest_asyncio-0.24.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/b4/f7e396030e3b11394436358ca258a81d6010106582422f23443c16ca1873/anyio-4.5.2-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.15"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/23/408243171aa9aaba178d3e2559159c24c1171a641aa83b67bdd3394ead8e/idna-3.15-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e8/d9/3a6300309e312f8ed529ae57d565f69abdb520e4f12460cefa7996d0716c/jiter-0.9.1-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.10.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/3c/8cc1cc84deffa6e25d2d0c688ebb80635dfdbf1dbea3e30c541c8cf4d860/pydantic-2.10.6-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/20/26c549249769ed84877f862f7bb93f89a6ee08b4bee1ed8781616b7fbb5e/pydantic_core-2.27.2-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "8.3.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.13.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}], "install_targets_hash": "d84808ce0b2029981b5c45613f25aa8b"} -{"python_version": "3.8", "dependencies": [{"metadata": {"name": "chalice", "version": "1.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5a/13/e2336421984c28392c864256c1b7f1faa0bdcb725b0fabd841512e667c3e/chalice-1.16.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "mypy-extensions", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5c/eb/975c7c080f3223a5cdaff09612f3a5221e4ba534f7039db34c35d95fa6a5/mypy_extensions-0.4.3-py2.py3-none-any.whl"}}, {"metadata": {"name": "pytest-chalice", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/0f/3344996a9ca6d1b301f55805bd2aa0daf9055f13317720b4567226e4cb38/pytest-chalice-0.0.5.tar.gz"}}, {"metadata": {"name": "setuptools", "version": "75.3.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cd/b1/961ba076c7d3732e3a97e6681c55ef647afb795fe8bfcd27becec8a762ce/setuptools-75.3.4-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "19.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a2/db/4313ab3be961f7a763066401fb77f7748373b6094076ae2bda2806988af6/attrs-19.3.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.37.38"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/1b/93f3504afc7c523dcaa8a8147cfc75421983e30b08d9f93a533929589630/botocore-1.37.38-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "7.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/3d/fa76db83bf75c4f8d338c2fd15c8d33fdd7ad23a9b5e57eb6c5de26b430e/click-7.1.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "enum-compat", "version": "0.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/55/ae/467bc4509246283bb59746e21a1a2f5a8aecbef56b1fa6eaca78cd438c8b/enum_compat-0.0.3-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "0.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/07/cb/5f001272b6faeb23c1c9e0acc04d48eaaf5c862c17709d20e3469c6e0139/jmespath-0.10.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "pip", "version": "20.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/43/84/23ed6a1796480a6f1a2d38f2802901d078266bda38388954d01d3f2e821d/pip-20.1.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "8.3.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "5.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/70/96/c7245e551b1cb496bfb95840ace55ca60f20d3d8e33d70faf8c78a976899/PyYAML-5.4.1-cp38-cp38-manylinux1_x86_64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "wheel", "version": "0.45.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/2c/87f3254fd8ffd29e4c02732eee68a83a1d3c346ae39bc6822dcbcb697f2b/wheel-0.45.1-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "1.26.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/33/cf/8435d5a7159e2a9c83a95896ed596f68cf798005fe107cc655b5c5c14704/urllib3-1.26.20-py2.py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.13.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl"}}], "install_targets_hash": "db06f0a5a85d36a36c51c4dce6af148c"} {"python_version": "3.8", "dependencies": [{"metadata": {"name": "huggingface_hub", "version": "0.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/af/48ac8483240de756d2438c380746e7130d1c6f75802ef22f3c6d49982787/huggingface_hub-0.36.2-py3-none-any.whl"}}, {"metadata": {"name": "responses", "version": "0.26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/28/693e1d9ebf72baa062ded80d837a035b86ce75eda5a269379e9e2b1008a8/responses-0.26.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest-httpx", "version": "0.22.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/23/a8438a0e11bc159d922a62c868593088b78285628e61f01c78bc1f1251e4/pytest_httpx-0.22.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.24.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/91/e41f64f03d2a13aee7e8c819d82ee3aa7cdc484d18c0ae859742597d5aa0/httpx-0.24.1-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2025.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/53/eb690efa8513166adef3e0669afd31e95ffde69fb3c52ec2ac7223ed6018/fsspec-2025.3.0-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/35/94/4b2ecfbad8f8b04701a23aefb62f540b9137d058b7e1dbef16a32676f0e9/hf_xet-1.5.1-cp37-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "7.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ff/f6e8b8f39e08547faece4bd80f89d5a8de68a38b2d179cc1c4490ffa3286/pytest-7.4.4-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz"}}, {"metadata": {"name": "requests", "version": "2.32.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.68.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d8/8e/bb97bb0c71802080bfc8952937d174e49cfc50de5c951dd47b2496f0dcdb/tqdm-4.68.3-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.13.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ce/d9/5f4c13cecde62396b0d3fe530a50ccea91e7dfc1ccf0e09c228841bb5ba8/urllib3-2.2.3-py3-none-any.whl"}}, {"metadata": {"name": "filelock", "version": "3.16.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/f8/feced7779d755758a52d1f6635d990b8d98dc0a29fa568bbe0625f18fdf3/filelock-3.16.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/46/fce169ad09419b8e8a5a81db61e08cd7b9fd31332221b84bd176fe0a3136/charset_normalizer-3.4.7-cp38-cp38-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "0.17.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/2c/2bde7ff8dd2064395555220cbf7cba79991172bf5315a07eb3ac7688d9f1/httpcore-0.17.3-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.15"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/23/408243171aa9aaba178d3e2559159c24c1171a641aa83b67bdd3394ead8e/idna-3.15-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/b4/f7e396030e3b11394436358ca258a81d6010106582422f23443c16ca1873/anyio-4.5.2-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/04/ff642e65ad6b90db43e668d70ffb6736436c7ce41fcc549f4e9472234127/h11-0.14.0-py3-none-any.whl"}}], "install_targets_hash": "dfd10ffb6fbe157d72679f5940ede3a2"} -{"python_version": "3.8", "dependencies": [{"metadata": {"name": "redis", "version": "5.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/26/5c5fa0e83c3621db835cfc1f1d789b37e7fa99ed54423b5f519beb931aa7/redis-5.3.1-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.25.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/ae/0a522205b23e2f3d2d67c69114baee9381873849f676de221267f3ad759e/fakeredis-2.25.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "7.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ff/f6e8b8f39e08547faece4bd80f89d5a8de68a38b2d179cc1c4490ffa3286/pytest-7.4.4-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.23.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ee/82/62e2d63639ecb0fbe8a7ee59ef0bc69a4669ec50f6d3459f74ad4e4189a2/pytest_asyncio-0.23.8-py3-none-any.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/84/0fdf9b18ba31d69877bd39c9cd6052b47f3761e9910c15de788e519f079f/PyJWT-2.9.0-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.13.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}], "install_targets_hash": "e1bdd632cbf3ee087c2b973404704d73"} -{"python_version": "3.8", "dependencies": [{"metadata": {"name": "redis", "version": "3.5.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/7c/24fb0511df653cf1a5d938d8f5d19802a88cef255706fdda242ff97e91b7/redis-3.5.3-py2.py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/38/5d/db8b7c995fc76b1bc00261d7e73782d727aa0b3b716465bc78c80eb22b30/fakeredis-2.7.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "7.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ff/f6e8b8f39e08547faece4bd80f89d5a8de68a38b2d179cc1c4490ffa3286/pytest-7.4.4-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.23.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ee/82/62e2d63639ecb0fbe8a7ee59ef0bc69a4669ec50f6d3459f74ad4e4189a2/pytest_asyncio-0.23.8-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.13.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl"}}], "install_targets_hash": "e20f6f1d4793fe2882a88cba513a9421"} -{"python_version": "3.8", "dependencies": [{"metadata": {"name": "sanic", "version": "20.12.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/46/af86e7cfadb04ce694abd380485328d224457c3df58196253703df32c7af/sanic-20.12.7-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.15.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/01/0b3a83352d75e3e57134abf5bef8fa3c64152e6107b5d57d510ad8d49a2a/httpx-0.15.4-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "0.11.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d8/e7/f25e08617b4be99d38e4ef6c4d1b744bf065b9c93156ecd691d95897e0e4/httpcore-0.11.1-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/bd/5262054455ab2067e51de331bfbc53a1dfa9071af7c424cf7c0793c4349a/websockets-9.1.tar.gz"}}, {"metadata": {"name": "aiohttp", "version": "3.10.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/31/bb/2890a3c77126758ef58536ca9f7476a12ba2021e0cd074108fb99b8c8747/aiohttp-3.10.11-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tracerite", "version": "1.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/71/127927fdd41dd577fd946c319cf9c012366f3ff9f048d0b0689dc72819ef/tracerite-1.1.1-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "75.3.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cd/b1/961ba076c7d3732e3a97e6681c55ef647afb795fe8bfcd27becec8a762ce/setuptools-75.3.4-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "24.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a5/45/30bb92d442636f570cb5651bc661f52b610e2eec3f891a5dc3a4c3667db0/aiofiles-24.1.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/74/fbb6559de3607b3300b9be3cc64e97548d55678e44623db17820dbd20002/aiohappyeyeballs-2.4.4-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/76/ac/a7305707cb852b7e16ff80eaf5692309bde30e2b1100a1fcacdc8f731d97/aiosignal-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "25.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/77/06/bb80f5f86020c4551da315d78b3ab75e8228f89f0162f2c3a819e407941a/attrs-25.3.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/76/a3/c08322a91e73d1199901a77ce73971cffa06d3c74974270ff97aed6e152a/frozenlist-1.5.0-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "html5tagger", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/12/2f5d43ee912ea14a6baba4b3db6d309b02d932e3b7074c3339b4aded98ff/html5tagger-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "httptools", "version": "0.6.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/06/24f105db5254d9689d9126ca09cd55c471241f26549041f33aea91a4c77e/httptools-0.6.4-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "5.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/28/bb841e6acfee8d441568c3e27a2ddf2a78a084d16faedf5ad67fa5d884c1/multidict-5.2.0-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "ujson", "version": "5.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/8d/0902429667065ee1a30f400ff4f0e97f1139fc958121856d520c35da3d1e/ujson-5.10.0-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "uvloop", "version": "0.22.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f2/82/8a4a6785b53ee42f9235e9d7aacab8b691204e96554c80135a8806a940d4/uvloop-0.22.1-cp38-cp38-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "yarl", "version": "1.15.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/34/ede8d8ed7350b4b21e33fc4eff71e08de31da697034969b41190132d421f/yarl-1.15.2-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "idna", "version": "3.15"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/23/408243171aa9aaba178d3e2559159c24c1171a641aa83b67bdd3394ead8e/idna-3.15-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/80/ef/18af27caaae5589c08bb5a461cfa136b83b7e7983be604f2140d91f92b97/propcache-0.2.0-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "rfc3986", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c4/e5/63ca2c4edf4e00657584608bee1001302bbf8c5f569340b78304f2f446cb/rfc3986-1.5.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5a/fd/3dad730b0f95e78aeeb742f96fa7bbecbdd56a58e405d3da440d5bfb90c6/h11-0.9.0-py2.py3-none-any.whl"}}], "install_targets_hash": "e7403700b4036b7b3cb75824d601a8e5"} +{"python_version": "3.8", "dependencies": [{"metadata": {"name": "huggingface_hub", "version": "0.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/af/48ac8483240de756d2438c380746e7130d1c6f75802ef22f3c6d49982787/huggingface_hub-0.36.2-py3-none-any.whl"}}, {"metadata": {"name": "responses", "version": "0.26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/28/693e1d9ebf72baa062ded80d837a035b86ce75eda5a269379e9e2b1008a8/responses-0.26.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest-httpx", "version": "0.22.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/23/a8438a0e11bc159d922a62c868593088b78285628e61f01c78bc1f1251e4/pytest_httpx-0.22.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.24.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/91/e41f64f03d2a13aee7e8c819d82ee3aa7cdc484d18c0ae859742597d5aa0/httpx-0.24.1-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2025.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/53/eb690efa8513166adef3e0669afd31e95ffde69fb3c52ec2ac7223ed6018/fsspec-2025.3.0-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/35/94/4b2ecfbad8f8b04701a23aefb62f540b9137d058b7e1dbef16a32676f0e9/hf_xet-1.5.1-cp37-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "7.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ff/f6e8b8f39e08547faece4bd80f89d5a8de68a38b2d179cc1c4490ffa3286/pytest-7.4.4-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz"}}, {"metadata": {"name": "requests", "version": "2.32.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.68.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d8/8e/bb97bb0c71802080bfc8952937d174e49cfc50de5c951dd47b2496f0dcdb/tqdm-4.68.3-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.13.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ce/d9/5f4c13cecde62396b0d3fe530a50ccea91e7dfc1ccf0e09c228841bb5ba8/urllib3-2.2.3-py3-none-any.whl"}}, {"metadata": {"name": "filelock", "version": "3.16.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/f8/feced7779d755758a52d1f6635d990b8d98dc0a29fa568bbe0625f18fdf3/filelock-3.16.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/46/fce169ad09419b8e8a5a81db61e08cd7b9fd31332221b84bd176fe0a3136/charset_normalizer-3.4.7-cp38-cp38-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "0.17.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/2c/2bde7ff8dd2064395555220cbf7cba79991172bf5315a07eb3ac7688d9f1/httpcore-0.17.3-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.15"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/23/408243171aa9aaba178d3e2559159c24c1171a641aa83b67bdd3394ead8e/idna-3.15-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/b4/f7e396030e3b11394436358ca258a81d6010106582422f23443c16ca1873/anyio-4.5.2-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/04/ff642e65ad6b90db43e668d70ffb6736436c7ce41fcc549f4e9472234127/h11-0.14.0-py3-none-any.whl"}}], "install_targets_hash": "dfd10ffb6fbe157d72679f5940ede3a2"} +{"python_version": "3.8", "dependencies": [{"metadata": {"name": "huggingface_hub", "version": "0.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/af/48ac8483240de756d2438c380746e7130d1c6f75802ef22f3c6d49982787/huggingface_hub-0.36.2-py3-none-any.whl"}}, {"metadata": {"name": "responses", "version": "0.26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/28/693e1d9ebf72baa062ded80d837a035b86ce75eda5a269379e9e2b1008a8/responses-0.26.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest-httpx", "version": "0.22.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/23/a8438a0e11bc159d922a62c868593088b78285628e61f01c78bc1f1251e4/pytest_httpx-0.22.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.24.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/91/e41f64f03d2a13aee7e8c819d82ee3aa7cdc484d18c0ae859742597d5aa0/httpx-0.24.1-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2025.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/53/eb690efa8513166adef3e0669afd31e95ffde69fb3c52ec2ac7223ed6018/fsspec-2025.3.0-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/35/94/4b2ecfbad8f8b04701a23aefb62f540b9137d058b7e1dbef16a32676f0e9/hf_xet-1.5.1-cp37-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "7.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ff/f6e8b8f39e08547faece4bd80f89d5a8de68a38b2d179cc1c4490ffa3286/pytest-7.4.4-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz"}}, {"metadata": {"name": "requests", "version": "2.32.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.68.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d8/8e/bb97bb0c71802080bfc8952937d174e49cfc50de5c951dd47b2496f0dcdb/tqdm-4.68.3-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.13.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ce/d9/5f4c13cecde62396b0d3fe530a50ccea91e7dfc1ccf0e09c228841bb5ba8/urllib3-2.2.3-py3-none-any.whl"}}, {"metadata": {"name": "filelock", "version": "3.16.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/f8/feced7779d755758a52d1f6635d990b8d98dc0a29fa568bbe0625f18fdf3/filelock-3.16.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/46/fce169ad09419b8e8a5a81db61e08cd7b9fd31332221b84bd176fe0a3136/charset_normalizer-3.4.7-cp38-cp38-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "0.17.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/94/2c/2bde7ff8dd2064395555220cbf7cba79991172bf5315a07eb3ac7688d9f1/httpcore-0.17.3-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.15"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/23/408243171aa9aaba178d3e2559159c24c1171a641aa83b67bdd3394ead8e/idna-3.15-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/b4/f7e396030e3b11394436358ca258a81d6010106582422f23443c16ca1873/anyio-4.5.2-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/04/ff642e65ad6b90db43e668d70ffb6736436c7ce41fcc549f4e9472234127/h11-0.14.0-py3-none-any.whl"}}], "install_targets_hash": "dfd10ffb6fbe157d72679f5940ede3a2"} +{"python_version": "3.8", "dependencies": [{"metadata": {"name": "sanic", "version": "23.12.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/e6/5adc2ca570f165d6027a775a655c1c09b9b8432a6c4a6fcb4c43a08eac7e/sanic-23.12.2-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/58/69435f1479acb56b3678905b5f2be57908a201c28465d4368d91f52cad76/websockets-10.4-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.10.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/31/bb/2890a3c77126758ef58536ca9f7476a12ba2021e0cd074108fb99b8c8747/aiohttp-3.10.11-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-testing", "version": "24.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/93/1d588f1cb9b710b9f22fa78b53d699a8062edc94204d50dd0d78c5f5b495/sanic_testing-24.6.0-py3-none-any.whl"}}, {"metadata": {"name": "tracerite", "version": "1.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/71/127927fdd41dd577fd946c319cf9c012366f3ff9f048d0b0689dc72819ef/tracerite-1.1.1-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "75.3.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cd/b1/961ba076c7d3732e3a97e6681c55ef647afb795fe8bfcd27becec8a762ce/setuptools-75.3.4-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "24.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a5/45/30bb92d442636f570cb5651bc661f52b610e2eec3f891a5dc3a4c3667db0/aiofiles-24.1.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/74/fbb6559de3607b3300b9be3cc64e97548d55678e44623db17820dbd20002/aiohappyeyeballs-2.4.4-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/76/ac/a7305707cb852b7e16ff80eaf5692309bde30e2b1100a1fcacdc8f731d97/aiosignal-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "25.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/77/06/bb80f5f86020c4551da315d78b3ab75e8228f89f0162f2c3a819e407941a/attrs-25.3.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/76/a3/c08322a91e73d1199901a77ce73971cffa06d3c74974270ff97aed6e152a/frozenlist-1.5.0-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "html5tagger", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/12/2f5d43ee912ea14a6baba4b3db6d309b02d932e3b7074c3339b4aded98ff/html5tagger-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "httptools", "version": "0.6.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/06/24f105db5254d9689d9126ca09cd55c471241f26549041f33aea91a4c77e/httptools-0.6.4-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/7f/5d1ce7f47d44393d429922910afbe88fcd29ee3069babbb47507a4c3a7ea/multidict-6.1.0-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-routing", "version": "23.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/e3/3425c9a8773807ac2c01d6a56c8521733f09b627e5827e733c5cd36b9ac5/sanic_routing-23.12.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.13.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "5.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/8d/0902429667065ee1a30f400ff4f0e97f1139fc958121856d520c35da3d1e/ujson-5.10.0-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "uvloop", "version": "0.22.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f2/82/8a4a6785b53ee42f9235e9d7aacab8b691204e96554c80135a8806a940d4/uvloop-0.22.1-cp38-cp38-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "yarl", "version": "1.15.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/34/ede8d8ed7350b4b21e33fc4eff71e08de31da697034969b41190132d421f/yarl-1.15.2-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "idna", "version": "3.15"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/23/408243171aa9aaba178d3e2559159c24c1171a641aa83b67bdd3394ead8e/idna-3.15-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/80/ef/18af27caaae5589c08bb5a461cfa136b83b7e7983be604f2140d91f92b97/propcache-0.2.0-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anyio", "version": "4.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/b4/f7e396030e3b11394436358ca258a81d6010106582422f23443c16ca1873/anyio-4.5.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "ec568d53833902c7306f15bb2f5c73e4"} {"python_version": "3.8", "dependencies": [{"metadata": {"name": "sanic", "version": "23.12.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/e6/5adc2ca570f165d6027a775a655c1c09b9b8432a6c4a6fcb4c43a08eac7e/sanic-23.12.2-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/58/69435f1479acb56b3678905b5f2be57908a201c28465d4368d91f52cad76/websockets-10.4-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.10.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/31/bb/2890a3c77126758ef58536ca9f7476a12ba2021e0cd074108fb99b8c8747/aiohttp-3.10.11-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-testing", "version": "24.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/93/1d588f1cb9b710b9f22fa78b53d699a8062edc94204d50dd0d78c5f5b495/sanic_testing-24.6.0-py3-none-any.whl"}}, {"metadata": {"name": "tracerite", "version": "1.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4e/71/127927fdd41dd577fd946c319cf9c012366f3ff9f048d0b0689dc72819ef/tracerite-1.1.1-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "75.3.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cd/b1/961ba076c7d3732e3a97e6681c55ef647afb795fe8bfcd27becec8a762ce/setuptools-75.3.4-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "24.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a5/45/30bb92d442636f570cb5651bc661f52b610e2eec3f891a5dc3a4c3667db0/aiofiles-24.1.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b9/74/fbb6559de3607b3300b9be3cc64e97548d55678e44623db17820dbd20002/aiohappyeyeballs-2.4.4-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/76/ac/a7305707cb852b7e16ff80eaf5692309bde30e2b1100a1fcacdc8f731d97/aiosignal-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "25.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/77/06/bb80f5f86020c4551da315d78b3ab75e8228f89f0162f2c3a819e407941a/attrs-25.3.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/76/a3/c08322a91e73d1199901a77ce73971cffa06d3c74974270ff97aed6e152a/frozenlist-1.5.0-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "html5tagger", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9b/12/2f5d43ee912ea14a6baba4b3db6d309b02d932e3b7074c3339b4aded98ff/html5tagger-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "httptools", "version": "0.6.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/06/24f105db5254d9689d9126ca09cd55c471241f26549041f33aea91a4c77e/httptools-0.6.4-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/7f/5d1ce7f47d44393d429922910afbe88fcd29ee3069babbb47507a4c3a7ea/multidict-6.1.0-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-routing", "version": "23.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/e3/3425c9a8773807ac2c01d6a56c8521733f09b627e5827e733c5cd36b9ac5/sanic_routing-23.12.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.13.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "5.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/8d/0902429667065ee1a30f400ff4f0e97f1139fc958121856d520c35da3d1e/ujson-5.10.0-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "uvloop", "version": "0.22.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f2/82/8a4a6785b53ee42f9235e9d7aacab8b691204e96554c80135a8806a940d4/uvloop-0.22.1-cp38-cp38-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "yarl", "version": "1.15.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/34/ede8d8ed7350b4b21e33fc4eff71e08de31da697034969b41190132d421f/yarl-1.15.2-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "idna", "version": "3.15"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/23/408243171aa9aaba178d3e2559159c24c1171a641aa83b67bdd3394ead8e/idna-3.15-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/80/ef/18af27caaae5589c08bb5a461cfa136b83b7e7983be604f2140d91f92b97/propcache-0.2.0-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anyio", "version": "4.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/b4/f7e396030e3b11394436358ca258a81d6010106582422f23443c16ca1873/anyio-4.5.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "ec568d53833902c7306f15bb2f5c73e4"} {"python_version": "3.8", "dependencies": [{"metadata": {"name": "pure_eval", "version": "0.2.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6d/18/83376915176eb058cb86470eb7396388a13350b09a8f233a79303bbcbc5b/pure_eval-0.2.4-py3-none-any.whl"}}, {"metadata": {"name": "asttokens", "version": "3.0.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d4/2b/04b8a15f3a1c77bc79ddf5c73875327f34b4fa75982df2b76e45e402d364/asttokens-3.0.2-py3-none-any.whl"}}, {"metadata": {"name": "executing", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl"}}], "install_targets_hash": "ef91391ff2fb8720438fb9fbd1e2fc94"} {"python_version": "3.8", "dependencies": [{"metadata": {"name": "litestar", "version": "2.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/b5/ad040f923f1661240eaae883b7d3fec29ea6614d7e732d051fc16400998f/litestar-2.0.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/31/6607dab48616902f76885dfcf62c08d929796fc3b2d2318faf9fd54dbed9/pytest_asyncio-0.24.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/45/58/38b5afbc1a800eeea951b9285d3912613f2603bdf897a4ab0f4bd7f405fc/python_multipart-0.0.20-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.32.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "47.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/34/a4fae8ae7c3bc227460c9ae43f56abf1b911da0ec29e0ebac53bb0a4b6b7/cryptography-47.0.0-cp38-abi3-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.5.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/b4/f7e396030e3b11394436358ca258a81d6010106582422f23443c16ca1873/anyio-4.5.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cffi", "version": "1.17.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/46/fce169ad09419b8e8a5a81db61e08cd7b9fd31332221b84bd176fe0a3136/charset_normalizer-3.4.7-cp38-cp38-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "fast-query-parsers", "version": "1.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c5/21/c8c160f61a740efc4577079eb5747a6b2cb8d1168a84a0bfda6044113768/fast_query_parsers-1.0.3-cp38-abi3-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.15"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/23/408243171aa9aaba178d3e2559159c24c1171a641aa83b67bdd3394ead8e/idna-3.15-py3-none-any.whl"}}, {"metadata": {"name": "importlib_resources", "version": "6.4.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/6a/4604f9ae2fa62ef47b9de2fa5ad599589d28c9fd1d335f32759813dfa91e/importlib_resources-6.4.5-py3-none-any.whl"}}, {"metadata": {"name": "msgspec", "version": "0.18.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/86/6f/1da53a2ba5f312c3dca9e5f38912732e77f996a22945c8d62df7617c4733/msgspec-0.18.6-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "multidict", "version": "6.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/7f/5d1ce7f47d44393d429922910afbe88fcd29ee3069babbb47507a4c3a7ea/multidict-6.1.0-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "polyfactory", "version": "2.22.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/11/87/6cd69c43e86bc5863f93dba3c9fb42ee4fda36a0fe5aa3cbd25001fb26f8/polyfactory-2.22.5-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "8.3.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.13.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ce/d9/5f4c13cecde62396b0d3fe530a50ccea91e7dfc1ccf0e09c228841bb5ba8/urllib3-2.2.3-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/d9/a1e041c5e7caa9a05c925f4bdbdfb7f006d1f74996af53467bc394c97be7/importlib_metadata-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "Faker", "version": "35.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/18/f70c67c9d3a71f1749faa027dad3cd626c728df5682458091d73c69ed9a9/Faker-35.2.2-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "zipp", "version": "3.20.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/8b/5ba542fa83c90e09eac972fc9baca7a88e7e7ca4b221a89251954019308b/zipp-3.20.2-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "2.23"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}], "install_targets_hash": "eff25fb572d2faba9c895f2319049fe6"} {"python_version": "3.8", "dependencies": [{"metadata": {"name": "openai", "version": "1.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/94/99a674bd1dd3a74d5b679bfdd9e1396f08407f933eb15672207e5a8abf1d/openai-1.0.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.24.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/31/6607dab48616902f76885dfcf62c08d929796fc3b2d2318faf9fd54dbed9/pytest_asyncio-0.24.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.15"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/23/408243171aa9aaba178d3e2559159c24c1171a641aa83b67bdd3394ead8e/idna-3.15-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.10.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/3c/8cc1cc84deffa6e25d2d0c688ebb80635dfdbf1dbea3e30c541c8cf4d860/pydantic-2.10.6-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/20/26c549249769ed84877f862f7bb93f89a6ee08b4bee1ed8781616b7fbb5e/pydantic_core-2.27.2-cp38-cp38-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest", "version": "8.3.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.13.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}], "install_targets_hash": "f61ada90175867ade45a2b9f33f30ae0"} -{"python_version": "3.9", "dependencies": [{"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-httpx", "version": "0.35.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/ed/026d467c1853dd83102411a78126b4842618e86c895f93528b0528c7a620/pytest_httpx-0.35.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/93/2fa34714b7a4ae72f2f8dad66ba17dd9a2c793220719e736dda28b7aec27/pytest_asyncio-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}], "install_targets_hash": "0bb79de8dbba0e02df12fe5e7e7fd9b6"} +{"python_version": "3.9", "dependencies": [{"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-httpx", "version": "0.35.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b0/ed/026d467c1853dd83102411a78126b4842618e86c895f93528b0528c7a620/pytest_httpx-0.35.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/93/2fa34714b7a4ae72f2f8dad66ba17dd9a2c793220719e736dda28b7aec27/pytest_asyncio-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}], "install_targets_hash": "0bb79de8dbba0e02df12fe5e7e7fd9b6"} {"python_version": "3.9", "dependencies": [{"metadata": {"name": "langgraph", "version": "0.6.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/94/430f0341c5c2fe3e3b9f5ab2622f35e2bda12c4a7d655c519468e853d1b0/langgraph-0.6.11-py3-none-any.whl"}}, {"metadata": {"name": "langgraph-checkpoint", "version": "2.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c4/f2/06bf5addf8ee664291e1b9ffa1f28fc9d97e59806dc7de5aea9844cbf335/langgraph_checkpoint-2.1.2-py3-none-any.whl"}}, {"metadata": {"name": "langgraph-prebuilt", "version": "0.6.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8e/d1/e4727f4822943befc3b7046f79049b1086c9493a34b4d44a1adf78577693/langgraph_prebuilt-0.6.5-py3-none-any.whl"}}, {"metadata": {"name": "langgraph-sdk", "version": "0.2.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/66/05/b2d34e16638241e6f27a6946d28160d4b8b641383787646d41a3727e0896/langgraph_sdk-0.2.9-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "langchain-core", "version": "0.3.86"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/93/ba19ca54701c6118e68f8785949b6c0eab1df3a5cfa5310508cc86877994/langchain_core-0.3.86-py3-none-any.whl"}}, {"metadata": {"name": "jsonpatch", "version": "1.33"}, "download_info": {"url": "https://files.pythonhosted.org/packages/73/07/02e16ed01e04a374e644b575638ec7987ae846d25ad97bcc9945a3ee4b0e/jsonpatch-1.33-py2.py3-none-any.whl"}}, {"metadata": {"name": "langsmith", "version": "0.4.37"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/e8/edff4de49cf364eb9ee88d13da0a555844df32438413bf53d90d507b97cd/langsmith-0.4.37-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "25.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/60/e70fa1ee03e243bdfd4b1fddf1e1f2a8fba681df3034b51b9376c0fb5bf5/pydantic_core-2.46.4-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ae/92/861f152ce87c452b11b9d0977952259aa7df792d71c1053365cc7b09cc08/pyyaml-6.0.3-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e5/30/643397144bfbfec6f6ef821f36f33e57d35946c44a2352d3c9f0ae847619/tenacity-9.1.2-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "uuid_utils", "version": "0.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1d/c8/5a05247c1b7cbf49849523e1a26e3a8a76c0c1ec6dc84c7cc7b9a8c66503/uuid_utils-0.15.0-cp39-cp39-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonpointer", "version": "3.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/92/5e77f98553e9e75130c78900d000368476aed74276eb8ae8796f65f00918/jsonpointer-3.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "orjson", "version": "3.11.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/c7/7b682849dd4c9fb701a981669b964ea700516ecbd8e88f62aae07c6852bd/orjson-3.11.5-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl"}}, {"metadata": {"name": "ormsgpack", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f0/9e/a1f32d7b4b03b8af5178cf8990c60bb36997d46089c1fee93eed31c04341/ormsgpack-1.11.0-cp39-cp39-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl"}}, {"metadata": {"name": "requests", "version": "2.32.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/1b/ef725f8eb19b5a261b30f78efa9252ef9d017985cb499102f6f49834cd12/charset_normalizer-3.4.7-cp39-cp39-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "xxhash", "version": "3.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/70/86bd231cd8fc550f90776184c8632f18d2d3e0c6ed020958851710c29699/xxhash-3.8.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "zstandard", "version": "0.25.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/aa/ceb8d79cbad6dabd4cb1178ca853f6a4374d791c5e0241a0988173e2a341/zstandard-0.25.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anyio", "version": "4.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "0ee3a52436b4f61e9cdbe5013bf352c3"} +{"python_version": "3.9", "dependencies": [{"metadata": {"name": "langgraph", "version": "0.6.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/94/430f0341c5c2fe3e3b9f5ab2622f35e2bda12c4a7d655c519468e853d1b0/langgraph-0.6.11-py3-none-any.whl"}}, {"metadata": {"name": "langgraph-checkpoint", "version": "2.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c4/f2/06bf5addf8ee664291e1b9ffa1f28fc9d97e59806dc7de5aea9844cbf335/langgraph_checkpoint-2.1.2-py3-none-any.whl"}}, {"metadata": {"name": "langgraph-prebuilt", "version": "0.6.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8e/d1/e4727f4822943befc3b7046f79049b1086c9493a34b4d44a1adf78577693/langgraph_prebuilt-0.6.5-py3-none-any.whl"}}, {"metadata": {"name": "langgraph-sdk", "version": "0.2.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/66/05/b2d34e16638241e6f27a6946d28160d4b8b641383787646d41a3727e0896/langgraph_sdk-0.2.9-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "langchain-core", "version": "0.3.86"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/93/ba19ca54701c6118e68f8785949b6c0eab1df3a5cfa5310508cc86877994/langchain_core-0.3.86-py3-none-any.whl"}}, {"metadata": {"name": "jsonpatch", "version": "1.33"}, "download_info": {"url": "https://files.pythonhosted.org/packages/73/07/02e16ed01e04a374e644b575638ec7987ae846d25ad97bcc9945a3ee4b0e/jsonpatch-1.33-py2.py3-none-any.whl"}}, {"metadata": {"name": "langsmith", "version": "0.4.37"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/e8/edff4de49cf364eb9ee88d13da0a555844df32438413bf53d90d507b97cd/langsmith-0.4.37-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "25.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/60/e70fa1ee03e243bdfd4b1fddf1e1f2a8fba681df3034b51b9376c0fb5bf5/pydantic_core-2.46.4-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ae/92/861f152ce87c452b11b9d0977952259aa7df792d71c1053365cc7b09cc08/pyyaml-6.0.3-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e5/30/643397144bfbfec6f6ef821f36f33e57d35946c44a2352d3c9f0ae847619/tenacity-9.1.2-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "uuid_utils", "version": "0.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1d/c8/5a05247c1b7cbf49849523e1a26e3a8a76c0c1ec6dc84c7cc7b9a8c66503/uuid_utils-0.15.0-cp39-cp39-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonpointer", "version": "3.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/92/5e77f98553e9e75130c78900d000368476aed74276eb8ae8796f65f00918/jsonpointer-3.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "orjson", "version": "3.11.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/c7/7b682849dd4c9fb701a981669b964ea700516ecbd8e88f62aae07c6852bd/orjson-3.11.5-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl"}}, {"metadata": {"name": "ormsgpack", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f0/9e/a1f32d7b4b03b8af5178cf8990c60bb36997d46089c1fee93eed31c04341/ormsgpack-1.11.0-cp39-cp39-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl"}}, {"metadata": {"name": "requests", "version": "2.32.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/1b/ef725f8eb19b5a261b30f78efa9252ef9d017985cb499102f6f49834cd12/charset_normalizer-3.4.7-cp39-cp39-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "xxhash", "version": "3.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/70/86bd231cd8fc550f90776184c8632f18d2d3e0c6ed020958851710c29699/xxhash-3.8.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "zstandard", "version": "0.25.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/aa/ceb8d79cbad6dabd4cb1178ca853f6a4374d791c5e0241a0988173e2a341/zstandard-0.25.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anyio", "version": "4.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "0ee3a52436b4f61e9cdbe5013bf352c3"} +{"python_version": "3.9", "dependencies": [{"metadata": {"name": "cohere", "version": "5.21.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0a/50/5538f02ec6d10fbb84f29c1b18c68ff2a03d7877926a80275efdf8755a9f/cohere-5.21.1-py3-none-any.whl"}}, {"metadata": {"name": "fastavro", "version": "1.12.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/92/2c8efbb85f60c29b4eb5fd76852ad4dddb2b5ea65b972d22146ff78b5447/fastavro-1.12.2-cp39-cp39-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "requests", "version": "2.32.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/1b/ef725f8eb19b5a261b30f78efa9252ef9d017985cb499102f6f49834cd12/charset_normalizer-3.4.7-cp39-cp39-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "tokenizers", "version": "0.22.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2e/47/174dca0502ef88b28f1c9e06b73ce33500eedfac7a7692108aec220464e7/tokenizers-0.22.2-cp39-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "huggingface_hub", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/ae/8a3a16ea4d202cb641b51d2681bdd3d482c1c592d7570b3fa264730829ce/huggingface_hub-1.8.0-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/35/94/4b2ecfbad8f8b04701a23aefb62f540b9137d058b7e1dbef16a32676f0e9/hf_xet-1.5.1-cp37-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "types-requests", "version": "2.32.4.20260107"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1c/12/709ea261f2bf91ef0a26a9eed20f2623227a8ed85610c1e54c5805692ecb/types_requests-2.32.4.20260107-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "filelock", "version": "3.19.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/42/14/42b2651a2f46b022ccd948bca9f2d5af0fd8929c4eec235b8d6d844fbe67/filelock-3.19.1-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2025.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/02/a6b21098b1d5d6249b7c5ab69dde30108a71e4e819d4a9778f1de1d5b70d/fsspec-2025.10.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/60/e70fa1ee03e243bdfd4b1fddf1e1f2a8fba681df3034b51b9376c0fb5bf5/pydantic_core-2.46.4-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ae/92/861f152ce87c452b11b9d0977952259aa7df792d71c1053365cc7b09cc08/pyyaml-6.0.3-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tqdm", "version": "4.68.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d8/8e/bb97bb0c71802080bfc8952937d174e49cfc50de5c951dd47b2496f0dcdb/tqdm-4.68.3-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typer", "version": "0.23.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2c/dee705c427875402200fe779eb8a3c00ccb349471172c41178336e9599cc/typer-0.23.2-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "3.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "shellingham", "version": "1.5.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}], "install_targets_hash": "1119e874aeb67089151365fd5430145a"} {"python_version": "3.9", "dependencies": [{"metadata": {"name": "cohere", "version": "5.21.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0a/50/5538f02ec6d10fbb84f29c1b18c68ff2a03d7877926a80275efdf8755a9f/cohere-5.21.1-py3-none-any.whl"}}, {"metadata": {"name": "fastavro", "version": "1.12.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/92/2c8efbb85f60c29b4eb5fd76852ad4dddb2b5ea65b972d22146ff78b5447/fastavro-1.12.2-cp39-cp39-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "requests", "version": "2.32.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/1b/ef725f8eb19b5a261b30f78efa9252ef9d017985cb499102f6f49834cd12/charset_normalizer-3.4.7-cp39-cp39-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "tokenizers", "version": "0.22.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2e/47/174dca0502ef88b28f1c9e06b73ce33500eedfac7a7692108aec220464e7/tokenizers-0.22.2-cp39-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "huggingface_hub", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/ae/8a3a16ea4d202cb641b51d2681bdd3d482c1c592d7570b3fa264730829ce/huggingface_hub-1.8.0-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/35/94/4b2ecfbad8f8b04701a23aefb62f540b9137d058b7e1dbef16a32676f0e9/hf_xet-1.5.1-cp37-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "types-requests", "version": "2.32.4.20260107"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1c/12/709ea261f2bf91ef0a26a9eed20f2623227a8ed85610c1e54c5805692ecb/types_requests-2.32.4.20260107-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "filelock", "version": "3.19.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/42/14/42b2651a2f46b022ccd948bca9f2d5af0fd8929c4eec235b8d6d844fbe67/filelock-3.19.1-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2025.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/02/a6b21098b1d5d6249b7c5ab69dde30108a71e4e819d4a9778f1de1d5b70d/fsspec-2025.10.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/60/e70fa1ee03e243bdfd4b1fddf1e1f2a8fba681df3034b51b9376c0fb5bf5/pydantic_core-2.46.4-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ae/92/861f152ce87c452b11b9d0977952259aa7df792d71c1053365cc7b09cc08/pyyaml-6.0.3-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tqdm", "version": "4.68.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d8/8e/bb97bb0c71802080bfc8952937d174e49cfc50de5c951dd47b2496f0dcdb/tqdm-4.68.3-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typer", "version": "0.23.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2c/dee705c427875402200fe779eb8a3c00ccb349471172c41178336e9599cc/typer-0.23.2-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "3.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "shellingham", "version": "1.5.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}], "install_targets_hash": "1119e874aeb67089151365fd5430145a"} +{"python_version": "3.9", "dependencies": [{"metadata": {"name": "fastapi", "version": "0.85.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/99/d4/4256804791b1e822f46bf79015270e9e9f14e9b634cb8231a88f6dc100c3/fastapi-0.85.2-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "0.20.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/37/8ac52116984d6a0d8502ec2c7e4a4a78f862b76410cdb1a4bcb384c91cb3/starlette-0.20.4-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "1.26.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/33/cf/8435d5a7159e2a9c83a95896ed596f68cf798005fe107cc655b5c5c14704/urllib3-1.26.20-py2.py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "1.10.26"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f3/fa/343ac0db26918a033ac6256c036d72c3b6eb1196b7de622e2e8a94b19079/pydantic-1.10.26-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/93/2fa34714b7a4ae72f2f8dad66ba17dd9a2c793220719e736dda28b7aec27/pytest_asyncio-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/45/58/38b5afbc1a800eeea951b9285d3912613f2603bdf897a4ab0f4bd7f405fc/python_multipart-0.0.20-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.32.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/ec/81e22253f4b7091eca6515bb3da5e45d05a663f7f567bb745695dc60f892/charset_normalizer-3.4.9-cp39-cp39-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/23/07a2cb9a8045d5f3f0890a8c3bc0859d7a47bfd9a560b563899bec7b72ed/markupsafe-3.0.3-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}], "install_targets_hash": "19e353ce40ba92d24a84d4e21339caaa"} {"python_version": "3.9", "dependencies": [{"metadata": {"name": "anthropic", "version": "0.125.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2f/1a/b1bd30cda3790557e8791bec5922a6ec8fabb6fa8b008c76a39cf7be6152/anthropic-0.125.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/79/7b84250429f0e262b935c627a8522cab31b5303e617400b14e808b599bdb/jiter-0.16.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/60/e70fa1ee03e243bdfd4b1fddf1e1f2a8fba681df3034b51b9376c0fb5bf5/pydantic_core-2.46.4-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/93/2fa34714b7a4ae72f2f8dad66ba17dd9a2c793220719e736dda28b7aec27/pytest_asyncio-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}], "install_targets_hash": "1c358b0efef217a40b276bd14601c7b4"} +{"python_version": "3.9", "dependencies": [{"metadata": {"name": "anthropic", "version": "0.125.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2f/1a/b1bd30cda3790557e8791bec5922a6ec8fabb6fa8b008c76a39cf7be6152/anthropic-0.125.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/79/7b84250429f0e262b935c627a8522cab31b5303e617400b14e808b599bdb/jiter-0.16.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/60/e70fa1ee03e243bdfd4b1fddf1e1f2a8fba681df3034b51b9376c0fb5bf5/pydantic_core-2.46.4-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/93/2fa34714b7a4ae72f2f8dad66ba17dd9a2c793220719e736dda28b7aec27/pytest_asyncio-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}], "install_targets_hash": "1c358b0efef217a40b276bd14601c7b4"} +{"python_version": "3.9", "dependencies": [{"metadata": {"name": "celery", "version": "5.2.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1d/99/21fe9d1829cab4fc77d18f89d0c4cbcfe754e95f8b8f4af64fe4997c442f/celery-5.2.7-py3-none-any.whl"}}, {"metadata": {"name": "newrelic", "version": "10.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d4/71/07c41fd5e8c94e95216b000d00c3cf735f769cb406c0f33c6ff83b7b7418/newrelic-10.16.0.tar.gz"}}, {"metadata": {"name": "billiard", "version": "3.6.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2b/89/0c43de91d4e52eaa7bd748771d417f6ac9e51e66b2f61928c2151bf65878/billiard-3.6.4.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl"}}, {"metadata": {"name": "kombu", "version": "5.6.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/0f/834427d8c03ff1d7e867d3db3d176470c64871753252b21b4f4897d1fa45/kombu-5.6.2-py3-none-any.whl"}}, {"metadata": {"name": "vine", "version": "5.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/ff/7c0c86c43b3cbb927e0ccc0255cb4057ceba4799cd44ae95174ce8e8b5b2/vine-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "amqp", "version": "5.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/26/99/fc813cd978842c26c82534010ea849eee9ab3a13ea2b74e95cb9c99e747b/amqp-5.3.1-py3-none-any.whl"}}, {"metadata": {"name": "redis", "version": "7.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/97/9f22a33c475cda519f20aba6babb340fb2f2254a02fb947816960d1e669a/redis-7.0.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/af/9c0bda43e486a3c9bf1e0f876d0f241bc3f229d7d65d09331a0868db9629/pytest_forked-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "click-didyoumean", "version": "0.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/5b/974430b5ffdb7a4f1941d13d83c64a0395114503cc357c6b9ae4ce5047ed/click_didyoumean-0.3.1-py3-none-any.whl"}}, {"metadata": {"name": "click-plugins", "version": "1.1.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/9a/2abecb28ae875e39c8cad711eb1186d8d14eab564705325e77e4e6ab9ae5/click_plugins-1.1.1.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "click-repl", "version": "0.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/52/40/9d857001228658f0d59e97ebd4c346fe73e138c6de1bce61dc568a57c7f8/click_repl-0.3.0-py3-none-any.whl"}}, {"metadata": {"name": "prompt_toolkit", "version": "3.0.52"}, "download_info": {"url": "https://files.pythonhosted.org/packages/84/03/0d3ce49e2505ae70cf43bc5bb3033955d2fc9f932163e84dc0779cc47f48/prompt_toolkit-3.0.52-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "pytz", "version": "2026.3.post1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0f/7b/39c34ca613b0b198cb866466651b26b045e2009864c5183c979a3b83f383/pytz-2026.3.post1-py2.py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "tzdata", "version": "2026.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e5/6d/b53b99a9f2766d095985947a5782f1702cabb129a34f7a802d7197af832f/tzdata-2026.3-py2.py3-none-any.whl"}}, {"metadata": {"name": "py", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl"}}], "install_targets_hash": "21a451706547ac63c2f4503acadf8746"} {"python_version": "3.9", "dependencies": [{"metadata": {"name": "asyncpg", "version": "0.23.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/97/b0/acacd8496670b24bad90b92c105fd2f66e83051bf5e23b978a059e5f9608/asyncpg-0.23.0.tar.gz"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/93/2fa34714b7a4ae72f2f8dad66ba17dd9a2c793220719e736dda28b7aec27/pytest_asyncio-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}], "install_targets_hash": "258979437b2e8714e61c32eff07271c3"} +{"python_version": "3.9", "dependencies": [{"metadata": {"name": "falcon", "version": "3.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/22/6a9009c53ad78e65d88a44db8eccc7f39c6f54fc05fb43b1e9cbbc481d06/falcon-3.0.1.tar.gz"}}], "install_targets_hash": "2963e8711ff6a3e310e62912cd678f80"} {"python_version": "3.9", "dependencies": [{"metadata": {"name": "aiohttp", "version": "3.7.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7a/95/eb60aaad7943e18c9d091de93c9b0b5ed40aa67c7d5e3c5ee9b36f100a38/aiohttp-3.7.4.tar.gz"}}, {"metadata": {"name": "async-timeout", "version": "3.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/1e/5a4441be21b0726c4464f3f23c8b19628372f606755a9d2e46c187e65ec4/async_timeout-3.0.1-py3-none-any.whl"}}, {"metadata": {"name": "chardet", "version": "3.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/a9/01ffebfb562e4274b6487b4bb1ddec7ca55ec7510b22e4c51f14098443b8/chardet-3.0.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/83/9c/1d2a283d9c6f31e260cb6c2fccadc3edcf6c4c14ee0929cd2af4d2606dd7/multidict-6.7.1-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "yarl", "version": "1.22.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/58/b8055273c203968e89808413ea4c984988b6649baabf10f4522e67c22d2f/yarl-1.22.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-aiohttp", "version": "0.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c9/2f/34f8581a799d1e58f0b64d9eb4aa0864b53f520d160281c2eb692340fefc/pytest_aiohttp-0.3.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/19/b65d98ae21384518b291d9939e24a8aeac4fdb5101b732576f8f7540e834/propcache-0.4.1-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}], "install_targets_hash": "297ddb3a2529f85d96683b8bc493a96d"} {"python_version": "3.9", "dependencies": [{"metadata": {"name": "cohere", "version": "5.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/8d/67ea6917f6ec6a094858c7b2514cd3be3e1fed45b8b9769e2571d781704b/cohere-5.4.0-py3-none-any.whl"}}, {"metadata": {"name": "boto3", "version": "1.42.97"}, "download_info": {"url": "https://files.pythonhosted.org/packages/38/43/84c1888139aa1aaf1dc53f8f914e6ec629e5a571fbafdd42fb2d98ac361f/boto3-1.42.97-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.42.97"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e3/d2/8e025ba1a4e257879af72d06913272311af79673d82fa2581a351b924317/botocore-1.42.97-py3-none-any.whl"}}, {"metadata": {"name": "fastavro", "version": "1.12.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/92/2c8efbb85f60c29b4eb5fd76852ad4dddb2b5ea65b972d22146ff78b5447/fastavro-1.12.2-cp39-cp39-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.32.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/1b/ef725f8eb19b5a261b30f78efa9252ef9d017985cb499102f6f49834cd12/charset_normalizer-3.4.7-cp39-cp39-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "s3transfer", "version": "0.16.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/19/90d7d4ed51932c022d53f1d02d564b62d10e272692a1f9b76425c1ad2a02/s3transfer-0.16.1-py3-none-any.whl"}}, {"metadata": {"name": "tokenizers", "version": "0.19.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0a/2b/4e5718e806ff23e5e758e02bd4b34967b5218f085b0c189335fd27c14dc1/tokenizers-0.19.1-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "huggingface_hub", "version": "0.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/af/48ac8483240de756d2438c380746e7130d1c6f75802ef22f3c6d49982787/huggingface_hub-0.36.2-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/35/94/4b2ecfbad8f8b04701a23aefb62f540b9137d058b7e1dbef16a32676f0e9/hf_xet-1.5.1-cp37-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "types-requests", "version": "2.31.0.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5c/a1/6f8dc74d9069e790d604ddae70cb46dcbac668f1bb08136e7b0f2f5cd3bf/types_requests-2.31.0.6-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "1.26.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/33/cf/8435d5a7159e2a9c83a95896ed596f68cf798005fe107cc655b5c5c14704/urllib3-1.26.20-py2.py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2025.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/02/a6b21098b1d5d6249b7c5ab69dde30108a71e4e819d4a9778f1de1d5b70d/fsspec-2025.10.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/60/e70fa1ee03e243bdfd4b1fddf1e1f2a8fba681df3034b51b9376c0fb5bf5/pydantic_core-2.46.4-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ae/92/861f152ce87c452b11b9d0977952259aa7df792d71c1053365cc7b09cc08/pyyaml-6.0.3-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.68.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d8/8e/bb97bb0c71802080bfc8952937d174e49cfc50de5c951dd47b2496f0dcdb/tqdm-4.68.3-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "filelock", "version": "3.19.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/42/14/42b2651a2f46b022ccd948bca9f2d5af0fd8929c4eec235b8d6d844fbe67/filelock-3.19.1-py3-none-any.whl"}}, {"metadata": {"name": "types-urllib3", "version": "1.26.25.14"}, "download_info": {"url": "https://files.pythonhosted.org/packages/11/7b/3fc711b2efea5e85a7a0bbfe269ea944aa767bbba5ec52f9ee45d362ccf3/types_urllib3-1.26.25.14-py3-none-any.whl"}}], "install_targets_hash": "2d88f925409259ac1c50c7222be95be6"} {"python_version": "3.9", "dependencies": [{"metadata": {"name": "gql", "version": "4.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ac/94/30bbd09e8d45339fa77a48f5778d74d47e9242c11b3cd1093b3d994770a5/gql-4.0.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d5/34/8413eafee3421ade2d6ce9e7c0da1213e1d7f0049be09dcdc342b03a39ba/aiohttp-3.13.5-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anyio", "version": "4.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "backoff", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/73/b6e24bd22e6720ca8ee9a85a0c4a2971af8497d8f3193fa05390cbd46e09/backoff-2.2.1-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.42.97"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e3/d2/8e025ba1a4e257879af72d06913272311af79673d82fa2581a351b924317/botocore-1.42.97-py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/15/b92b4e1d88d02c6eff9733c9eea21846ab435cc4d813d84ccc5d335955df/graphql_core-3.2.11-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/83/9c/1d2a283d9c6f31e260cb6c2fccadc3edcf6c4c14ee0929cd2af4d2606dd7/multidict-6.7.1-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.32.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/1b/ef725f8eb19b5a261b30f78efa9252ef9d017985cb499102f6f49834cd12/charset_normalizer-3.4.7-cp39-cp39-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "1.26.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/33/cf/8435d5a7159e2a9c83a95896ed596f68cf798005fe107cc655b5c5c14704/urllib3-1.26.20-py2.py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "15.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1a/21/c0712e382df64c93a0d16449ecbf87b647163485ca1cc3f6cbadb36d2b03/websockets-15.0.1-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "yarl", "version": "1.22.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/58/b8055273c203968e89808413ea4c984988b6649baabf10f4522e67c22d2f/yarl-1.22.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "responses", "version": "0.26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/28/693e1d9ebf72baa062ded80d837a035b86ce75eda5a269379e9e2b1008a8/responses-0.26.2-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.6.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/de/ad9d82ca8e5fa8f0c636e64606553c79e2b859ad253030b62a21fe9986f5/frozenlist-1.8.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/19/b65d98ae21384518b291d9939e24a8aeac4fdb5101b732576f8f7540e834/propcache-0.4.1-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ae/92/861f152ce87c452b11b9d0977952259aa7df792d71c1053365cc7b09cc08/pyyaml-6.0.3-cp39-cp39-macosx_11_0_arm64.whl"}}], "install_targets_hash": "2de3e70bcf4f337f5ecb64d5671c312a"} -{"python_version": "3.9", "dependencies": [{"metadata": {"name": "quart", "version": "0.16.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/41/2405163b533eb53a7563e899d13ad5b62bfa11a7ea6b066b9f3d0a04f797/Quart-0.16.3-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "2.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/f8/9da63c1617ae2a1dec2fbf6412f3a0cfe9d4ce029eccbda6e1e4258ca45f/Werkzeug-2.2.3-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/41/caa5da2dbe6d26029dfe11d31dfa8132b4d6d30b6d6b61a24824075a5f06/blinker-1.5-py2.py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/9a/e5d9ec41927401e41aea8af6d16e78b5e612bca4699d417f646a9610a076/Jinja2-3.0.3-py3-none-any.whl"}}, {"metadata": {"name": "hypercorn", "version": "0.14.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f8/aa/0632f628205f09ec7daa5875e4142db519bfa7a161d48a6417b0f9ab5e08/hypercorn-0.14.4-py3-none-any.whl"}}, {"metadata": {"name": "quart-auth", "version": "0.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6f/ed/3226df1bb2cafcf33142622c856a4931018973ccd799e47094e1d4356222/quart_auth-0.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/93/2fa34714b7a4ae72f2f8dad66ba17dd9a2c793220719e736dda28b7aec27/pytest_asyncio-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/af/9c0bda43e486a3c9bf1e0f876d0f241bc3f229d7d65d09331a0868db9629/pytest_forked-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h2", "version": "4.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/b2/119f6e6dcbd96f9069ce9a2665e0146588dc9f88f29549711853645e736a/h2-4.3.0-py3-none-any.whl"}}, {"metadata": {"name": "hpack", "version": "4.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/07/c6/80c95b1b2b94682a72cbdbfb85b81ae2daffa4291fbfa1b1464502ede10d/hpack-4.1.0-py3-none-any.whl"}}, {"metadata": {"name": "hyperframe", "version": "6.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/48/30/47d0bf6072f7252e6521f3447ccfa40b421b6824517f82854703d0f5a98b/hyperframe-6.1.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/23/07a2cb9a8045d5f3f0890a8c3bc0859d7a47bfd9a560b563899bec7b72ed/markupsafe-3.0.3-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "wsproto", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/58/e860788190eba3bcce367f74d29c4675466ce8dddfba85f7827588416f01/wsproto-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "priority", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5e/5f/82c8074f7e84978129347c2c6ec8b6c59f3584ff1a20bc3c940a3e061790/priority-2.0.0-py3-none-any.whl"}}, {"metadata": {"name": "py", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "toml", "version": "0.10.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/44/6f/7120676b6d73228c96e17f1f794d8ab046fc910d781c8d151120c3f1569e/toml-0.10.2-py2.py3-none-any.whl"}}], "install_targets_hash": "3000515a7f6417494c5933d27bad674f"} {"python_version": "3.9", "dependencies": [{"metadata": {"name": "aiomysql", "version": "0.3.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4c/af/aae0153c3e28712adaf462328f6c7a3c196a1c1c27b491de4377dd3e6b52/aiomysql-0.3.2-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/93/2fa34714b7a4ae72f2f8dad66ba17dd9a2c793220719e736dda28b7aec27/pytest_asyncio-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/2a/5bb823f5bedcf80718cea7fbc95ec5515cca3769633c4b01a32be7f30e7c/cryptography-49.0.0-cp39-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/de/38d9726324e127f727b4ecc376bc85e505bfe61ef130eaf3f290c6847dd4/cffi-2.0.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "PyMySQL", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c4/bd/2534e130295c8cfd4f0a2e31623baab7502278f1e97bcfe61db75656a77f/pymysql-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "2.23"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl"}}], "install_targets_hash": "3680161bd7dab16c5a7cb3161b3427a9"} {"python_version": "3.9", "dependencies": [{"metadata": {"name": "clickhouse-driver", "version": "0.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/f1/69fbaa40bb1d72cb8019379bac2ecfc11db56af65b52db7c2cb1ff2efec2/clickhouse_driver-0.2.11-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytz", "version": "2026.3.post1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0f/7b/39c34ca613b0b198cb866466651b26b045e2009864c5183c979a3b83f383/pytz-2026.3.post1-py2.py3-none-any.whl"}}, {"metadata": {"name": "tzlocal", "version": "5.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c2/14/e2a54fabd4f08cd7af1c07030603c3356b74da07f7cc056e600436edfa17/tzlocal-5.3.1-py3-none-any.whl"}}], "install_targets_hash": "38bca3e47a0c5c6404ea5b79801cb472"} {"python_version": "3.9", "dependencies": [{"metadata": {"name": "Django", "version": "2.2.28"}, "download_info": {"url": "https://files.pythonhosted.org/packages/43/69/eaac9a827335898d626066989865974fa48bfc23efd1b34628d64543b2d9/Django-2.2.28-py3-none-any.whl"}}, {"metadata": {"name": "djangorestframework", "version": "3.13.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c8/45/2588c7c5a01a7da6822c6ffbc9a731d498c318a803a29ae780ec635ea41d/djangorestframework-3.13.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-django", "version": "3.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/5d/c43af4d29cd0380cfac100c86f9496f6a2fc2c5864ca40ce64575a634e65/pytest_django-3.10.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "2.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/f3/22afbdb20cc4654b10c98043414a14057cd27fdba9d4ae61cea596000ba2/Werkzeug-2.0.3-py3-none-any.whl"}}, {"metadata": {"name": "psycopg2-binary", "version": "2.9.12"}, "download_info": {"url": "https://files.pythonhosted.org/packages/26/78/92cf978d7a73c1e6df828f76d53e4f92466382fa5fbfaf38d29faa64abe0/psycopg2_binary-2.9.12-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/af/9c0bda43e486a3c9bf1e0f876d0f241bc3f229d7d65d09331a0868db9629/pytest_forked-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "channels", "version": "3.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/45/31031f6b405b41fdc5f5d9f2b1fc1ddf5717a23bb2c64d62838cdc63ce5c/channels-3.0.5-py3-none-any.whl"}}, {"metadata": {"name": "asgiref", "version": "3.11.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5c/0a/a72d10ed65068e115044937873362e6e32fab1b7dce0046aeb224682c989/asgiref-3.11.1-py3-none-any.whl"}}, {"metadata": {"name": "daphne", "version": "3.0.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5c/a3/52d62474eae7f665837434c2685d1b7ec55d1c0336ea84e1cd5693699554/daphne-3.0.2-py3-none-any.whl"}}, {"metadata": {"name": "executing", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "autobahn", "version": "24.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/13/ee/a6475f39ef6c6f41c33da6b193e0ffd2c6048f52e1698be6253c59301b72/autobahn-24.4.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/2a/5bb823f5bedcf80718cea7fbc95ec5515cca3769633c4b01a32be7f30e7c/cryptography-49.0.0-cp39-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/de/38d9726324e127f727b4ecc376bc85e505bfe61ef130eaf3f290c6847dd4/cffi-2.0.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "hyperlink", "version": "21.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/aa/8caf6a0a3e62863cbb9dab27135660acba46903b703e224f14f447e57934/hyperlink-21.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "sqlparse", "version": "0.5.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/4b/359f28a903c13438ef59ebeee215fb25da53066db67b305c125f1c6d2a25/sqlparse-0.5.5-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "Twisted", "version": "25.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/66/ab7efd8941f0bc7b2bd555b0f0471bff77df4c88e0cc31120c82737fec77/twisted-25.5.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "Automat", "version": "25.4.16"}, "download_info": {"url": "https://files.pythonhosted.org/packages/02/ff/1175b0b7371e46244032d43a56862d0af455823b5280a50c63d99cc50f18/automat-25.4.16-py3-none-any.whl"}}, {"metadata": {"name": "constantly", "version": "23.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b8/40/c199d095151addf69efdb4b9ca3a4f20f70e20508d6222bffb9b76f58573/constantly-23.10.4-py3-none-any.whl"}}, {"metadata": {"name": "Incremental", "version": "24.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1d/55/0f4df2a44053867ea9cbea73fc588b03c55605cd695cee0a3d86f0029cb2/incremental-24.11.0-py3-none-any.whl"}}, {"metadata": {"name": "pyOpenSSL", "version": "26.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/18/1dd71c9b43192ab83f1d531ad6002dc81108ac36c475f79fb7a295abe2f4/pyopenssl-26.3.0-py3-none-any.whl"}}, {"metadata": {"name": "service-identity", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/eb/2433e1af4ff903499144de4846569fb3300b816179ae99a03c2f011b666a/service_identity-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "txaio", "version": "23.6.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/15/88/0d000ddcebd54469ffd84688b578578e3d180b23fa91114d22ec205b9e5d/txaio-23.6.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "zope.interface", "version": "8.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/76/565cf6db478ba344b27cfd6828f17da2888cf1beb521bce31142b3041fb5/zope_interface-8.0.1-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "py", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "2.23"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl"}}, {"metadata": {"name": "pytz", "version": "2026.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/dd/96da98f892250475bdf2328112d7468abdd4acc7b902b6af23f4ed958ea0/pytz-2026.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "82.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/76/f789f7a86709c6b087c5a2f52f911838cad707cc613162401badc665acfe/setuptools-82.0.1-py3-none-any.whl"}}], "install_targets_hash": "3c126f25877b64fcb94712f28ab545f3"} {"python_version": "3.9", "dependencies": [{"metadata": {"name": "Django", "version": "3.2.25"}, "download_info": {"url": "https://files.pythonhosted.org/packages/30/8e/cc23c762c5dcd1d367d73cf006a326e0df2bd0e785cba18b658b39904c1e/Django-3.2.25-py3-none-any.whl"}}, {"metadata": {"name": "djangorestframework", "version": "3.15.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c0/7e/8c45ea7f85dd5d52ceddbacc6f56ecaca21ecbfc0e8c34c95618a14d5082/djangorestframework-3.15.1-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "2.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/f3/22afbdb20cc4654b10c98043414a14057cd27fdba9d4ae61cea596000ba2/Werkzeug-2.0.3-py3-none-any.whl"}}, {"metadata": {"name": "asgiref", "version": "3.11.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5c/0a/a72d10ed65068e115044937873362e6e32fab1b7dce0046aeb224682c989/asgiref-3.11.1-py3-none-any.whl"}}, {"metadata": {"name": "psycopg2-binary", "version": "2.9.12"}, "download_info": {"url": "https://files.pythonhosted.org/packages/26/78/92cf978d7a73c1e6df828f76d53e4f92466382fa5fbfaf38d29faa64abe0/psycopg2_binary-2.9.12-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-django", "version": "4.11.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/be/ac/bd0608d229ec808e51a21044f3f2f27b9a37e7a0ebaca7247882e67876af/pytest_django-4.11.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/af/9c0bda43e486a3c9bf1e0f876d0f241bc3f229d7d65d09331a0868db9629/pytest_forked-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "channels", "version": "4.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f5/52/a233dc63996547f171c2013f2d0505dcfa7d0557e7cde8748a2bd70b5a31/channels-4.0.0-py3-none-any.whl"}}, {"metadata": {"name": "executing", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/93/2fa34714b7a4ae72f2f8dad66ba17dd9a2c793220719e736dda28b7aec27/pytest_asyncio-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "daphne", "version": "4.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/ab/85534d9cbca09f3c10f58fc2093659062280ed5703707c0b41dbca8ec297/daphne-4.2.2-py3-none-any.whl"}}, {"metadata": {"name": "autobahn", "version": "24.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/13/ee/a6475f39ef6c6f41c33da6b193e0ffd2c6048f52e1698be6253c59301b72/autobahn-24.4.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/2a/5bb823f5bedcf80718cea7fbc95ec5515cca3769633c4b01a32be7f30e7c/cryptography-49.0.0-cp39-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/de/38d9726324e127f727b4ecc376bc85e505bfe61ef130eaf3f290c6847dd4/cffi-2.0.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "hyperlink", "version": "21.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6e/aa/8caf6a0a3e62863cbb9dab27135660acba46903b703e224f14f447e57934/hyperlink-21.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "sqlparse", "version": "0.5.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/4b/359f28a903c13438ef59ebeee215fb25da53066db67b305c125f1c6d2a25/sqlparse-0.5.5-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "Twisted", "version": "25.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/66/ab7efd8941f0bc7b2bd555b0f0471bff77df4c88e0cc31120c82737fec77/twisted-25.5.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "Automat", "version": "25.4.16"}, "download_info": {"url": "https://files.pythonhosted.org/packages/02/ff/1175b0b7371e46244032d43a56862d0af455823b5280a50c63d99cc50f18/automat-25.4.16-py3-none-any.whl"}}, {"metadata": {"name": "constantly", "version": "23.10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b8/40/c199d095151addf69efdb4b9ca3a4f20f70e20508d6222bffb9b76f58573/constantly-23.10.4-py3-none-any.whl"}}, {"metadata": {"name": "Incremental", "version": "24.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1d/55/0f4df2a44053867ea9cbea73fc588b03c55605cd695cee0a3d86f0029cb2/incremental-24.11.0-py3-none-any.whl"}}, {"metadata": {"name": "pyOpenSSL", "version": "26.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/18/1dd71c9b43192ab83f1d531ad6002dc81108ac36c475f79fb7a295abe2f4/pyopenssl-26.3.0-py3-none-any.whl"}}, {"metadata": {"name": "service-identity", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/eb/2433e1af4ff903499144de4846569fb3300b816179ae99a03c2f011b666a/service_identity-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "txaio", "version": "23.6.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/15/88/0d000ddcebd54469ffd84688b578578e3d180b23fa91114d22ec205b9e5d/txaio-23.6.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "zope.interface", "version": "8.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/76/565cf6db478ba344b27cfd6828f17da2888cf1beb521bce31142b3041fb5/zope_interface-8.0.1-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "py", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "2.23"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl"}}, {"metadata": {"name": "pytz", "version": "2026.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/dd/96da98f892250475bdf2328112d7468abdd4acc7b902b6af23f4ed958ea0/pytz-2026.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "82.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/76/f789f7a86709c6b087c5a2f52f911838cad707cc613162401badc665acfe/setuptools-82.0.1-py3-none-any.whl"}}], "install_targets_hash": "44564eb565ac68ae270112ab5e229c6c"} {"python_version": "3.9", "dependencies": [{"metadata": {"name": "trytond", "version": "7.8.16"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d8/05/24ac74eee184cc503c8ab1f39c0b16e17ebd4a5a7622b5517ecbec665db8/trytond-7.8.16-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "lxml", "version": "6.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/c9/bd00ce7ba1f7b6cd0c8d531921a05c750ac7582438212810e87b4f08680c/lxml-6.1.3-cp39-cp39-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6f/bc/4dc914ead3fe6ddaef035341fee0fc956949bbd27335b611829292b89ee2/markupsafe-3.0.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "pwdlib", "version": "0.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/f3/0dae5078a486f0fdf4d4a1121e103bc42694a9da9bea7b0f2c63f29cfbd3/pwdlib-0.2.1-py3-none-any.whl"}}, {"metadata": {"name": "argon2-cffi", "version": "23.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a4/6a/e8a041599e78b6b3752da48000b14c8d1e8a04ded09c88c714ba047f34f5/argon2_cffi-23.1.0-py3-none-any.whl"}}, {"metadata": {"name": "python-sql", "version": "1.8.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/77/ac/3603bbdde340f7354c975431c94b70ef3e99966c5b170fa121f8e64d269e/python_sql-1.8.1-py3-none-any.whl"}}, {"metadata": {"name": "relatorio", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/74/eb/798c426ebd54f52c27aed6593eaf96ed07dca3ca1d084822cc34f0db5159/relatorio-1.0.0-py3-none-any.whl"}}, {"metadata": {"name": "Genshi", "version": "0.7.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/27/503016bc329720ba2856eb4831d6ba36089cd6f15bc4fe85db69fea5b563/genshi-0.7.11-py3-none-any.whl"}}, {"metadata": {"name": "argon2-cffi-bindings", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/09/52/94108adfdd6e2ddf58be64f959a0b9c7d4ef2fa71086c38356d22dc501ea/argon2_cffi_bindings-25.1.0-cp39-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1f/74/cc4096ce66f5939042ae094e2e96f53426a979864aa1f96a621ad128be27/cffi-2.0.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"metadata": {"name": "backports.entry-points-selectable", "version": "1.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5a/78/b3ba5d804ae21e26e6179bbe4e1338deaaba9d20161918f59e20e9d92ea0/backports.entry_points_selectable-1.3.0-py3-none-any.whl"}}, {"metadata": {"name": "defusedxml", "version": "0.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "polib", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6b/99/45bb1f9926efe370c6dbe324741c749658e44cb060124f28dad201202274/polib-1.2.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "puremagic", "version": "1.30"}, "download_info": {"url": "https://files.pythonhosted.org/packages/91/ed/1e347d85d05b37a8b9a039ca832e5747e1e5248d0bd66042783ef48b4a37/puremagic-1.30-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "2.23"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "simpleeval", "version": "1.0.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/33/d1ecd9f4f5f272b36ad7b268e307ba0a59c109d8ad134a231cda780baac9/simpleeval-1.0.8-py3-none-any.whl"}}], "install_targets_hash": "4a8515036fcaf8193b6feebd535cc37d"} {"python_version": "3.9", "dependencies": [{"metadata": {"name": "arq", "version": "0.28.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/48/32/66b616976c5058d434ca2017979bfffd784888177b16b5038abcec93954a/arq-0.28.0-py3-none-any.whl"}}, {"metadata": {"name": "redis", "version": "5.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/26/5c5fa0e83c3621db835cfc1f1d789b37e7fa99ed54423b5f519beb931aa7/redis-5.3.1-py3-none-any.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/93/2fa34714b7a4ae72f2f8dad66ba17dd9a2c793220719e736dda28b7aec27/pytest_asyncio-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/4d/e6e40f93031adbf654d34e542bd396e9f3bc1c6209b40c920d58c9e1317a/fakeredis-2.36.2-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "hiredis", "version": "3.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/f1/f7bd4a80c695d2196bb7c3a4a1c25c0a84b8681dee931b85137e301e58d3/hiredis-3.4.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "PyJWT", "version": "2.13.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}], "install_targets_hash": "4bd147206b5343b7421e83fb1f8cf3a4"} -{"python_version": "3.9", "dependencies": [{"metadata": {"name": "sanic", "version": "20.12.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/46/af86e7cfadb04ce694abd380485328d224457c3df58196253703df32c7af/sanic-20.12.7-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.15.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/01/0b3a83352d75e3e57134abf5bef8fa3c64152e6107b5d57d510ad8d49a2a/httpx-0.15.4-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0d/bd/5262054455ab2067e51de331bfbc53a1dfa9071af7c424cf7c0793c4349a/websockets-9.1.tar.gz"}}, {"metadata": {"name": "httpcore", "version": "0.11.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d8/e7/f25e08617b4be99d38e4ef6c4d1b744bf065b9c93156ecd691d95897e0e4/httpcore-0.11.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5a/fd/3dad730b0f95e78aeeb742f96fa7bbecbdd56a58e405d3da440d5bfb90c6/h11-0.9.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "5.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6f/df/362e39296123c375072c6a385a0b901f09d8cbd7afb43108019a06f46257/multidict-5.2.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "rfc3986", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c4/e5/63ca2c4edf4e00657584608bee1001302bbf8c5f569340b78304f2f446cb/rfc3986-1.5.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d5/34/8413eafee3421ade2d6ce9e7c0da1213e1d7f0049be09dcdc342b03a39ba/aiohttp-3.13.5-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.22.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/58/b8055273c203968e89808413ea4c984988b6649baabf10f4522e67c22d2f/yarl-1.22.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.6.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/de/ad9d82ca8e5fa8f0c636e64606553c79e2b859ad253030b62a21fe9986f5/frozenlist-1.8.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httptools", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/5b/1f9b7462464294db5d0b4e0fcb285c2f8233fb29ce48141c26b40fd505f3/httptools-0.8.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/19/b65d98ae21384518b291d9939e24a8aeac4fdb5101b732576f8f7540e834/propcache-0.4.1-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "5.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8d/c1/a52d55638c0c644b8a63059f95ad5ffcb4ad8f60d8bc3e8680f78e77cc75/ujson-5.11.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "uvloop", "version": "0.22.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/1b/6fbd611aeba01ef802c5876c94d7be603a9710db055beacbad39e75a31aa/uvloop-0.22.1-cp39-cp39-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}], "install_targets_hash": "5346cb805bb57502834962281083ee9a"} +{"python_version": "3.9", "dependencies": [{"metadata": {"name": "aiohttp", "version": "3.11.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0e/79/3b3f5b29e1c7313569cf86bc6a08484de700a8af5b7c98daa2e25cfe3f31/aiohttp-3.11.18-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/83/9c/1d2a283d9c6f31e260cb6c2fccadc3edcf6c4c14ee0929cd2af4d2606dd7/multidict-6.7.1-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "yarl", "version": "1.22.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/58/b8055273c203968e89808413ea4c984988b6649baabf10f4522e67c22d2f/yarl-1.22.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-aiohttp", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ba/0f/e6af71c02e0f1098eaf7d2dbf3ffdf0a69fc1e0ef174f96af05cef161f1b/pytest_aiohttp-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/93/2fa34714b7a4ae72f2f8dad66ba17dd9a2c793220719e736dda28b7aec27/pytest_asyncio-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.6.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/de/ad9d82ca8e5fa8f0c636e64606553c79e2b859ad253030b62a21fe9986f5/frozenlist-1.8.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/19/b65d98ae21384518b291d9939e24a8aeac4fdb5101b732576f8f7540e834/propcache-0.4.1-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}], "install_targets_hash": "4dcb68c9e098057b61d8630a385f1e96"} {"python_version": "3.9", "dependencies": [{"metadata": {"name": "falcon", "version": "4.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/ef/5790e74a7b39d2c085554f347be22a1882649a29a7a65e9c81bfaf9e8fc6/falcon-4.3.1-py3-none-any.whl"}}], "install_targets_hash": "5935d22936c24189f0d18cf0311cca5c"} -{"python_version": "3.9", "dependencies": [{"metadata": {"name": "SQLAlchemy", "version": "1.2.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/67/d07cf7ac7e6dd0bc55ba62816753f86d7c558107104ca915e730c9ec2512/SQLAlchemy-1.2.19.tar.gz"}}], "install_targets_hash": "6367cf90dccc4dd9cc10d0a07a7946da"} -{"python_version": "3.9", "dependencies": [{"metadata": {"name": "pyramid", "version": "1.10.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3c/0b/6a56fe7dd5ccb1dc9188c3f337c776d7bc6d3f2fc6044c458b0799d37b0d/pyramid-1.10.8-py2.py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "2.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/f3/22afbdb20cc4654b10c98043414a14057cd27fdba9d4ae61cea596000ba2/Werkzeug-2.0.3-py3-none-any.whl"}}, {"metadata": {"name": "setuptools", "version": "81.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/e3/c164c88b2e5ce7b24d667b9bd83589cf4f3520d97cad01534cd3c4f55fdb/setuptools-81.0.0-py3-none-any.whl"}}, {"metadata": {"name": "hupper", "version": "1.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/86/7d/3888833e4f5ea56af4a9935066ec09a83228e533d7b8877f65889d706ee4/hupper-1.12.1-py3-none-any.whl"}}, {"metadata": {"name": "translationstring", "version": "1.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3b/98/36187601a15e3d37e9bfcf0e0e1055532b39d044353b06861c3a519737a9/translationstring-1.4-py2.py3-none-any.whl"}}, {"metadata": {"name": "venusian", "version": "3.1.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5a/4b/34d926eba40db81b204066a60b4efdc5d8867a8efcbfe44d69b634b1c907/venusian-3.1.1-py3-none-any.whl"}}, {"metadata": {"name": "WebOb", "version": "1.8.10"}, "download_info": {"url": "https://files.pythonhosted.org/packages/83/21/fce134877fb6fc6ad3c464e4a07ede0ee9219f705d26a981ae58ea36ca13/webob-1.8.10-py2.py3-none-any.whl"}}, {"metadata": {"name": "zope.deprecation", "version": "6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/ed/da7f8b1c73caf989a0ff7096cc73c59e6c36f35a8f967c51104098602e2d/zope_deprecation-6.0-py3-none-any.whl"}}, {"metadata": {"name": "zope.interface", "version": "8.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/76/565cf6db478ba344b27cfd6828f17da2888cf1beb521bce31142b3041fb5/zope_interface-8.0.1-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "plaster", "version": "1.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e7/8b/3f98db1448e3b4d2d142716874a7e02f6101685fdaa0f55a8668e9ffa048/plaster-1.1.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "plaster-pastedeploy", "version": "1.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/30/2d4cf89035c22a89bf0e34dbc50fdc07c42c9bdc90fd972d495257ad2b6e/plaster_pastedeploy-1.0.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "PasteDeploy", "version": "3.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/85/30/cdddd9a88969683a59222a6d61cd6dce923977f2e9f9ffba38e1324149cd/PasteDeploy-3.1.0-py3-none-any.whl"}}], "install_targets_hash": "67c9f9c2d02d8933f4796a9f37629c55"} +{"python_version": "3.9", "dependencies": [{"metadata": {"name": "sanic", "version": "22.3.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d9/84/e6cf5cd2aa1c0f000cd10c8601f198143ab2c9273912a57d63c3c4c269cd/sanic-22.3.2-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/d7/df17197565e8874f0a77f8211304169ad4f39ffa3e8c008a7b0bf187a238/websockets-10.4-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sanic-testing", "version": "22.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/f2/df592d4cac9212355a7de5931258f3a25c86ec894a3e50f168956d8d1a00/sanic_testing-22.6.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.23.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ac/a2/0260c0f5d73bdf06e8d3fc1013a82b9f0633dc21750c9e3f3cb1dba7bb8c/httpx-0.23.3-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "0.16.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/7e/ef97af4623024e8159993b3114ce208de4f677098ae058ec5882a1bf7605/httpcore-0.16.3-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/95/04/ff642e65ad6b90db43e668d70ffb6736436c7ce41fcc549f4e9472234127/h11-0.14.0-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/83/9c/1d2a283d9c6f31e260cb6c2fccadc3edcf6c4c14ee0929cd2af4d2606dd7/multidict-6.7.1-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "rfc3986", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c4/e5/63ca2c4edf4e00657584608bee1001302bbf8c5f569340b78304f2f446cb/rfc3986-1.5.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "sanic-routing", "version": "22.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e4/3d/c704085138f7a70c4879a96844f922dd5540ffd524b1de7d7a49150e0e28/sanic_routing-22.3.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d5/34/8413eafee3421ade2d6ce9e7c0da1213e1d7f0049be09dcdc342b03a39ba/aiohttp-3.13.5-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.22.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/58/b8055273c203968e89808413ea4c984988b6649baabf10f4522e67c22d2f/yarl-1.22.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiofiles", "version": "25.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.6.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/de/ad9d82ca8e5fa8f0c636e64606553c79e2b859ad253030b62a21fe9986f5/frozenlist-1.8.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "httptools", "version": "0.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/5b/1f9b7462464294db5d0b4e0fcb285c2f8233fb29ce48141c26b40fd505f3/httptools-0.8.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/19/b65d98ae21384518b291d9939e24a8aeac4fdb5101b732576f8f7540e834/propcache-0.4.1-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "ujson", "version": "5.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8d/c1/a52d55638c0c644b8a63059f95ad5ffcb4ad8f60d8bc3e8680f78e77cc75/ujson-5.11.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "uvloop", "version": "0.22.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bd/1b/6fbd611aeba01ef802c5876c94d7be603a9710db055beacbad39e75a31aa/uvloop-0.22.1-cp39-cp39-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}], "install_targets_hash": "5d067be4256a3d8225e2000b2e369c37"} {"python_version": "3.9", "dependencies": [{"metadata": {"name": "celery", "version": "5.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cf/c9/6eccdda96e098f7ae843162db2d3c149c6931a24fda69fe4ab84d0027eb5/celery-5.6.3-py3-none-any.whl"}}, {"metadata": {"name": "newrelic", "version": "10.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d4/71/07c41fd5e8c94e95216b000d00c3cf735f769cb406c0f33c6ff83b7b7418/newrelic-10.16.0.tar.gz"}}, {"metadata": {"name": "billiard", "version": "4.2.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cb/87/8bab77b323f16d67be364031220069f79159117dd5e43eeb4be2fef1ac9b/billiard-4.2.4-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl"}}, {"metadata": {"name": "vine", "version": "5.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/ff/7c0c86c43b3cbb927e0ccc0255cb4057ceba4799cd44ae95174ce8e8b5b2/vine-5.1.0-py3-none-any.whl"}}, {"metadata": {"name": "redis", "version": "7.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/97/9f22a33c475cda519f20aba6babb340fb2f2254a02fb947816960d1e669a/redis-7.0.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-forked", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/af/9c0bda43e486a3c9bf1e0f876d0f241bc3f229d7d65d09331a0868db9629/pytest_forked-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "click-didyoumean", "version": "0.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/5b/974430b5ffdb7a4f1941d13d83c64a0395114503cc357c6b9ae4ce5047ed/click_didyoumean-0.3.1-py3-none-any.whl"}}, {"metadata": {"name": "click-plugins", "version": "1.1.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/9a/2abecb28ae875e39c8cad711eb1186d8d14eab564705325e77e4e6ab9ae5/click_plugins-1.1.1.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "click-repl", "version": "0.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/52/40/9d857001228658f0d59e97ebd4c346fe73e138c6de1bce61dc568a57c7f8/click_repl-0.3.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "kombu", "version": "5.6.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/0f/834427d8c03ff1d7e867d3db3d176470c64871753252b21b4f4897d1fa45/kombu-5.6.2-py3-none-any.whl"}}, {"metadata": {"name": "amqp", "version": "5.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/26/99/fc813cd978842c26c82534010ea849eee9ab3a13ea2b74e95cb9c99e747b/amqp-5.3.1-py3-none-any.whl"}}, {"metadata": {"name": "prompt_toolkit", "version": "3.0.52"}, "download_info": {"url": "https://files.pythonhosted.org/packages/84/03/0d3ce49e2505ae70cf43bc5bb3033955d2fc9f932163e84dc0779cc47f48/prompt_toolkit-3.0.52-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "tzdata", "version": "2026.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ce/e4/dccd7f47c4b64213ac01ef921a1337ee6e30e8c6466046018326977efd95/tzdata-2026.2-py2.py3-none-any.whl"}}, {"metadata": {"name": "py", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tzlocal", "version": "5.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c2/14/e2a54fabd4f08cd7af1c07030603c3356b74da07f7cc056e600436edfa17/tzlocal-5.3.1-py3-none-any.whl"}}, {"metadata": {"name": "wcwidth", "version": "0.8.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/42/3e5985a0a7e57de470b320c6d6a1a67c844f6737a587f3d44dd13d1819e7/wcwidth-0.8.2-py3-none-any.whl"}}], "install_targets_hash": "68a613b2517fdb654276eddecbf135d5"} +{"python_version": "3.9", "dependencies": [{"metadata": {"name": "pymongo", "version": "4.18.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ea/5a/d6d77039a3c84339b0db36398815e8e6f741e4c4b1c2e0aa077b642abd84/pymongo-4.18.1-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "dnspython", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/68/1b/e0a87d256e40e8c888847551b20a017a6b98139178505dc7ffb96f04e954/dnspython-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "mockupdb", "version": "1.8.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2f/c0/bc0c3e82bf91993bf2337b125c4d49c3cadae39f5a4c642baada958f976e/mockupdb-1.8.1-py2.py3-none-any.whl"}}], "install_targets_hash": "69c2fba3fd9077f55ce7488963967c53"} {"python_version": "3.9", "dependencies": [{"metadata": {"name": "pymongo", "version": "4.18.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f5/49/b1198da44fe42f5e085ef2c97cc86132e43e41ac127fcfb042fb3089cd46/pymongo-4.18.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"metadata": {"name": "dnspython", "version": "2.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/68/1b/e0a87d256e40e8c888847551b20a017a6b98139178505dc7ffb96f04e954/dnspython-2.7.0-py3-none-any.whl"}}, {"metadata": {"name": "mockupdb", "version": "1.8.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2f/c0/bc0c3e82bf91993bf2337b125c4d49c3cadae39f5a4c642baada958f976e/mockupdb-1.8.1-py2.py3-none-any.whl"}}], "install_targets_hash": "69c2fba3fd9077f55ce7488963967c53"} +{"python_version": "3.9", "dependencies": [{"metadata": {"name": "redis", "version": "4.2.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d3/2d/1aefc345181d53d618b48f7c2bdc491a6ec4f2be1923c37e04536ef2f9c4/redis-4.2.2-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.24.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/70/15/7db6bdc128638aa9e6d8ce2d744288674072566060ac0e7424495cff5c77/fakeredis-2.24.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "7.4.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/ff/f6e8b8f39e08547faece4bd80f89d5a8de68a38b2d179cc1c4490ffa3286/pytest-7.4.4-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.23.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ee/82/62e2d63639ecb0fbe8a7ee59ef0bc69a4669ec50f6d3459f74ad4e4189a2/pytest_asyncio-0.23.8-py3-none-any.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "Deprecated", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/84/d0/205d54408c08b13550c733c4b85429e7ead111c7f0014309637425520a9a/deprecated-1.3.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "wrapt", "version": "2.3.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/cb/1e1bbdb39ea166b4b2568c5eec3d82f59cddecf1ed57e5c4a1ed54692107/wrapt-2.3.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}], "install_targets_hash": "7714b24b1f75f284b6047e417e725b9b"} +{"python_version": "3.9", "dependencies": [{"metadata": {"name": "arq", "version": "0.23"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ff/f8/cec0e703750504d653fe048d79f4f97e555e2e3b89b9d8598a6aea368d12/arq-0.23-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "1.10.26"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f3/fa/343ac0db26918a033ac6256c036d72c3b6eb1196b7de622e2e8a94b19079/pydantic-1.10.26-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/93/2fa34714b7a4ae72f2f8dad66ba17dd9a2c793220719e736dda28b7aec27/pytest_asyncio-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/4d/e6e40f93031adbf654d34e542bd396e9f3bc1c6209b40c920d58c9e1317a/fakeredis-2.36.2-py3-none-any.whl"}}, {"metadata": {"name": "redis", "version": "7.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/97/9f22a33c475cda519f20aba6babb340fb2f2254a02fb947816960d1e669a/redis-7.0.1-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}], "install_targets_hash": "861238b3e47ffcf341fe6a7baecfea04"} {"python_version": "3.9", "dependencies": [{"metadata": {"name": "arq", "version": "0.23"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ff/f8/cec0e703750504d653fe048d79f4f97e555e2e3b89b9d8598a6aea368d12/arq-0.23-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "1.10.26"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f3/fa/343ac0db26918a033ac6256c036d72c3b6eb1196b7de622e2e8a94b19079/pydantic-1.10.26-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/93/2fa34714b7a4ae72f2f8dad66ba17dd9a2c793220719e736dda28b7aec27/pytest_asyncio-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "fakeredis", "version": "2.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/4d/e6e40f93031adbf654d34e542bd396e9f3bc1c6209b40c920d58c9e1317a/fakeredis-2.36.2-py3-none-any.whl"}}, {"metadata": {"name": "redis", "version": "7.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/97/9f22a33c475cda519f20aba6babb340fb2f2254a02fb947816960d1e669a/redis-7.0.1-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "sortedcontainers", "version": "2.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}], "install_targets_hash": "861238b3e47ffcf341fe6a7baecfea04"} {"python_version": "3.9", "dependencies": [{"metadata": {"name": "langchain", "version": "0.1.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/28/da40a6b12e7842a0c8b443f8cc5c6f59e49d7a9071cfad064b9639c6b044/langchain-0.1.20-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d5/34/8413eafee3421ade2d6ce9e7c0da1213e1d7f0049be09dcdc342b03a39ba/aiohttp-3.13.5-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "async-timeout", "version": "4.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/fa/e01228c2938de91d47b307831c62ab9e4001e747789d0b05baf779a6488c/async_timeout-4.0.3-py3-none-any.whl"}}, {"metadata": {"name": "dataclasses-json", "version": "0.6.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c3/be/d0d44e092656fe7a06b55e6103cbce807cdbdee17884a5367c68c9860853/dataclasses_json-0.6.7-py3-none-any.whl"}}, {"metadata": {"name": "langchain-community", "version": "0.0.38"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/d3/1f4d1941ae5a627299c8ea052847b99ad6674b97b699d8a08fc4faf25d3e/langchain_community-0.0.38-py3-none-any.whl"}}, {"metadata": {"name": "langchain-core", "version": "0.1.53"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6a/10/285fa149ce95300d91ea0bb124eec28889e5ebbcb59434d1fe2f31098d72/langchain_core-0.1.53-py3-none-any.whl"}}, {"metadata": {"name": "jsonpatch", "version": "1.33"}, "download_info": {"url": "https://files.pythonhosted.org/packages/73/07/02e16ed01e04a374e644b575638ec7987ae846d25ad97bcc9945a3ee4b0e/jsonpatch-1.33-py2.py3-none-any.whl"}}, {"metadata": {"name": "langchain-text-splitters", "version": "0.0.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/68/6a/804fe5ca07129046a4cedc0697222ddde6156cd874c4c4ba29e4d271828a/langchain_text_splitters-0.0.2-py3-none-any.whl"}}, {"metadata": {"name": "langsmith", "version": "0.1.147"}, "download_info": {"url": "https://files.pythonhosted.org/packages/de/f0/63b06b99b730b9954f8709f6f7d9b8d076fa0a973e472efe278089bde42b/langsmith-0.1.147-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "marshmallow", "version": "3.26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/be/2f/5108cb3ee4ba6501748c4908b908e55f42a5b66245b4cfe0c99326e1ef6e/marshmallow-3.26.2-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/83/9c/1d2a283d9c6f31e260cb6c2fccadc3edcf6c4c14ee0929cd2af4d2606dd7/multidict-6.7.1-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "numpy", "version": "1.26.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ae/8c/ab03a7c25741f9ebc92684a20125fbc9fc1b8e1e700beb9197d750fdff88/numpy-1.26.4-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "orjson", "version": "3.11.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/c7/7b682849dd4c9fb701a981669b964ea700516ecbd8e88f62aae07c6852bd/orjson-3.11.5-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl"}}, {"metadata": {"name": "packaging", "version": "23.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/1a/610693ac4ee14fcdf2d9bf3c493370e4f2ef7ae2e19217d7a237ff42367d/packaging-23.2-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/60/e70fa1ee03e243bdfd4b1fddf1e1f2a8fba681df3034b51b9376c0fb5bf5/pydantic_core-2.46.4-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.32.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d0/91/bc145e42f93d6601b9a26f5421af2d7c3093ae6e6d03b8e583c9cebbf530/charset_normalizer-3.5.1-cp39-cp39-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "SQLAlchemy", "version": "2.0.52"}, "download_info": {"url": "https://files.pythonhosted.org/packages/48/4b/c5c0fe0b2d606b34618933f7448ebf93e1aeb60d896149a8061b7ac5bfd9/sqlalchemy-2.0.52-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tenacity", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/3f/8ba87d9e287b9d385a02a7114ddcef61b26f86411e121c9003eb509a1773/tenacity-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspect", "version": "0.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/f3/107a22063bf27bdccf2024833d3445f4eea42b2e598abfbd46f6a63b6cb0/typing_inspect-0.9.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.22.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/58/b8055273c203968e89808413ea4c984988b6649baabf10f4522e67c22d2f/yarl-1.22.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/93/2fa34714b7a4ae72f2f8dad66ba17dd9a2c793220719e736dda28b7aec27/pytest_asyncio-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/79/7b84250429f0e262b935c627a8522cab31b5303e617400b14e808b599bdb/jiter-0.16.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ff/b2/9a49f8a9923167adfb25429415a66b46b6c22a9ff357a3393c1e334408b4/tiktoken-0.14.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "langchain-openai", "version": "0.1.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/27/43f785670a340363fe46e2893a80293fa12448584f19ba4f9e6d03673552/langchain_openai-0.1.7-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "1.109.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1d/2a/7dd3d207ec669cacc1f186fd856a0f61dbc255d24f6fdc1a6715d6051b0f/openai-1.109.1-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.6.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/de/ad9d82ca8e5fa8f0c636e64606553c79e2b859ad253030b62a21fe9986f5/frozenlist-1.8.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonpointer", "version": "3.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/92/5e77f98553e9e75130c78900d000368476aed74276eb8ae8796f65f00918/jsonpointer-3.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "mypy_extensions", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/19/b65d98ae21384518b291d9939e24a8aeac4fdb5101b732576f8f7540e834/propcache-0.4.1-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ae/92/861f152ce87c452b11b9d0977952259aa7df792d71c1053365cc7b09cc08/pyyaml-6.0.3-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.1.15"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/d2/a2fef3717deaff647d7de2bccf899a576c7eaf042b6b271fc4474515fe97/regex-2026.1.15-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "877a90b1b55e01d25a299fb8949b9fd9"} +{"python_version": "3.9", "dependencies": [{"metadata": {"name": "langchain", "version": "0.1.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/28/da40a6b12e7842a0c8b443f8cc5c6f59e49d7a9071cfad064b9639c6b044/langchain-0.1.20-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d5/34/8413eafee3421ade2d6ce9e7c0da1213e1d7f0049be09dcdc342b03a39ba/aiohttp-3.13.5-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "async-timeout", "version": "4.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/fa/e01228c2938de91d47b307831c62ab9e4001e747789d0b05baf779a6488c/async_timeout-4.0.3-py3-none-any.whl"}}, {"metadata": {"name": "dataclasses-json", "version": "0.6.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c3/be/d0d44e092656fe7a06b55e6103cbce807cdbdee17884a5367c68c9860853/dataclasses_json-0.6.7-py3-none-any.whl"}}, {"metadata": {"name": "langchain-community", "version": "0.0.38"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/d3/1f4d1941ae5a627299c8ea052847b99ad6674b97b699d8a08fc4faf25d3e/langchain_community-0.0.38-py3-none-any.whl"}}, {"metadata": {"name": "langchain-core", "version": "0.1.53"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6a/10/285fa149ce95300d91ea0bb124eec28889e5ebbcb59434d1fe2f31098d72/langchain_core-0.1.53-py3-none-any.whl"}}, {"metadata": {"name": "jsonpatch", "version": "1.33"}, "download_info": {"url": "https://files.pythonhosted.org/packages/73/07/02e16ed01e04a374e644b575638ec7987ae846d25ad97bcc9945a3ee4b0e/jsonpatch-1.33-py2.py3-none-any.whl"}}, {"metadata": {"name": "langchain-text-splitters", "version": "0.0.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/68/6a/804fe5ca07129046a4cedc0697222ddde6156cd874c4c4ba29e4d271828a/langchain_text_splitters-0.0.2-py3-none-any.whl"}}, {"metadata": {"name": "langsmith", "version": "0.1.147"}, "download_info": {"url": "https://files.pythonhosted.org/packages/de/f0/63b06b99b730b9954f8709f6f7d9b8d076fa0a973e472efe278089bde42b/langsmith-0.1.147-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "marshmallow", "version": "3.26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/be/2f/5108cb3ee4ba6501748c4908b908e55f42a5b66245b4cfe0c99326e1ef6e/marshmallow-3.26.2-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/83/9c/1d2a283d9c6f31e260cb6c2fccadc3edcf6c4c14ee0929cd2af4d2606dd7/multidict-6.7.1-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "numpy", "version": "1.26.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ae/8c/ab03a7c25741f9ebc92684a20125fbc9fc1b8e1e700beb9197d750fdff88/numpy-1.26.4-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "orjson", "version": "3.11.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/c7/7b682849dd4c9fb701a981669b964ea700516ecbd8e88f62aae07c6852bd/orjson-3.11.5-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl"}}, {"metadata": {"name": "packaging", "version": "23.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/1a/610693ac4ee14fcdf2d9bf3c493370e4f2ef7ae2e19217d7a237ff42367d/packaging-23.2-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/60/e70fa1ee03e243bdfd4b1fddf1e1f2a8fba681df3034b51b9376c0fb5bf5/pydantic_core-2.46.4-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.32.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d0/91/bc145e42f93d6601b9a26f5421af2d7c3093ae6e6d03b8e583c9cebbf530/charset_normalizer-3.5.1-cp39-cp39-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "SQLAlchemy", "version": "2.0.52"}, "download_info": {"url": "https://files.pythonhosted.org/packages/48/4b/c5c0fe0b2d606b34618933f7448ebf93e1aeb60d896149a8061b7ac5bfd9/sqlalchemy-2.0.52-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tenacity", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/3f/8ba87d9e287b9d385a02a7114ddcef61b26f86411e121c9003eb509a1773/tenacity-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspect", "version": "0.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/f3/107a22063bf27bdccf2024833d3445f4eea42b2e598abfbd46f6a63b6cb0/typing_inspect-0.9.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.22.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/58/b8055273c203968e89808413ea4c984988b6649baabf10f4522e67c22d2f/yarl-1.22.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/93/2fa34714b7a4ae72f2f8dad66ba17dd9a2c793220719e736dda28b7aec27/pytest_asyncio-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/79/7b84250429f0e262b935c627a8522cab31b5303e617400b14e808b599bdb/jiter-0.16.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ff/b2/9a49f8a9923167adfb25429415a66b46b6c22a9ff357a3393c1e334408b4/tiktoken-0.14.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "langchain-openai", "version": "0.1.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/27/43f785670a340363fe46e2893a80293fa12448584f19ba4f9e6d03673552/langchain_openai-0.1.7-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "1.109.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1d/2a/7dd3d207ec669cacc1f186fd856a0f61dbc255d24f6fdc1a6715d6051b0f/openai-1.109.1-py3-none-any.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.6.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/de/ad9d82ca8e5fa8f0c636e64606553c79e2b859ad253030b62a21fe9986f5/frozenlist-1.8.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonpointer", "version": "3.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/92/5e77f98553e9e75130c78900d000368476aed74276eb8ae8796f65f00918/jsonpointer-3.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "mypy_extensions", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/19/b65d98ae21384518b291d9939e24a8aeac4fdb5101b732576f8f7540e834/propcache-0.4.1-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ae/92/861f152ce87c452b11b9d0977952259aa7df792d71c1053365cc7b09cc08/pyyaml-6.0.3-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.1.15"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/d2/a2fef3717deaff647d7de2bccf899a576c7eaf042b6b271fc4474515fe97/regex-2026.1.15-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "877a90b1b55e01d25a299fb8949b9fd9"} +{"python_version": "3.9", "dependencies": [{"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "Flask-Login", "version": "0.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/59/f5/67e9cc5c2036f58115f9fe0f00d203cf6780c3ff8ae0e705e7a9d9e8ff9e/Flask_Login-0.6.3-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fa/5e/f8e9a1d23b9c20a551a8a02ea3637b4642e22c2626e3a13a9a29cdea99eb/importlib_metadata-8.7.1-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/23/07a2cb9a8045d5f3f0890a8c3bc0859d7a47bfd9a560b563899bec7b72ed/markupsafe-3.0.3-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "zipp", "version": "3.23.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/08/8a/0861bec20485572fbddf3dfba2910e38fe249796cb73ecdeb74e07eeb8d3/zipp-3.23.1-py3-none-any.whl"}}], "install_targets_hash": "8e9f2612223a3ea6906a34018db168cd"} {"python_version": "3.9", "dependencies": [{"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "Flask-Login", "version": "0.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/59/f5/67e9cc5c2036f58115f9fe0f00d203cf6780c3ff8ae0e705e7a9d9e8ff9e/Flask_Login-0.6.3-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fa/5e/f8e9a1d23b9c20a551a8a02ea3637b4642e22c2626e3a13a9a29cdea99eb/importlib_metadata-8.7.1-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/23/07a2cb9a8045d5f3f0890a8c3bc0859d7a47bfd9a560b563899bec7b72ed/markupsafe-3.0.3-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "zipp", "version": "3.23.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/08/8a/0861bec20485572fbddf3dfba2910e38fe249796cb73ecdeb74e07eeb8d3/zipp-3.23.1-py3-none-any.whl"}}], "install_targets_hash": "8e9f2612223a3ea6906a34018db168cd"} +{"python_version": "3.9", "dependencies": [{"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "Flask-Login", "version": "0.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/59/f5/67e9cc5c2036f58115f9fe0f00d203cf6780c3ff8ae0e705e7a9d9e8ff9e/Flask_Login-0.6.3-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fa/5e/f8e9a1d23b9c20a551a8a02ea3637b4642e22c2626e3a13a9a29cdea99eb/importlib_metadata-8.7.1-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/23/07a2cb9a8045d5f3f0890a8c3bc0859d7a47bfd9a560b563899bec7b72ed/markupsafe-3.0.3-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "zipp", "version": "3.23.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/08/8a/0861bec20485572fbddf3dfba2910e38fe249796cb73ecdeb74e07eeb8d3/zipp-3.23.1-py3-none-any.whl"}}], "install_targets_hash": "8e9f2612223a3ea6906a34018db168cd"} +{"python_version": "3.9", "dependencies": [{"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "Flask-Login", "version": "0.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/59/f5/67e9cc5c2036f58115f9fe0f00d203cf6780c3ff8ae0e705e7a9d9e8ff9e/Flask_Login-0.6.3-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fa/5e/f8e9a1d23b9c20a551a8a02ea3637b4642e22c2626e3a13a9a29cdea99eb/importlib_metadata-8.7.1-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/23/07a2cb9a8045d5f3f0890a8c3bc0859d7a47bfd9a560b563899bec7b72ed/markupsafe-3.0.3-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "zipp", "version": "3.23.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/08/8a/0861bec20485572fbddf3dfba2910e38fe249796cb73ecdeb74e07eeb8d3/zipp-3.23.1-py3-none-any.whl"}}], "install_targets_hash": "8e9f2612223a3ea6906a34018db168cd"} +{"python_version": "3.9", "dependencies": [{"metadata": {"name": "starlette", "version": "0.20.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/51/37/8ac52116984d6a0d8502ec2c7e4a4a78f862b76410cdb1a4bcb384c91cb3/starlette-0.20.4-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/93/2fa34714b7a4ae72f2f8dad66ba17dd9a2c793220719e736dda28b7aec27/pytest_asyncio-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/45/58/38b5afbc1a800eeea951b9285d3912613f2603bdf897a4ab0f4bd7f405fc/python_multipart-0.0.20-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.32.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/ec/81e22253f4b7091eca6515bb3da5e45d05a663f7f567bb745695dc60f892/charset_normalizer-3.4.9-cp39-cp39-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/23/07a2cb9a8045d5f3f0890a8c3bc0859d7a47bfd9a560b563899bec7b72ed/markupsafe-3.0.3-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}], "install_targets_hash": "a344a2d6c61f7e17d28378a4c4d05102"} {"python_version": "3.9", "dependencies": [{"metadata": {"name": "google-genai", "version": "1.29.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9c/33/9b22b0b3734f93655d0d28cfcd64496ef46dd68efe8ae19278f3b1297998/google_genai-1.29.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.50.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/cf/4880c2137c14280b2f59975cdf12cc442bc0ae1f9ea473a26eaa0c146786/google_auth-2.50.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/60/e70fa1ee03e243bdfd4b1fddf1e1f2a8fba681df3034b51b9376c0fb5bf5/pydantic_core-2.46.4-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.32.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/1b/ef725f8eb19b5a261b30f78efa9252ef9d017985cb499102f6f49834cd12/charset_normalizer-3.4.7-cp39-cp39-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e5/30/643397144bfbfec6f6ef821f36f33e57d35946c44a2352d3c9f0ae847619/tenacity-9.1.2-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "15.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1a/21/c0712e382df64c93a0d16449ecbf87b647163485ca1cc3f6cbadb36d2b03/websockets-15.0.1-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/93/2fa34714b7a4ae72f2f8dad66ba17dd9a2c793220719e736dda28b7aec27/pytest_asyncio-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "49.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/2a/5bb823f5bedcf80718cea7fbc95ec5515cca3769633c4b01a32be7f30e7c/cryptography-49.0.0-cp39-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/de/38d9726324e127f727b4ecc376bc85e505bfe61ef130eaf3f290c6847dd4/cffi-2.0.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5d/a0/7d793dce3fa811fe047d6ae2431c672364b462850c6235ae306c0efd025f/pyasn1-0.6.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "2.23"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl"}}], "install_targets_hash": "a43cdff61ea105e2cfc9e159c1a78f1a"} {"python_version": "3.9", "dependencies": [{"metadata": {"name": "langchain", "version": "0.1.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/28/da40a6b12e7842a0c8b443f8cc5c6f59e49d7a9071cfad064b9639c6b044/langchain-0.1.20-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d5/34/8413eafee3421ade2d6ce9e7c0da1213e1d7f0049be09dcdc342b03a39ba/aiohttp-3.13.5-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "async-timeout", "version": "4.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/fa/e01228c2938de91d47b307831c62ab9e4001e747789d0b05baf779a6488c/async_timeout-4.0.3-py3-none-any.whl"}}, {"metadata": {"name": "dataclasses-json", "version": "0.6.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c3/be/d0d44e092656fe7a06b55e6103cbce807cdbdee17884a5367c68c9860853/dataclasses_json-0.6.7-py3-none-any.whl"}}, {"metadata": {"name": "langchain-community", "version": "0.0.38"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1b/d3/1f4d1941ae5a627299c8ea052847b99ad6674b97b699d8a08fc4faf25d3e/langchain_community-0.0.38-py3-none-any.whl"}}, {"metadata": {"name": "langchain-core", "version": "0.1.53"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6a/10/285fa149ce95300d91ea0bb124eec28889e5ebbcb59434d1fe2f31098d72/langchain_core-0.1.53-py3-none-any.whl"}}, {"metadata": {"name": "jsonpatch", "version": "1.33"}, "download_info": {"url": "https://files.pythonhosted.org/packages/73/07/02e16ed01e04a374e644b575638ec7987ae846d25ad97bcc9945a3ee4b0e/jsonpatch-1.33-py2.py3-none-any.whl"}}, {"metadata": {"name": "langchain-text-splitters", "version": "0.0.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/68/6a/804fe5ca07129046a4cedc0697222ddde6156cd874c4c4ba29e4d271828a/langchain_text_splitters-0.0.2-py3-none-any.whl"}}, {"metadata": {"name": "langsmith", "version": "0.1.147"}, "download_info": {"url": "https://files.pythonhosted.org/packages/de/f0/63b06b99b730b9954f8709f6f7d9b8d076fa0a973e472efe278089bde42b/langsmith-0.1.147-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "marshmallow", "version": "3.26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/be/2f/5108cb3ee4ba6501748c4908b908e55f42a5b66245b4cfe0c99326e1ef6e/marshmallow-3.26.2-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/83/9c/1d2a283d9c6f31e260cb6c2fccadc3edcf6c4c14ee0929cd2af4d2606dd7/multidict-6.7.1-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "numpy", "version": "1.26.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ae/8c/ab03a7c25741f9ebc92684a20125fbc9fc1b8e1e700beb9197d750fdff88/numpy-1.26.4-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "orjson", "version": "3.11.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/c7/7b682849dd4c9fb701a981669b964ea700516ecbd8e88f62aae07c6852bd/orjson-3.11.5-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl"}}, {"metadata": {"name": "packaging", "version": "23.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/1a/610693ac4ee14fcdf2d9bf3c493370e4f2ef7ae2e19217d7a237ff42367d/packaging-23.2-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/60/e70fa1ee03e243bdfd4b1fddf1e1f2a8fba681df3034b51b9376c0fb5bf5/pydantic_core-2.46.4-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.32.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d0/91/bc145e42f93d6601b9a26f5421af2d7c3093ae6e6d03b8e583c9cebbf530/charset_normalizer-3.5.1-cp39-cp39-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "SQLAlchemy", "version": "2.0.52"}, "download_info": {"url": "https://files.pythonhosted.org/packages/48/4b/c5c0fe0b2d606b34618933f7448ebf93e1aeb60d896149a8061b7ac5bfd9/sqlalchemy-2.0.52-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tenacity", "version": "8.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/3f/8ba87d9e287b9d385a02a7114ddcef61b26f86411e121c9003eb509a1773/tenacity-8.5.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspect", "version": "0.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/f3/107a22063bf27bdccf2024833d3445f4eea42b2e598abfbd46f6a63b6cb0/typing_inspect-0.9.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.22.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/58/b8055273c203968e89808413ea4c984988b6649baabf10f4522e67c22d2f/yarl-1.22.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/93/2fa34714b7a4ae72f2f8dad66ba17dd9a2c793220719e736dda28b7aec27/pytest_asyncio-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/79/7b84250429f0e262b935c627a8522cab31b5303e617400b14e808b599bdb/jiter-0.16.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "langchain-openai", "version": "0.1.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/27/43f785670a340363fe46e2893a80293fa12448584f19ba4f9e6d03673552/langchain_openai-0.1.7-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "1.109.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1d/2a/7dd3d207ec669cacc1f186fd856a0f61dbc255d24f6fdc1a6715d6051b0f/openai-1.109.1-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ff/b2/9a49f8a9923167adfb25429415a66b46b6c22a9ff357a3393c1e334408b4/tiktoken-0.14.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.6.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/de/ad9d82ca8e5fa8f0c636e64606553c79e2b859ad253030b62a21fe9986f5/frozenlist-1.8.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonpointer", "version": "3.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/92/5e77f98553e9e75130c78900d000368476aed74276eb8ae8796f65f00918/jsonpointer-3.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "mypy_extensions", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/19/b65d98ae21384518b291d9939e24a8aeac4fdb5101b732576f8f7540e834/propcache-0.4.1-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ae/92/861f152ce87c452b11b9d0977952259aa7df792d71c1053365cc7b09cc08/pyyaml-6.0.3-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.1.15"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/d2/a2fef3717deaff647d7de2bccf899a576c7eaf042b6b271fc4474515fe97/regex-2026.1.15-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "aa1fb60a0df2b501cda6dfe6922f3f17"} {"python_version": "3.9", "dependencies": [{"metadata": {"name": "ray", "version": "2.7.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0a/94/d037f3b81603dc78248252f281b275399bf62c31788c261021900cae4adc/ray-2.7.2-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "setuptools", "version": "81.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e1/e3/c164c88b2e5ce7b24d667b9bd83589cf4f3520d97cad01534cd3c4f55fdb/setuptools-81.0.0-py3-none-any.whl"}}, {"metadata": {"name": "msgpack", "version": "1.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/6c/3a/7d4077e8ae720b29d2b299a9591969f0d105146960681ea6f4121e6d0f8d/msgpack-1.1.2-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "click", "version": "8.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl"}}, {"metadata": {"name": "numpy", "version": "2.0.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/ff/06d1aa3eeb1c614eda245c1ba4fb88c483bee6520d361641331872ac4b82/numpy-2.0.2-cp39-cp39-macosx_14_0_arm64.whl"}}, {"metadata": {"name": "protobuf", "version": "6.33.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5c/01/a3c3ed5cd186f39e7880f8303cc51385a198a81469d53d0fdecf1f64d929/protobuf-6.33.6-cp39-abi3-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/de/ad9d82ca8e5fa8f0c636e64606553c79e2b859ad253030b62a21fe9986f5/frozenlist-1.8.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "filelock", "version": "3.19.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/42/14/42b2651a2f46b022ccd948bca9f2d5af0fd8929c4eec235b8d6d844fbe67/filelock-3.19.1-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.25.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bf/9c/8c95d856233c1f82500c2450b8c68576b4cf1c871db3afac5c34ff84e6fd/jsonschema-4.25.1-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/b1/3baf80dc6d2b7bc27a95a67752d0208e410351e3feb4eb78de5f77454d8d/referencing-0.36.2-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "0.27.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/71/949c195d927c5aeb0d0629d329a20de43a64c423a6aa53836290609ef7ec/rpds_py-0.27.1-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ae/92/861f152ce87c452b11b9d0977952259aa7df792d71c1053365cc7b09cc08/pyyaml-6.0.3-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.32.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/1b/ef725f8eb19b5a261b30f78efa9252ef9d017985cb499102f6f49834cd12/charset_normalizer-3.4.7-cp39-cp39-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}], "install_targets_hash": "ad451cdabab2f03c19f03edf7f7b19e6"} -{"python_version": "3.9", "dependencies": [{"metadata": {"name": "fastapi", "version": "0.79.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/29/95/31db8826daec0bfc9a4bb6ceac3ceeb7e8e6c6b81b6d204aaec788445c8c/fastapi-0.79.1-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "0.19.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f1/9d/1fa96008b302dd3e398f89f3fc5afb19fb0b0f341fefa05c65b3a38d64cf/starlette-0.19.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "1.10.26"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f3/fa/343ac0db26918a033ac6256c036d72c3b6eb1196b7de622e2e8a94b19079/pydantic-1.10.26-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/93/2fa34714b7a4ae72f2f8dad66ba17dd9a2c793220719e736dda28b7aec27/pytest_asyncio-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/45/58/38b5afbc1a800eeea951b9285d3912613f2603bdf897a4ab0f4bd7f405fc/python_multipart-0.0.20-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.32.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/1b/ef725f8eb19b5a261b30f78efa9252ef9d017985cb499102f6f49834cd12/charset_normalizer-3.4.7-cp39-cp39-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/23/07a2cb9a8045d5f3f0890a8c3bc0859d7a47bfd9a560b563899bec7b72ed/markupsafe-3.0.3-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}], "install_targets_hash": "ad4cf39e76d2eefdf95ba4058faa7738"} {"python_version": "3.9", "dependencies": [{"metadata": {"name": "tornado", "version": "6.5.10"}, "download_info": {"url": "https://files.pythonhosted.org/packages/60/33/df6d7d04854a58619f8349a51e3edb138324130a7562b0bb21f115bb940f/tornado-6.5.10-cp39-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl"}}, {"metadata": {"name": "pytest", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}], "install_targets_hash": "b29e9ff3837ebc143e8b2f14e7600a10"} +{"python_version": "3.9", "dependencies": [{"metadata": {"name": "httpx", "version": "0.16.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2d/c6/59aa4188e7eddb9e89ec67a51598ca6bfc09f1b38c9b45f7ee45af7a4df4/httpx-0.16.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-httpx", "version": "0.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5f/c2/5afbb915233722136b1acaa019b4a3eeb220135376e89adcda4a46ba9413/pytest_httpx-0.10.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "0.12.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/ce/544244e2145075896d38f7db3e822c24d1be9f7966ed3d83f158e388d195/httpcore-0.12.3-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "6.2.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/40/76/86f886e750b81a4357b6ed606b2bcf0ce6d6c27ad3c09ebf63ed674fc86e/pytest-6.2.5-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "rfc3986", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c4/e5/63ca2c4edf4e00657584608bee1001302bbf8c5f569340b78304f2f446cb/rfc3986-1.5.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.20.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/45/74/9421cfde8def10c265b4f9ae19c95b8f4dc227f639cb8b89287d4946ac97/pytest_asyncio-0.20.3-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "py", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "toml", "version": "0.10.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/44/6f/7120676b6d73228c96e17f1f794d8ab046fc910d781c8d151120c3f1569e/toml-0.10.2-py2.py3-none-any.whl"}}], "install_targets_hash": "b3e4935a42940aab9f3a4cc71bd17b0b"} {"python_version": "3.9", "dependencies": [{"metadata": {"name": "httpx", "version": "0.16.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2d/c6/59aa4188e7eddb9e89ec67a51598ca6bfc09f1b38c9b45f7ee45af7a4df4/httpx-0.16.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-httpx", "version": "0.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/5f/c2/5afbb915233722136b1acaa019b4a3eeb220135376e89adcda4a46ba9413/pytest_httpx-0.10.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "0.12.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/ce/544244e2145075896d38f7db3e822c24d1be9f7966ed3d83f158e388d195/httpcore-0.12.3-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "6.2.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/40/76/86f886e750b81a4357b6ed606b2bcf0ce6d6c27ad3c09ebf63ed674fc86e/pytest-6.2.5-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "rfc3986", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c4/e5/63ca2c4edf4e00657584608bee1001302bbf8c5f569340b78304f2f446cb/rfc3986-1.5.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.20.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/45/74/9421cfde8def10c265b4f9ae19c95b8f4dc227f639cb8b89287d4946ac97/pytest_asyncio-0.20.3-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "py", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "toml", "version": "0.10.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/44/6f/7120676b6d73228c96e17f1f794d8ab046fc910d781c8d151120c3f1569e/toml-0.10.2-py2.py3-none-any.whl"}}], "install_targets_hash": "b3e4935a42940aab9f3a4cc71bd17b0b"} {"python_version": "3.9", "dependencies": [{"metadata": {"name": "litellm", "version": "1.77.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/86/50/53df2244d4aca2af73d2f2c6ad21c731cf24bd0dbe89d896184a1eaa874f/litellm-1.77.7-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.25.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bf/9c/8c95d856233c1f82500c2450b8c68576b4cf1c871db3afac5c34ff84e6fd/jsonschema-4.25.1-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/60/e70fa1ee03e243bdfd4b1fddf1e1f2a8fba681df3034b51b9376c0fb5bf5/pydantic_core-2.46.4-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anthropic", "version": "0.125.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2f/1a/b1bd30cda3790557e8791bec5922a6ec8fabb6fa8b008c76a39cf7be6152/anthropic-0.125.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/79/7b84250429f0e262b935c627a8522cab31b5303e617400b14e808b599bdb/jiter-0.16.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "google-genai", "version": "1.47.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/ef/e080e8d67c270ea320956bb911a9359664fc46d3b87d1f029decd33e5c4c/google_genai-1.47.0-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.50.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/cf/4880c2137c14280b2f59975cdf12cc442bc0ae1f9ea473a26eaa0c146786/google_auth-2.50.0-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.32.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d0/91/bc145e42f93d6601b9a26f5421af2d7c3093ae6e6d03b8e583c9cebbf530/charset_normalizer-3.5.1-cp39-cp39-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e5/30/643397144bfbfec6f6ef821f36f33e57d35946c44a2352d3c9f0ae847619/tenacity-9.1.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "15.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1a/21/c0712e382df64c93a0d16449ecbf87b647163485ca1cc3f6cbadb36d2b03/websockets-15.0.1-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/93/2fa34714b7a4ae72f2f8dad66ba17dd9a2c793220719e736dda28b7aec27/pytest_asyncio-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d5/34/8413eafee3421ade2d6ce9e7c0da1213e1d7f0049be09dcdc342b03a39ba/aiohttp-3.13.5-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/83/9c/1d2a283d9c6f31e260cb6c2fccadc3edcf6c4c14ee0929cd2af4d2606dd7/multidict-6.7.1-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "yarl", "version": "1.22.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/58/b8055273c203968e89808413ea4c984988b6649baabf10f4522e67c22d2f/yarl-1.22.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.6.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/37/73d005be173aff344af30e9fd2a576575cb2391a7101d9cd3842e1fa8cce/cryptography-50.0.0-cp39-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/de/38d9726324e127f727b4ecc376bc85e505bfe61ef130eaf3f290c6847dd4/cffi-2.0.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "fastuuid", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f2/9e/758e0d751ed53099e2fe4c98a1a26c537dca0cbcdb35a67b2ccfe2619e76/fastuuid-0.14.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/de/ad9d82ca8e5fa8f0c636e64606553c79e2b859ad253030b62a21fe9986f5/frozenlist-1.8.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fa/5e/f8e9a1d23b9c20a551a8a02ea3637b4642e22c2626e3a13a9a29cdea99eb/importlib_metadata-8.7.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/23/07a2cb9a8045d5f3f0890a8c3bc0859d7a47bfd9a560b563899bec7b72ed/markupsafe-3.0.3-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "openai", "version": "2.48.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b5/2a/dcb891114e303c4379d4a498f10222e33eee540bcef4e1e493bd0af2b242/openai-2.48.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/19/b65d98ae21384518b291d9939e24a8aeac4fdb5101b732576f8f7540e834/propcache-0.4.1-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/3b/6163796d69c3977d1e4287bea4a6979161cbbdd170ebb430511e8e1999ce/pyasn1-0.6.4-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/1b/a298b06749107c305e1fe0f814c6c74aea7b2f1e10989cb30f544a1b3253/python_dotenv-1.2.1-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/b1/3baf80dc6d2b7bc27a95a67752d0208e410351e3feb4eb78de5f77454d8d/referencing-0.36.2-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "0.27.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/71/949c195d927c5aeb0d0629d329a20de43a64c423a6aa53836290609ef7ec/rpds_py-0.27.1-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ff/b2/9a49f8a9923167adfb25429415a66b46b6c22a9ff357a3393c1e334408b4/tiktoken-0.14.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "zipp", "version": "3.23.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/08/8a/0861bec20485572fbddf3dfba2910e38fe249796cb73ecdeb74e07eeb8d3/zipp-3.23.1-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "2.23"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.1.15"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/d2/a2fef3717deaff647d7de2bccf899a576c7eaf042b6b271fc4474515fe97/regex-2026.1.15-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tokenizers", "version": "0.22.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2e/47/174dca0502ef88b28f1c9e06b73ce33500eedfac7a7692108aec220464e7/tokenizers-0.22.2-cp39-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "huggingface_hub", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/ae/8a3a16ea4d202cb641b51d2681bdd3d482c1c592d7570b3fa264730829ce/huggingface_hub-1.8.0-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/69/55b8dcf636142ae660fec1869fcac14c4da2e8412e14d6eee1523be77e9f/hf_xet-1.6.0-cp38-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "filelock", "version": "3.19.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/42/14/42b2651a2f46b022ccd948bca9f2d5af0fd8929c4eec235b8d6d844fbe67/filelock-3.19.1-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2025.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/02/a6b21098b1d5d6249b7c5ab69dde30108a71e4e819d4a9778f1de1d5b70d/fsspec-2025.10.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ae/92/861f152ce87c452b11b9d0977952259aa7df792d71c1053365cc7b09cc08/pyyaml-6.0.3-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typer", "version": "0.23.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2c/dee705c427875402200fe779eb8a3c00ccb349471172c41178336e9599cc/typer-0.23.2-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "3.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "shellingham", "version": "1.5.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}], "install_targets_hash": "b512ff6d7a8009ab10bb0b7c9175af2f"} -{"python_version": "3.9", "dependencies": [{"metadata": {"name": "starlette", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/74/4e60dbbf61567bf5adea89433068d5f7c18c86ca77617b5de5b3ddd83f62/starlette-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.27.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/93/2fa34714b7a4ae72f2f8dad66ba17dd9a2c793220719e736dda28b7aec27/pytest_asyncio-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "python-multipart", "version": "0.0.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/45/58/38b5afbc1a800eeea951b9285d3912613f2603bdf897a4ab0f4bd7f405fc/python_multipart-0.0.20-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.32.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/1b/ef725f8eb19b5a261b30f78efa9252ef9d017985cb499102f6f49834cd12/charset_normalizer-3.4.7-cp39-cp39-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/23/07a2cb9a8045d5f3f0890a8c3bc0859d7a47bfd9a560b563899bec7b72ed/markupsafe-3.0.3-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}], "install_targets_hash": "cbbd2c92dce74693f6b4444c00c5c36f"} +{"python_version": "3.9", "dependencies": [{"metadata": {"name": "litellm", "version": "1.77.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/86/50/53df2244d4aca2af73d2f2c6ad21c731cf24bd0dbe89d896184a1eaa874f/litellm-1.77.7-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema", "version": "4.25.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/bf/9c/8c95d856233c1f82500c2450b8c68576b4cf1c871db3afac5c34ff84e6fd/jsonschema-4.25.1-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/60/e70fa1ee03e243bdfd4b1fddf1e1f2a8fba681df3034b51b9376c0fb5bf5/pydantic_core-2.46.4-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "anthropic", "version": "0.125.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2f/1a/b1bd30cda3790557e8791bec5922a6ec8fabb6fa8b008c76a39cf7be6152/anthropic-0.125.0-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "docstring_parser", "version": "0.18.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/5f/ed01f9a3cdffbd5a008556fc7b2a08ddb1cc6ace7effa7340604b1d16699/docstring_parser-0.18.0-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/79/7b84250429f0e262b935c627a8522cab31b5303e617400b14e808b599bdb/jiter-0.16.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "google-genai", "version": "1.47.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/89/ef/e080e8d67c270ea320956bb911a9359664fc46d3b87d1f029decd33e5c4c/google_genai-1.47.0-py3-none-any.whl"}}, {"metadata": {"name": "google-auth", "version": "2.50.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/37/cf/4880c2137c14280b2f59975cdf12cc442bc0ae1f9ea473a26eaa0c146786/google_auth-2.50.0-py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.32.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d0/91/bc145e42f93d6601b9a26f5421af2d7c3093ae6e6d03b8e583c9cebbf530/charset_normalizer-3.5.1-cp39-cp39-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e5/30/643397144bfbfec6f6ef821f36f33e57d35946c44a2352d3c9f0ae847619/tenacity-9.1.2-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "15.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1a/21/c0712e382df64c93a0d16449ecbf87b647163485ca1cc3f6cbadb36d2b03/websockets-15.0.1-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/93/2fa34714b7a4ae72f2f8dad66ba17dd9a2c793220719e736dda28b7aec27/pytest_asyncio-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d5/34/8413eafee3421ade2d6ce9e7c0da1213e1d7f0049be09dcdc342b03a39ba/aiohttp-3.13.5-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/83/9c/1d2a283d9c6f31e260cb6c2fccadc3edcf6c4c14ee0929cd2af4d2606dd7/multidict-6.7.1-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "yarl", "version": "1.22.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/58/b8055273c203968e89808413ea4c984988b6649baabf10f4522e67c22d2f/yarl-1.22.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.6.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "cryptography", "version": "50.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/03/37/73d005be173aff344af30e9fd2a576575cb2391a7101d9cd3842e1fa8cce/cryptography-50.0.0-cp39-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "cffi", "version": "2.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3d/de/38d9726324e127f727b4ecc376bc85e505bfe61ef130eaf3f290c6847dd4/cffi-2.0.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "fastuuid", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f2/9e/758e0d751ed53099e2fe4c98a1a26c537dca0cbcdb35a67b2ccfe2619e76/fastuuid-0.14.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/de/ad9d82ca8e5fa8f0c636e64606553c79e2b859ad253030b62a21fe9986f5/frozenlist-1.8.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fa/5e/f8e9a1d23b9c20a551a8a02ea3637b4642e22c2626e3a13a9a29cdea99eb/importlib_metadata-8.7.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonschema-specifications", "version": "2025.9.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/23/07a2cb9a8045d5f3f0890a8c3bc0859d7a47bfd9a560b563899bec7b72ed/markupsafe-3.0.3-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "openai", "version": "2.48.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b5/2a/dcb891114e303c4379d4a498f10222e33eee540bcef4e1e493bd0af2b242/openai-2.48.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "propcache", "version": "0.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/19/b65d98ae21384518b291d9939e24a8aeac4fdb5101b732576f8f7540e834/propcache-0.4.1-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pyasn1_modules", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pyasn1", "version": "0.6.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9a/3b/6163796d69c3977d1e4287bea4a6979161cbbdd170ebb430511e8e1999ce/pyasn1-0.6.4-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/1b/a298b06749107c305e1fe0f814c6c74aea7b2f1e10989cb30f544a1b3253/python_dotenv-1.2.1-py3-none-any.whl"}}, {"metadata": {"name": "referencing", "version": "0.36.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c1/b1/3baf80dc6d2b7bc27a95a67752d0208e410351e3feb4eb78de5f77454d8d/referencing-0.36.2-py3-none-any.whl"}}, {"metadata": {"name": "rpds-py", "version": "0.27.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9d/71/949c195d927c5aeb0d0629d329a20de43a64c423a6aa53836290609ef7ec/rpds_py-0.27.1-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ff/b2/9a49f8a9923167adfb25429415a66b46b6c22a9ff357a3393c1e334408b4/tiktoken-0.14.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "zipp", "version": "3.23.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/08/8a/0861bec20485572fbddf3dfba2910e38fe249796cb73ecdeb74e07eeb8d3/zipp-3.23.1-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl"}}, {"metadata": {"name": "pycparser", "version": "2.23"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl"}}, {"metadata": {"name": "regex", "version": "2026.1.15"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/d2/a2fef3717deaff647d7de2bccf899a576c7eaf042b6b271fc4474515fe97/regex-2026.1.15-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tokenizers", "version": "0.22.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2e/47/174dca0502ef88b28f1c9e06b73ce33500eedfac7a7692108aec220464e7/tokenizers-0.22.2-cp39-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "huggingface_hub", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a9/ae/8a3a16ea4d202cb641b51d2681bdd3d482c1c592d7570b3fa264730829ce/huggingface_hub-1.8.0-py3-none-any.whl"}}, {"metadata": {"name": "hf-xet", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/69/55b8dcf636142ae660fec1869fcac14c4da2e8412e14d6eee1523be77e9f/hf_xet-1.6.0-cp38-abi3-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "filelock", "version": "3.19.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/42/14/42b2651a2f46b022ccd948bca9f2d5af0fd8929c4eec235b8d6d844fbe67/filelock-3.19.1-py3-none-any.whl"}}, {"metadata": {"name": "fsspec", "version": "2025.10.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/eb/02/a6b21098b1d5d6249b7c5ab69dde30108a71e4e819d4a9778f1de1d5b70d/fsspec-2025.10.0-py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ae/92/861f152ce87c452b11b9d0977952259aa7df792d71c1053365cc7b09cc08/pyyaml-6.0.3-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "typer", "version": "0.23.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2c/dee705c427875402200fe779eb8a3c00ccb349471172c41178336e9599cc/typer-0.23.2-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl"}}, {"metadata": {"name": "rich", "version": "15.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"metadata": {"name": "markdown-it-py", "version": "3.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl"}}, {"metadata": {"name": "mdurl", "version": "0.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"metadata": {"name": "shellingham", "version": "1.5.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}], "install_targets_hash": "b512ff6d7a8009ab10bb0b7c9175af2f"} +{"python_version": "3.9", "dependencies": [{"metadata": {"name": "langchain", "version": "0.3.30"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/54/c0775c29bf9ae27c8cbf8484ad600edd2e787a0eacf3a374cb6561613de9/langchain-0.3.30-py3-none-any.whl"}}, {"metadata": {"name": "async-timeout", "version": "4.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/fa/e01228c2938de91d47b307831c62ab9e4001e747789d0b05baf779a6488c/async_timeout-4.0.3-py3-none-any.whl"}}, {"metadata": {"name": "langchain-core", "version": "0.3.86"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/93/ba19ca54701c6118e68f8785949b6c0eab1df3a5cfa5310508cc86877994/langchain_core-0.3.86-py3-none-any.whl"}}, {"metadata": {"name": "jsonpatch", "version": "1.33"}, "download_info": {"url": "https://files.pythonhosted.org/packages/73/07/02e16ed01e04a374e644b575638ec7987ae846d25ad97bcc9945a3ee4b0e/jsonpatch-1.33-py2.py3-none-any.whl"}}, {"metadata": {"name": "langchain-text-splitters", "version": "0.3.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/0d/41a51b40d24ff0384ec4f7ab8dd3dcea8353c05c973836b5e289f1465d4f/langchain_text_splitters-0.3.11-py3-none-any.whl"}}, {"metadata": {"name": "langsmith", "version": "0.4.37"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/e8/edff4de49cf364eb9ee88d13da0a555844df32438413bf53d90d507b97cd/langsmith-0.4.37-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "25.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/60/e70fa1ee03e243bdfd4b1fddf1e1f2a8fba681df3034b51b9376c0fb5bf5/pydantic_core-2.46.4-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ae/92/861f152ce87c452b11b9d0977952259aa7df792d71c1053365cc7b09cc08/pyyaml-6.0.3-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.32.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d0/91/bc145e42f93d6601b9a26f5421af2d7c3093ae6e6d03b8e583c9cebbf530/charset_normalizer-3.5.1-cp39-cp39-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "SQLAlchemy", "version": "2.0.52"}, "download_info": {"url": "https://files.pythonhosted.org/packages/48/4b/c5c0fe0b2d606b34618933f7448ebf93e1aeb60d896149a8061b7ac5bfd9/sqlalchemy-2.0.52-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e5/30/643397144bfbfec6f6ef821f36f33e57d35946c44a2352d3c9f0ae847619/tenacity-9.1.2-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl"}}, {"metadata": {"name": "uuid_utils", "version": "0.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1d/c8/5a05247c1b7cbf49849523e1a26e3a8a76c0c1ec6dc84c7cc7b9a8c66503/uuid_utils-0.15.0-cp39-cp39-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/93/2fa34714b7a4ae72f2f8dad66ba17dd9a2c793220719e736dda28b7aec27/pytest_asyncio-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "2.48.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b5/2a/dcb891114e303c4379d4a498f10222e33eee540bcef4e1e493bd0af2b242/openai-2.48.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/79/7b84250429f0e262b935c627a8522cab31b5303e617400b14e808b599bdb/jiter-0.16.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ff/b2/9a49f8a9923167adfb25429415a66b46b6c22a9ff357a3393c1e334408b4/tiktoken-0.14.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "langchain-openai", "version": "0.3.35"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d8/d5/c90c5478215c20ee71d8feaf676f7ffd78d0568f8c98bd83f81ce7562ed7/langchain_openai-0.3.35-py3-none-any.whl"}}, {"metadata": {"name": "langchain-community", "version": "0.3.31"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e6/0a/b8848db67ad7c8d4652cb6f4cb78d49b5b5e6e8e51d695d62025aa3f7dbc/langchain_community-0.3.31-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d5/34/8413eafee3421ade2d6ce9e7c0da1213e1d7f0049be09dcdc342b03a39ba/aiohttp-3.13.5-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "dataclasses-json", "version": "0.6.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c3/be/d0d44e092656fe7a06b55e6103cbce807cdbdee17884a5367c68c9860853/dataclasses_json-0.6.7-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "marshmallow", "version": "3.26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/be/2f/5108cb3ee4ba6501748c4908b908e55f42a5b66245b4cfe0c99326e1ef6e/marshmallow-3.26.2-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/83/9c/1d2a283d9c6f31e260cb6c2fccadc3edcf6c4c14ee0929cd2af4d2606dd7/multidict-6.7.1-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/83/d6/887a1ff844e64aa823fb4905978d882a633cfe295c32eacad582b78a7d8b/pydantic_settings-2.11.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspect", "version": "0.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/f3/107a22063bf27bdccf2024833d3445f4eea42b2e598abfbd46f6a63b6cb0/typing_inspect-0.9.0-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.22.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/58/b8055273c203968e89808413ea4c984988b6649baabf10f4522e67c22d2f/yarl-1.22.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.6.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/de/ad9d82ca8e5fa8f0c636e64606553c79e2b859ad253030b62a21fe9986f5/frozenlist-1.8.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonpointer", "version": "3.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/92/5e77f98553e9e75130c78900d000368476aed74276eb8ae8796f65f00918/jsonpointer-3.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "mypy_extensions", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "numpy", "version": "2.0.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/ff/06d1aa3eeb1c614eda245c1ba4fb88c483bee6520d361641331872ac4b82/numpy-2.0.2-cp39-cp39-macosx_14_0_arm64.whl"}}, {"metadata": {"name": "orjson", "version": "3.11.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/c7/7b682849dd4c9fb701a981669b964ea700516ecbd8e88f62aae07c6852bd/orjson-3.11.5-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl"}}, {"metadata": {"name": "propcache", "version": "0.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/19/b65d98ae21384518b291d9939e24a8aeac4fdb5101b732576f8f7540e834/propcache-0.4.1-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/1b/a298b06749107c305e1fe0f814c6c74aea7b2f1e10989cb30f544a1b3253/python_dotenv-1.2.1-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "zstandard", "version": "0.25.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/aa/ceb8d79cbad6dabd4cb1178ca853f6a4374d791c5e0241a0988173e2a341/zstandard-0.25.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "regex", "version": "2026.1.15"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/d2/a2fef3717deaff647d7de2bccf899a576c7eaf042b6b271fc4474515fe97/regex-2026.1.15-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "cf8681468fca1e6ce2b515327a36b948"} {"python_version": "3.9", "dependencies": [{"metadata": {"name": "langchain", "version": "0.3.30"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/54/c0775c29bf9ae27c8cbf8484ad600edd2e787a0eacf3a374cb6561613de9/langchain-0.3.30-py3-none-any.whl"}}, {"metadata": {"name": "async-timeout", "version": "4.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/fa/e01228c2938de91d47b307831c62ab9e4001e747789d0b05baf779a6488c/async_timeout-4.0.3-py3-none-any.whl"}}, {"metadata": {"name": "langchain-core", "version": "0.3.86"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/93/ba19ca54701c6118e68f8785949b6c0eab1df3a5cfa5310508cc86877994/langchain_core-0.3.86-py3-none-any.whl"}}, {"metadata": {"name": "jsonpatch", "version": "1.33"}, "download_info": {"url": "https://files.pythonhosted.org/packages/73/07/02e16ed01e04a374e644b575638ec7987ae846d25ad97bcc9945a3ee4b0e/jsonpatch-1.33-py2.py3-none-any.whl"}}, {"metadata": {"name": "langchain-text-splitters", "version": "0.3.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/0d/41a51b40d24ff0384ec4f7ab8dd3dcea8353c05c973836b5e289f1465d4f/langchain_text_splitters-0.3.11-py3-none-any.whl"}}, {"metadata": {"name": "langsmith", "version": "0.4.37"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/e8/edff4de49cf364eb9ee88d13da0a555844df32438413bf53d90d507b97cd/langsmith-0.4.37-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "25.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/60/e70fa1ee03e243bdfd4b1fddf1e1f2a8fba681df3034b51b9376c0fb5bf5/pydantic_core-2.46.4-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ae/92/861f152ce87c452b11b9d0977952259aa7df792d71c1053365cc7b09cc08/pyyaml-6.0.3-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.32.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d0/91/bc145e42f93d6601b9a26f5421af2d7c3093ae6e6d03b8e583c9cebbf530/charset_normalizer-3.5.1-cp39-cp39-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "SQLAlchemy", "version": "2.0.52"}, "download_info": {"url": "https://files.pythonhosted.org/packages/48/4b/c5c0fe0b2d606b34618933f7448ebf93e1aeb60d896149a8061b7ac5bfd9/sqlalchemy-2.0.52-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e5/30/643397144bfbfec6f6ef821f36f33e57d35946c44a2352d3c9f0ae847619/tenacity-9.1.2-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl"}}, {"metadata": {"name": "uuid_utils", "version": "0.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1d/c8/5a05247c1b7cbf49849523e1a26e3a8a76c0c1ec6dc84c7cc7b9a8c66503/uuid_utils-0.15.0-cp39-cp39-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/93/2fa34714b7a4ae72f2f8dad66ba17dd9a2c793220719e736dda28b7aec27/pytest_asyncio-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "2.48.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b5/2a/dcb891114e303c4379d4a498f10222e33eee540bcef4e1e493bd0af2b242/openai-2.48.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/79/7b84250429f0e262b935c627a8522cab31b5303e617400b14e808b599bdb/jiter-0.16.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ff/b2/9a49f8a9923167adfb25429415a66b46b6c22a9ff357a3393c1e334408b4/tiktoken-0.14.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "langchain-openai", "version": "0.3.35"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d8/d5/c90c5478215c20ee71d8feaf676f7ffd78d0568f8c98bd83f81ce7562ed7/langchain_openai-0.3.35-py3-none-any.whl"}}, {"metadata": {"name": "langchain-community", "version": "0.3.31"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e6/0a/b8848db67ad7c8d4652cb6f4cb78d49b5b5e6e8e51d695d62025aa3f7dbc/langchain_community-0.3.31-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d5/34/8413eafee3421ade2d6ce9e7c0da1213e1d7f0049be09dcdc342b03a39ba/aiohttp-3.13.5-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "dataclasses-json", "version": "0.6.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c3/be/d0d44e092656fe7a06b55e6103cbce807cdbdee17884a5367c68c9860853/dataclasses_json-0.6.7-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "marshmallow", "version": "3.26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/be/2f/5108cb3ee4ba6501748c4908b908e55f42a5b66245b4cfe0c99326e1ef6e/marshmallow-3.26.2-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/83/9c/1d2a283d9c6f31e260cb6c2fccadc3edcf6c4c14ee0929cd2af4d2606dd7/multidict-6.7.1-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/83/d6/887a1ff844e64aa823fb4905978d882a633cfe295c32eacad582b78a7d8b/pydantic_settings-2.11.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspect", "version": "0.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/f3/107a22063bf27bdccf2024833d3445f4eea42b2e598abfbd46f6a63b6cb0/typing_inspect-0.9.0-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.22.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/58/b8055273c203968e89808413ea4c984988b6649baabf10f4522e67c22d2f/yarl-1.22.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.6.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/de/ad9d82ca8e5fa8f0c636e64606553c79e2b859ad253030b62a21fe9986f5/frozenlist-1.8.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonpointer", "version": "3.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/92/5e77f98553e9e75130c78900d000368476aed74276eb8ae8796f65f00918/jsonpointer-3.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "mypy_extensions", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "numpy", "version": "2.0.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/ff/06d1aa3eeb1c614eda245c1ba4fb88c483bee6520d361641331872ac4b82/numpy-2.0.2-cp39-cp39-macosx_14_0_arm64.whl"}}, {"metadata": {"name": "orjson", "version": "3.11.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/c7/7b682849dd4c9fb701a981669b964ea700516ecbd8e88f62aae07c6852bd/orjson-3.11.5-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl"}}, {"metadata": {"name": "propcache", "version": "0.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/19/b65d98ae21384518b291d9939e24a8aeac4fdb5101b732576f8f7540e834/propcache-0.4.1-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/1b/a298b06749107c305e1fe0f814c6c74aea7b2f1e10989cb30f544a1b3253/python_dotenv-1.2.1-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "zstandard", "version": "0.25.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/aa/ceb8d79cbad6dabd4cb1178ca853f6a4374d791c5e0241a0988173e2a341/zstandard-0.25.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "regex", "version": "2026.1.15"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/d2/a2fef3717deaff647d7de2bccf899a576c7eaf042b6b271fc4474515fe97/regex-2026.1.15-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "cf8681468fca1e6ce2b515327a36b948"} {"python_version": "3.9", "dependencies": [{"metadata": {"name": "pyspark", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/15/4ee019bfbf9e3e7af2c8e94a900f17c079bc39eafe0868b1b50bcade77de/pyspark-3.0.3.tar.gz"}}, {"metadata": {"name": "py4j", "version": "0.10.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/b6/6a4fb90cd235dc8e265a6a2067f2a2c99f0d91787f06aca4bcf7c23f3f80/py4j-0.10.9-py2.py3-none-any.whl"}}], "install_targets_hash": "d73494848bf6993086fc370f2ab4fb6d"} +{"python_version": "3.9", "dependencies": [{"metadata": {"name": "pyspark", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d7/15/4ee019bfbf9e3e7af2c8e94a900f17c079bc39eafe0868b1b50bcade77de/pyspark-3.0.3.tar.gz"}}, {"metadata": {"name": "py4j", "version": "0.10.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9e/b6/6a4fb90cd235dc8e265a6a2067f2a2c99f0d91787f06aca4bcf7c23f3f80/py4j-0.10.9-py2.py3-none-any.whl"}}], "install_targets_hash": "d73494848bf6993086fc370f2ab4fb6d"} +{"python_version": "3.9", "dependencies": [{"metadata": {"name": "asyncpg", "version": "0.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e4/57/0a4c4d3f2307b12f633b28c370669d6115a1780416310ec536f01ace09ad/asyncpg-0.26.0.tar.gz"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/93/2fa34714b7a4ae72f2f8dad66ba17dd9a2c793220719e736dda28b7aec27/pytest_asyncio-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}], "install_targets_hash": "d7d7d0053f539679c74eddc1935b5205"} {"python_version": "3.9", "dependencies": [{"metadata": {"name": "asyncpg", "version": "0.26.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e4/57/0a4c4d3f2307b12f633b28c370669d6115a1780416310ec536f01ace09ad/asyncpg-0.26.0.tar.gz"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/93/2fa34714b7a4ae72f2f8dad66ba17dd9a2c793220719e736dda28b7aec27/pytest_asyncio-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}], "install_targets_hash": "d7d7d0053f539679c74eddc1935b5205"} {"python_version": "3.9", "dependencies": [{"metadata": {"name": "graphene", "version": "3.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/70/96f6027cdfc9bb89fc07627b615cb43fb1c443c93498412beaeaf157e9f1/graphene-3.3-py2.py3-none-any.whl"}}, {"metadata": {"name": "aniso8601", "version": "9.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e3/04/e97c12dc034791d7b504860acfcdd2963fa21ae61eaca1c9d31245f812c3/aniso8601-9.0.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/15/b92b4e1d88d02c6eff9733c9eea21846ab435cc4d813d84ccc5d335955df/graphql_core-3.2.11-py3-none-any.whl"}}, {"metadata": {"name": "graphql-relay", "version": "3.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/74/16/a4cf06adbc711bd364a73ce043b0b08d8fa5aae3df11b6ee4248bcdad2e0/graphql_relay-3.2.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "fastapi", "version": "0.128.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9f/37/37b07e276f8923c69a5df266bfcb5bac4ba8b55dfe4a126720f8c48681d1/fastapi-0.128.8-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "0.49.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/e0/021c772d6a662f43b63044ab481dc6ac7592447605b5b35a957785363122/starlette-0.49.3-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fa/5e/f8e9a1d23b9c20a551a8a02ea3637b4642e22c2626e3a13a9a29cdea99eb/importlib_metadata-8.7.1-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/23/07a2cb9a8045d5f3f0890a8c3bc0859d7a47bfd9a560b563899bec7b72ed/markupsafe-3.0.3-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/60/e70fa1ee03e243bdfd4b1fddf1e1f2a8fba681df3034b51b9376c0fb5bf5/pydantic_core-2.46.4-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "zipp", "version": "3.23.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/08/8a/0861bec20485572fbddf3dfba2910e38fe249796cb73ecdeb74e07eeb8d3/zipp-3.23.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}], "install_targets_hash": "dff9e5a8db205ce5600a48e786aba109"} -{"python_version": "3.9", "dependencies": [{"metadata": {"name": "httpx", "version": "0.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/05/148ebadb30f498754a738bab07fa88e39b6e401bcd86710f9b36b1cd737d/httpx-0.20.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-httpx", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/43/f1fd8c7f972af4dc95cc9f293515671d826e8960b8fbfe6092840436cf71/pytest_httpx-0.14.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "0.13.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/73/a1/e347135b0ebb4d4c29a4258cb6d2e03c2d0c4ea207bf9ce5d255d7887a56/httpcore-0.13.7-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/60/0f/7a0eeea938eaf61074f29fed9717f2010e8d0e0905d36b38d3275a1e4622/h11-0.12.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "6.2.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/40/76/86f886e750b81a4357b6ed606b2bcf0ce6d6c27ad3c09ebf63ed674fc86e/pytest-6.2.5-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "rfc3986", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c4/e5/63ca2c4edf4e00657584608bee1001302bbf8c5f569340b78304f2f446cb/rfc3986-1.5.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.20.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/45/74/9421cfde8def10c265b4f9ae19c95b8f4dc227f639cb8b89287d4946ac97/pytest_asyncio-0.20.3-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "py", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a6/ec/81e22253f4b7091eca6515bb3da5e45d05a663f7f567bb745695dc60f892/charset_normalizer-3.4.9-cp39-cp39-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "toml", "version": "0.10.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/44/6f/7120676b6d73228c96e17f1f794d8ab046fc910d781c8d151120c3f1569e/toml-0.10.2-py2.py3-none-any.whl"}}], "install_targets_hash": "eaa16b0c40489ad714b5873dabc2a800"} +{"python_version": "3.9", "dependencies": [{"metadata": {"name": "graphene", "version": "3.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/24/70/96f6027cdfc9bb89fc07627b615cb43fb1c443c93498412beaeaf157e9f1/graphene-3.3-py2.py3-none-any.whl"}}, {"metadata": {"name": "aniso8601", "version": "9.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e3/04/e97c12dc034791d7b504860acfcdd2963fa21ae61eaca1c9d31245f812c3/aniso8601-9.0.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/15/b92b4e1d88d02c6eff9733c9eea21846ab435cc4d813d84ccc5d335955df/graphql_core-3.2.11-py3-none-any.whl"}}, {"metadata": {"name": "graphql-relay", "version": "3.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/74/16/a4cf06adbc711bd364a73ce043b0b08d8fa5aae3df11b6ee4248bcdad2e0/graphql_relay-3.2.0-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "fastapi", "version": "0.128.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/9f/37/37b07e276f8923c69a5df266bfcb5bac4ba8b55dfe4a126720f8c48681d1/fastapi-0.128.8-py3-none-any.whl"}}, {"metadata": {"name": "starlette", "version": "0.49.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a3/e0/021c772d6a662f43b63044ab481dc6ac7592447605b5b35a957785363122/starlette-0.49.3-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl"}}, {"metadata": {"name": "Flask", "version": "3.1.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "annotated-doc", "version": "0.0.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "importlib_metadata", "version": "8.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fa/5e/f8e9a1d23b9c20a551a8a02ea3637b4642e22c2626e3a13a9a29cdea99eb/importlib_metadata-8.7.1-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/23/07a2cb9a8045d5f3f0890a8c3bc0859d7a47bfd9a560b563899bec7b72ed/markupsafe-3.0.3-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/60/e70fa1ee03e243bdfd4b1fddf1e1f2a8fba681df3034b51b9376c0fb5bf5/pydantic_core-2.46.4-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "3.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"metadata": {"name": "zipp", "version": "3.23.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/08/8a/0861bec20485572fbddf3dfba2910e38fe249796cb73ecdeb74e07eeb8d3/zipp-3.23.1-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}], "install_targets_hash": "dff9e5a8db205ce5600a48e786aba109"} +{"python_version": "3.9", "dependencies": [{"metadata": {"name": "Flask", "version": "2.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/cd/77/59df23681f4fd19b7cbbb5e92484d46ad587554f5d490f33ef907e456132/Flask-2.0.3-py3-none-any.whl"}}, {"metadata": {"name": "Werkzeug", "version": "2.2.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/f8/9da63c1617ae2a1dec2fbf6412f3a0cfe9d4ce029eccbda6e1e4258ca45f/Werkzeug-2.2.3-py3-none-any.whl"}}, {"metadata": {"name": "Flask-Login", "version": "0.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/59/f5/67e9cc5c2036f58115f9fe0f00d203cf6780c3ff8ae0e705e7a9d9e8ff9e/Flask_Login-0.6.3-py3-none-any.whl"}}, {"metadata": {"name": "blinker", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "click", "version": "8.1.8"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl"}}, {"metadata": {"name": "itsdangerous", "version": "2.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"metadata": {"name": "Jinja2", "version": "3.1.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"metadata": {"name": "MarkupSafe", "version": "3.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/23/07a2cb9a8045d5f3f0890a8c3bc0859d7a47bfd9a560b563899bec7b72ed/markupsafe-3.0.3-cp39-cp39-macosx_11_0_arm64.whl"}}], "install_targets_hash": "e7a6e5268797db2431fe5b6f53613732"} +{"python_version": "3.9", "dependencies": [{"metadata": {"name": "httpx", "version": "0.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/05/148ebadb30f498754a738bab07fa88e39b6e401bcd86710f9b36b1cd737d/httpx-0.20.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest-httpx", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/43/f1fd8c7f972af4dc95cc9f293515671d826e8960b8fbfe6092840436cf71/pytest_httpx-0.14.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "3.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/19/24/44299477fe7dcc9cb58d0a57d5a7588d6af2ff403fdd2d47a246c91a3246/anyio-3.7.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "0.13.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/73/a1/e347135b0ebb4d4c29a4258cb6d2e03c2d0c4ea207bf9ce5d255d7887a56/httpcore-0.13.7-py3-none-any.whl"}}, {"metadata": {"name": "h11", "version": "0.12.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/60/0f/7a0eeea938eaf61074f29fed9717f2010e8d0e0905d36b38d3275a1e4622/h11-0.12.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "6.2.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/40/76/86f886e750b81a4357b6ed606b2bcf0ce6d6c27ad3c09ebf63ed674fc86e/pytest-6.2.5-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "rfc3986", "version": "1.5.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c4/e5/63ca2c4edf4e00657584608bee1001302bbf8c5f569340b78304f2f446cb/rfc3986-1.5.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "0.20.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/45/74/9421cfde8def10c265b4f9ae19c95b8f4dc227f639cb8b89287d4946ac97/pytest_asyncio-0.20.3-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "py", "version": "1.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d0/91/bc145e42f93d6601b9a26f5421af2d7c3093ae6e6d03b8e583c9cebbf530/charset_normalizer-3.5.1-cp39-cp39-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl"}}, {"metadata": {"name": "toml", "version": "0.10.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/44/6f/7120676b6d73228c96e17f1f794d8ab046fc910d781c8d151120c3f1569e/toml-0.10.2-py2.py3-none-any.whl"}}], "install_targets_hash": "eaa16b0c40489ad714b5873dabc2a800"} {"python_version": "3.9", "dependencies": [{"metadata": {"name": "gql", "version": "3.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/1c/2facac9c192d4470960537cf8cdf92d41af10e300a8095ebc37740b4df38/gql-3.4.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.8.6"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/b7/a1543a5f90b6c5cdff4d2e6b73fcaa65a568ff9cc3381c5abfadcefe38e0/aiohttp-3.8.6-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "async-timeout", "version": "4.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/fa/e01228c2938de91d47b307831c62ab9e4001e747789d0b05baf779a6488c/async_timeout-4.0.3-py3-none-any.whl"}}, {"metadata": {"name": "backoff", "version": "2.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/73/b6e24bd22e6720ca8ee9a85a0c4a2971af8497d8f3193fa05390cbd46e09/backoff-2.2.1-py3-none-any.whl"}}, {"metadata": {"name": "botocore", "version": "1.42.97"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e3/d2/8e025ba1a4e257879af72d06913272311af79673d82fa2581a351b924317/botocore-1.42.97-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.4.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/01/1b/ef725f8eb19b5a261b30f78efa9252ef9d017985cb499102f6f49834cd12/charset_normalizer-3.4.7-cp39-cp39-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "graphql-core", "version": "3.2.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/00/15/b92b4e1d88d02c6eff9733c9eea21846ab435cc4d813d84ccc5d335955df/graphql_core-3.2.11-py3-none-any.whl"}}, {"metadata": {"name": "jmespath", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/83/9c/1d2a283d9c6f31e260cb6c2fccadc3edcf6c4c14ee0929cd2af4d2606dd7/multidict-6.7.1-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "python-dateutil", "version": "2.9.0.post0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"metadata": {"name": "requests", "version": "2.32.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl"}}, {"metadata": {"name": "idna", "version": "3.18"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "0.10.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/05/d3/bf87a36bff1cb88fd30a509fd366c70ec30676517ee791b2f77e0e29817a/requests_toolbelt-0.10.1-py2.py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "1.26.20"}, "download_info": {"url": "https://files.pythonhosted.org/packages/33/cf/8435d5a7159e2a9c83a95896ed596f68cf798005fe107cc655b5c5c14704/urllib3-1.26.20-py2.py3-none-any.whl"}}, {"metadata": {"name": "websockets", "version": "10.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/d7/df17197565e8874f0a77f8211304169ad4f39ffa3e8c008a7b0bf187a238/websockets-10.4-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "yarl", "version": "1.22.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/58/b8055273c203968e89808413ea4c984988b6649baabf10f4522e67c22d2f/yarl-1.22.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "responses", "version": "0.26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/28/693e1d9ebf72baa062ded80d837a035b86ce75eda5a269379e9e2b1008a8/responses-0.26.2-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.6.17"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/de/ad9d82ca8e5fa8f0c636e64606553c79e2b859ad253030b62a21fe9986f5/frozenlist-1.8.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "propcache", "version": "0.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/19/b65d98ae21384518b291d9939e24a8aeac4fdb5101b732576f8f7540e834/propcache-0.4.1-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "six", "version": "1.17.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ae/92/861f152ce87c452b11b9d0977952259aa7df792d71c1053365cc7b09cc08/pyyaml-6.0.3-cp39-cp39-macosx_11_0_arm64.whl"}}], "install_targets_hash": "ec03e83b12e89730c3e80a2126d3d0ca"} {"python_version": "3.9", "dependencies": [{"metadata": {"name": "langchain", "version": "0.3.30"}, "download_info": {"url": "https://files.pythonhosted.org/packages/da/54/c0775c29bf9ae27c8cbf8484ad600edd2e787a0eacf3a374cb6561613de9/langchain-0.3.30-py3-none-any.whl"}}, {"metadata": {"name": "async-timeout", "version": "4.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a7/fa/e01228c2938de91d47b307831c62ab9e4001e747789d0b05baf779a6488c/async_timeout-4.0.3-py3-none-any.whl"}}, {"metadata": {"name": "langchain-core", "version": "0.3.86"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0c/93/ba19ca54701c6118e68f8785949b6c0eab1df3a5cfa5310508cc86877994/langchain_core-0.3.86-py3-none-any.whl"}}, {"metadata": {"name": "jsonpatch", "version": "1.33"}, "download_info": {"url": "https://files.pythonhosted.org/packages/73/07/02e16ed01e04a374e644b575638ec7987ae846d25ad97bcc9945a3ee4b0e/jsonpatch-1.33-py2.py3-none-any.whl"}}, {"metadata": {"name": "langchain-text-splitters", "version": "0.3.11"}, "download_info": {"url": "https://files.pythonhosted.org/packages/58/0d/41a51b40d24ff0384ec4f7ab8dd3dcea8353c05c973836b5e289f1465d4f/langchain_text_splitters-0.3.11-py3-none-any.whl"}}, {"metadata": {"name": "langsmith", "version": "0.4.37"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/e8/edff4de49cf364eb9ee88d13da0a555844df32438413bf53d90d507b97cd/langsmith-0.4.37-py3-none-any.whl"}}, {"metadata": {"name": "httpx", "version": "0.28.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"metadata": {"name": "httpcore", "version": "1.0.9"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "25.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl"}}, {"metadata": {"name": "pydantic", "version": "2.13.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl"}}, {"metadata": {"name": "pydantic_core", "version": "2.46.4"}, "download_info": {"url": "https://files.pythonhosted.org/packages/41/60/e70fa1ee03e243bdfd4b1fddf1e1f2a8fba681df3034b51b9376c0fb5bf5/pydantic_core-2.46.4-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "PyYAML", "version": "6.0.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ae/92/861f152ce87c452b11b9d0977952259aa7df792d71c1053365cc7b09cc08/pyyaml-6.0.3-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "requests", "version": "2.32.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl"}}, {"metadata": {"name": "charset-normalizer", "version": "3.5.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d0/91/bc145e42f93d6601b9a26f5421af2d7c3093ae6e6d03b8e583c9cebbf530/charset_normalizer-3.5.1-cp39-cp39-macosx_10_9_universal2.whl"}}, {"metadata": {"name": "idna", "version": "3.19"}, "download_info": {"url": "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl"}}, {"metadata": {"name": "SQLAlchemy", "version": "2.0.52"}, "download_info": {"url": "https://files.pythonhosted.org/packages/48/4b/c5c0fe0b2d606b34618933f7448ebf93e1aeb60d896149a8061b7ac5bfd9/sqlalchemy-2.0.52-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "tenacity", "version": "9.1.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e5/30/643397144bfbfec6f6ef821f36f33e57d35946c44a2352d3c9f0ae847619/tenacity-9.1.2-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}, {"metadata": {"name": "urllib3", "version": "2.6.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl"}}, {"metadata": {"name": "uuid_utils", "version": "0.15.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/1d/c8/5a05247c1b7cbf49849523e1a26e3a8a76c0c1ec6dc84c7cc7b9a8c66503/uuid_utils-0.15.0-cp39-cp39-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/93/2fa34714b7a4ae72f2f8dad66ba17dd9a2c793220719e736dda28b7aec27/pytest_asyncio-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "openai", "version": "2.48.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/b5/2a/dcb891114e303c4379d4a498f10222e33eee540bcef4e1e493bd0af2b242/openai-2.48.0-py3-none-any.whl"}}, {"metadata": {"name": "anyio", "version": "4.12.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl"}}, {"metadata": {"name": "distro", "version": "1.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"metadata": {"name": "jiter", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/69/79/7b84250429f0e262b935c627a8522cab31b5303e617400b14e808b599bdb/jiter-0.16.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "langchain-openai", "version": "0.3.35"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d8/d5/c90c5478215c20ee71d8feaf676f7ffd78d0568f8c98bd83f81ce7562ed7/langchain_openai-0.3.35-py3-none-any.whl"}}, {"metadata": {"name": "tiktoken", "version": "0.14.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ff/b2/9a49f8a9923167adfb25429415a66b46b6c22a9ff357a3393c1e334408b4/tiktoken-0.14.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "langchain-community", "version": "0.3.31"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e6/0a/b8848db67ad7c8d4652cb6f4cb78d49b5b5e6e8e51d695d62025aa3f7dbc/langchain_community-0.3.31-py3-none-any.whl"}}, {"metadata": {"name": "aiohttp", "version": "3.13.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d5/34/8413eafee3421ade2d6ce9e7c0da1213e1d7f0049be09dcdc342b03a39ba/aiohttp-3.13.5-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "dataclasses-json", "version": "0.6.7"}, "download_info": {"url": "https://files.pythonhosted.org/packages/c3/be/d0d44e092656fe7a06b55e6103cbce807cdbdee17884a5367c68c9860853/dataclasses_json-0.6.7-py3-none-any.whl"}}, {"metadata": {"name": "httpx-sse", "version": "0.4.3"}, "download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"metadata": {"name": "marshmallow", "version": "3.26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/be/2f/5108cb3ee4ba6501748c4908b908e55f42a5b66245b4cfe0c99326e1ef6e/marshmallow-3.26.2-py3-none-any.whl"}}, {"metadata": {"name": "multidict", "version": "6.7.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/83/9c/1d2a283d9c6f31e260cb6c2fccadc3edcf6c4c14ee0929cd2af4d2606dd7/multidict-6.7.1-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pydantic-settings", "version": "2.11.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/83/d6/887a1ff844e64aa823fb4905978d882a633cfe295c32eacad582b78a7d8b/pydantic_settings-2.11.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspect", "version": "0.9.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/65/f3/107a22063bf27bdccf2024833d3445f4eea42b2e598abfbd46f6a63b6cb0/typing_inspect-0.9.0-py3-none-any.whl"}}, {"metadata": {"name": "yarl", "version": "1.22.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/32/58/b8055273c203968e89808413ea4c984988b6649baabf10f4522e67c22d2f/yarl-1.22.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "aiohappyeyeballs", "version": "2.6.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl"}}, {"metadata": {"name": "aiosignal", "version": "1.4.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"metadata": {"name": "annotated-types", "version": "0.7.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"metadata": {"name": "attrs", "version": "26.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"metadata": {"name": "certifi", "version": "2026.7.22"}, "download_info": {"url": "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "frozenlist", "version": "1.8.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/de/ad9d82ca8e5fa8f0c636e64606553c79e2b859ad253030b62a21fe9986f5/frozenlist-1.8.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "h11", "version": "0.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "jsonpointer", "version": "3.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/92/5e77f98553e9e75130c78900d000368476aed74276eb8ae8796f65f00918/jsonpointer-3.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "mypy_extensions", "version": "1.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl"}}, {"metadata": {"name": "numpy", "version": "2.0.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/96/ff/06d1aa3eeb1c614eda245c1ba4fb88c483bee6520d361641331872ac4b82/numpy-2.0.2-cp39-cp39-macosx_14_0_arm64.whl"}}, {"metadata": {"name": "orjson", "version": "3.11.5"}, "download_info": {"url": "https://files.pythonhosted.org/packages/50/c7/7b682849dd4c9fb701a981669b964ea700516ecbd8e88f62aae07c6852bd/orjson-3.11.5-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl"}}, {"metadata": {"name": "propcache", "version": "0.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7c/19/b65d98ae21384518b291d9939e24a8aeac4fdb5101b732576f8f7540e834/propcache-0.4.1-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "Pygments", "version": "2.21.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl"}}, {"metadata": {"name": "python-dotenv", "version": "1.2.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/14/1b/a298b06749107c305e1fe0f814c6c74aea7b2f1e10989cb30f544a1b3253/python_dotenv-1.2.1-py3-none-any.whl"}}, {"metadata": {"name": "requests-toolbelt", "version": "1.0.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "tqdm", "version": "4.70.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl"}}, {"metadata": {"name": "typing-inspection", "version": "0.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"metadata": {"name": "zstandard", "version": "0.25.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/ca/aa/ceb8d79cbad6dabd4cb1178ca853f6a4374d791c5e0241a0988173e2a341/zstandard-0.25.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "regex", "version": "2026.1.15"}, "download_info": {"url": "https://files.pythonhosted.org/packages/4b/d2/a2fef3717deaff647d7de2bccf899a576c7eaf042b6b271fc4474515fe97/regex-2026.1.15-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "sniffio", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}], "install_targets_hash": "f4e4bb9460bd93d74ce9abd6823fc735"} {"python_version": "3.9", "dependencies": [{"metadata": {"name": "asyncpg", "version": "0.31.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/13/38/bbb09ea041a935dc7720e283b6876c3487ace4b180b8d58c07db6cd8c941/asyncpg-0.31.0-cp39-cp39-macosx_11_0_arm64.whl"}}, {"metadata": {"name": "pytest-asyncio", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/04/93/2fa34714b7a4ae72f2f8dad66ba17dd9a2c793220719e736dda28b7aec27/pytest_asyncio-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "backports.asyncio.runner", "version": "1.2.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl"}}, {"metadata": {"name": "pytest", "version": "8.4.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl"}}, {"metadata": {"name": "pluggy", "version": "1.6.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl"}}, {"metadata": {"name": "async-timeout", "version": "5.0.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl"}}, {"metadata": {"name": "exceptiongroup", "version": "1.3.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"metadata": {"name": "iniconfig", "version": "2.1.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl"}}, {"metadata": {"name": "packaging", "version": "26.2"}, "download_info": {"url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl"}}, {"metadata": {"name": "Pygments", "version": "2.20.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"metadata": {"name": "tomli", "version": "2.4.1"}, "download_info": {"url": "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl"}}, {"metadata": {"name": "typing_extensions", "version": "4.16.0"}, "download_info": {"url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl"}}], "install_targets_hash": "f737563b075b37dba35f4a4e7631e9cd"} diff --git a/scripts/populate_tox/populate_tox.py b/scripts/populate_tox/populate_tox.py index d70af722f3..8a9be72df0 100644 --- a/scripts/populate_tox/populate_tox.py +++ b/scripts/populate_tox/populate_tox.py @@ -65,13 +65,10 @@ "aws_lambda", "cloud_resource_context", "common", - "integration_deactivation", "shadowed_module", "gcp", "gevent", - "opentelemetry", "otlp", - "potel", } # Free-threading is experimentally supported in 3.13, and officially supported in 3.14. diff --git a/scripts/populate_tox/releases.jsonl b/scripts/populate_tox/releases.jsonl index 982dfc4f8d..8b715656a3 100644 --- a/scripts/populate_tox/releases.jsonl +++ b/scripts/populate_tox/releases.jsonl @@ -1,5 +1,212 @@ +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Framework :: Django", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Topic :: Internet :: WWW/HTTP", "Topic :: Internet :: WWW/HTTP :: Dynamic Content", "Topic :: Internet :: WWW/HTTP :: WSGI", "Topic :: Software Development :: Libraries :: Application Frameworks", "Topic :: Software Development :: Libraries :: Python Modules"], "name": "Django", "requires_python": ">=3.4", "version": "2.0.13", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "Django-2.0.13-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "Django-2.0.13.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Framework :: Django", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Topic :: Internet :: WWW/HTTP", "Topic :: Internet :: WWW/HTTP :: Dynamic Content", "Topic :: Internet :: WWW/HTTP :: WSGI", "Topic :: Software Development :: Libraries :: Application Frameworks", "Topic :: Software Development :: Libraries :: Python Modules"], "name": "Django", "requires_python": ">=3.5", "version": "2.2.28", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "Django-2.2.28-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "Django-2.2.28.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Framework :: Django", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Topic :: Internet :: WWW/HTTP", "Topic :: Internet :: WWW/HTTP :: Dynamic Content", "Topic :: Internet :: WWW/HTTP :: WSGI", "Topic :: Software Development :: Libraries :: Application Frameworks", "Topic :: Software Development :: Libraries :: Python Modules"], "name": "Django", "requires_python": ">=3.6", "version": "3.2.25", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "Django-3.2.25-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "Django-3.2.25.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Framework :: Django", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Topic :: Internet :: WWW/HTTP", "Topic :: Internet :: WWW/HTTP :: Dynamic Content", "Topic :: Internet :: WWW/HTTP :: WSGI", "Topic :: Software Development :: Libraries :: Application Frameworks", "Topic :: Software Development :: Libraries :: Python Modules"], "name": "Django", "requires_python": ">=3.8", "version": "4.2.30", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "django-4.2.30-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "django-4.2.30.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Framework :: Django", "Intended Audience :: Developers", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Topic :: Internet :: WWW/HTTP", "Topic :: Internet :: WWW/HTTP :: Dynamic Content", "Topic :: Internet :: WWW/HTTP :: WSGI", "Topic :: Software Development :: Libraries :: Application Frameworks", "Topic :: Software Development :: Libraries :: Python Modules"], "name": "Django", "requires_python": ">=3.10", "version": "5.2.17", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "django-5.2.17-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "django-5.2.17.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Framework :: Django", "Intended Audience :: Developers", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Topic :: Internet :: WWW/HTTP", "Topic :: Internet :: WWW/HTTP :: Dynamic Content", "Topic :: Internet :: WWW/HTTP :: WSGI", "Topic :: Software Development :: Libraries :: Application Frameworks", "Topic :: Software Development :: Libraries :: Python Modules"], "name": "Django", "requires_python": ">=3.12", "version": "6.1.1", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "django-6.1.1-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "django-6.1.1.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Framework :: Flask", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python", "Topic :: Internet :: WWW/HTTP :: Dynamic Content", "Topic :: Internet :: WWW/HTTP :: WSGI", "Topic :: Internet :: WWW/HTTP :: WSGI :: Application", "Topic :: Software Development :: Libraries :: Application Frameworks"], "name": "Flask", "requires_python": ">=3.6", "version": "2.0.3", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "Flask-2.0.3-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "Flask-2.0.3.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Framework :: Flask", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python", "Topic :: Internet :: WWW/HTTP :: Dynamic Content", "Topic :: Internet :: WWW/HTTP :: WSGI", "Topic :: Internet :: WWW/HTTP :: WSGI :: Application", "Topic :: Software Development :: Libraries :: Application Frameworks"], "name": "Flask", "requires_python": ">=3.8", "version": "2.3.3", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "flask-2.3.3-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "flask-2.3.3.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Framework :: Flask", "Intended Audience :: Developers", "Operating System :: OS Independent", "Programming Language :: Python", "Topic :: Internet :: WWW/HTTP :: Dynamic Content", "Topic :: Internet :: WWW/HTTP :: WSGI", "Topic :: Internet :: WWW/HTTP :: WSGI :: Application", "Topic :: Software Development :: Libraries :: Application Frameworks", "Typing :: Typed"], "name": "Flask", "requires_python": ">=3.9", "version": "3.1.3", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "flask-3.1.3-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "flask-3.1.3.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Intended Audience :: Developers", "Operating System :: OS Independent", "Programming Language :: Python", "Topic :: Internet :: WWW/HTTP :: Dynamic Content", "Topic :: Text Processing :: Markup :: HTML", "Typing :: Typed"], "name": "MarkupSafe", "requires_python": ">=3.9", "version": "3.0.3", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp310-cp310-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp310-cp310-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp310-cp310-musllinux_1_2_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp310-cp310-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp310-cp310-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp310-cp310-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp310-cp310-win_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp311-cp311-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp311-cp311-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp311-cp311-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp311-cp311-musllinux_1_2_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp311-cp311-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp311-cp311-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp311-cp311-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp311-cp311-win_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp312-cp312-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp312-cp312-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp312-cp312-win_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp313-cp313-musllinux_1_2_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp313-cp313t-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp313-cp313t-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp313-cp313t-win_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp313-cp313-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp313-cp313-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp313-cp313-win_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp314-cp314-macosx_10_13_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp314-cp314-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp314-cp314-musllinux_1_2_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp314-cp314-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp314-cp314t-macosx_10_13_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp314-cp314t-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp314-cp314t-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp314-cp314t-win_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp314-cp314-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp314-cp314-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp314-cp314-win_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp39-cp39-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp39-cp39-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp39-cp39-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp39-cp39-musllinux_1_2_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp39-cp39-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp39-cp39-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp39-cp39-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "markupsafe-3.0.3-cp39-cp39-win_arm64.whl"}, {"packagetype": "sdist", "filename": "markupsafe-3.0.3.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 4 - Beta", "Environment :: Web Environment", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Topic :: Internet :: WWW/HTTP :: Dynamic Content", "Topic :: Software Development :: Libraries :: Python Modules"], "name": "Quart", "requires_python": ">=3.8", "version": "0.19.9", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "quart-0.19.9-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "quart-0.19.9.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 4 - Beta", "Environment :: Web Environment", "Framework :: Flask", "Intended Audience :: Developers", "Operating System :: OS Independent", "Programming Language :: Python", "Topic :: Internet :: WWW/HTTP :: Dynamic Content", "Topic :: Software Development :: Libraries :: Application Frameworks", "Typing :: Typed"], "name": "Quart", "requires_python": ">=3.13", "version": "0.23.1", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "quart-0.23.1-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "quart-0.23.1.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Database :: Front-Ends"], "name": "SQLAlchemy", "requires_python": "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7", "version": "1.4.54", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "SQLAlchemy-1.4.54-cp310-cp310-macosx_12_0_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "SQLAlchemy-1.4.54-cp310-cp310-manylinux1_x86_64.manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_5_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "SQLAlchemy-1.4.54-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "SQLAlchemy-1.4.54-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "SQLAlchemy-1.4.54-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "SQLAlchemy-1.4.54-cp310-cp310-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "SQLAlchemy-1.4.54-cp310-cp310-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "SQLAlchemy-1.4.54-cp311-cp311-macosx_10_9_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "SQLAlchemy-1.4.54-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "SQLAlchemy-1.4.54-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "SQLAlchemy-1.4.54-cp311-cp311-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "SQLAlchemy-1.4.54-cp311-cp311-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "SQLAlchemy-1.4.54-cp312-cp312-macosx_10_9_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "SQLAlchemy-1.4.54-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "SQLAlchemy-1.4.54-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "SQLAlchemy-1.4.54-cp312-cp312-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "SQLAlchemy-1.4.54-cp312-cp312-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "SQLAlchemy-1.4.54-cp36-cp36m-macosx_10_14_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "SQLAlchemy-1.4.54-cp36-cp36m-manylinux1_x86_64.manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_5_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "SQLAlchemy-1.4.54-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "SQLAlchemy-1.4.54-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "SQLAlchemy-1.4.54-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "SQLAlchemy-1.4.54-cp37-cp37m-macosx_11_0_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "SQLAlchemy-1.4.54-cp37-cp37m-manylinux1_x86_64.manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_5_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "SQLAlchemy-1.4.54-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "SQLAlchemy-1.4.54-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "SQLAlchemy-1.4.54-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "SQLAlchemy-1.4.54-cp37-cp37m-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "SQLAlchemy-1.4.54-cp37-cp37m-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "SQLAlchemy-1.4.54-cp38-cp38-macosx_12_0_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "SQLAlchemy-1.4.54-cp38-cp38-manylinux1_x86_64.manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_5_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "SQLAlchemy-1.4.54-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "SQLAlchemy-1.4.54-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "SQLAlchemy-1.4.54-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "SQLAlchemy-1.4.54-cp38-cp38-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "SQLAlchemy-1.4.54-cp38-cp38-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "SQLAlchemy-1.4.54-cp39-cp39-macosx_12_0_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "SQLAlchemy-1.4.54-cp39-cp39-manylinux1_x86_64.manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_5_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "SQLAlchemy-1.4.54-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "SQLAlchemy-1.4.54-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "SQLAlchemy-1.4.54-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "SQLAlchemy-1.4.54-cp39-cp39-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "SQLAlchemy-1.4.54-cp39-cp39-win_amd64.whl"}, {"packagetype": "sdist", "filename": "sqlalchemy-1.4.54.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Programming Language :: Python :: 3.15", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Database :: Front-Ends"], "name": "SQLAlchemy", "requires_python": ">=3.7", "version": "2.0.54", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.54-cp310-cp310-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.54-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.54-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.54-cp310-cp310-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.54-cp310-cp310-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.54-cp310-cp310-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.54-cp310-cp310-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.54-cp311-cp311-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.54-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.54-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.54-cp311-cp311-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.54-cp311-cp311-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.54-cp311-cp311-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.54-cp311-cp311-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.54-cp312-cp312-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.54-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.54-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.54-cp312-cp312-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.54-cp312-cp312-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.54-cp312-cp312-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.54-cp312-cp312-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.54-cp313-cp313-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.54-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.54-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.54-cp313-cp313-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.54-cp313-cp313-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.54-cp313-cp313-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.54-cp313-cp313-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.54-cp314-cp314-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.54-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.54-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.54-cp314-cp314-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.54-cp314-cp314-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.54-cp314-cp314t-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.54-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.54-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.54-cp314-cp314t-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.54-cp314-cp314t-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.54-cp314-cp314t-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.54-cp314-cp314t-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.54-cp314-cp314-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.54-cp314-cp314-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.54-cp38-cp38-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.54-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.54-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.54-cp38-cp38-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.54-cp38-cp38-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.54-cp38-cp38-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.54-cp38-cp38-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.54-cp39-cp39-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.54-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.54-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.54-cp39-cp39-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.54-cp39-cp39-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.54-cp39-cp39-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.54-cp39-cp39-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.54-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "sqlalchemy-2.0.54.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Programming Language :: Python :: 3.15", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Database :: Front-Ends"], "name": "SQLAlchemy", "requires_python": ">=3.11", "version": "2.1.0rc2", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp311-cp311-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp311-cp311-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp311-cp311-musllinux_1_2_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp311-cp311-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp311-cp311-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp311-cp311-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp311-cp311-win_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp312-cp312-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp312-cp312-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp312-cp312-musllinux_1_2_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp312-cp312-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp312-cp312-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp312-cp312-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp312-cp312-win_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp313-cp313-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp313-cp313-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp313-cp313-musllinux_1_2_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp313-cp313-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp313-cp313-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp313-cp313-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp313-cp313-win_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp314-cp314-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp314-cp314-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp314-cp314-musllinux_1_2_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp314-cp314-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp314-cp314t-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp314-cp314t-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp314-cp314t-musllinux_1_2_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp314-cp314t-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp314-cp314t-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp314-cp314t-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp314-cp314t-win_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp314-cp314-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp314-cp314-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp314-cp314-win_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp315-cp315-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp315-cp315-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp315-cp315-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp315-cp315-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp315-cp315-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp315-cp315-musllinux_1_2_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp315-cp315-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp315-cp315t-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp315-cp315t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp315-cp315t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp315-cp315t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp315-cp315t-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp315-cp315t-musllinux_1_2_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp315-cp315t-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp315-cp315t-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp315-cp315t-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp315-cp315t-win_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp315-cp315-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp315-cp315-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-cp315-cp315-win_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0rc2-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "sqlalchemy-2.1.0rc2.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Typing :: Typed"], "name": "UnleashClient", "requires_python": ">=3.8", "version": "6.0.1", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "UnleashClient-6.0.1-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "unleashclient-6.0.1.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Typing :: Typed"], "name": "UnleashClient", "requires_python": ">=3.8", "version": "6.8.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "unleashclient-6.8.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "unleashclient-6.8.0.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Framework :: AsyncIO", "Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "Operating System :: MacOS :: MacOS X", "Operating System :: Microsoft :: Windows", "Operating System :: POSIX", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.9", "Topic :: Internet :: WWW/HTTP"], "name": "aiohttp", "requires_python": ">=3.9", "version": "3.11.18", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp310-cp310-macosx_10_9_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp310-cp310-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp310-cp310-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp310-cp310-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp310-cp310-musllinux_1_2_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp310-cp310-musllinux_1_2_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp310-cp310-musllinux_1_2_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp310-cp310-musllinux_1_2_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp310-cp310-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp310-cp310-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp310-cp310-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp311-cp311-macosx_10_9_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp311-cp311-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp311-cp311-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp311-cp311-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp311-cp311-musllinux_1_2_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp311-cp311-musllinux_1_2_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp311-cp311-musllinux_1_2_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp311-cp311-musllinux_1_2_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp311-cp311-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp311-cp311-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp311-cp311-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp312-cp312-macosx_10_13_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp312-cp312-macosx_10_13_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp312-cp312-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp312-cp312-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp312-cp312-musllinux_1_2_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp312-cp312-musllinux_1_2_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp312-cp312-musllinux_1_2_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp312-cp312-musllinux_1_2_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp312-cp312-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp312-cp312-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp312-cp312-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp313-cp313-macosx_10_13_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp313-cp313-macosx_10_13_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp313-cp313-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp313-cp313-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp313-cp313-musllinux_1_2_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp313-cp313-musllinux_1_2_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp313-cp313-musllinux_1_2_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp313-cp313-musllinux_1_2_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp313-cp313-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp313-cp313-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp313-cp313-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp39-cp39-macosx_10_9_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp39-cp39-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp39-cp39-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp39-cp39-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp39-cp39-musllinux_1_2_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp39-cp39-musllinux_1_2_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp39-cp39-musllinux_1_2_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp39-cp39-musllinux_1_2_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp39-cp39-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp39-cp39-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.11.18-cp39-cp39-win_amd64.whl"}, {"packagetype": "sdist", "filename": "aiohttp-3.11.18.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Sta\u00df\u00df\u00dfble", "Framework :: AsyncIO", "Intended Audience :: Developers", "Operating System :: MacOS :: MacOS X", "Operating System :: Microsoft :: Windows", "Operating System :: POSIX", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Topic :: Internet :: WWW/HTTP"], "name": "aiohttp", "requires_python": ">=3.10", "version": "3.14.3", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp310-cp310-macosx_10_9_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp310-cp310-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp310-cp310-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp310-cp310-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp310-cp310-musllinux_1_2_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp310-cp310-musllinux_1_2_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp310-cp310-musllinux_1_2_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp310-cp310-musllinux_1_2_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp310-cp310-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp310-cp310-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp310-cp310-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp310-cp310-win_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp311-cp311-macosx_10_9_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp311-cp311-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp311-cp311-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp311-cp311-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp311-cp311-musllinux_1_2_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp311-cp311-musllinux_1_2_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp311-cp311-musllinux_1_2_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp311-cp311-musllinux_1_2_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp311-cp311-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp311-cp311-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp311-cp311-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp311-cp311-win_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp312-cp312-macosx_10_13_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp312-cp312-macosx_10_13_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp312-cp312-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp312-cp312-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp312-cp312-musllinux_1_2_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp312-cp312-musllinux_1_2_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp312-cp312-musllinux_1_2_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp312-cp312-musllinux_1_2_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp312-cp312-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp312-cp312-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp312-cp312-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp312-cp312-win_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp313-cp313-android_21_arm64_v8a.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp313-cp313-android_21_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp313-cp313-ios_13_0_arm64_iphoneos.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp313-cp313-macosx_10_13_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp313-cp313-macosx_10_13_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp313-cp313-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp313-cp313-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp313-cp313-musllinux_1_2_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp313-cp313-musllinux_1_2_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp313-cp313-musllinux_1_2_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp313-cp313-musllinux_1_2_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp313-cp313-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp313-cp313-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp313-cp313-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp313-cp313-win_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp314-cp314-android_24_arm64_v8a.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp314-cp314-android_24_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp314-cp314-ios_13_0_arm64_iphoneos.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp314-cp314-macosx_10_15_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp314-cp314-macosx_10_15_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp314-cp314-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp314-cp314-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp314-cp314-musllinux_1_2_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp314-cp314-musllinux_1_2_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp314-cp314-musllinux_1_2_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp314-cp314-musllinux_1_2_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp314-cp314-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp314-cp314t-macosx_10_15_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp314-cp314t-macosx_10_15_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp314-cp314t-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp314-cp314t-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp314-cp314t-musllinux_1_2_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp314-cp314t-musllinux_1_2_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp314-cp314t-musllinux_1_2_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp314-cp314t-musllinux_1_2_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp314-cp314t-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp314-cp314t-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp314-cp314t-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp314-cp314t-win_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp314-cp314-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp314-cp314-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.14.3-cp314-cp314-win_arm64.whl"}, {"packagetype": "sdist", "filename": "aiohttp-3.14.3.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Framework :: AsyncIO", "Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "Operating System :: MacOS :: MacOS X", "Operating System :: Microsoft :: Windows", "Operating System :: POSIX", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Topic :: Internet :: WWW/HTTP"], "name": "aiohttp", "requires_python": ">=3.6", "version": "3.7.4", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "aiohttp-3.7.4-cp36-cp36m-macosx_10_14_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.7.4-cp36-cp36m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.7.4-cp36-cp36m-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.7.4-cp36-cp36m-manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.7.4-cp36-cp36m-manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.7.4-cp36-cp36m-manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.7.4-cp36-cp36m-manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.7.4-cp36-cp36m-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.7.4-cp36-cp36m-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.7.4-cp37-cp37m-macosx_10_14_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.7.4-cp37-cp37m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.7.4-cp37-cp37m-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.7.4-cp37-cp37m-manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.7.4-cp37-cp37m-manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.7.4-cp37-cp37m-manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.7.4-cp37-cp37m-manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.7.4-cp37-cp37m-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.7.4-cp37-cp37m-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.7.4-cp38-cp38-macosx_10_14_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.7.4-cp38-cp38-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.7.4-cp38-cp38-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.7.4-cp38-cp38-manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.7.4-cp38-cp38-manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.7.4-cp38-cp38-manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.7.4-cp38-cp38-manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.7.4-cp38-cp38-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.7.4-cp38-cp38-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.7.4-cp39-cp39-macosx_10_14_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.7.4-cp39-cp39-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.7.4-cp39-cp39-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.7.4-cp39-cp39-manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.7.4-cp39-cp39-manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.7.4-cp39-cp39-manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.7.4-cp39-cp39-manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.7.4-cp39-cp39-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.7.4-cp39-cp39-win_amd64.whl"}, {"packagetype": "sdist", "filename": "aiohttp-3.7.4.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Framework :: AsyncIO", "Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "Operating System :: MacOS :: MacOS X", "Operating System :: Microsoft :: Windows", "Operating System :: POSIX", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Topic :: Internet :: WWW/HTTP"], "name": "aiohttp", "requires_python": ">=3.8", "version": "3.9.5", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp310-cp310-macosx_10_9_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp310-cp310-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp310-cp310-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp310-cp310-musllinux_1_1_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp310-cp310-musllinux_1_1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp310-cp310-musllinux_1_1_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp310-cp310-musllinux_1_1_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp310-cp310-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp310-cp310-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp310-cp310-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp311-cp311-macosx_10_9_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp311-cp311-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp311-cp311-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp311-cp311-musllinux_1_1_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp311-cp311-musllinux_1_1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp311-cp311-musllinux_1_1_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp311-cp311-musllinux_1_1_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp311-cp311-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp311-cp311-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp311-cp311-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp312-cp312-macosx_10_9_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp312-cp312-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp312-cp312-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp312-cp312-musllinux_1_1_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp312-cp312-musllinux_1_1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp312-cp312-musllinux_1_1_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp312-cp312-musllinux_1_1_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp312-cp312-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp312-cp312-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp312-cp312-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp38-cp38-macosx_10_9_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp38-cp38-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp38-cp38-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp38-cp38-musllinux_1_1_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp38-cp38-musllinux_1_1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp38-cp38-musllinux_1_1_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp38-cp38-musllinux_1_1_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp38-cp38-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp38-cp38-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp38-cp38-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp39-cp39-macosx_10_9_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp39-cp39-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp39-cp39-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp39-cp39-musllinux_1_1_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp39-cp39-musllinux_1_1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp39-cp39-musllinux_1_1_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp39-cp39-musllinux_1_1_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp39-cp39-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp39-cp39-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.9.5-cp39-cp39-win_amd64.whl"}, {"packagetype": "sdist", "filename": "aiohttp-3.9.5.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 3 - Alpha", "Environment :: Web Environment", "Framework :: AsyncIO", "Intended Audience :: Developers", "Operating System :: POSIX", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.9", "Topic :: Database", "Topic :: Database :: Front-Ends"], "name": "aiomysql", "requires_python": ">=3.9", "version": "0.3.2", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "aiomysql-0.3.2-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "aiomysql-0.3.2.tar.gz"}]} +{"info": {"classifiers": ["Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: MacOS", "Operating System :: Microsoft :: Windows", "Operating System :: OS Independent", "Operating System :: POSIX", "Operating System :: POSIX :: Linux", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Programming Language :: Python :: 3.9", "Topic :: Software Development :: Libraries :: Python Modules", "Typing :: Typed"], "name": "anthropic", "requires_python": ">=3.9", "version": "0.125.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "anthropic-0.125.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "anthropic-0.125.0.tar.gz"}]} +{"info": {"classifiers": ["Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: MacOS", "Operating System :: Microsoft :: Windows", "Operating System :: OS Independent", "Operating System :: POSIX", "Operating System :: POSIX :: Linux", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Topic :: Software Development :: Libraries :: Python Modules", "Typing :: Typed"], "name": "anthropic", "requires_python": ">=3.7", "version": "0.16.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "anthropic-0.16.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "anthropic-0.16.0.tar.gz"}]} +{"info": {"classifiers": ["Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: MacOS", "Operating System :: Microsoft :: Windows", "Operating System :: OS Independent", "Operating System :: POSIX", "Operating System :: POSIX :: Linux", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Topic :: Software Development :: Libraries :: Python Modules", "Typing :: Typed"], "name": "anthropic", "requires_python": ">=3.10", "version": "1.7.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "anthropic-1.7.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "anthropic-1.7.0.tar.gz"}]} +{"info": {"classifiers": ["Intended Audience :: End Users/Desktop", "License :: OSI Approved :: Apache Software License", "Operating System :: POSIX :: Linux", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3.5", "Topic :: Software Development :: Libraries", "Topic :: Software Development :: Libraries :: Python Modules"], "name": "apache-beam", "requires_python": ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*", "version": "2.12.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "apache_beam-2.12.0-cp27-cp27m-macosx_10_6_intel.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.12.0-cp27-cp27m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.12.0-cp27-cp27m-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.12.0-cp27-cp27mu-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.12.0-cp27-cp27mu-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.12.0-cp35-cp35m-macosx_10_6_intel.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.12.0-cp35-cp35m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.12.0-cp35-cp35m-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.12.0-cp36-cp36m-macosx_10_6_intel.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.12.0-cp36-cp36m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.12.0-cp36-cp36m-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.12.0-cp37-cp37m-macosx_10_6_intel.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.12.0-cp37-cp37m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.12.0-cp37-cp37m-manylinux1_x86_64.whl"}, {"packagetype": "sdist", "filename": "apache-beam-2.12.0.zip"}]} +{"info": {"classifiers": ["Intended Audience :: End Users/Desktop", "License :: OSI Approved :: Apache Software License", "Operating System :: POSIX :: Linux", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3.5", "Topic :: Software Development :: Libraries", "Topic :: Software Development :: Libraries :: Python Modules"], "name": "apache-beam", "requires_python": ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*", "version": "2.13.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "apache_beam-2.13.0-cp27-cp27m-macosx_10_6_intel.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.13.0-cp27-cp27m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.13.0-cp27-cp27m-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.13.0-cp27-cp27mu-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.13.0-cp27-cp27mu-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.13.0-cp35-cp35m-macosx_10_6_intel.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.13.0-cp35-cp35m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.13.0-cp35-cp35m-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.13.0-cp36-cp36m-macosx_10_6_intel.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.13.0-cp36-cp36m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.13.0-cp36-cp36m-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.13.0-cp37-cp37m-macosx_10_6_intel.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.13.0-cp37-cp37m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.13.0-cp37-cp37m-manylinux1_x86_64.whl"}, {"packagetype": "sdist", "filename": "apache-beam-2.13.0.zip"}]} +{"info": {"classifiers": ["Intended Audience :: End Users/Desktop", "License :: OSI Approved :: Apache Software License", "Operating System :: POSIX :: Linux", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Topic :: Software Development :: Libraries", "Topic :: Software Development :: Libraries :: Python Modules"], "name": "apache-beam", "requires_python": ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*", "version": "2.14.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "apache_beam-2.14.0-cp27-cp27m-macosx_10_6_intel.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.14.0-cp27-cp27m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.14.0-cp27-cp27m-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.14.0-cp27-cp27mu-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.14.0-cp27-cp27mu-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.14.0-cp35-cp35m-macosx_10_6_intel.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.14.0-cp35-cp35m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.14.0-cp35-cp35m-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.14.0-cp36-cp36m-macosx_10_6_intel.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.14.0-cp36-cp36m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.14.0-cp36-cp36m-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.14.0-cp37-cp37m-macosx_10_6_intel.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.14.0-cp37-cp37m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.14.0-cp37-cp37m-manylinux1_x86_64.whl"}, {"packagetype": "sdist", "filename": "apache-beam-2.14.0.zip"}]} +{"info": {"classifiers": ["Intended Audience :: End Users/Desktop", "License :: OSI Approved :: Apache Software License", "Operating System :: POSIX :: Linux", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Topic :: Software Development :: Libraries", "Topic :: Software Development :: Libraries :: Python Modules"], "name": "apache-beam", "requires_python": ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*", "version": "2.16.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "apache_beam-2.16.0-cp27-cp27m-macosx_10_6_intel.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.16.0-cp27-cp27m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.16.0-cp27-cp27m-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.16.0-cp27-cp27mu-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.16.0-cp27-cp27mu-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.16.0-cp35-cp35m-macosx_10_6_intel.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.16.0-cp35-cp35m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.16.0-cp35-cp35m-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.16.0-cp36-cp36m-macosx_10_6_intel.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.16.0-cp36-cp36m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.16.0-cp36-cp36m-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.16.0-cp37-cp37m-macosx_10_6_intel.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.16.0-cp37-cp37m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.16.0-cp37-cp37m-manylinux1_x86_64.whl"}, {"packagetype": "sdist", "filename": "apache-beam-2.16.0.zip"}]} +{"info": {"classifiers": ["Intended Audience :: End Users/Desktop", "License :: OSI Approved :: Apache Software License", "Operating System :: POSIX :: Linux", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Topic :: Software Development :: Libraries", "Topic :: Software Development :: Libraries :: Python Modules"], "name": "apache-beam", "requires_python": ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*", "version": "2.20.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "apache_beam-2.20.0-cp27-cp27m-macosx_10_6_intel.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.20.0-cp27-cp27m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.20.0-cp27-cp27m-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.20.0-cp27-cp27mu-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.20.0-cp27-cp27mu-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.20.0-cp35-cp35m-macosx_10_6_intel.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.20.0-cp35-cp35m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.20.0-cp35-cp35m-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.20.0-cp36-cp36m-macosx_10_6_intel.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.20.0-cp36-cp36m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.20.0-cp36-cp36m-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.20.0-cp37-cp37m-macosx_10_6_intel.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.20.0-cp37-cp37m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.20.0-cp37-cp37m-manylinux1_x86_64.whl"}, {"packagetype": "sdist", "filename": "apache-beam-2.20.0.zip"}]} +{"info": {"classifiers": ["Intended Audience :: End Users/Desktop", "License :: OSI Approved :: Apache Software License", "Operating System :: POSIX :: Linux", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Topic :: Software Development :: Libraries", "Topic :: Software Development :: Libraries :: Python Modules"], "name": "apache-beam", "requires_python": ">=3.6", "version": "2.28.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "apache_beam-2.28.0-cp36-cp36m-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.28.0-cp36-cp36m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.28.0-cp36-cp36m-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.28.0-cp36-cp36m-manylinux2010_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.28.0-cp36-cp36m-manylinux2010_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.28.0-cp36-cp36m-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.28.0-cp36-cp36m-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.28.0-cp37-cp37m-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.28.0-cp37-cp37m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.28.0-cp37-cp37m-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.28.0-cp37-cp37m-manylinux2010_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.28.0-cp37-cp37m-manylinux2010_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.28.0-cp37-cp37m-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.28.0-cp37-cp37m-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.28.0-cp38-cp38-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.28.0-cp38-cp38-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.28.0-cp38-cp38-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.28.0-cp38-cp38-manylinux2010_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.28.0-cp38-cp38-manylinux2010_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.28.0-cp38-cp38-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.28.0-cp38-cp38-win_amd64.whl"}, {"packagetype": "sdist", "filename": "apache-beam-2.28.0.zip"}]} +{"info": {"classifiers": ["Intended Audience :: End Users/Desktop", "License :: OSI Approved :: Apache Software License", "Operating System :: POSIX :: Linux", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Topic :: Software Development :: Libraries", "Topic :: Software Development :: Libraries :: Python Modules"], "name": "apache-beam", "requires_python": ">=3.7", "version": "2.44.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "apache_beam-2.44.0-cp310-cp310-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.44.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.44.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.44.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.44.0-cp310-cp310-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.44.0-cp310-cp310-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.44.0-cp37-cp37m-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.44.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.44.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.44.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.44.0-cp37-cp37m-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.44.0-cp37-cp37m-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.44.0-cp38-cp38-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.44.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.44.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.44.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.44.0-cp38-cp38-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.44.0-cp38-cp38-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.44.0-cp39-cp39-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.44.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.44.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.44.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.44.0-cp39-cp39-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.44.0-cp39-cp39-win_amd64.whl"}, {"packagetype": "sdist", "filename": "apache-beam-2.44.0.zip"}]} +{"info": {"classifiers": ["Intended Audience :: End Users/Desktop", "License :: OSI Approved :: Apache Software License", "Operating System :: POSIX :: Linux", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Topic :: Software Development :: Libraries", "Topic :: Software Development :: Libraries :: Python Modules"], "name": "apache-beam", "requires_python": ">=3.10", "version": "2.76.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "apache_beam-2.76.0-cp310-cp310-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.76.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.76.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.76.0-cp310-cp310-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.76.0-cp310-cp310-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.76.0-cp311-cp311-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.76.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.76.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.76.0-cp311-cp311-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.76.0-cp311-cp311-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.76.0-cp312-cp312-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.76.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.76.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.76.0-cp312-cp312-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.76.0-cp312-cp312-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.76.0-cp313-cp313-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.76.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.76.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.76.0-cp313-cp313-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.76.0-cp313-cp313-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.76.0-cp314-cp314-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.76.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.76.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.76.0-cp314-cp314-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.76.0-cp314-cp314-win_amd64.whl"}, {"packagetype": "sdist", "filename": "apache_beam-2.76.0.tar.gz"}]} +{"info": {"classifiers": ["Intended Audience :: End Users/Desktop", "License :: OSI Approved :: Apache Software License", "Operating System :: POSIX :: Linux", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Topic :: Software Development :: Libraries", "Topic :: Software Development :: Libraries :: Python Modules"], "name": "apache-beam", "requires_python": ">=3.10", "version": "2.77.0rc1", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "apache_beam-2.77.0rc1-cp310-cp310-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.77.0rc1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.77.0rc1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.77.0rc1-cp310-cp310-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.77.0rc1-cp310-cp310-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.77.0rc1-cp311-cp311-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.77.0rc1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.77.0rc1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.77.0rc1-cp311-cp311-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.77.0rc1-cp311-cp311-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.77.0rc1-cp312-cp312-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.77.0rc1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.77.0rc1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.77.0rc1-cp312-cp312-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.77.0rc1-cp312-cp312-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.77.0rc1-cp313-cp313-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.77.0rc1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.77.0rc1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.77.0rc1-cp313-cp313-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.77.0rc1-cp313-cp313-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.77.0rc1-cp314-cp314-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.77.0rc1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.77.0rc1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.77.0rc1-cp314-cp314-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.77.0rc1-cp314-cp314-win_amd64.whl"}, {"packagetype": "sdist", "filename": "apache_beam-2.77.0rc1.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Topic :: Software Development :: Libraries :: Python Modules"], "name": "ariadne", "requires_python": "", "version": "0.20.1", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "ariadne-0.20.1-py2.py3-none-any.whl"}, {"packagetype": "sdist", "filename": "ariadne-0.20.1.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Topic :: Internet :: WWW/HTTP", "Topic :: Software Development :: Libraries :: Python Modules"], "name": "ariadne", "requires_python": ">=3.10", "version": "1.1.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "ariadne-1.1.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "ariadne-1.1.0.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 4 - Beta", "Environment :: Console", "Framework :: AsyncIO", "Intended Audience :: Developers", "Intended Audience :: Information Technology", "Intended Audience :: System Administrators", "License :: OSI Approved :: MIT License", "Operating System :: POSIX :: Linux", "Operating System :: Unix", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Topic :: Internet", "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: System :: Clustering", "Topic :: System :: Distributed Computing", "Topic :: System :: Monitoring", "Topic :: System :: Systems Administration"], "name": "arq", "requires_python": ">=3.6", "version": "0.23", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "arq-0.23-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "arq-0.23.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Console", "Framework :: AsyncIO", "Intended Audience :: Developers", "Intended Audience :: Information Technology", "Intended Audience :: System Administrators", "License :: OSI Approved :: MIT License", "Operating System :: POSIX :: Linux", "Operating System :: Unix", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Programming Language :: Python :: 3.9", "Topic :: Internet", "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: System :: Clustering", "Topic :: System :: Distributed Computing", "Topic :: System :: Monitoring", "Topic :: System :: Systems Administration"], "name": "arq", "requires_python": ">=3.9", "version": "0.28.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "arq-0.28.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "arq-0.28.0.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Framework :: AsyncIO", "Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "Operating System :: MacOS :: MacOS X", "Operating System :: Microsoft :: Windows", "Operating System :: POSIX", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: Implementation :: CPython", "Topic :: Database :: Front-Ends"], "name": "asyncpg", "requires_python": ">=3.5.0", "version": "0.23.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "asyncpg-0.23.0-cp35-cp35m-macosx_10_14_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.23.0-cp35-cp35m-manylinux_2_5_x86_64.manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.23.0-cp36-cp36m-macosx_10_14_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.23.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.23.0-cp36-cp36m-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.23.0-cp37-cp37m-macosx_10_14_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.23.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.23.0-cp37-cp37m-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.23.0-cp38-cp38-macosx_10_14_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.23.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.23.0-cp38-cp38-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.23.0-cp39-cp39-macosx_10_14_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.23.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.23.0-cp39-cp39-win_amd64.whl"}, {"packagetype": "sdist", "filename": "asyncpg-0.23.0.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Framework :: AsyncIO", "Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "Operating System :: MacOS :: MacOS X", "Operating System :: Microsoft :: Windows", "Operating System :: POSIX", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: Implementation :: CPython", "Topic :: Database :: Front-Ends"], "name": "asyncpg", "requires_python": ">=3.6.0", "version": "0.26.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "asyncpg-0.26.0-cp310-cp310-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.26.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.26.0-cp310-cp310-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.26.0-cp310-cp310-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.26.0-cp310-cp310-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.26.0-cp36-cp36m-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.26.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.26.0-cp36-cp36m-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.26.0-cp36-cp36m-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.26.0-cp36-cp36m-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.26.0-cp37-cp37m-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.26.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.26.0-cp37-cp37m-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.26.0-cp37-cp37m-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.26.0-cp37-cp37m-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.26.0-cp38-cp38-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.26.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.26.0-cp38-cp38-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.26.0-cp38-cp38-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.26.0-cp38-cp38-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.26.0-cp39-cp39-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.26.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.26.0-cp39-cp39-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.26.0-cp39-cp39-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.26.0-cp39-cp39-win_amd64.whl"}, {"packagetype": "sdist", "filename": "asyncpg-0.26.0.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Framework :: AsyncIO", "Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "Operating System :: MacOS :: MacOS X", "Operating System :: Microsoft :: Windows", "Operating System :: POSIX", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: Implementation :: CPython", "Topic :: Database :: Front-Ends"], "name": "asyncpg", "requires_python": ">=3.8.0", "version": "0.29.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "asyncpg-0.29.0-cp310-cp310-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.29.0-cp310-cp310-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.29.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.29.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.29.0-cp310-cp310-musllinux_1_1_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.29.0-cp310-cp310-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.29.0-cp310-cp310-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.29.0-cp310-cp310-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.29.0-cp311-cp311-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.29.0-cp311-cp311-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.29.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.29.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.29.0-cp311-cp311-musllinux_1_1_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.29.0-cp311-cp311-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.29.0-cp311-cp311-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.29.0-cp311-cp311-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.29.0-cp312-cp312-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.29.0-cp312-cp312-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.29.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.29.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.29.0-cp312-cp312-musllinux_1_1_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.29.0-cp312-cp312-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.29.0-cp312-cp312-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.29.0-cp312-cp312-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.29.0-cp38-cp38-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.29.0-cp38-cp38-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.29.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.29.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.29.0-cp38-cp38-musllinux_1_1_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.29.0-cp38-cp38-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.29.0-cp38-cp38-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.29.0-cp38-cp38-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.29.0-cp39-cp39-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.29.0-cp39-cp39-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.29.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.29.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.29.0-cp39-cp39-musllinux_1_1_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.29.0-cp39-cp39-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.29.0-cp39-cp39-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.29.0-cp39-cp39-win_amd64.whl"}, {"packagetype": "sdist", "filename": "asyncpg-0.29.0.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Framework :: AsyncIO", "Intended Audience :: Developers", "Operating System :: MacOS :: MacOS X", "Operating System :: Microsoft :: Windows", "Operating System :: POSIX", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: Free Threading :: 2 - Beta", "Programming Language :: Python :: Implementation :: CPython", "Topic :: Database :: Front-Ends"], "name": "asyncpg", "requires_python": ">=3.9.0", "version": "0.31.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "asyncpg-0.31.0-cp310-cp310-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.31.0-cp310-cp310-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.31.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.31.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.31.0-cp310-cp310-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.31.0-cp310-cp310-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.31.0-cp310-cp310-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.31.0-cp310-cp310-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.31.0-cp311-cp311-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.31.0-cp311-cp311-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.31.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.31.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.31.0-cp311-cp311-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.31.0-cp311-cp311-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.31.0-cp311-cp311-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.31.0-cp311-cp311-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.31.0-cp312-cp312-macosx_10_13_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.31.0-cp312-cp312-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.31.0-cp312-cp312-manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.31.0-cp312-cp312-manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.31.0-cp312-cp312-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.31.0-cp312-cp312-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.31.0-cp312-cp312-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.31.0-cp312-cp312-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.31.0-cp313-cp313-macosx_10_13_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.31.0-cp313-cp313-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.31.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.31.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.31.0-cp313-cp313-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.31.0-cp313-cp313-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.31.0-cp313-cp313-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.31.0-cp313-cp313-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.31.0-cp314-cp314-macosx_10_15_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.31.0-cp314-cp314-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.31.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.31.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.31.0-cp314-cp314-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.31.0-cp314-cp314-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.31.0-cp314-cp314t-macosx_10_15_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.31.0-cp314-cp314t-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.31.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.31.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.31.0-cp314-cp314t-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.31.0-cp314-cp314t-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.31.0-cp314-cp314t-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.31.0-cp314-cp314t-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.31.0-cp314-cp314-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.31.0-cp314-cp314-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.31.0-cp39-cp39-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.31.0-cp39-cp39-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.31.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.31.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.31.0-cp39-cp39-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.31.0-cp39-cp39-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.31.0-cp39-cp39-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "asyncpg-0.31.0-cp39-cp39-win_amd64.whl"}, {"packagetype": "sdist", "filename": "asyncpg-0.31.0.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "Natural Language :: English", "Programming Language :: Python", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8"], "name": "boto3", "requires_python": "", "version": "1.16.63", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "boto3-1.16.63-py2.py3-none-any.whl"}, {"packagetype": "sdist", "filename": "boto3-1.16.63.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "Natural Language :: English", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9"], "name": "boto3", "requires_python": ">= 3.7", "version": "1.24.96", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "boto3-1.24.96-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "boto3-1.24.96.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "Natural Language :: English", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9"], "name": "boto3", "requires_python": ">=3.8", "version": "1.35.99", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "boto3-1.35.99-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "boto3-1.35.99.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "Natural Language :: English", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Programming Language :: Python :: Free Threading :: 2 - Beta"], "name": "boto3", "requires_python": ">=3.10", "version": "1.43.99", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "boto3-1.43.99-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "boto3-1.43.99.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 2.5", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.2", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Topic :: Internet :: WWW/HTTP :: Dynamic Content :: CGI Tools/Libraries", "Topic :: Internet :: WWW/HTTP :: HTTP Servers", "Topic :: Internet :: WWW/HTTP :: WSGI", "Topic :: Internet :: WWW/HTTP :: WSGI :: Application", "Topic :: Internet :: WWW/HTTP :: WSGI :: Middleware", "Topic :: Internet :: WWW/HTTP :: WSGI :: Server", "Topic :: Software Development :: Libraries :: Application Frameworks"], "name": "bottle", "requires_python": "", "version": "0.12.25", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "bottle-0.12.25-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "bottle-0.12.25.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Topic :: Internet :: WWW/HTTP :: Dynamic Content :: CGI Tools/Libraries", "Topic :: Internet :: WWW/HTTP :: HTTP Servers", "Topic :: Internet :: WWW/HTTP :: WSGI", "Topic :: Internet :: WWW/HTTP :: WSGI :: Application", "Topic :: Internet :: WWW/HTTP :: WSGI :: Middleware", "Topic :: Internet :: WWW/HTTP :: WSGI :: Server", "Topic :: Software Development :: Libraries :: Application Frameworks"], "name": "bottle", "requires_python": null, "version": "0.13.4", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "bottle-0.13.4-py2.py3-none-any.whl"}, {"packagetype": "sdist", "filename": "bottle-0.13.4.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 4 - Beta", "Environment :: Console", "Intended Audience :: Developers", "Operating System :: MacOS :: MacOS X", "Operating System :: Microsoft :: Windows", "Operating System :: POSIX :: Linux", "Programming Language :: C", "Programming Language :: C++", "Programming Language :: Python", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Unix Shell", "Topic :: Software Development :: Libraries", "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: System :: Archiving", "Topic :: System :: Archiving :: Compression", "Topic :: Text Processing :: Fonts", "Topic :: Utilities"], "name": "brotli", "requires_python": null, "version": "1.2.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp27-cp27m-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp27-cp27m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp27-cp27m-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp27-cp27mu-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp27-cp27mu-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp27-cp27m-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp27-cp27m-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp310-cp310-macosx_10_9_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp310-cp310-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp310-cp310-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp310-cp310-musllinux_1_2_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp310-cp310-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp310-cp310-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp310-cp310-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp311-cp311-macosx_10_9_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp311-cp311-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp311-cp311-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp311-cp311-musllinux_1_2_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp311-cp311-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp311-cp311-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp311-cp311-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp312-cp312-macosx_10_13_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp312-cp312-macosx_10_13_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp312-cp312-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp312-cp312-musllinux_1_2_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp312-cp312-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp312-cp312-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp312-cp312-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp313-cp313-macosx_10_13_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp313-cp313-macosx_10_13_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp313-cp313-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp313-cp313-musllinux_1_2_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp313-cp313-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp313-cp313-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp313-cp313-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp314-cp314-macosx_10_15_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp314-cp314-macosx_10_15_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp314-cp314-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp314-cp314-musllinux_1_2_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp314-cp314-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp314-cp314-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp314-cp314-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp36-cp36m-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp36-cp36m-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp36-cp36m-musllinux_1_2_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp36-cp36m-musllinux_1_2_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp36-cp36m-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp36-cp36m-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp36-cp36m-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp37-cp37m-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp37-cp37m-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp37-cp37m-musllinux_1_2_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp37-cp37m-musllinux_1_2_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp37-cp37m-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp37-cp37m-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp37-cp37m-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp38-cp38-macosx_10_9_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp38-cp38-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp38-cp38-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp38-cp38-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp38-cp38-musllinux_1_2_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp38-cp38-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp38-cp38-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp38-cp38-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp39-cp39-macosx_10_9_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp39-cp39-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp39-cp39-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp39-cp39-musllinux_1_2_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp39-cp39-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp39-cp39-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "brotli-1.2.0-cp39-cp39-win_amd64.whl"}, {"packagetype": "sdist", "filename": "brotli-1.2.0.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Software Development :: Object Brokering", "Topic :: System :: Distributed Computing"], "name": "celery", "requires_python": ">=3.6,", "version": "5.0.5", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "celery-5.0.5-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "celery-5.0.5.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Framework :: Celery", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Software Development :: Object Brokering", "Topic :: System :: Distributed Computing"], "name": "celery", "requires_python": ">=3.7", "version": "5.2.7", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "celery-5.2.7-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "celery-5.2.7.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Framework :: Celery", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Software Development :: Object Brokering", "Topic :: System :: Distributed Computing"], "name": "celery", "requires_python": ">=3.8", "version": "5.4.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "celery-5.4.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "celery-5.4.0.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Framework :: Celery", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Software Development :: Object Brokering", "Topic :: System :: Distributed Computing"], "name": "celery", "requires_python": ">=3.9", "version": "5.6.3", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "celery-5.6.3-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "celery-5.6.3.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Framework :: Celery", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Software Development :: Object Brokering", "Topic :: System :: Distributed Computing"], "name": "celery", "requires_python": ">=3.10", "version": "5.7.0a1", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "celery-5.7.0a1-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "celery-5.7.0a1.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "Natural Language :: English", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8"], "name": "chalice", "requires_python": "", "version": "1.22.4", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "chalice-1.22.4-py2.py3-none-any.whl"}, {"packagetype": "sdist", "filename": "chalice-1.22.4.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "Natural Language :: English", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14"], "name": "chalice", "requires_python": ">=3.10", "version": "1.33.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "chalice-1.33.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "chalice-1.33.0.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 4 - Beta", "Environment :: Console", "Intended Audience :: Developers", "Intended Audience :: Information Technology", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: Implementation :: PyPy", "Programming Language :: SQL", "Topic :: Database", "Topic :: Scientific/Engineering :: Information Analysis", "Topic :: Software Development", "Topic :: Software Development :: Libraries", "Topic :: Software Development :: Libraries :: Application Frameworks", "Topic :: Software Development :: Libraries :: Python Modules"], "name": "clickhouse-driver", "requires_python": "<4,>=3.9", "version": "0.2.11", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp310-cp310-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp310-cp310-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp310-cp310-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp310-cp310-musllinux_1_2_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp310-cp310-musllinux_1_2_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp310-cp310-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp310-cp310-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp310-cp310-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp311-cp311-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp311-cp311-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp311-cp311-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp311-cp311-musllinux_1_2_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp311-cp311-musllinux_1_2_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp311-cp311-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp311-cp311-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp311-cp311-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp312-cp312-macosx_10_13_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp312-cp312-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp312-cp312-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp312-cp312-musllinux_1_2_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp312-cp312-musllinux_1_2_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp312-cp312-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp312-cp312-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp312-cp312-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp313-cp313-macosx_10_13_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp313-cp313-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp313-cp313-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp313-cp313-musllinux_1_2_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp313-cp313-musllinux_1_2_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp313-cp313-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp313-cp313-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp313-cp313-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp314-cp314-macosx_10_15_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp314-cp314-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp314-cp314-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp314-cp314-musllinux_1_2_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp314-cp314-musllinux_1_2_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp314-cp314-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp314-cp314-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp314-cp314-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp39-cp39-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp39-cp39-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp39-cp39-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp39-cp39-musllinux_1_2_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp39-cp39-musllinux_1_2_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp39-cp39-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp39-cp39-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-cp39-cp39-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-pp310-pypy310_pp73-macosx_10_15_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-pp310-pypy310_pp73-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-pp310-pypy310_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-pp310-pypy310_pp73-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-pp311-pypy311_pp73-macosx_10_15_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-pp311-pypy311_pp73-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-pp311-pypy311_pp73-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-pp39-pypy39_pp73-macosx_10_15_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-pp39-pypy39_pp73-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-pp39-pypy39_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-pp39-pypy39_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.11-pp39-pypy39_pp73-win_amd64.whl"}, {"packagetype": "sdist", "filename": "clickhouse_driver-0.2.11.tar.gz"}]} +{"info": {"classifiers": ["Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: MacOS", "Operating System :: Microsoft :: Windows", "Operating System :: OS Independent", "Operating System :: POSIX", "Operating System :: POSIX :: Linux", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Programming Language :: Python :: 3.15", "Programming Language :: Python :: 3.9", "Topic :: Software Development :: Libraries :: Python Modules", "Typing :: Typed"], "name": "cohere", "requires_python": "<4.0,>=3.9", "version": "5.21.1", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "cohere-5.21.1-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "cohere-5.21.1.tar.gz"}]} +{"info": {"classifiers": ["Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9"], "name": "cohere", "requires_python": "<4.0,>=3.8", "version": "5.4.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "cohere-5.4.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "cohere-5.4.0.tar.gz"}]} +{"info": {"classifiers": ["Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: MacOS", "Operating System :: Microsoft :: Windows", "Operating System :: OS Independent", "Operating System :: POSIX", "Operating System :: POSIX :: Linux", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Programming Language :: Python :: 3.15", "Topic :: Software Development :: Libraries :: Python Modules", "Typing :: Typed"], "name": "cohere", "requires_python": "<4.0,>=3.10", "version": "6.1.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "cohere-6.1.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "cohere-6.1.0.tar.gz"}]} +{"info": {"classifiers": ["Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: MacOS", "Operating System :: Microsoft :: Windows", "Operating System :: OS Independent", "Operating System :: POSIX", "Operating System :: POSIX :: Linux", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Programming Language :: Python :: 3.15", "Topic :: Software Development :: Libraries :: Python Modules", "Typing :: Typed"], "name": "cohere", "requires_python": "<4.0,>=3.10", "version": "7.1.1", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "cohere-7.1.1-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "cohere-7.1.1.tar.gz"}]} +{"info": {"classifiers": ["License :: OSI Approved :: GNU Lesser General Public License v3 or later (LGPLv3+)", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Topic :: System :: Distributed Computing"], "name": "dramatiq", "requires_python": ">=3.5", "version": "1.9.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "dramatiq-1.9.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "dramatiq-1.9.0.tar.gz"}]} +{"info": {"classifiers": ["License :: OSI Approved :: GNU Lesser General Public License v3 or later (LGPLv3+)", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Topic :: System :: Distributed Computing"], "name": "dramatiq", "requires_python": ">=3.10", "version": "2.2.1", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "dramatiq-2.2.1-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "dramatiq-2.2.1.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Intended Audience :: Developers", "Intended Audience :: System Administrators", "License :: OSI Approved :: Apache Software License", "Natural Language :: English", "Operating System :: MacOS :: MacOS X", "Operating System :: Microsoft :: Windows", "Operating System :: POSIX", "Operating System :: POSIX :: Linux", "Programming Language :: Cython", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Internet :: WWW/HTTP", "Topic :: Internet :: WWW/HTTP :: WSGI", "Topic :: Software Development :: Libraries :: Application Frameworks"], "name": "falcon", "requires_python": ">=3.5", "version": "3.0.1", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "falcon-3.0.1-cp35-cp35m-macosx_10_14_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-3.0.1-cp35-cp35m-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-3.0.1-cp36-cp36m-macosx_10_14_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-3.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-3.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-3.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-3.0.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-3.0.1-cp36-cp36m-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-3.0.1-cp37-cp37m-macosx_10_14_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-3.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-3.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-3.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-3.0.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-3.0.1-cp37-cp37m-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-3.0.1-cp38-cp38-macosx_10_14_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-3.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-3.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-3.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-3.0.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-3.0.1-cp38-cp38-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-3.0.1-cp39-cp39-macosx_10_14_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-3.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-3.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-3.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-3.0.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-3.0.1-cp39-cp39-win_amd64.whl"}, {"packagetype": "sdist", "filename": "falcon-3.0.1.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Intended Audience :: Developers", "Intended Audience :: System Administrators", "License :: OSI Approved :: Apache Software License", "Natural Language :: English", "Operating System :: MacOS :: MacOS X", "Operating System :: Microsoft :: Windows", "Operating System :: POSIX", "Programming Language :: Cython", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Internet :: WWW/HTTP :: WSGI", "Topic :: Software Development :: Libraries :: Application Frameworks"], "name": "falcon", "requires_python": ">=3.5", "version": "3.1.3", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "falcon-3.1.3-cp310-cp310-macosx_11_0_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-3.1.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-3.1.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-3.1.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-3.1.3-cp310-cp310-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-3.1.3-cp311-cp311-macosx_10_9_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-3.1.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-3.1.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-3.1.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-3.1.3-cp311-cp311-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-3.1.3-cp312-cp312-macosx_10_9_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-3.1.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-3.1.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-3.1.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-3.1.3-cp312-cp312-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-3.1.3-cp36-cp36m-macosx_10_14_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-3.1.3-cp36-cp36m-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-3.1.3-cp37-cp37m-macosx_11_0_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-3.1.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-3.1.3-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-3.1.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-3.1.3-cp37-cp37m-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-3.1.3-cp38-cp38-macosx_11_0_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-3.1.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-3.1.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-3.1.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-3.1.3-cp38-cp38-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-3.1.3-cp39-cp39-macosx_11_0_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-3.1.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-3.1.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-3.1.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-3.1.3-cp39-cp39-win_amd64.whl"}, {"packagetype": "sdist", "filename": "falcon-3.1.3.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Intended Audience :: Developers", "Intended Audience :: System Administrators", "Natural Language :: English", "Operating System :: MacOS :: MacOS X", "Operating System :: Microsoft :: Windows", "Operating System :: POSIX", "Programming Language :: Cython", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: Free Threading", "Programming Language :: Python :: Free Threading :: 3 - Stable", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Internet :: WWW/HTTP :: WSGI", "Topic :: Software Development :: Libraries :: Application Frameworks", "Typing :: Typed"], "name": "falcon", "requires_python": ">=3.9", "version": "4.3.1", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "falcon-4.3.1-cp310-cp310-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.3.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.3.1-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.3.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.3.1-cp310-cp310-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.3.1-cp310-cp310-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.3.1-cp310-cp310-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.3.1-cp311-cp311-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.3.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.3.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.3.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.3.1-cp311-cp311-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.3.1-cp311-cp311-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.3.1-cp311-cp311-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.3.1-cp312-cp312-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.3.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.3.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.3.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.3.1-cp312-cp312-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.3.1-cp312-cp312-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.3.1-cp312-cp312-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.3.1-cp313-cp313-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.3.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.3.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.3.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.3.1-cp313-cp313-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.3.1-cp313-cp313-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.3.1-cp313-cp313-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.3.1-cp314-cp314-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.3.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.3.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.3.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.3.1-cp314-cp314-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.3.1-cp314-cp314-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.3.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.3.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.3.1-cp314-cp314t-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.3.1-cp314-cp314t-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.3.1-cp314-cp314-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.3.1-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "falcon-4.3.1.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 4 - Beta", "Environment :: Web Environment", "Framework :: AsyncIO", "Framework :: FastAPI", "Framework :: Pydantic", "Framework :: Pydantic :: 1", "Intended Audience :: Developers", "Intended Audience :: Information Technology", "Intended Audience :: System Administrators", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Topic :: Internet", "Topic :: Internet :: WWW/HTTP", "Topic :: Internet :: WWW/HTTP :: HTTP Servers", "Topic :: Software Development", "Topic :: Software Development :: Libraries", "Topic :: Software Development :: Libraries :: Application Frameworks", "Topic :: Software Development :: Libraries :: Python Modules", "Typing :: Typed"], "name": "fastapi", "requires_python": ">=3.8", "version": "0.104.1", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "fastapi-0.104.1-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "fastapi-0.104.1.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 4 - Beta", "Environment :: Web Environment", "Framework :: AsyncIO", "Framework :: FastAPI", "Framework :: Pydantic", "Framework :: Pydantic :: 1", "Framework :: Pydantic :: 2", "Intended Audience :: Developers", "Intended Audience :: Information Technology", "Intended Audience :: System Administrators", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Topic :: Internet", "Topic :: Internet :: WWW/HTTP", "Topic :: Internet :: WWW/HTTP :: HTTP Servers", "Topic :: Software Development", "Topic :: Software Development :: Libraries", "Topic :: Software Development :: Libraries :: Application Frameworks", "Topic :: Software Development :: Libraries :: Python Modules", "Typing :: Typed"], "name": "fastapi", "requires_python": ">=3.8", "version": "0.123.10", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "fastapi-0.123.10-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "fastapi-0.123.10.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 4 - Beta", "Environment :: Web Environment", "Framework :: AsyncIO", "Framework :: FastAPI", "Framework :: Pydantic", "Framework :: Pydantic :: 2", "Intended Audience :: Developers", "Intended Audience :: Information Technology", "Intended Audience :: System Administrators", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Topic :: Internet", "Topic :: Internet :: WWW/HTTP", "Topic :: Internet :: WWW/HTTP :: HTTP Servers", "Topic :: Software Development", "Topic :: Software Development :: Libraries", "Topic :: Software Development :: Libraries :: Application Frameworks", "Topic :: Software Development :: Libraries :: Python Modules", "Typing :: Typed"], "name": "fastapi", "requires_python": ">=3.10", "version": "0.141.1", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "fastapi-0.141.1-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "fastapi-0.141.1.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 4 - Beta", "Environment :: Web Environment", "Framework :: AsyncIO", "Framework :: FastAPI", "Intended Audience :: Developers", "Intended Audience :: Information Technology", "Intended Audience :: System Administrators", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Topic :: Internet", "Topic :: Internet :: WWW/HTTP", "Topic :: Internet :: WWW/HTTP :: HTTP Servers", "Topic :: Software Development", "Topic :: Software Development :: Libraries", "Topic :: Software Development :: Libraries :: Application Frameworks", "Topic :: Software Development :: Libraries :: Python Modules", "Typing :: Typed"], "name": "fastapi", "requires_python": ">=3.7", "version": "0.85.2", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "fastapi-0.85.2-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "fastapi-0.85.2.tar.gz"}]} +{"info": {"classifiers": ["Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Topic :: Scientific/Engineering :: Artificial Intelligence", "Typing :: Typed"], "name": "fastmcp", "requires_python": ">=3.10", "version": "4.0.5", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "fastmcp-4.0.5-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "fastmcp-4.0.5.tar.gz"}]} +{"info": {"classifiers": ["Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.9", "Topic :: Internet", "Topic :: Software Development :: Libraries :: Python Modules"], "name": "google-genai", "requires_python": ">=3.9", "version": "1.29.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "google_genai-1.29.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "google_genai-1.29.0.tar.gz"}]} +{"info": {"classifiers": ["Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.9", "Topic :: Internet", "Topic :: Software Development :: Libraries :: Python Modules"], "name": "google-genai", "requires_python": ">=3.9", "version": "1.29.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "google_genai-1.29.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "google_genai-1.29.0.tar.gz"}]} +{"info": {"classifiers": ["Intended Audience :: Developers", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Topic :: Internet", "Topic :: Software Development :: Libraries :: Python Modules"], "name": "google-genai", "requires_python": ">=3.10", "version": "1.75.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "google_genai-1.75.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "google_genai-1.75.0.tar.gz"}]} +{"info": {"classifiers": ["Intended Audience :: Developers", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Topic :: Internet", "Topic :: Software Development :: Libraries :: Python Modules"], "name": "google-genai", "requires_python": ">=3.10", "version": "1.75.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "google_genai-1.75.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "google_genai-1.75.0.tar.gz"}]} +{"info": {"classifiers": ["Intended Audience :: Developers", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Topic :: Internet", "Topic :: Software Development :: Libraries :: Python Modules"], "name": "google-genai", "requires_python": ">=3.10", "version": "2.24.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "google_genai-2.24.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "google_genai-2.24.0.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Software Development :: Libraries"], "name": "gql", "requires_python": "", "version": "3.4.1", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "gql-3.4.1-py2.py3-none-any.whl"}, {"packagetype": "sdist", "filename": "gql-3.4.1.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Software Development :: Libraries"], "name": "gql", "requires_python": ">=3.8.1", "version": "4.0.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "gql-4.0.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "gql-4.0.0.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Software Development :: Libraries"], "name": "gql", "requires_python": ">=3.10", "version": "4.4.0b0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "gql-4.4.0b0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "gql-4.4.0b0.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 3 - Alpha", "Intended Audience :: Developers", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Topic :: Software Development :: Libraries"], "name": "graphene", "requires_python": "", "version": "3.3", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "graphene-3.3-py2.py3-none-any.whl"}, {"packagetype": "sdist", "filename": "graphene-3.3.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Topic :: Software Development :: Libraries"], "name": "graphene", "requires_python": null, "version": "3.4.3", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "graphene-3.4.3-py2.py3-none-any.whl"}, {"packagetype": "sdist", "filename": "graphene-3.4.3.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "License :: OSI Approved :: Apache Software License", "Programming Language :: Python", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8"], "name": "grpcio", "requires_python": "", "version": "1.32.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "grpcio-1.32.0-cp27-cp27m-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.32.0-cp27-cp27m-manylinux2010_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.32.0-cp27-cp27m-manylinux2010_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.32.0-cp27-cp27mu-linux_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.32.0-cp27-cp27mu-manylinux2010_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.32.0-cp27-cp27mu-manylinux2010_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.32.0-cp27-cp27m-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.32.0-cp27-cp27m-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.32.0-cp35-cp35m-linux_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.32.0-cp35-cp35m-macosx_10_7_intel.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.32.0-cp35-cp35m-manylinux2010_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.32.0-cp35-cp35m-manylinux2010_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.32.0-cp35-cp35m-manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.32.0-cp35-cp35m-manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.32.0-cp35-cp35m-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.32.0-cp35-cp35m-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.32.0-cp36-cp36m-linux_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.32.0-cp36-cp36m-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.32.0-cp36-cp36m-manylinux2010_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.32.0-cp36-cp36m-manylinux2010_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.32.0-cp36-cp36m-manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.32.0-cp36-cp36m-manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.32.0-cp36-cp36m-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.32.0-cp36-cp36m-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.32.0-cp37-cp37m-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.32.0-cp37-cp37m-manylinux2010_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.32.0-cp37-cp37m-manylinux2010_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.32.0-cp37-cp37m-manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.32.0-cp37-cp37m-manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.32.0-cp37-cp37m-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.32.0-cp37-cp37m-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.32.0-cp38-cp38-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.32.0-cp38-cp38-manylinux2010_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.32.0-cp38-cp38-manylinux2010_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.32.0-cp38-cp38-manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.32.0-cp38-cp38-manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.32.0-cp38-cp38-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.32.0-cp38-cp38-win_amd64.whl"}, {"packagetype": "sdist", "filename": "grpcio-1.32.0.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "License :: OSI Approved :: Apache Software License", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9"], "name": "grpcio", "requires_python": ">=3.7", "version": "1.49.1", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "grpcio-1.49.1-cp310-cp310-linux_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.49.1-cp310-cp310-macosx_10_10_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.49.1-cp310-cp310-manylinux_2_17_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.49.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.49.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.49.1-cp310-cp310-musllinux_1_1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.49.1-cp310-cp310-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.49.1-cp310-cp310-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.49.1-cp310-cp310-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.49.1-cp311-cp311-linux_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.49.1-cp311-cp311-macosx_10_10_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.49.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.49.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.49.1-cp311-cp311-musllinux_1_1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.49.1-cp311-cp311-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.49.1-cp311-cp311-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.49.1-cp311-cp311-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.49.1-cp37-cp37m-linux_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.49.1-cp37-cp37m-macosx_10_10_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.49.1-cp37-cp37m-manylinux_2_17_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.49.1-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.49.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.49.1-cp37-cp37m-musllinux_1_1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.49.1-cp37-cp37m-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.49.1-cp37-cp37m-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.49.1-cp37-cp37m-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.49.1-cp38-cp38-linux_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.49.1-cp38-cp38-macosx_10_10_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.49.1-cp38-cp38-manylinux_2_17_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.49.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.49.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.49.1-cp38-cp38-musllinux_1_1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.49.1-cp38-cp38-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.49.1-cp38-cp38-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.49.1-cp38-cp38-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.49.1-cp39-cp39-linux_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.49.1-cp39-cp39-macosx_10_10_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.49.1-cp39-cp39-manylinux_2_17_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.49.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.49.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.49.1-cp39-cp39-musllinux_1_1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.49.1-cp39-cp39-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.49.1-cp39-cp39-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.49.1-cp39-cp39-win_amd64.whl"}, {"packagetype": "sdist", "filename": "grpcio-1.49.1.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "License :: OSI Approved :: Apache Software License", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9"], "name": "grpcio", "requires_python": ">=3.8", "version": "1.66.2", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "grpcio-1.66.2-cp310-cp310-linux_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.66.2-cp310-cp310-macosx_12_0_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.66.2-cp310-cp310-manylinux_2_17_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.66.2-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.66.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.66.2-cp310-cp310-musllinux_1_1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.66.2-cp310-cp310-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.66.2-cp310-cp310-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.66.2-cp310-cp310-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.66.2-cp311-cp311-linux_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.66.2-cp311-cp311-macosx_10_9_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.66.2-cp311-cp311-manylinux_2_17_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.66.2-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.66.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.66.2-cp311-cp311-musllinux_1_1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.66.2-cp311-cp311-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.66.2-cp311-cp311-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.66.2-cp311-cp311-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.66.2-cp312-cp312-linux_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.66.2-cp312-cp312-macosx_10_9_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.66.2-cp312-cp312-manylinux_2_17_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.66.2-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.66.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.66.2-cp312-cp312-musllinux_1_1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.66.2-cp312-cp312-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.66.2-cp312-cp312-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.66.2-cp312-cp312-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.66.2-cp313-cp313-linux_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.66.2-cp313-cp313-macosx_10_13_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.66.2-cp313-cp313-manylinux_2_17_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.66.2-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.66.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.66.2-cp313-cp313-musllinux_1_1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.66.2-cp313-cp313-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.66.2-cp313-cp313-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.66.2-cp313-cp313-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.66.2-cp38-cp38-linux_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.66.2-cp38-cp38-macosx_10_9_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.66.2-cp38-cp38-manylinux_2_17_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.66.2-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.66.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.66.2-cp38-cp38-musllinux_1_1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.66.2-cp38-cp38-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.66.2-cp38-cp38-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.66.2-cp38-cp38-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.66.2-cp39-cp39-linux_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.66.2-cp39-cp39-macosx_10_9_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.66.2-cp39-cp39-manylinux_2_17_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.66.2-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.66.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.66.2-cp39-cp39-musllinux_1_1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.66.2-cp39-cp39-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.66.2-cp39-cp39-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.66.2-cp39-cp39-win_amd64.whl"}, {"packagetype": "sdist", "filename": "grpcio-1.66.2.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Programming Language :: Python :: 3.15"], "name": "grpcio", "requires_python": ">=3.10", "version": "1.84.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "grpcio-1.84.0-cp310-cp310-linux_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.84.0-cp310-cp310-macosx_11_0_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.84.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.84.0-cp310-cp310-manylinux2014_i686.manylinux_2_17_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.84.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.84.0-cp310-cp310-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.84.0-cp310-cp310-musllinux_1_2_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.84.0-cp310-cp310-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.84.0-cp310-cp310-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.84.0-cp310-cp310-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.84.0-cp311-cp311-linux_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.84.0-cp311-cp311-macosx_11_0_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.84.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.84.0-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.84.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.84.0-cp311-cp311-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.84.0-cp311-cp311-musllinux_1_2_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.84.0-cp311-cp311-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.84.0-cp311-cp311-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.84.0-cp311-cp311-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.84.0-cp312-cp312-linux_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.84.0-cp312-cp312-macosx_11_0_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.84.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.84.0-cp312-cp312-manylinux2014_i686.manylinux_2_17_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.84.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.84.0-cp312-cp312-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.84.0-cp312-cp312-musllinux_1_2_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.84.0-cp312-cp312-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.84.0-cp312-cp312-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.84.0-cp312-cp312-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.84.0-cp313-cp313-linux_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.84.0-cp313-cp313-macosx_11_0_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.84.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.84.0-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.84.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.84.0-cp313-cp313-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.84.0-cp313-cp313-musllinux_1_2_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.84.0-cp313-cp313-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.84.0-cp313-cp313-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.84.0-cp313-cp313-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.84.0-cp314-cp314-linux_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.84.0-cp314-cp314-macosx_11_0_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.84.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.84.0-cp314-cp314-manylinux2014_i686.manylinux_2_17_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.84.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.84.0-cp314-cp314-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.84.0-cp314-cp314-musllinux_1_2_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.84.0-cp314-cp314-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.84.0-cp314-cp314-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.84.0-cp314-cp314-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.84.0-cp315-cp315-linux_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.84.0-cp315-cp315-macosx_10_15_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.84.0-cp315-cp315-manylinux2014_aarch64.manylinux_2_17_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.84.0-cp315-cp315-manylinux2014_i686.manylinux_2_17_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.84.0-cp315-cp315-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.84.0-cp315-cp315-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.84.0-cp315-cp315-musllinux_1_2_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.84.0-cp315-cp315-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.84.0-cp315-cp315-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.84.0-cp315-cp315-win_amd64.whl"}, {"packagetype": "sdist", "filename": "grpcio-1.84.0.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 4 - Beta", "Environment :: Web Environment", "Framework :: AsyncIO", "Framework :: Trio", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Topic :: Internet :: WWW/HTTP"], "name": "httpx", "requires_python": ">=3.6", "version": "0.16.1", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "httpx-0.16.1-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "httpx-0.16.1.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 4 - Beta", "Environment :: Web Environment", "Framework :: AsyncIO", "Framework :: Trio", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Topic :: Internet :: WWW/HTTP"], "name": "httpx", "requires_python": ">=3.6", "version": "0.20.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "httpx-0.20.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "httpx-0.20.0.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 4 - Beta", "Environment :: Web Environment", "Framework :: AsyncIO", "Framework :: Trio", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Topic :: Internet :: WWW/HTTP"], "name": "httpx", "requires_python": ">=3.6", "version": "0.22.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "httpx-0.22.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "httpx-0.22.0.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 4 - Beta", "Environment :: Web Environment", "Framework :: AsyncIO", "Framework :: Trio", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Topic :: Internet :: WWW/HTTP"], "name": "httpx", "requires_python": ">=3.7", "version": "0.24.1", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "httpx-0.24.1-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "httpx-0.24.1.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 4 - Beta", "Environment :: Web Environment", "Framework :: AsyncIO", "Framework :: Trio", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Topic :: Internet :: WWW/HTTP"], "name": "httpx", "requires_python": ">=3.8", "version": "0.26.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "httpx-0.26.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "httpx-0.26.0.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 4 - Beta", "Environment :: Web Environment", "Framework :: AsyncIO", "Framework :: Trio", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Topic :: Internet :: WWW/HTTP"], "name": "httpx", "requires_python": ">=3.8", "version": "0.28.1", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "httpx-0.28.1-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "httpx-0.28.1.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 4 - Beta", "Environment :: Web Environment", "Framework :: AsyncIO", "Framework :: Trio", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.9", "Topic :: Internet :: WWW/HTTP"], "name": "httpx2", "requires_python": ">=3.9", "version": "2.0.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "httpx2-2.0.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "httpx2-2.0.0.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Framework :: AnyIO", "Framework :: AsyncIO", "Framework :: Trio", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Programming Language :: Python :: 3.15", "Topic :: Internet :: WWW/HTTP"], "name": "httpx2", "requires_python": ">=3.10", "version": "2.13.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "httpx2-2.13.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "httpx2-2.13.0.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Framework :: AnyIO", "Framework :: AsyncIO", "Framework :: Trio", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Topic :: Internet :: WWW/HTTP"], "name": "httpx2", "requires_python": ">=3.10", "version": "2.4.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "httpx2-2.4.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "httpx2-2.4.0.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Framework :: AnyIO", "Framework :: AsyncIO", "Framework :: Trio", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Topic :: Internet :: WWW/HTTP"], "name": "httpx2", "requires_python": ">=3.10", "version": "2.8.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "httpx2-2.8.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "httpx2-2.8.0.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 4 - Beta", "Environment :: Web Environment", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python"], "name": "huey", "requires_python": "", "version": "2.0.1", "yanked": false}, "urls": [{"packagetype": "sdist", "filename": "huey-2.0.1.tar.gz"}]} +{"info": {"classifiers": ["Programming Language :: Python :: 2", "Programming Language :: Python :: 3", "Topic :: Software Development :: Libraries :: Python Modules"], "name": "huey", "requires_python": null, "version": "2.6.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "huey-2.6.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "huey-2.6.0.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "Programming Language :: Python :: 3", "Topic :: Software Development :: Libraries :: Python Modules"], "name": "huey", "requires_python": null, "version": "3.2.1", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "huey-3.2.1-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "huey-3.2.1.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "Programming Language :: Python :: 3", "Topic :: Software Development :: Libraries :: Python Modules"], "name": "huey", "requires_python": null, "version": "3.4.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "huey-3.4.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "huey-3.4.0.tar.gz"}]} +{"info": {"classifiers": ["Intended Audience :: Developers", "Intended Audience :: Education", "Intended Audience :: Science/Research", "License :: OSI Approved :: Apache Software License", "Operating System :: OS Independent", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Topic :: Scientific/Engineering :: Artificial Intelligence"], "name": "huggingface-hub", "requires_python": ">=3.8.0", "version": "0.24.7", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "huggingface_hub-0.24.7-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "huggingface_hub-0.24.7.tar.gz"}]} +{"info": {"classifiers": ["Intended Audience :: Developers", "Intended Audience :: Education", "Intended Audience :: Science/Research", "License :: OSI Approved :: Apache Software License", "Operating System :: OS Independent", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Topic :: Scientific/Engineering :: Artificial Intelligence"], "name": "huggingface-hub", "requires_python": ">=3.8.0", "version": "0.36.2", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "huggingface_hub-0.36.2-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "huggingface_hub-0.36.2.tar.gz"}]} +{"info": {"classifiers": ["Intended Audience :: Developers", "Intended Audience :: Education", "Intended Audience :: Science/Research", "License :: OSI Approved :: Apache Software License", "Operating System :: OS Independent", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Topic :: Scientific/Engineering :: Artificial Intelligence"], "name": "huggingface-hub", "requires_python": ">=3.10.0", "version": "1.32.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "huggingface_hub-1.32.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "huggingface_hub-1.32.0.tar.gz"}]} +{"info": {"classifiers": ["License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.9"], "name": "langchain", "requires_python": "<4.0,>=3.8.1", "version": "0.1.20", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "langchain-0.1.20-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "langchain-0.1.20.tar.gz"}]} +{"info": {"classifiers": [], "name": "langchain", "requires_python": "<4.0.0,>=3.9.0", "version": "0.3.30", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "langchain-0.3.30-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "langchain-0.3.30.tar.gz"}]} +{"info": {"classifiers": [], "name": "langchain", "requires_python": "<4.0.0,>=3.10.0", "version": "1.1.3", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "langchain-1.1.3-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "langchain-1.1.3.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Topic :: Scientific/Engineering :: Artificial Intelligence", "Topic :: Software Development :: Libraries :: Python Modules"], "name": "langchain", "requires_python": "<4.0.0,>=3.10.0", "version": "1.3.18", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "langchain-1.3.18-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "langchain-1.3.18.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Topic :: Scientific/Engineering :: Artificial Intelligence", "Topic :: Software Development :: Libraries :: Python Modules"], "name": "langchain", "requires_python": "<4.0.0,>=3.10.0", "version": "1.4.2", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "langchain-1.4.2-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "langchain-1.4.2.tar.gz"}]} +{"info": {"classifiers": [], "name": "langgraph", "requires_python": ">=3.9", "version": "0.6.11", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "langgraph-0.6.11-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "langgraph-0.6.11.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy"], "name": "langgraph", "requires_python": ">=3.10", "version": "1.2.12", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "langgraph-1.2.12-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "langgraph-1.2.12.tar.gz"}]} +{"info": {"classifiers": ["Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "Operating System :: OS Independent", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Topic :: Software Development", "Topic :: Software Development :: Libraries"], "name": "launchdarkly-server-sdk", "requires_python": ">=3.10", "version": "9.17.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "launchdarkly_server_sdk-9.17.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "launchdarkly_server_sdk-9.17.0.tar.gz"}]} +{"info": {"classifiers": ["Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "Operating System :: OS Independent", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Topic :: Software Development", "Topic :: Software Development :: Libraries"], "name": "launchdarkly-server-sdk", "requires_python": ">=3.8", "version": "9.8.1", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "launchdarkly_server_sdk-9.8.1-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "launchdarkly_server_sdk-9.8.1.tar.gz"}]} +{"info": {"classifiers": ["License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.9"], "name": "litellm", "requires_python": "!=2.7.*,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,!=3.7.*,>=3.8", "version": "1.77.7", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "litellm-1.77.7-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "litellm-1.77.7.tar.gz"}]} +{"info": {"classifiers": [], "name": "litellm", "requires_python": "<3.14,>=3.10", "version": "1.83.14", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "litellm-1.83.14-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "litellm-1.83.14.tar.gz"}]} +{"info": {"classifiers": [], "name": "litellm", "requires_python": "<3.14,>=3.10", "version": "1.89.7", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "litellm-1.89.7-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "litellm-1.89.7.tar.gz"}]} +{"info": {"classifiers": [], "name": "litellm", "requires_python": "<3.15,>=3.10", "version": "1.96.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "litellm-1.96.0-cp310-cp310-macosx_10_12_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "litellm-1.96.0-cp310-cp310-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "litellm-1.96.0-cp310-cp310-manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "litellm-1.96.0-cp310-cp310-manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "litellm-1.96.0-cp310-cp310-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "litellm-1.96.0-cp310-cp310-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "litellm-1.96.0-cp310-cp310-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "litellm-1.96.0-cp311-cp311-macosx_10_12_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "litellm-1.96.0-cp311-cp311-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "litellm-1.96.0-cp311-cp311-manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "litellm-1.96.0-cp311-cp311-manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "litellm-1.96.0-cp311-cp311-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "litellm-1.96.0-cp311-cp311-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "litellm-1.96.0-cp311-cp311-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "litellm-1.96.0-cp312-cp312-macosx_10_12_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "litellm-1.96.0-cp312-cp312-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "litellm-1.96.0-cp312-cp312-manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "litellm-1.96.0-cp312-cp312-manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "litellm-1.96.0-cp312-cp312-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "litellm-1.96.0-cp312-cp312-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "litellm-1.96.0-cp312-cp312-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "litellm-1.96.0-cp313-cp313-macosx_10_12_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "litellm-1.96.0-cp313-cp313-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "litellm-1.96.0-cp313-cp313-manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "litellm-1.96.0-cp313-cp313-manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "litellm-1.96.0-cp313-cp313-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "litellm-1.96.0-cp313-cp313-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "litellm-1.96.0-cp313-cp313-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "litellm-1.96.0-cp314-cp314-macosx_10_12_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "litellm-1.96.0-cp314-cp314-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "litellm-1.96.0-cp314-cp314-manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "litellm-1.96.0-cp314-cp314-manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "litellm-1.96.0-cp314-cp314-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "litellm-1.96.0-cp314-cp314-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "litellm-1.96.0-cp314-cp314-win_amd64.whl"}, {"packagetype": "sdist", "filename": "litellm-1.96.0.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Framework :: AsyncIO", "Framework :: Pydantic", "Framework :: Pydantic :: 1", "Intended Audience :: Developers", "Intended Audience :: Information Technology", "Intended Audience :: System Administrators", "License :: OSI Approved :: MIT License", "Natural Language :: English", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Topic :: Internet", "Topic :: Internet :: WWW/HTTP", "Topic :: Internet :: WWW/HTTP :: HTTP Servers", "Topic :: Software Development", "Topic :: Software Development :: Libraries", "Topic :: Software Development :: Libraries :: Application Frameworks", "Topic :: Software Development :: Libraries :: Python Modules", "Typing :: Typed"], "name": "litestar", "requires_python": ">=3.8,<4.0", "version": "2.0.1", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "litestar-2.0.1-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "litestar-2.0.1.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Intended Audience :: Developers", "Intended Audience :: Information Technology", "Intended Audience :: System Administrators", "License :: OSI Approved :: MIT License", "Natural Language :: English", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Topic :: Internet", "Topic :: Internet :: WWW/HTTP", "Topic :: Internet :: WWW/HTTP :: HTTP Servers", "Topic :: Software Development", "Topic :: Software Development :: Libraries", "Topic :: Software Development :: Libraries :: Application Frameworks", "Topic :: Software Development :: Libraries :: Python Modules", "Typing :: Typed"], "name": "litestar", "requires_python": "<4.0,>=3.8", "version": "2.16.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "litestar-2.16.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "litestar-2.16.0.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Intended Audience :: Developers", "Intended Audience :: Information Technology", "Intended Audience :: System Administrators", "License :: OSI Approved :: MIT License", "Natural Language :: English", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Topic :: Internet", "Topic :: Internet :: WWW/HTTP", "Topic :: Internet :: WWW/HTTP :: HTTP Servers", "Topic :: Software Development", "Topic :: Software Development :: Libraries", "Topic :: Software Development :: Libraries :: Application Frameworks", "Topic :: Software Development :: Libraries :: Python Modules", "Typing :: Typed"], "name": "litestar", "requires_python": "<4.0,>=3.8", "version": "2.24.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "litestar-2.24.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "litestar-2.24.0.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Intended Audience :: Developers", "Intended Audience :: Information Technology", "Intended Audience :: System Administrators", "License :: OSI Approved :: MIT License", "Natural Language :: English", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Topic :: Internet", "Topic :: Internet :: WWW/HTTP", "Topic :: Internet :: WWW/HTTP :: HTTP Servers", "Topic :: Software Development", "Topic :: Software Development :: Libraries", "Topic :: Software Development :: Libraries :: Application Frameworks", "Topic :: Software Development :: Libraries :: Python Modules", "Typing :: Typed"], "name": "litestar", "requires_python": "<4.0,>=3.8", "version": "2.8.3", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "litestar-2.8.3-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "litestar-2.8.3.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Natural Language :: English", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: System :: Logging"], "name": "loguru", "requires_python": "<4.0,>=3.5", "version": "0.7.3", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "loguru-0.7.3-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "loguru-0.7.3.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14"], "name": "mcp", "requires_python": ">=3.10", "version": "2.0.1", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "mcp-2.0.1-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "mcp-2.0.1.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14"], "name": "mcp", "requires_python": ">=3.10", "version": "2.1.1", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "mcp-2.1.1-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "mcp-2.1.1.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14"], "name": "mcp", "requires_python": ">=3.10", "version": "2.2.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "mcp-2.2.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "mcp-2.2.0.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14"], "name": "mcp", "requires_python": ">=3.10", "version": "2.2.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "mcp-2.2.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "mcp-2.2.0.tar.gz"}]} {"info": {"classifiers": [], "name": "mistralai", "requires_python": ">=3.10", "version": "2.0.5", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "mistralai-2.0.5-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "mistralai-2.0.5.tar.gz"}]} {"info": {"classifiers": [], "name": "mistralai", "requires_python": ">=3.10", "version": "2.10.1", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "mistralai-2.10.1-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "mistralai-2.10.1.tar.gz"}]} {"info": {"classifiers": [], "name": "mistralai", "requires_python": ">=3.10", "version": "2.3.2", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "mistralai-2.3.2-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "mistralai-2.3.2.tar.gz"}]} {"info": {"classifiers": [], "name": "mistralai", "requires_python": ">=3.10", "version": "2.6.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "mistralai-2.6.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "mistralai-2.6.0.tar.gz"}]} +{"info": {"classifiers": ["Intended Audience :: Developers", "Operating System :: MacOS", "Operating System :: Microsoft :: Windows", "Operating System :: OS Independent", "Operating System :: POSIX", "Operating System :: POSIX :: Linux", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Topic :: Software Development :: Libraries :: Python Modules", "Typing :: Typed"], "name": "openai", "requires_python": ">=3.7.1", "version": "1.0.1", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "openai-1.0.1-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "openai-1.0.1.tar.gz"}]} +{"info": {"classifiers": ["Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "Operating System :: MacOS", "Operating System :: Microsoft :: Windows", "Operating System :: OS Independent", "Operating System :: POSIX", "Operating System :: POSIX :: Linux", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Topic :: Software Development :: Libraries :: Python Modules", "Typing :: Typed"], "name": "openai", "requires_python": ">=3.8", "version": "1.109.1", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "openai-1.109.1-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "openai-1.109.1.tar.gz"}]} +{"info": {"classifiers": ["Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "Operating System :: MacOS", "Operating System :: Microsoft :: Windows", "Operating System :: OS Independent", "Operating System :: POSIX", "Operating System :: POSIX :: Linux", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Topic :: Software Development :: Libraries :: Python Modules", "Typing :: Typed"], "name": "openai", "requires_python": ">=3.8", "version": "1.91.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "openai-1.91.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "openai-1.91.0.tar.gz"}]} +{"info": {"classifiers": ["Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "Operating System :: MacOS", "Operating System :: Microsoft :: Windows", "Operating System :: OS Independent", "Operating System :: POSIX", "Operating System :: POSIX :: Linux", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Programming Language :: Python :: 3.9", "Topic :: Software Development :: Libraries :: Python Modules", "Typing :: Typed"], "name": "openai", "requires_python": ">=3.9", "version": "2.28.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "openai-2.28.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "openai-2.28.0.tar.gz"}]} +{"info": {"classifiers": ["Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "Operating System :: MacOS", "Operating System :: Microsoft :: Windows", "Operating System :: OS Independent", "Operating System :: POSIX", "Operating System :: POSIX :: Linux", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Topic :: Software Development :: Libraries :: Python Modules", "Typing :: Typed"], "name": "openai", "requires_python": ">=3.10", "version": "2.51.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "openai-2.51.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "openai-2.51.0.tar.gz"}]} +{"info": {"classifiers": ["Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "Operating System :: MacOS", "Operating System :: Microsoft :: Windows", "Operating System :: OS Independent", "Operating System :: POSIX", "Operating System :: POSIX :: Linux", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Topic :: Software Development :: Libraries :: Python Modules", "Typing :: Typed"], "name": "openai", "requires_python": ">=3.10", "version": "2.54.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "openai-2.54.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "openai-2.54.0.tar.gz"}]} +{"info": {"classifiers": ["Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "Operating System :: MacOS", "Operating System :: Microsoft :: Windows", "Operating System :: OS Independent", "Operating System :: POSIX", "Operating System :: POSIX :: Linux", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Topic :: Software Development :: Libraries :: Python Modules", "Typing :: Typed"], "name": "openai", "requires_python": ">=3.10", "version": "3.13.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "openai-3.13.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "openai-3.13.0.tar.gz"}]} +{"info": {"classifiers": ["Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "Operating System :: MacOS", "Operating System :: Microsoft :: Windows", "Operating System :: OS Independent", "Operating System :: POSIX", "Operating System :: POSIX :: Linux", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Topic :: Software Development :: Libraries :: Python Modules", "Typing :: Typed"], "name": "openai", "requires_python": ">=3.10", "version": "3.16.2", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "openai-3.16.2-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "openai-3.16.2.tar.gz"}]} +{"info": {"classifiers": ["Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "Operating System :: MacOS", "Operating System :: Microsoft :: Windows", "Operating System :: OS Independent", "Operating System :: POSIX", "Operating System :: POSIX :: Linux", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Topic :: Software Development :: Libraries :: Python Modules", "Typing :: Typed"], "name": "openai", "requires_python": ">=3.10", "version": "3.17.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "openai-3.17.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "openai-3.17.0.tar.gz"}]} +{"info": {"classifiers": ["Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "Operating System :: MacOS", "Operating System :: Microsoft :: Windows", "Operating System :: OS Independent", "Operating System :: POSIX", "Operating System :: POSIX :: Linux", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Topic :: Software Development :: Libraries :: Python Modules", "Typing :: Typed"], "name": "openai", "requires_python": ">=3.10", "version": "3.7.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "openai-3.7.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "openai-3.7.0.tar.gz"}]} +{"info": {"classifiers": ["Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Topic :: Software Development :: Libraries :: Python Modules", "Typing :: Typed"], "name": "openai-agents", "requires_python": ">=3.10", "version": "0.10.5", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "openai_agents-0.10.5-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "openai_agents-0.10.5.tar.gz"}]} +{"info": {"classifiers": ["Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Topic :: Software Development :: Libraries :: Python Modules", "Typing :: Typed"], "name": "openai-agents", "requires_python": ">=3.10", "version": "0.14.8", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "openai_agents-0.14.8-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "openai_agents-0.14.8.tar.gz"}]} +{"info": {"classifiers": ["Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Topic :: Software Development :: Libraries :: Python Modules", "Typing :: Typed"], "name": "openai-agents", "requires_python": ">=3.10", "version": "0.18.3", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "openai_agents-0.18.3-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "openai_agents-0.18.3.tar.gz"}]} +{"info": {"classifiers": ["Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Topic :: Software Development :: Libraries :: Python Modules", "Typing :: Typed"], "name": "openai-agents", "requires_python": ">=3.10", "version": "0.22.3", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "openai_agents-0.22.3-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "openai_agents-0.22.3.tar.gz"}]} +{"info": {"classifiers": ["Programming Language :: Python", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14"], "name": "openfeature-sdk", "requires_python": ">=3.10", "version": "0.10.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "openfeature_sdk-0.10.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "openfeature_sdk-0.10.0.tar.gz"}]} +{"info": {"classifiers": ["License :: OSI Approved :: Apache Software License", "Programming Language :: Python", "Programming Language :: Python :: 3"], "name": "openfeature-sdk", "requires_python": ">=3.8", "version": "0.7.5", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "openfeature_sdk-0.7.5-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "openfeature_sdk-0.7.5.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "License :: OSI Approved :: MIT License", "License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)", "Operating System :: MacOS", "Operating System :: Microsoft :: Windows", "Operating System :: POSIX :: Linux", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Programming Language :: Python :: 3.15", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Rust", "Typing :: Typed"], "name": "orjson", "requires_python": ">=3.10", "version": "3.12.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "orjson-3.12.0-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "orjson-3.12.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "orjson-3.12.0-cp310-cp310-manylinux2014_i686.manylinux_2_17_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "orjson-3.12.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "orjson-3.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "orjson-3.12.0-cp310-cp310-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "orjson-3.12.0-cp310-cp310-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "orjson-3.12.0-cp310-cp310-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "orjson-3.12.0-cp310-cp310-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "orjson-3.12.0-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "orjson-3.12.0-cp311-cp311-macosx_15_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "orjson-3.12.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "orjson-3.12.0-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "orjson-3.12.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "orjson-3.12.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "orjson-3.12.0-cp311-cp311-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "orjson-3.12.0-cp311-cp311-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "orjson-3.12.0-cp311-cp311-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "orjson-3.12.0-cp311-cp311-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "orjson-3.12.0-cp311-cp311-win_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "orjson-3.12.0-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "orjson-3.12.0-cp312-cp312-macosx_15_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "orjson-3.12.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "orjson-3.12.0-cp312-cp312-manylinux2014_i686.manylinux_2_17_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "orjson-3.12.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "orjson-3.12.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "orjson-3.12.0-cp312-cp312-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "orjson-3.12.0-cp312-cp312-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "orjson-3.12.0-cp312-cp312-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "orjson-3.12.0-cp312-cp312-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "orjson-3.12.0-cp312-cp312-win_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "orjson-3.12.0-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "orjson-3.12.0-cp313-cp313-macosx_15_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "orjson-3.12.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "orjson-3.12.0-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "orjson-3.12.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "orjson-3.12.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "orjson-3.12.0-cp313-cp313-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "orjson-3.12.0-cp313-cp313-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "orjson-3.12.0-cp313-cp313-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "orjson-3.12.0-cp313-cp313-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "orjson-3.12.0-cp313-cp313-win_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "orjson-3.12.0-cp314-cp314-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "orjson-3.12.0-cp314-cp314-macosx_15_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "orjson-3.12.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "orjson-3.12.0-cp314-cp314-manylinux2014_i686.manylinux_2_17_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "orjson-3.12.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "orjson-3.12.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "orjson-3.12.0-cp314-cp314-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "orjson-3.12.0-cp314-cp314-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "orjson-3.12.0-cp314-cp314-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "orjson-3.12.0-cp314-cp314-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "orjson-3.12.0-cp314-cp314-win_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "orjson-3.12.0-cp315-cp315-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "orjson-3.12.0-cp315-cp315-macosx_15_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "orjson-3.12.0-cp315-cp315-manylinux_2_39_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "orjson-3.12.0-cp315-cp315-manylinux_2_39_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "orjson-3.12.0-cp315-cp315-manylinux_2_39_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "orjson-3.12.0-cp315-cp315-manylinux_2_39_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "orjson-3.12.0-cp315-cp315-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "orjson-3.12.0-cp315-cp315-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "orjson-3.12.0-cp315-cp315-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "orjson-3.12.0-cp315-cp315-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "orjson-3.12.0-cp315-cp315-win_arm64.whl"}, {"packagetype": "sdist", "filename": "orjson-3.12.0.tar.gz"}]} +{"info": {"classifiers": ["Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8"], "name": "pure-eval", "requires_python": "", "version": "0.0.3", "yanked": false}, "urls": [{"packagetype": "sdist", "filename": "pure_eval-0.0.3.tar.gz"}]} +{"info": {"classifiers": ["Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Programming Language :: Python :: 3.15", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9"], "name": "pure-eval", "requires_python": null, "version": "0.2.4", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "pure_eval-0.2.4-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "pure_eval-0.2.4.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Framework :: Pydantic", "Framework :: Pydantic :: 2", "Intended Audience :: Developers", "Intended Audience :: Information Technology", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Topic :: Internet", "Topic :: Scientific/Engineering :: Artificial Intelligence", "Topic :: Software Development :: Libraries :: Python Modules"], "name": "pydantic-ai", "requires_python": ">=3.10", "version": "1.107.6", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "pydantic_ai-1.107.6-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "pydantic_ai-1.107.6.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Framework :: Pydantic", "Framework :: Pydantic :: 2", "Intended Audience :: Developers", "Intended Audience :: Information Technology", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Topic :: Internet", "Topic :: Scientific/Engineering :: Artificial Intelligence", "Topic :: Software Development :: Libraries :: Python Modules"], "name": "pydantic-ai", "requires_python": ">=3.10", "version": "1.76.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "pydantic_ai-1.76.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "pydantic_ai-1.76.0.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Framework :: Pydantic", "Framework :: Pydantic :: 2", "Intended Audience :: Developers", "Intended Audience :: Information Technology", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Topic :: Internet", "Topic :: Scientific/Engineering :: Artificial Intelligence", "Topic :: Software Development :: Libraries :: Python Modules"], "name": "pydantic-ai", "requires_python": ">=3.10", "version": "2.47.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "pydantic_ai-2.47.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "pydantic_ai-2.47.0.tar.gz"}]} {"info": {"classifiers": ["Development Status :: 3 - Alpha", "Framework :: Pydantic", "Intended Audience :: Developers", "Intended Audience :: Information Technology", "Operating System :: MacOS", "Operating System :: Microsoft :: Windows", "Operating System :: POSIX :: Linux", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: GraalPy", "Programming Language :: Python :: Implementation :: PyPy", "Programming Language :: Rust", "Typing :: Typed"], "name": "pydantic_core", "requires_python": ">=3.9", "version": "2.46.5", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp310-cp310-macosx_10_12_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp310-cp310-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp310-cp310-manylinux_2_31_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp310-cp310-musllinux_1_1_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp310-cp310-musllinux_1_1_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp310-cp310-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp310-cp310-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp310-cp310-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp311-cp311-macosx_10_12_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp311-cp311-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp311-cp311-manylinux_2_31_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp311-cp311-musllinux_1_1_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp311-cp311-musllinux_1_1_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp311-cp311-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp311-cp311-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp311-cp311-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp311-cp311-win_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp312-cp312-macosx_10_12_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp312-cp312-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp312-cp312-manylinux_2_31_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp312-cp312-musllinux_1_1_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp312-cp312-musllinux_1_1_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp312-cp312-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp312-cp312-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp312-cp312-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp312-cp312-win_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp313-cp313-macosx_10_12_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp313-cp313-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp313-cp313-manylinux_2_31_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp313-cp313-musllinux_1_1_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp313-cp313-musllinux_1_1_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp313-cp313-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp313-cp313-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp313-cp313-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp313-cp313-win_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp314-cp314-macosx_10_12_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp314-cp314-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp314-cp314-manylinux_2_31_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp314-cp314-musllinux_1_1_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp314-cp314-musllinux_1_1_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp314-cp314-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp314-cp314t-macosx_10_12_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp314-cp314t-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp314-cp314t-manylinux_2_31_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp314-cp314t-musllinux_1_1_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp314-cp314t-musllinux_1_1_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp314-cp314t-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp314-cp314t-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp314-cp314t-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp314-cp314t-win_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp314-cp314-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp314-cp314-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp314-cp314-win_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp39-cp39-macosx_10_12_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp39-cp39-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp39-cp39-manylinux_2_31_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp39-cp39-musllinux_1_1_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp39-cp39-musllinux_1_1_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp39-cp39-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp39-cp39-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-cp39-cp39-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-pp311-pypy311_pp73-macosx_10_12_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-pp311-pypy311_pp73-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pydantic_core-2.46.5-pp311-pypy311_pp73-win_amd64.whl"}, {"packagetype": "sdist", "filename": "pydantic_core-2.46.5.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "Operating System :: MacOS :: MacOS X", "Operating System :: Microsoft :: Windows", "Operating System :: POSIX", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Database"], "name": "pymongo", "requires_python": "", "version": "3.12.3", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp27-cp27m-macosx_10_14_intel.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp27-cp27m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp27-cp27m-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp27-cp27m-manylinux_2_5_i686.manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp27-cp27mu-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp27-cp27mu-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp27-cp27mu-manylinux_2_5_i686.manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp27-cp27m-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp27-cp27m-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp310-cp310-macosx_10_15_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp310-cp310-macosx_10_9_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp310-cp310-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp310-cp310-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp310-cp310-manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp310-cp310-manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp310-cp310-manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp310-cp310-manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp310-cp310-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp310-cp310-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp34-cp34m-macosx_10_6_intel.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp34-cp34m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp34-cp34m-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp34-cp34m-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp34-cp34m-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp35-cp35m-macosx_10_6_intel.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp35-cp35m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp35-cp35m-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp35-cp35m-manylinux_2_5_i686.manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp35-cp35m-manylinux_2_5_x86_64.manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp35-cp35m-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp35-cp35m-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp36-cp36m-macosx_10_6_intel.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp36-cp36m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp36-cp36m-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp36-cp36m-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp36-cp36m-manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp36-cp36m-manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp36-cp36m-manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp36-cp36m-manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp36-cp36m-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp36-cp36m-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp37-cp37m-macosx_10_6_intel.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp37-cp37m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp37-cp37m-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp37-cp37m-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp37-cp37m-manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp37-cp37m-manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp37-cp37m-manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp37-cp37m-manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp37-cp37m-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp37-cp37m-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp38-cp38-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp38-cp38-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp38-cp38-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp38-cp38-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp38-cp38-manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp38-cp38-manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp38-cp38-manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp38-cp38-manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp38-cp38-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp38-cp38-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp39-cp39-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp39-cp39-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp39-cp39-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp39-cp39-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp39-cp39-manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp39-cp39-manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp39-cp39-manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp39-cp39-manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp39-cp39-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.12.3-cp39-cp39-win_amd64.whl"}, {"packagetype": "bdist_egg", "filename": "pymongo-3.12.3-py2.7-macosx-10.14-intel.egg"}, {"packagetype": "sdist", "filename": "pymongo-3.12.3.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "Operating System :: MacOS :: MacOS X", "Operating System :: Microsoft :: Windows", "Operating System :: POSIX", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Database"], "name": "pymongo", "requires_python": "", "version": "3.13.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp27-cp27m-macosx_10_14_intel.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp27-cp27m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp27-cp27m-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp27-cp27m-manylinux_2_5_i686.manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp27-cp27mu-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp27-cp27mu-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp27-cp27mu-manylinux_2_5_i686.manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp27-cp27m-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp27-cp27m-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp310-cp310-macosx_10_9_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp310-cp310-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp310-cp310-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp310-cp310-manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp310-cp310-manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp310-cp310-manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp310-cp310-manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp310-cp310-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp310-cp310-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp311-cp311-macosx_10_9_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp311-cp311-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp311-cp311-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp35-cp35m-macosx_10_6_intel.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp35-cp35m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp35-cp35m-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp35-cp35m-manylinux_2_5_i686.manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp35-cp35m-manylinux_2_5_x86_64.manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp35-cp35m-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp35-cp35m-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp36-cp36m-macosx_10_6_intel.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp36-cp36m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp36-cp36m-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp36-cp36m-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp36-cp36m-manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp36-cp36m-manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp36-cp36m-manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp36-cp36m-manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp36-cp36m-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp36-cp36m-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp37-cp37m-macosx_10_6_intel.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp37-cp37m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp37-cp37m-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp37-cp37m-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp37-cp37m-manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp37-cp37m-manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp37-cp37m-manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp37-cp37m-manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp37-cp37m-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp37-cp37m-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp38-cp38-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp38-cp38-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp38-cp38-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp38-cp38-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp38-cp38-manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp38-cp38-manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp38-cp38-manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp38-cp38-manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp38-cp38-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp38-cp38-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp39-cp39-macosx_10_9_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp39-cp39-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp39-cp39-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp39-cp39-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp39-cp39-manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp39-cp39-manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp39-cp39-manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp39-cp39-manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp39-cp39-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.13.0-cp39-cp39-win_amd64.whl"}, {"packagetype": "bdist_egg", "filename": "pymongo-3.13.0-py2.7-macosx-10.14-intel.egg"}, {"packagetype": "sdist", "filename": "pymongo-3.13.0.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "Operating System :: MacOS :: MacOS X", "Operating System :: Microsoft :: Windows", "Operating System :: POSIX", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Database"], "name": "pymongo", "requires_python": "", "version": "3.5.1", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "pymongo-3.5.1-cp26-cp26m-macosx_10_12_intel.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.5.1-cp26-cp26m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.5.1-cp26-cp26m-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.5.1-cp26-cp26mu-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.5.1-cp26-cp26mu-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.5.1-cp26-cp26m-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.5.1-cp26-cp26m-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.5.1-cp27-cp27m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.5.1-cp27-cp27m-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.5.1-cp27-cp27mu-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.5.1-cp27-cp27mu-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.5.1-cp27-cp27m-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.5.1-cp27-cp27m-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.5.1-cp27-none-macosx_10_12_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.5.1-cp33-cp33m-macosx_10_6_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.5.1-cp33-cp33m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.5.1-cp33-cp33m-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.5.1-cp33-cp33m-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.5.1-cp33-cp33m-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.5.1-cp34-cp34m-macosx_10_6_intel.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.5.1-cp34-cp34m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.5.1-cp34-cp34m-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.5.1-cp34-cp34m-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.5.1-cp34-cp34m-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.5.1-cp35-cp35m-macosx_10_6_intel.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.5.1-cp35-cp35m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.5.1-cp35-cp35m-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.5.1-cp35-cp35m-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.5.1-cp35-cp35m-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.5.1-cp36-cp36m-macosx_10_6_intel.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.5.1-cp36-cp36m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.5.1-cp36-cp36m-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.5.1-cp36-cp36m-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.5.1-cp36-cp36m-win_amd64.whl"}, {"packagetype": "bdist_egg", "filename": "pymongo-3.5.1-py2.6-macosx-10.12-intel.egg"}, {"packagetype": "bdist_egg", "filename": "pymongo-3.5.1-py2.6-win32.egg"}, {"packagetype": "bdist_egg", "filename": "pymongo-3.5.1-py2.6-win-amd64.egg"}, {"packagetype": "bdist_egg", "filename": "pymongo-3.5.1-py2.7-macosx-10.12-x86_64.egg"}, {"packagetype": "bdist_egg", "filename": "pymongo-3.5.1-py2.7-win32.egg"}, {"packagetype": "bdist_egg", "filename": "pymongo-3.5.1-py2.7-win-amd64.egg"}, {"packagetype": "bdist_egg", "filename": "pymongo-3.5.1-py3.3-macosx-10.6-x86_64.egg"}, {"packagetype": "bdist_egg", "filename": "pymongo-3.5.1-py3.3-win32.egg"}, {"packagetype": "bdist_egg", "filename": "pymongo-3.5.1-py3.3-win-amd64.egg"}, {"packagetype": "bdist_egg", "filename": "pymongo-3.5.1-py3.4-macosx-10.6-intel.egg"}, {"packagetype": "bdist_egg", "filename": "pymongo-3.5.1-py3.4-win32.egg"}, {"packagetype": "bdist_egg", "filename": "pymongo-3.5.1-py3.4-win-amd64.egg"}, {"packagetype": "bdist_egg", "filename": "pymongo-3.5.1-py3.5-macosx-10.6-intel.egg"}, {"packagetype": "bdist_egg", "filename": "pymongo-3.5.1-py3.5-win32.egg"}, {"packagetype": "bdist_egg", "filename": "pymongo-3.5.1-py3.5-win-amd64.egg"}, {"packagetype": "bdist_egg", "filename": "pymongo-3.5.1-py3.6-macosx-10.6-intel.egg"}, {"packagetype": "bdist_egg", "filename": "pymongo-3.5.1-py3.6-win32.egg"}, {"packagetype": "bdist_egg", "filename": "pymongo-3.5.1-py3.6-win-amd64.egg"}, {"packagetype": "sdist", "filename": "pymongo-3.5.1.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "Operating System :: MacOS :: MacOS X", "Operating System :: Microsoft :: Windows", "Operating System :: POSIX", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Database"], "name": "pymongo", "requires_python": "", "version": "3.6.1", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "pymongo-3.6.1-cp26-cp26m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.6.1-cp26-cp26m-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.6.1-cp26-cp26mu-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.6.1-cp26-cp26mu-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.6.1-cp26-cp26m-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.6.1-cp26-cp26m-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.6.1-cp27-cp27m-macosx_10_13_intel.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.6.1-cp27-cp27m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.6.1-cp27-cp27m-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.6.1-cp27-cp27mu-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.6.1-cp27-cp27mu-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.6.1-cp27-cp27m-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.6.1-cp27-cp27m-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.6.1-cp34-cp34m-macosx_10_6_intel.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.6.1-cp34-cp34m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.6.1-cp34-cp34m-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.6.1-cp34-cp34m-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.6.1-cp34-cp34m-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.6.1-cp35-cp35m-macosx_10_6_intel.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.6.1-cp35-cp35m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.6.1-cp35-cp35m-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.6.1-cp35-cp35m-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.6.1-cp35-cp35m-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.6.1-cp36-cp36m-macosx_10_6_intel.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.6.1-cp36-cp36m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.6.1-cp36-cp36m-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.6.1-cp36-cp36m-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.6.1-cp36-cp36m-win_amd64.whl"}, {"packagetype": "bdist_egg", "filename": "pymongo-3.6.1-py2.6-win32.egg"}, {"packagetype": "bdist_egg", "filename": "pymongo-3.6.1-py2.6-win-amd64.egg"}, {"packagetype": "bdist_egg", "filename": "pymongo-3.6.1-py2.7-macosx-10.13-intel.egg"}, {"packagetype": "bdist_egg", "filename": "pymongo-3.6.1-py2.7-win32.egg"}, {"packagetype": "bdist_egg", "filename": "pymongo-3.6.1-py2.7-win-amd64.egg"}, {"packagetype": "bdist_egg", "filename": "pymongo-3.6.1-py3.4-macosx-10.6-intel.egg"}, {"packagetype": "bdist_egg", "filename": "pymongo-3.6.1-py3.4-win32.egg"}, {"packagetype": "bdist_egg", "filename": "pymongo-3.6.1-py3.4-win-amd64.egg"}, {"packagetype": "bdist_egg", "filename": "pymongo-3.6.1-py3.5-macosx-10.6-intel.egg"}, {"packagetype": "bdist_egg", "filename": "pymongo-3.6.1-py3.5-win32.egg"}, {"packagetype": "bdist_egg", "filename": "pymongo-3.6.1-py3.5-win-amd64.egg"}, {"packagetype": "bdist_egg", "filename": "pymongo-3.6.1-py3.6-macosx-10.6-intel.egg"}, {"packagetype": "bdist_egg", "filename": "pymongo-3.6.1-py3.6-win32.egg"}, {"packagetype": "bdist_egg", "filename": "pymongo-3.6.1-py3.6-win-amd64.egg"}, {"packagetype": "sdist", "filename": "pymongo-3.6.1.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "Operating System :: MacOS :: MacOS X", "Operating System :: Microsoft :: Windows", "Operating System :: POSIX", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Database"], "name": "pymongo", "requires_python": "", "version": "3.7.2", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "pymongo-3.7.2-cp26-cp26m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.7.2-cp26-cp26m-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.7.2-cp26-cp26mu-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.7.2-cp26-cp26mu-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.7.2-cp26-cp26m-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.7.2-cp26-cp26m-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.7.2-cp27-cp27m-macosx_10_13_intel.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.7.2-cp27-cp27m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.7.2-cp27-cp27m-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.7.2-cp27-cp27mu-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.7.2-cp27-cp27mu-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.7.2-cp27-cp27m-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.7.2-cp27-cp27m-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.7.2-cp34-cp34m-macosx_10_6_intel.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.7.2-cp34-cp34m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.7.2-cp34-cp34m-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.7.2-cp34-cp34m-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.7.2-cp34-cp34m-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.7.2-cp35-cp35m-macosx_10_6_intel.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.7.2-cp35-cp35m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.7.2-cp35-cp35m-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.7.2-cp35-cp35m-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.7.2-cp35-cp35m-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.7.2-cp36-cp36m-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.7.2-cp36-cp36m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.7.2-cp36-cp36m-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.7.2-cp36-cp36m-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.7.2-cp36-cp36m-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.7.2-cp37-cp37m-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.7.2-cp37-cp37m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.7.2-cp37-cp37m-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.7.2-cp37-cp37m-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.7.2-cp37-cp37m-win_amd64.whl"}, {"packagetype": "bdist_egg", "filename": "pymongo-3.7.2-py2.6-win32.egg"}, {"packagetype": "bdist_egg", "filename": "pymongo-3.7.2-py2.6-win-amd64.egg"}, {"packagetype": "bdist_egg", "filename": "pymongo-3.7.2-py2.7-macosx-10.13-intel.egg"}, {"packagetype": "bdist_egg", "filename": "pymongo-3.7.2-py2.7-win32.egg"}, {"packagetype": "bdist_egg", "filename": "pymongo-3.7.2-py2.7-win-amd64.egg"}, {"packagetype": "sdist", "filename": "pymongo-3.7.2.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "Operating System :: MacOS :: MacOS X", "Operating System :: Microsoft :: Windows", "Operating System :: POSIX", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Database"], "name": "pymongo", "requires_python": "", "version": "3.8.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "pymongo-3.8.0-cp27-cp27m-macosx_10_13_intel.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.8.0-cp27-cp27m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.8.0-cp27-cp27m-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.8.0-cp27-cp27mu-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.8.0-cp27-cp27mu-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.8.0-cp27-cp27m-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.8.0-cp27-cp27m-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.8.0-cp34-cp34m-macosx_10_6_intel.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.8.0-cp34-cp34m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.8.0-cp34-cp34m-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.8.0-cp34-cp34m-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.8.0-cp34-cp34m-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.8.0-cp35-cp35m-macosx_10_6_intel.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.8.0-cp35-cp35m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.8.0-cp35-cp35m-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.8.0-cp35-cp35m-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.8.0-cp35-cp35m-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.8.0-cp36-cp36m-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.8.0-cp36-cp36m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.8.0-cp36-cp36m-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.8.0-cp36-cp36m-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.8.0-cp36-cp36m-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.8.0-cp37-cp37m-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.8.0-cp37-cp37m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.8.0-cp37-cp37m-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.8.0-cp37-cp37m-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-3.8.0-cp37-cp37m-win_amd64.whl"}, {"packagetype": "bdist_egg", "filename": "pymongo-3.8.0-py2.7-macosx-10.13-intel.egg"}, {"packagetype": "bdist_egg", "filename": "pymongo-3.8.0-py2.7-win32.egg"}, {"packagetype": "bdist_egg", "filename": "pymongo-3.8.0-py2.7-win-amd64.egg"}, {"packagetype": "sdist", "filename": "pymongo-3.8.0.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "Operating System :: MacOS :: MacOS X", "Operating System :: Microsoft :: Windows", "Operating System :: POSIX", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Database", "Typing :: Typed"], "name": "pymongo", "requires_python": ">=3.9", "version": "4.18.1", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp310-cp310-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp310-cp310-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp310-cp310-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp310-cp310-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp310-cp310-win_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp311-cp311-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp311-cp311-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp311-cp311-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp311-cp311-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp311-cp311-win_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp312-cp312-macosx_10_13_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp312-cp312-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp312-cp312-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp312-cp312-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp312-cp312-win_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp313-cp313-macosx_10_13_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp313-cp313-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp313-cp313-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp313-cp313-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp313-cp313-win_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp314-cp314-macosx_10_15_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp314-cp314-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp314-cp314t-macosx_10_15_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp314-cp314t-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp314-cp314t-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp314-cp314t-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp314-cp314t-win_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp314-cp314-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp314-cp314-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp314-cp314-win_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp39-cp39-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp39-cp39-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp39-cp39-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp39-cp39-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp39-cp39-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.18.1-cp39-cp39-win_arm64.whl"}, {"packagetype": "sdist", "filename": "pymongo-4.18.1.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "Operating System :: MacOS :: MacOS X", "Operating System :: Microsoft :: Windows", "Operating System :: POSIX", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Database", "Typing :: Typed"], "name": "pymongo", "requires_python": ">=3.7", "version": "4.5.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp310-cp310-macosx_10_9_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp310-cp310-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp310-cp310-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp310-cp310-manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp310-cp310-manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp310-cp310-manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp310-cp310-manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp310-cp310-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp310-cp310-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp311-cp311-macosx_10_9_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp311-cp311-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp311-cp311-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp312-cp312-macosx_10_9_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp312-cp312-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp312-cp312-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp37-cp37m-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp37-cp37m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp37-cp37m-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp37-cp37m-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp37-cp37m-manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp37-cp37m-manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp37-cp37m-manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp37-cp37m-manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp37-cp37m-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp37-cp37m-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp38-cp38-macosx_11_0_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp38-cp38-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp38-cp38-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp38-cp38-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp38-cp38-manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp38-cp38-manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp38-cp38-manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp38-cp38-manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp38-cp38-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp38-cp38-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp39-cp39-macosx_10_9_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp39-cp39-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp39-cp39-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp39-cp39-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp39-cp39-manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp39-cp39-manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp39-cp39-manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp39-cp39-manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp39-cp39-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.5.0-cp39-cp39-win_amd64.whl"}, {"packagetype": "sdist", "filename": "pymongo-4.5.0.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 6 - Mature", "Framework :: Pyramid", "Intended Audience :: Developers", "License :: Repoze Public License", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Internet :: WWW/HTTP", "Topic :: Internet :: WWW/HTTP :: WSGI"], "name": "pyramid", "requires_python": ">=3.6", "version": "2.0.2", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "pyramid-2.0.2-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "pyramid-2.0.2.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 6 - Mature", "Framework :: Pyramid", "Intended Audience :: Developers", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Internet :: WWW/HTTP", "Topic :: Internet :: WWW/HTTP :: WSGI"], "name": "pyramid", "requires_python": ">=3.10", "version": "2.1", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "pyramid-2.1-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "pyramid-2.1.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 4 - Beta", "Intended Audience :: Developers", "Intended Audience :: Information Technology", "Operating System :: MacOS", "Operating System :: Microsoft :: Windows", "Operating System :: POSIX :: Linux", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: GraalPy", "Programming Language :: Python :: Implementation :: PyPy", "Programming Language :: Rust", "Typing :: Typed"], "name": "pyreqwest", "requires_python": ">=3.11", "version": "0.11.8", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.8-cp311-cp311-macosx_10_12_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.8-cp311-cp311-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.8-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.8-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.8-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.8-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.8-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.8-cp311-cp311-musllinux_1_1_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.8-cp311-cp311-musllinux_1_1_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.8-cp311-cp311-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.8-cp311-cp311-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.8-cp311-cp311-win_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.8-cp312-cp312-macosx_10_12_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.8-cp312-cp312-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.8-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.8-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.8-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.8-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.8-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.8-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.8-cp312-cp312-musllinux_1_1_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.8-cp312-cp312-musllinux_1_1_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.8-cp312-cp312-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.8-cp312-cp312-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.8-cp312-cp312-win_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.8-cp313-cp313-macosx_10_12_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.8-cp313-cp313-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.8-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.8-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.8-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.8-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.8-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.8-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.8-cp313-cp313-musllinux_1_1_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.8-cp313-cp313-musllinux_1_1_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.8-cp313-cp313-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.8-cp313-cp313-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.8-cp313-cp313-win_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.8-cp314-cp314-macosx_10_12_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.8-cp314-cp314-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.8-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.8-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.8-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.8-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.8-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.8-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.8-cp314-cp314-musllinux_1_1_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.8-cp314-cp314-musllinux_1_1_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.8-cp314-cp314-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.8-cp314-cp314-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.8-cp314-cp314-win_arm64.whl"}, {"packagetype": "sdist", "filename": "pyreqwest-0.11.8.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 4 - Beta", "Intended Audience :: Developers", "Intended Audience :: Information Technology", "Operating System :: MacOS", "Operating System :: Microsoft :: Windows", "Operating System :: POSIX :: Linux", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: GraalPy", "Programming Language :: Python :: Implementation :: PyPy", "Programming Language :: Rust", "Typing :: Typed"], "name": "pyreqwest", "requires_python": ">=3.11", "version": "0.12.4", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "pyreqwest-0.12.4-cp311-cp311-macosx_10_12_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.12.4-cp311-cp311-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.12.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.12.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.12.4-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.12.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.12.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.12.4-cp311-cp311-manylinux_2_28_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.12.4-cp311-cp311-musllinux_1_1_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.12.4-cp311-cp311-musllinux_1_1_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.12.4-cp311-cp311-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.12.4-cp311-cp311-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.12.4-cp311-cp311-win_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.12.4-cp312-cp312-macosx_10_12_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.12.4-cp312-cp312-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.12.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.12.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.12.4-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.12.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.12.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.12.4-cp312-cp312-manylinux_2_28_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.12.4-cp312-cp312-musllinux_1_1_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.12.4-cp312-cp312-musllinux_1_1_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.12.4-cp312-cp312-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.12.4-cp312-cp312-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.12.4-cp312-cp312-win_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.12.4-cp313-cp313-macosx_10_12_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.12.4-cp313-cp313-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.12.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.12.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.12.4-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.12.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.12.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.12.4-cp313-cp313-manylinux_2_28_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.12.4-cp313-cp313-musllinux_1_1_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.12.4-cp313-cp313-musllinux_1_1_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.12.4-cp313-cp313-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.12.4-cp313-cp313-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.12.4-cp313-cp313-win_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.12.4-cp314-cp314-macosx_10_12_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.12.4-cp314-cp314-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.12.4-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.12.4-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.12.4-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.12.4-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.12.4-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.12.4-cp314-cp314-manylinux_2_28_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.12.4-cp314-cp314-musllinux_1_1_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.12.4-cp314-cp314-musllinux_1_1_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.12.4-cp314-cp314-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.12.4-cp314-cp314-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.12.4-cp314-cp314-win_arm64.whl"}, {"packagetype": "sdist", "filename": "pyreqwest-0.12.4.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 4 - Beta", "Intended Audience :: Developers", "Intended Audience :: Information Technology", "Operating System :: MacOS", "Operating System :: Microsoft :: Windows", "Operating System :: POSIX :: Linux", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: GraalPy", "Programming Language :: Python :: Implementation :: PyPy", "Programming Language :: Rust", "Typing :: Typed"], "name": "pyreqwest", "requires_python": ">=3.11", "version": "0.13.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "pyreqwest-0.13.0-cp311-cp311-macosx_10_12_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.13.0-cp311-cp311-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.13.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.13.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.13.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.13.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.13.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.13.0-cp311-cp311-manylinux_2_28_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.13.0-cp311-cp311-musllinux_1_1_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.13.0-cp311-cp311-musllinux_1_1_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.13.0-cp311-cp311-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.13.0-cp311-cp311-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.13.0-cp311-cp311-win_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.13.0-cp312-cp312-macosx_10_12_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.13.0-cp312-cp312-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.13.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.13.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.13.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.13.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.13.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.13.0-cp312-cp312-manylinux_2_28_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.13.0-cp312-cp312-musllinux_1_1_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.13.0-cp312-cp312-musllinux_1_1_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.13.0-cp312-cp312-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.13.0-cp312-cp312-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.13.0-cp312-cp312-win_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.13.0-cp313-cp313-macosx_10_12_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.13.0-cp313-cp313-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.13.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.13.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.13.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.13.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.13.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.13.0-cp313-cp313-manylinux_2_28_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.13.0-cp313-cp313-musllinux_1_1_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.13.0-cp313-cp313-musllinux_1_1_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.13.0-cp313-cp313-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.13.0-cp313-cp313-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.13.0-cp313-cp313-win_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.13.0-cp314-cp314-macosx_10_12_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.13.0-cp314-cp314-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.13.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.13.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.13.0-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.13.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.13.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.13.0-cp314-cp314-manylinux_2_28_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.13.0-cp314-cp314-musllinux_1_1_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.13.0-cp314-cp314-musllinux_1_1_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.13.0-cp314-cp314-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.13.0-cp314-cp314-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.13.0-cp314-cp314-win_arm64.whl"}, {"packagetype": "sdist", "filename": "pyreqwest-0.13.0.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "License :: OSI Approved :: Apache Software License", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy"], "name": "pyspark", "requires_python": "", "version": "3.0.3", "yanked": false}, "urls": [{"packagetype": "sdist", "filename": "pyspark-3.0.3.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "License :: OSI Approved :: Apache Software License", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Typing :: Typed"], "name": "pyspark", "requires_python": ">=3.8", "version": "3.5.9", "yanked": false}, "urls": [{"packagetype": "sdist", "filename": "pyspark-3.5.9.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Programming Language :: Python :: Implementation :: CPython", "Typing :: Typed"], "name": "pyspark", "requires_python": ">=3.10", "version": "4.2.0", "yanked": false}, "urls": [{"packagetype": "sdist", "filename": "pyspark-4.2.0.tar.gz"}]} +{"info": {"classifiers": ["Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.9"], "name": "ray", "requires_python": ">=3.9", "version": "2.39.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "ray-2.39.0-cp310-cp310-macosx_10_15_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.39.0-cp310-cp310-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.39.0-cp310-cp310-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.39.0-cp310-cp310-manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.39.0-cp310-cp310-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.39.0-cp311-cp311-macosx_10_15_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.39.0-cp311-cp311-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.39.0-cp311-cp311-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.39.0-cp311-cp311-manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.39.0-cp311-cp311-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.39.0-cp312-cp312-macosx_10_15_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.39.0-cp312-cp312-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.39.0-cp312-cp312-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.39.0-cp312-cp312-manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.39.0-cp312-cp312-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.39.0-cp39-cp39-macosx_10_15_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.39.0-cp39-cp39-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.39.0-cp39-cp39-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.39.0-cp39-cp39-manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.39.0-cp39-cp39-win_amd64.whl"}]} +{"info": {"classifiers": ["Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.9"], "name": "ray", "requires_python": ">=3.9", "version": "2.49.2", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "ray-2.49.2-cp310-cp310-macosx_12_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.49.2-cp310-cp310-macosx_12_0_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.49.2-cp310-cp310-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.49.2-cp310-cp310-manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.49.2-cp310-cp310-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.49.2-cp311-cp311-macosx_12_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.49.2-cp311-cp311-macosx_12_0_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.49.2-cp311-cp311-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.49.2-cp311-cp311-manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.49.2-cp311-cp311-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.49.2-cp312-cp312-macosx_12_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.49.2-cp312-cp312-macosx_12_0_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.49.2-cp312-cp312-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.49.2-cp312-cp312-manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.49.2-cp312-cp312-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.49.2-cp313-cp313-macosx_12_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.49.2-cp313-cp313-macosx_12_0_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.49.2-cp313-cp313-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.49.2-cp313-cp313-manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.49.2-cp39-cp39-macosx_12_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.49.2-cp39-cp39-macosx_12_0_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.49.2-cp39-cp39-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.49.2-cp39-cp39-manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.49.2-cp39-cp39-win_amd64.whl"}]} +{"info": {"classifiers": ["Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13"], "name": "ray", "requires_python": ">=3.10", "version": "2.54.1", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "ray-2.54.1-cp310-cp310-macosx_12_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.54.1-cp310-cp310-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.54.1-cp310-cp310-manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.54.1-cp310-cp310-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.54.1-cp311-cp311-macosx_12_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.54.1-cp311-cp311-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.54.1-cp311-cp311-manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.54.1-cp311-cp311-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.54.1-cp312-cp312-macosx_12_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.54.1-cp312-cp312-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.54.1-cp312-cp312-manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.54.1-cp312-cp312-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.54.1-cp313-cp313-macosx_12_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.54.1-cp313-cp313-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.54.1-cp313-cp313-manylinux2014_x86_64.whl"}]} +{"info": {"classifiers": ["Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14"], "name": "ray", "requires_python": ">=3.10", "version": "2.57.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "ray-2.57.0-cp310-cp310-macosx_12_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.57.0-cp310-cp310-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.57.0-cp310-cp310-manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.57.0-cp310-cp310-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.57.0-cp311-cp311-macosx_12_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.57.0-cp311-cp311-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.57.0-cp311-cp311-manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.57.0-cp311-cp311-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.57.0-cp312-cp312-macosx_12_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.57.0-cp312-cp312-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.57.0-cp312-cp312-manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.57.0-cp312-cp312-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.57.0-cp313-cp313-macosx_12_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.57.0-cp313-cp313-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.57.0-cp313-cp313-manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.57.0-cp314-cp314-macosx_12_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.57.0-cp314-cp314-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.57.0-cp314-cp314-manylinux2014_x86_64.whl"}]} +{"info": {"classifiers": ["Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14"], "name": "ray", "requires_python": ">=3.10", "version": "2.58.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "ray-2.58.0-cp310-cp310-macosx_12_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.58.0-cp310-cp310-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.58.0-cp310-cp310-manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.58.0-cp310-cp310-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.58.0-cp311-cp311-macosx_12_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.58.0-cp311-cp311-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.58.0-cp311-cp311-manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.58.0-cp311-cp311-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.58.0-cp312-cp312-macosx_12_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.58.0-cp312-cp312-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.58.0-cp312-cp312-manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.58.0-cp312-cp312-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.58.0-cp313-cp313-macosx_12_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.58.0-cp313-cp313-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.58.0-cp313-cp313-manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.58.0-cp313-cp313-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.58.0-cp314-cp314-macosx_12_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.58.0-cp314-cp314-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.58.0-cp314-cp314-manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.58.0-cp314-cp314-win_amd64.whl"}]} +{"info": {"classifiers": ["Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9"], "name": "ray", "requires_python": "", "version": "2.7.2", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "ray-2.7.2-cp310-cp310-macosx_10_15_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.7.2-cp310-cp310-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.7.2-cp310-cp310-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.7.2-cp310-cp310-manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.7.2-cp310-cp310-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.7.2-cp311-cp311-macosx_10_15_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.7.2-cp311-cp311-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.7.2-cp311-cp311-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.7.2-cp311-cp311-manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.7.2-cp311-cp311-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.7.2-cp37-cp37m-macosx_10_15_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.7.2-cp37-cp37m-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.7.2-cp37-cp37m-manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.7.2-cp37-cp37m-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.7.2-cp38-cp38-macosx_10_15_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.7.2-cp38-cp38-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.7.2-cp38-cp38-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.7.2-cp38-cp38-manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.7.2-cp38-cp38-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.7.2-cp39-cp39-macosx_10_15_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.7.2-cp39-cp39-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.7.2-cp39-cp39-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.7.2-cp39-cp39-manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.7.2-cp39-cp39-win_amd64.whl"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Console", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy"], "name": "redis", "requires_python": ">=3.6", "version": "4.2.2", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "redis-4.2.2-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "redis-4.2.2.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Console", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy"], "name": "redis", "requires_python": ">=3.7", "version": "4.6.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "redis-4.6.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "redis-4.6.0.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Console", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy"], "name": "redis", "requires_python": ">=3.8", "version": "5.3.1", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "redis-5.3.1-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "redis-5.3.1.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Console", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy"], "name": "redis", "requires_python": ">=3.9", "version": "6.4.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "redis-6.4.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "redis-6.4.0.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Console", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy"], "name": "redis", "requires_python": ">=3.10", "version": "7.4.1", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "redis-7.4.1-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "redis-7.4.1.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Console", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy"], "name": "redis", "requires_python": ">=3.10", "version": "8.1.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "redis-8.1.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "redis-8.1.0.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "Natural Language :: English", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Internet :: WWW/HTTP", "Topic :: Software Development :: Libraries"], "name": "requests", "requires_python": ">=3.7", "version": "2.30.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "requests-2.30.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "requests-2.30.0.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "Natural Language :: English", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Programming Language :: Python :: 3.15", "Programming Language :: Python :: Free Threading :: 2 - Beta", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Internet :: WWW/HTTP", "Topic :: Software Development :: Libraries"], "name": "requests", "requires_python": ">=3.10", "version": "2.34.2", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "requests-2.34.2-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "requests-2.34.2.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "Intended Audience :: End Users/Desktop", "Intended Audience :: Information Technology", "Intended Audience :: Science/Research", "Intended Audience :: System Administrators", "License :: OSI Approved :: BSD License", "Operating System :: MacOS", "Operating System :: POSIX", "Operating System :: Unix", "Programming Language :: Python", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Topic :: Internet", "Topic :: Scientific/Engineering", "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: System :: Distributed Computing", "Topic :: System :: Monitoring", "Topic :: System :: Systems Administration"], "name": "rq", "requires_python": ">=2.7", "version": "1.0", "yanked": false}, "urls": [{"packagetype": "sdist", "filename": "rq-1.0.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "Intended Audience :: End Users/Desktop", "Intended Audience :: Information Technology", "Intended Audience :: Science/Research", "Intended Audience :: System Administrators", "License :: OSI Approved :: BSD License", "Operating System :: MacOS", "Operating System :: POSIX", "Operating System :: Unix", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Topic :: Internet", "Topic :: Scientific/Engineering", "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: System :: Distributed Computing", "Topic :: System :: Monitoring", "Topic :: System :: Systems Administration"], "name": "rq", "requires_python": ">=3.6", "version": "1.15.1", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "rq-1.15.1-py2.py3-none-any.whl"}, {"packagetype": "sdist", "filename": "rq-1.15.1.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "Intended Audience :: End Users/Desktop", "Intended Audience :: Information Technology", "Intended Audience :: Science/Research", "Intended Audience :: System Administrators", "License :: OSI Approved :: BSD License", "Operating System :: MacOS", "Operating System :: POSIX", "Operating System :: Unix", "Programming Language :: Python", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Topic :: Internet", "Topic :: Scientific/Engineering", "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: System :: Distributed Computing", "Topic :: System :: Monitoring", "Topic :: System :: Systems Administration"], "name": "rq", "requires_python": ">=3.7", "version": "1.16.2", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "rq-1.16.2-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "rq-1.16.2.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "Intended Audience :: End Users/Desktop", "Intended Audience :: Information Technology", "Intended Audience :: Science/Research", "Intended Audience :: System Administrators", "License :: OSI Approved :: BSD License", "Operating System :: MacOS", "Operating System :: POSIX", "Operating System :: Unix", "Programming Language :: Python", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Topic :: Internet", "Topic :: Scientific/Engineering", "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: System :: Distributed Computing", "Topic :: System :: Monitoring", "Topic :: System :: Systems Administration"], "name": "rq", "requires_python": ">=3.10", "version": "2.10.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "rq-2.10.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "rq-2.10.0.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "Intended Audience :: End Users/Desktop", "Intended Audience :: Information Technology", "Intended Audience :: Science/Research", "Intended Audience :: System Administrators", "License :: OSI Approved :: BSD License", "Operating System :: MacOS", "Operating System :: POSIX", "Operating System :: Unix", "Programming Language :: Python", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Topic :: Internet", "Topic :: Scientific/Engineering", "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: System :: Distributed Computing", "Topic :: System :: Monitoring", "Topic :: System :: Systems Administration"], "name": "rq", "requires_python": ">=3.10", "version": "2.12.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "rq-2.12.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "rq-2.12.0.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "Intended Audience :: End Users/Desktop", "Intended Audience :: Information Technology", "Intended Audience :: Science/Research", "Intended Audience :: System Administrators", "License :: OSI Approved :: BSD License", "Operating System :: MacOS", "Operating System :: POSIX", "Operating System :: Unix", "Programming Language :: Python", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.9", "Topic :: Internet", "Topic :: Scientific/Engineering", "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: System :: Distributed Computing", "Topic :: System :: Monitoring", "Topic :: System :: Systems Administration"], "name": "rq", "requires_python": ">=3.9", "version": "2.6.1", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "rq-2.6.1-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "rq-2.6.1.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 4 - Beta", "Environment :: Web Environment", "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9"], "name": "sanic", "requires_python": ">=3.7", "version": "22.12.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "sanic-22.12.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "sanic-22.12.0.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 4 - Beta", "Environment :: Web Environment", "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9"], "name": "sanic", "requires_python": ">=3.7", "version": "22.3.2", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "sanic-22.3.2-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "sanic-22.3.2.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 4 - Beta", "Environment :: Web Environment", "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9"], "name": "sanic", "requires_python": ">=3.8", "version": "23.12.2", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "sanic-23.12.2-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "sanic-23.12.2.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 4 - Beta", "Environment :: Web Environment", "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14"], "name": "sanic", "requires_python": ">=3.10", "version": "25.12.1", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "sanic-25.12.1-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "sanic-25.12.1.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 3 - Alpha", "Environment :: Web Environment", "Framework :: AnyIO", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Topic :: Internet :: WWW/HTTP"], "name": "starlette", "requires_python": ">=3.7", "version": "0.20.4", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "starlette-0.20.4-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "starlette-0.20.4.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 3 - Alpha", "Environment :: Web Environment", "Framework :: AnyIO", "Intended Audience :: Developers", "Operating System :: OS Independent", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Topic :: Internet :: WWW/HTTP"], "name": "starlette", "requires_python": ">=3.10", "version": "0.52.1", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "starlette-0.52.1-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "starlette-0.52.1.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 3 - Alpha", "Environment :: Web Environment", "Framework :: AnyIO", "Intended Audience :: Developers", "Operating System :: OS Independent", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Topic :: Internet :: WWW/HTTP"], "name": "starlette", "requires_python": ">=3.10", "version": "1.6.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "starlette-1.6.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "starlette-1.6.0.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "License :: OSI Approved :: MIT License", "Natural Language :: English", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Topic :: Internet :: WWW/HTTP", "Topic :: Software Development", "Topic :: Software Development :: Libraries", "Typing :: Typed"], "name": "starlite", "requires_python": ">=3.8,<4.0", "version": "1.48.1", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "starlite-1.48.1-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "starlite-1.48.1.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "License :: OSI Approved :: MIT License", "Natural Language :: English", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Topic :: Internet :: WWW/HTTP", "Topic :: Software Development", "Topic :: Software Development :: Libraries", "Typing :: Typed"], "name": "starlite", "requires_python": "<4.0,>=3.8", "version": "1.51.16", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "starlite-1.51.16-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "starlite-1.51.16.tar.gz"}]} +{"info": {"classifiers": ["Intended Audience :: Developers", "Programming Language :: Python", "Programming Language :: Python :: 3", "Topic :: Software Development :: Libraries"], "name": "statsig", "requires_python": ">=3.7", "version": "0.55.3", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "statsig-0.55.3-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "statsig-0.55.3.tar.gz"}]} +{"info": {"classifiers": ["Intended Audience :: Developers", "Programming Language :: Python", "Programming Language :: Python :: 3", "Topic :: Software Development :: Libraries"], "name": "statsig", "requires_python": ">=3.7", "version": "0.72.1", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "statsig-0.72.1-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "statsig-0.72.1.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Topic :: Software Development :: Libraries", "Topic :: Software Development :: Libraries :: Python Modules"], "name": "strawberry-graphql", "requires_python": ">=3.8,<4.0", "version": "0.209.8", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "strawberry_graphql-0.209.8-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "strawberry_graphql-0.209.8.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "Topic :: Software Development :: Libraries", "Topic :: Software Development :: Libraries :: Python Modules"], "name": "strawberry-graphql", "requires_python": "<4.0,>=3.10", "version": "0.327.7", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "strawberry_graphql-0.327.7-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "strawberry_graphql-0.327.7.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "Intended Audience :: Education", "Intended Audience :: Science/Research", "License :: OSI Approved :: Apache Software License", "Operating System :: OS Independent", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Topic :: Scientific/Engineering :: Artificial Intelligence"], "name": "tokenizers", "requires_python": ">=3.10", "version": "0.23.1", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "tokenizers-0.23.1-cp310-abi3-macosx_10_12_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "tokenizers-0.23.1-cp310-abi3-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "tokenizers-0.23.1-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "tokenizers-0.23.1-cp310-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "tokenizers-0.23.1-cp310-abi3-manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "tokenizers-0.23.1-cp310-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "tokenizers-0.23.1-cp310-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "tokenizers-0.23.1-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "tokenizers-0.23.1-cp310-abi3-manylinux_2_31_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "tokenizers-0.23.1-cp310-abi3-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "tokenizers-0.23.1-cp310-abi3-musllinux_1_2_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "tokenizers-0.23.1-cp310-abi3-musllinux_1_2_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "tokenizers-0.23.1-cp310-abi3-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "tokenizers-0.23.1-cp310-abi3-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "tokenizers-0.23.1-cp310-abi3-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "tokenizers-0.23.1-cp310-abi3-win_arm64.whl"}, {"packagetype": "sdist", "filename": "tokenizers-0.23.1.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "Intended Audience :: Education", "Intended Audience :: Science/Research", "License :: OSI Approved :: Apache Software License", "Operating System :: OS Independent", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Topic :: Scientific/Engineering :: Artificial Intelligence"], "name": "tokenizers", "requires_python": ">=3.10", "version": "0.23.2", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "tokenizers-0.23.2-cp310-abi3-macosx_10_12_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "tokenizers-0.23.2-cp310-abi3-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "tokenizers-0.23.2-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "tokenizers-0.23.2-cp310-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "tokenizers-0.23.2-cp310-abi3-manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "tokenizers-0.23.2-cp310-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "tokenizers-0.23.2-cp310-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "tokenizers-0.23.2-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "tokenizers-0.23.2-cp310-abi3-manylinux_2_31_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "tokenizers-0.23.2-cp310-abi3-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "tokenizers-0.23.2-cp310-abi3-musllinux_1_2_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "tokenizers-0.23.2-cp310-abi3-musllinux_1_2_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "tokenizers-0.23.2-cp310-abi3-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "tokenizers-0.23.2-cp310-abi3-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "tokenizers-0.23.2-cp310-abi3-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "tokenizers-0.23.2-cp310-abi3-win_arm64.whl"}, {"packagetype": "sdist", "filename": "tokenizers-0.23.2.tar.gz"}]} +{"info": {"classifiers": ["License :: OSI Approved :: Apache Software License", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy"], "name": "tornado", "requires_python": ">= 3.5", "version": "6.0.4", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "tornado-6.0.4-cp35-cp35m-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "tornado-6.0.4-cp35-cp35m-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "tornado-6.0.4-cp36-cp36m-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "tornado-6.0.4-cp36-cp36m-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "tornado-6.0.4-cp37-cp37m-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "tornado-6.0.4-cp37-cp37m-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "tornado-6.0.4-cp38-cp38-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "tornado-6.0.4-cp38-cp38-win_amd64.whl"}, {"packagetype": "sdist", "filename": "tornado-6.0.4.tar.gz"}]} +{"info": {"classifiers": ["License :: OSI Approved :: Apache Software License", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy"], "name": "tornado", "requires_python": ">=3.9", "version": "6.5.10", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "tornado-6.5.10-cp39-abi3-macosx_10_9_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "tornado-6.5.10-cp39-abi3-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "tornado-6.5.10-cp39-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "tornado-6.5.10-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "tornado-6.5.10-cp39-abi3-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "tornado-6.5.10-cp39-abi3-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "tornado-6.5.10-cp39-abi3-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "tornado-6.5.10-cp39-abi3-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "tornado-6.5.10-cp39-abi3-win_arm64.whl"}, {"packagetype": "sdist", "filename": "tornado-6.5.10.tar.gz"}]} +{"info": {"classifiers": ["License :: OSI Approved :: Apache Software License", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Programming Language :: Python :: 3.15", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy"], "name": "tornado", "requires_python": ">=3.11", "version": "6.6a1", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "tornado-6.6a1-cp311-abi3-macosx_10_9_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "tornado-6.6a1-cp311-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "tornado-6.6a1-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "tornado-6.6a1-cp311-abi3-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "tornado-6.6a1-cp311-abi3-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "tornado-6.6a1-cp311-abi3-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "tornado-6.6a1-cp311-abi3-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "tornado-6.6a1-cp311-abi3-musllinux_1_2_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "tornado-6.6a1-cp311-abi3-musllinux_1_2_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "tornado-6.6a1-cp311-abi3-musllinux_1_2_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "tornado-6.6a1-cp311-abi3-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "tornado-6.6a1-cp311-abi3-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "tornado-6.6a1-cp311-abi3-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "tornado-6.6a1-cp311-abi3-win_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "tornado-6.6a1-cp314-cp314t-macosx_10_15_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "tornado-6.6a1-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "tornado-6.6a1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "tornado-6.6a1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "tornado-6.6a1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "tornado-6.6a1-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "tornado-6.6a1-cp314-cp314t-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "tornado-6.6a1-cp314-cp314t-musllinux_1_2_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "tornado-6.6a1-cp314-cp314t-musllinux_1_2_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "tornado-6.6a1-cp314-cp314t-musllinux_1_2_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "tornado-6.6a1-cp314-cp314t-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "tornado-6.6a1-cp314-cp314t-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "tornado-6.6a1-cp314-cp314t-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "tornado-6.6a1-cp314-cp314t-win_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "tornado-6.6a1-cp315-cp315t-macosx_10_15_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "tornado-6.6a1-cp315-cp315t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "tornado-6.6a1-cp315-cp315t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "tornado-6.6a1-cp315-cp315t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "tornado-6.6a1-cp315-cp315t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "tornado-6.6a1-cp315-cp315t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "tornado-6.6a1-cp315-cp315t-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "tornado-6.6a1-cp315-cp315t-musllinux_1_2_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "tornado-6.6a1-cp315-cp315t-musllinux_1_2_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "tornado-6.6a1-cp315-cp315t-musllinux_1_2_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "tornado-6.6a1-cp315-cp315t-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "tornado-6.6a1-cp315-cp315t-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "tornado-6.6a1-cp315-cp315t-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "tornado-6.6a1-cp315-cp315t-win_arm64.whl"}, {"packagetype": "sdist", "filename": "tornado-6.6a1.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Console", "Environment :: No Input/Output (Daemon)", "Framework :: Tryton", "Intended Audience :: Developers", "License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)", "Natural Language :: Bulgarian", "Natural Language :: Catalan", "Natural Language :: Chinese (Simplified)", "Natural Language :: Czech", "Natural Language :: Dutch", "Natural Language :: English", "Natural Language :: Finnish", "Natural Language :: French", "Natural Language :: German", "Natural Language :: Hungarian", "Natural Language :: Indonesian", "Natural Language :: Italian", "Natural Language :: Persian", "Natural Language :: Polish", "Natural Language :: Portuguese (Brazilian)", "Natural Language :: Russian", "Natural Language :: Slovenian", "Natural Language :: Spanish", "Natural Language :: Turkish", "Operating System :: OS Independent", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Software Development :: Libraries :: Application Frameworks"], "name": "trytond", "requires_python": ">=3.5", "version": "5.4.20", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "trytond-5.4.20-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "trytond-5.4.20.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Console", "Environment :: No Input/Output (Daemon)", "Framework :: Tryton", "Intended Audience :: Developers", "License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)", "Natural Language :: Bulgarian", "Natural Language :: Catalan", "Natural Language :: Chinese (Simplified)", "Natural Language :: Czech", "Natural Language :: Dutch", "Natural Language :: English", "Natural Language :: Finnish", "Natural Language :: French", "Natural Language :: German", "Natural Language :: Hungarian", "Natural Language :: Indonesian", "Natural Language :: Italian", "Natural Language :: Persian", "Natural Language :: Polish", "Natural Language :: Portuguese (Brazilian)", "Natural Language :: Russian", "Natural Language :: Slovenian", "Natural Language :: Spanish", "Natural Language :: Turkish", "Operating System :: OS Independent", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Software Development :: Libraries :: Application Frameworks"], "name": "trytond", "requires_python": ">=3.6", "version": "5.8.16", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "trytond-5.8.16-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "trytond-5.8.16.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Console", "Environment :: No Input/Output (Daemon)", "Framework :: Tryton", "Intended Audience :: Developers", "License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)", "Natural Language :: Bulgarian", "Natural Language :: Catalan", "Natural Language :: Chinese (Simplified)", "Natural Language :: Czech", "Natural Language :: Dutch", "Natural Language :: English", "Natural Language :: Finnish", "Natural Language :: French", "Natural Language :: German", "Natural Language :: Hungarian", "Natural Language :: Indonesian", "Natural Language :: Italian", "Natural Language :: Persian", "Natural Language :: Polish", "Natural Language :: Portuguese (Brazilian)", "Natural Language :: Romanian", "Natural Language :: Russian", "Natural Language :: Slovenian", "Natural Language :: Spanish", "Natural Language :: Turkish", "Natural Language :: Ukrainian", "Operating System :: OS Independent", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: Implementation :: CPython", "Topic :: Software Development :: Libraries :: Application Frameworks"], "name": "trytond", "requires_python": ">=3.8", "version": "6.8.17", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "trytond-6.8.17-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "trytond-6.8.17.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Console", "Environment :: No Input/Output (Daemon)", "Framework :: Tryton", "Intended Audience :: Developers", "License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)", "Natural Language :: Bulgarian", "Natural Language :: Catalan", "Natural Language :: Chinese (Simplified)", "Natural Language :: Czech", "Natural Language :: Dutch", "Natural Language :: English", "Natural Language :: Finnish", "Natural Language :: French", "Natural Language :: German", "Natural Language :: Hungarian", "Natural Language :: Indonesian", "Natural Language :: Italian", "Natural Language :: Persian", "Natural Language :: Polish", "Natural Language :: Portuguese (Brazilian)", "Natural Language :: Romanian", "Natural Language :: Russian", "Natural Language :: Slovenian", "Natural Language :: Spanish", "Natural Language :: Turkish", "Natural Language :: Ukrainian", "Operating System :: OS Independent", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: Implementation :: CPython", "Topic :: Software Development :: Libraries :: Application Frameworks"], "name": "trytond", "requires_python": ">=3.9", "version": "7.8.16", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "trytond-7.8.16-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "trytond-7.8.16.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Console", "Environment :: No Input/Output (Daemon)", "Framework :: Tryton", "Intended Audience :: Developers", "Topic :: Office/Business", "Topic :: Software Development :: Libraries :: Application Frameworks"], "name": "trytond", "requires_python": ">=3.10", "version": "8.0.10", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "trytond-8.0.10-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "trytond-8.0.10.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 4 - Beta", "Intended Audience :: Developers", "Intended Audience :: Information Technology", "Intended Audience :: System Administrators", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Topic :: Software Development", "Topic :: Software Development :: Libraries", "Topic :: Software Development :: Libraries :: Application Frameworks", "Topic :: Software Development :: Libraries :: Python Modules", "Typing :: Typed"], "name": "typer", "requires_python": ">=3.7", "version": "0.15.4", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "typer-0.15.4-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "typer-0.15.4.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 4 - Beta", "Intended Audience :: Developers", "Intended Audience :: Information Technology", "Intended Audience :: System Administrators", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Topic :: Software Development", "Topic :: Software Development :: Libraries", "Topic :: Software Development :: Libraries :: Application Frameworks", "Topic :: Software Development :: Libraries :: Python Modules", "Typing :: Typed"], "name": "typer", "requires_python": ">=3.10", "version": "0.27.2", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "typer-0.27.2-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "typer-0.27.2.tar.gz"}]} diff --git a/scripts/populate_tox/tox.jinja b/scripts/populate_tox/tox.jinja index ea5ca7e549..f47fe977e3 100644 --- a/scripts/populate_tox/tox.jinja +++ b/scripts/populate_tox/tox.jinja @@ -17,13 +17,10 @@ requires = tox-uv envlist = # === Common === - {py3.6,py3.7,py3.8,py3.9,py3.10,py3.11,py3.12,py3.13,py3.14,py3.14t,py3.15,py3.15t}-common + {py3.7,py3.8,py3.9,py3.10,py3.11,py3.12,py3.13,py3.14,py3.14t,py3.15,py3.15t}-common # === Gevent === - {py3.6,py3.8,py3.10,py3.11,py3.12}-gevent - - # === Integration Deactivation === - {py3.9,py3.10,py3.11,py3.12,py3.13,py3.14}-integration_deactivation + {py3.7,py3.8,py3.10,py3.11,py3.12}-gevent # === Shadowed Module === {py3.7,py3.8,py3.9,py3.10,py3.11,py3.12,py3.13,py3.14,py3.14t,py3.15,py3.15t}-shadowed_module @@ -37,20 +34,14 @@ envlist = {py3.8,py3.9,py3.11,py3.13}-aws_lambda # Cloud Resource Context - {py3.6,py3.12,py3.13}-cloud_resource_context + {py3.7,py3.12,py3.13}-cloud_resource_context # GCP {py3.7}-gcp - # OpenTelemetry (OTel) - {py3.7,py3.9,py3.12,py3.13,py3.14,py3.14t}-opentelemetry - # OpenTelemetry with OTLP {py3.7,py3.9,py3.12,py3.13,py3.14}-otlp - # OpenTelemetry Experimental (POTel) - {py3.8,py3.9,py3.10,py3.11,py3.12,py3.13}-potel - # === Integrations - Auto-generated === # These come from the populate_tox.py script. @@ -89,20 +80,20 @@ deps = # See https://github.com/pytest-dev/pytest/issues/9621 # and https://github.com/pytest-dev/pytest-forked/issues/67 # for justification of the upper bound on pytest - {py3.6,py3.7}-common: pytest<7.0.0 + py3.7-common: pytest<7.0.0 # Handled by importlib.metadata on Python 3.8+ - {py3.6,py3.7}-common: setuptools<82 + py3.7-common: setuptools<82 {py3.8,py3.9,py3.10,py3.11,py3.12,py3.13,py3.14,py3.14t,py3.15,py3.15t}-common: pytest # coverage 7.11.1-7.11.3 makes some of our tests flake {py3.14,py3.14t,py3.15,py3.15t}-common: coverage==7.11.0 # === Gevent === - {py3.6,py3.7,py3.8,py3.9,py3.10,py3.11}-gevent: gevent>=22.10.0, <22.11.0 + {py3.7,py3.8,py3.9,py3.10,py3.11}-gevent: gevent>=22.10.0, <22.11.0 {py3.12}-gevent: gevent # See https://github.com/pytest-dev/pytest/issues/9621 # and https://github.com/pytest-dev/pytest-forked/issues/67 # for justification of the upper bound on pytest - {py3.6,py3.7}-gevent: pytest<7.0.0 + py3.7-gevent: pytest<7.0.0 {py3.8,py3.9,py3.10,py3.11,py3.12}-gevent: pytest gevent: brotli gevent: executing @@ -119,11 +110,6 @@ deps = {py3.10,py3.11}-gevent: zope.event<5.0.0 {py3.10,py3.11}-gevent: zope.interface<8.0 - # === Integration Deactivation === - integration_deactivation: openai - integration_deactivation: anthropic - integration_deactivation: langchain - # === Integrations === # Asgi @@ -139,18 +125,10 @@ deps = aws_lambda: uvicorn aws_lambda: pyyaml - # OpenTelemetry (OTel) - opentelemetry: opentelemetry-distro - opentelemetry: pytest-forked - # OpenTelemetry with OTLP otlp: opentelemetry-distro[otlp] otlp: responses - # OpenTelemetry Experimental (POTel) - potel: opentelemetry-distro - potel: pytest-forked - # === Integrations - Auto-generated === # These come from the populate_tox.py script. @@ -198,10 +176,7 @@ deps = ; Install the SDK in deps so uv resolves runtime deps together with ; everything above in a single pass. - ; uv only supports PEP 660 editables; py3.6's max setuptools (~59) predates - ; PEP 660, so fall back to a non-editable install there. !py3.6: -e . - py3.6: . setenv = PYTHONDONTWRITEBYTECODE=1 @@ -218,8 +193,6 @@ setenv = {% endfor %} {% endfor %} - py3.6: COVERAGE_RCFILE=.coveragerc36 - django: DJANGO_SETTINGS_MODULE=tests.integrations.django.myapp.settings spark-v{3.0.3,3.5.6}: JAVA_HOME=/usr/lib/jvm/temurin-11-jdk-amd64 @@ -236,15 +209,12 @@ setenv = # TESTPATH definitions for test suites not managed by toxgen common: _TESTPATH=tests gevent: _TESTPATH=tests - integration_deactivation: _TESTPATH=tests/test_ai_integration_deactivation.py shadowed_module: _TESTPATH=tests/test_shadowed_module.py asgi: _TESTPATH=tests/integrations/asgi aws_lambda: _TESTPATH=tests/integrations/aws_lambda cloud_resource_context: _TESTPATH=tests/integrations/cloud_resource_context gcp: _TESTPATH=tests/integrations/gcp - opentelemetry: _TESTPATH=tests/integrations/opentelemetry otlp: _TESTPATH=tests/integrations/otlp - potel: _TESTPATH=tests/integrations/opentelemetry socket: _TESTPATH=tests/integrations/socket # These TESTPATH definitions are auto-generated by toxgen @@ -263,7 +233,6 @@ passenv = TESTPATH basepython = - py3.6: python3.6 py3.7: python3.7 py3.8: python3.8 py3.9: python3.9 diff --git a/scripts/runtox.sh b/scripts/runtox.sh index 61b6c492d3..9f370ebc67 100755 --- a/scripts/runtox.sh +++ b/scripts/runtox.sh @@ -21,7 +21,7 @@ fi # `uv run` itself uses the workspace venv's interpreter (uv's default # `managed` preference). tox-uv, which provisions per-env interpreters, may -# need a different preference (e.g. `only-system` inside the 3.6/3.7 +# need a different preference (e.g. `only-system` inside the 3.7 # container); the workflow passes that via TOX_UV_PYTHON_PREFERENCE. TOX_ENV=() if [ -n "$TOX_UV_PYTHON_PREFERENCE" ]; then diff --git a/scripts/split_tox_gh_actions/split_tox_gh_actions.py b/scripts/split_tox_gh_actions/split_tox_gh_actions.py index 32f89ab1db..923f8f2a2f 100755 --- a/scripts/split_tox_gh_actions/split_tox_gh_actions.py +++ b/scripts/split_tox_gh_actions/split_tox_gh_actions.py @@ -109,7 +109,6 @@ "clickhouse_driver", "pymongo", "redis", - "redis_py_cluster_legacy", "sqlalchemy", ], "Flags": [ @@ -164,13 +163,10 @@ ], "Misc": [ "loguru", - "opentelemetry", "otlp", - "potel", "pure_eval", - "trytond", + "trytond_wsgi", "typer", - "integration_deactivation", "shadowed_module", ], } diff --git a/scripts/split_tox_gh_actions/templates/test_group.jinja b/scripts/split_tox_gh_actions/templates/test_group.jinja index d6a1aea5a0..708c84f591 100644 --- a/scripts/split_tox_gh_actions/templates/test_group.jinja +++ b/scripts/split_tox_gh_actions/templates/test_group.jinja @@ -56,21 +56,21 @@ {% endif %} {% endif %} env: - # 3.6/3.7 run in the python:X.Y container; tell uv to use that system Python. - TOX_UV_PYTHON_PREFERENCE: {% raw %}${{ (matrix.python-version == '3.6' || matrix.python-version == '3.7') && 'only-system' || 'managed' }}{% endraw %} + # 3.7 runs in the python:X.Y container; tell uv to use that system Python. + TOX_UV_PYTHON_PREFERENCE: {% raw %}${{ (matrix.python-version == '3.7') && 'only-system' || 'managed' }}{% endraw %} {% if needs_postgres %} - SENTRY_PYTHON_TEST_POSTGRES_HOST: {% raw %}${{ (matrix.python-version == '3.6' || matrix.python-version == '3.7') && 'postgres' || 'localhost' }}{% endraw %} + SENTRY_PYTHON_TEST_POSTGRES_HOST: {% raw %}${{ (matrix.python-version == '3.7') && 'postgres' || 'localhost' }}{% endraw %} SENTRY_PYTHON_TEST_POSTGRES_USER: postgres SENTRY_PYTHON_TEST_POSTGRES_PASSWORD: sentry {% endif %} {% if needs_redis %} - SENTRY_PYTHON_TEST_REDIS_HOST: {% raw %}${{ (matrix.python-version == '3.6' || matrix.python-version == '3.7') && 'redis' || 'localhost' }}{% endraw %} + SENTRY_PYTHON_TEST_REDIS_HOST: {% raw %}${{ (matrix.python-version == '3.7') && 'redis' || 'localhost' }}{% endraw %} {% endif %} {% if needs_mysql %} SENTRY_PYTHON_TEST_MYSQL_USER: root SENTRY_PYTHON_TEST_MYSQL_PASSWORD: sentry {% endif %} - container: {% raw %}${{ (matrix.python-version == '3.6' || matrix.python-version == '3.7') && format('python:{0}', matrix.python-version) || null }}{% endraw %} + container: {% raw %}${{ (matrix.python-version == '3.7') && format('python:{0}', matrix.python-version) || null }}{% endraw %} steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Install uv @@ -91,10 +91,10 @@ java-version: '21' {% endif %} - - name: Mark workspace safe for git (3.6/3.7 container) + - name: Mark workspace safe for git (3.7 container) # needed to make git rev-parse work in the containers # subprocesses (e.g. sentry_sdk.utils.get_git_revision) can run git. - if: {% raw %}${{ matrix.python-version == '3.6' || matrix.python-version == '3.7' }}{% endraw %} + if: {% raw %}${{ matrix.python-version == '3.7' }}{% endraw %} run: git config --global --add safe.directory "$GITHUB_WORKSPACE" - name: Setup Test Env diff --git a/scripts/split_tox_gh_actions/templates/test_orchestrator.jinja b/scripts/split_tox_gh_actions/templates/test_orchestrator.jinja index c8944d3c65..ced712ed0f 100644 --- a/scripts/split_tox_gh_actions/templates/test_orchestrator.jinja +++ b/scripts/split_tox_gh_actions/templates/test_orchestrator.jinja @@ -64,7 +64,7 @@ jobs: - name: Combine coverage and generate XML run: | uv sync - # relative_files + [tool.coverage.paths] let the 3.6/3.7 container and + # relative_files + [tool.coverage.paths] let the 3.7 container and # the runner data files merge into one source tree. uv run coverage combine .coverage-sentry-* uv run coverage xml diff --git a/sentry_sdk/__init__.py b/sentry_sdk/__init__.py index 9163a06641..417220ecc1 100644 --- a/sentry_sdk/__init__.py +++ b/sentry_sdk/__init__.py @@ -8,7 +8,6 @@ from sentry_sdk.api import * # noqa # isort: skip __all__ = [ # noqa - "Hub", "Scope", "Client", "Transport", @@ -22,8 +21,8 @@ "capture_event", "capture_exception", "capture_message", - "configure_scope", "continue_trace", + "new_trace", "flush", "flush_async", "get_baggage", @@ -37,19 +36,16 @@ "isolation_scope", "last_event_id", "new_scope", - "push_scope", "remove_attribute", "set_attribute", "set_attributes", "set_context", "set_extra", "set_level", - "set_measurement", "set_tag", "set_tags", "set_user", "start_span", - "start_transaction", "trace", "monitor", "logger", @@ -58,7 +54,6 @@ "start_session", "end_session", "set_transaction_name", - "update_current_span", ] # Initialize the debug support after everything is loaded @@ -66,6 +61,3 @@ init_debug_support() del init_debug_support - -# circular imports -from sentry_sdk.hub import Hub diff --git a/sentry_sdk/_compat.py b/sentry_sdk/_compat.py index f62175c09f..6a016c22d5 100644 --- a/sentry_sdk/_compat.py +++ b/sentry_sdk/_compat.py @@ -61,30 +61,26 @@ def enabled(option: str) -> bool: lazy_mode = enabled("lazy-apps") or enabled("lazy") if lazy_mode and not threads_enabled: - from warnings import warn - - warn( - Warning( - "IMPORTANT: " - "We detected the use of uWSGI without thread support. " - "This might lead to unexpected issues. " - 'Please run uWSGI with "--enable-threads" for full support.' - ) + from sentry_sdk.utils import logger + + logger.warning( + "IMPORTANT: " + "We detected the use of uWSGI without thread support. " + "This might lead to unexpected issues. " + 'Please run uWSGI with "--enable-threads" for full support.' ) return False elif not lazy_mode and (not threads_enabled or not fork_hooks_on): - from warnings import warn - - warn( - Warning( - "IMPORTANT: " - "We detected the use of uWSGI in preforking mode without " - "thread support. This might lead to crashing workers. " - 'Please run uWSGI with both "--enable-threads" and ' - '"--py-call-uwsgi-fork-hooks" for full support.' - ) + from sentry_sdk.utils import logger + + logger.warning( + "IMPORTANT: " + "We detected the use of uWSGI in preforking mode without " + "thread support. This might lead to crashing workers. " + 'Please run uWSGI with both "--enable-threads" and ' + '"--py-call-uwsgi-fork-hooks" for full support.' ) return False diff --git a/sentry_sdk/_init_implementation.py b/sentry_sdk/_init_implementation.py index 923fcf6df8..e89a4e6489 100644 --- a/sentry_sdk/_init_implementation.py +++ b/sentry_sdk/_init_implementation.py @@ -1,73 +1,60 @@ -import warnings +import re from typing import TYPE_CHECKING import sentry_sdk +from sentry_sdk.utils import logger, parse_version if TYPE_CHECKING: - from typing import Any, ContextManager, Optional + from typing import Any, Optional import sentry_sdk.consts -class _InitGuard: - _CONTEXT_MANAGER_DEPRECATION_WARNING_MESSAGE = ( - "Using the return value of sentry_sdk.init as a context manager " - "and manually calling the __enter__ and __exit__ methods on the " - "return value are deprecated. We are no longer maintaining this " - "functionality, and we will remove it in the next major release." - ) +def _check_version_deprecations() -> None: + try: + import gevent - def __init__(self, client: "sentry_sdk.Client") -> None: - self._client = client - - def __enter__(self) -> "_InitGuard": - warnings.warn( - self._CONTEXT_MANAGER_DEPRECATION_WARNING_MESSAGE, - stacklevel=2, - category=DeprecationWarning, - ) - - return self - - def __exit__(self, exc_type: "Any", exc_value: "Any", tb: "Any") -> None: - warnings.warn( - self._CONTEXT_MANAGER_DEPRECATION_WARNING_MESSAGE, - stacklevel=2, - category=DeprecationWarning, + gevent_version = tuple( + int(part) for part in re.split(r"a|b|rc|\.", gevent.__version__)[:2] ) + if gevent_version < (20, 9): + logger.warning( + "sentry-sdk 3.x supports gevent 20.9.0 or newer. " + "Please upgrade gevent or downgrade to sentry-sdk 2.x." + ) + except Exception: + pass - c = self._client - if c is not None: - c.close() - + try: + import greenlet -def _check_python_deprecations() -> None: - # Since we're likely to deprecate Python versions in the future, I'm keeping - # this handy function around. Use this to detect the Python version used and - # to output logger.warning()s if it's deprecated. - pass + greenlet_version = parse_version(greenlet.__version__) + if greenlet_version is not None and greenlet_version < (0, 4, 17): + logger.warning( + "sentry-sdk 3.x supports greenlet 0.4.17 or newer. " + "Please upgrade greenlet or downgrade to sentry-sdk 2.x." + ) + except Exception: + pass -def _init(*args: "Optional[str]", **kwargs: "Any") -> "ContextManager[Any]": +def _init(*args: "Optional[str]", **kwargs: "Any") -> None: """Initializes the SDK and optionally integrations. This takes the same arguments as the client constructor. """ client = sentry_sdk.Client(*args, **kwargs) sentry_sdk.get_global_scope().set_client(client) - _check_python_deprecations() - rv = _InitGuard(client) - return rv + _check_version_deprecations() if TYPE_CHECKING: # Make mypy, PyCharm and other static analyzers think `init` is a type to # have nicer autocompletion for params. # - # Use `ClientConstructor` to define the argument types of `init` and - # `ContextManager[Any]` to tell static analyzers about the return type. + # Use `ClientConstructor` to define the argument types of `init`. - class init(sentry_sdk.consts.ClientConstructor, _InitGuard): # noqa: N801 + class init(sentry_sdk.consts.ClientConstructor): # noqa: N801 pass else: diff --git a/sentry_sdk/_types.py b/sentry_sdk/_types.py index 39e0ca43d7..aeff75f4c2 100644 --- a/sentry_sdk/_types.py +++ b/sentry_sdk/_types.py @@ -1,9 +1,4 @@ -try: - from re import Pattern -except ImportError: - # 3.6 - from typing import Pattern - +from re import Pattern from typing import TYPE_CHECKING, TypeVar, Union # Re-exported for compat, since code out there in the wild might use this variable. @@ -138,7 +133,7 @@ def substituted_because_contains_sensitive_data(cls) -> "AnnotatedValue": if TYPE_CHECKING: - from collections.abc import Container, MutableMapping, Sequence + from collections.abc import MutableMapping, Sequence from datetime import datetime from types import TracebackType from typing import Any, Callable, Dict, List, Mapping, NotRequired, Optional, Type @@ -236,17 +231,6 @@ class DataCollection(TypedDict): "exbibyte", ] - FractionUnit = Literal["ratio", "percent"] - MeasurementUnit = Union[DurationUnit, InformationUnit, FractionUnit, str] - - MeasurementValue = TypedDict( - "MeasurementValue", - { - "value": float, - "unit": NotRequired[Optional[MeasurementUnit]], - }, - ) - Event = TypedDict( "Event", { @@ -268,13 +252,11 @@ class DataCollection(TypedDict): "level": LogLevelStr, "logentry": Mapping[str, object], "logger": str, - "measurements": dict[str, MeasurementValue], "message": str, "modules": dict[str, str], "monitor_config": Mapping[str, object], "monitor_slug": Optional[str], "platform": Literal["python"], - "profile": object, # Should be sentry_sdk.profiler.Profile, but we can't import that here due to circular imports "release": Optional[str], "request": dict[str, object], "sdk": Mapping[str, object], @@ -385,7 +367,7 @@ class DataCollection(TypedDict): "start_timestamp": float, "end_timestamp": NotRequired[float], "attributes": NotRequired[Attributes], - "_segment_span": NotRequired["sentry_sdk.traces.StreamedSpan"], + "_segment_span": NotRequired["sentry_sdk.traces.Span"], }, ) @@ -401,7 +383,6 @@ class DataCollection(TypedDict): EventProcessor = Callable[[Event, Hint], Optional[Event]] ErrorProcessor = Callable[[Event, ExcInfo], Optional[Event]] BreadcrumbProcessor = Callable[[Breadcrumb, BreadcrumbHint], Optional[Breadcrumb]] - TransactionProcessor = Callable[[Event, Hint], Optional[Event]] LogProcessor = Callable[[Log, Hint], Optional[Log]] TracesSampler = Callable[[SamplingContext], Union[float, int, bool]] @@ -413,12 +394,10 @@ class DataCollection(TypedDict): "default", "error", "crash", - "transaction", "security", "attachment", "session", "internal", - "profile", "profile_chunk", "monitor", "span", @@ -429,7 +408,7 @@ class DataCollection(TypedDict): SessionStatus = Literal["ok", "exited", "crashed", "abnormal"] ContinuousProfilerMode = Literal["thread", "gevent", "unknown"] - ProfilerMode = Union[ContinuousProfilerMode, Literal["sleep"]] + ProfilerMode = Union[ContinuousProfilerMode] MonitorConfigScheduleType = Literal["crontab", "interval"] MonitorConfigScheduleUnit = Literal[ @@ -466,8 +445,6 @@ class DataCollection(TypedDict): total=False, ) - HttpStatusCodeRange = Union[int, Container[int]] - class TextPart(TypedDict): type: Literal["text"] content: str diff --git a/sentry_sdk/ai/monitoring.py b/sentry_sdk/ai/monitoring.py index 05aabd96a9..d0664adac4 100644 --- a/sentry_sdk/ai/monitoring.py +++ b/sentry_sdk/ai/monitoring.py @@ -1,190 +1,17 @@ -import inspect -import sys -import warnings -from functools import wraps from typing import TYPE_CHECKING -import sentry_sdk.utils -from sentry_sdk import start_span -from sentry_sdk.ai.utils import _set_span_data_attribute from sentry_sdk.consts import SPANDATA -from sentry_sdk.traces import StreamedSpan -from sentry_sdk.tracing import Span -from sentry_sdk.tracing_utils import has_span_streaming_enabled -from sentry_sdk.utils import ContextVar, capture_internal_exceptions, reraise if TYPE_CHECKING: from typing import Any, Awaitable, Callable, Optional, TypeVar, Union - F = TypeVar("F", bound=Union[Callable[..., Any], Callable[..., Awaitable[Any]]]) - -_ai_pipeline_name = ContextVar("ai_pipeline_name", default=None) - - -def set_ai_pipeline_name(name: "Optional[str]") -> None: - _ai_pipeline_name.set(name) - - -def get_ai_pipeline_name() -> "Optional[str]": - return _ai_pipeline_name.get() - - -def ai_track(description: str, **span_kwargs: "Any") -> "Callable[[F], F]": - warnings.warn( - "sentry_sdk.ai.ai_track is deprecated and will be removed in version 3.0 of sentry-sdk. " - "Use the manual span API instead, e.g. sentry_sdk.start_span().", - DeprecationWarning, - stacklevel=2, - ) - - def decorator(f: "F") -> "F": - def sync_wrapped(*args: "Any", **kwargs: "Any") -> "Any": - client = sentry_sdk.get_client() - - curr_pipeline = _ai_pipeline_name.get() - op = span_kwargs.pop("op", "ai.run" if curr_pipeline else "ai.pipeline") - - if has_span_streaming_enabled(client.options): - with sentry_sdk.traces.start_span( - name=description, attributes={"sentry.op": op} - ) as span: - for k, v in kwargs.pop("sentry_tags", {}).items(): - span.set_attribute(k, v) - for k, v in kwargs.pop("sentry_data", {}).items(): - span.set_attribute(k, v) + from sentry_sdk.traces import Span - if curr_pipeline: - span.set_attribute(SPANDATA.GEN_AI_PIPELINE_NAME, curr_pipeline) - return f(*args, **kwargs) - else: - _ai_pipeline_name.set(description) - try: - res = f(*args, **kwargs) - except Exception as e: - exc_info = sys.exc_info() - with capture_internal_exceptions(): - event, hint = sentry_sdk.utils.event_from_exception( - e, - client_options=sentry_sdk.get_client().options, - mechanism={ - "type": "ai_monitoring", - "handled": False, - }, - ) - sentry_sdk.capture_event(event, hint=hint) - reraise(*exc_info) - finally: - _ai_pipeline_name.set(None) - return res - - else: - with start_span(name=description, op=op, **span_kwargs) as span: - for k, v in kwargs.pop("sentry_tags", {}).items(): - span.set_tag(k, v) - for k, v in kwargs.pop("sentry_data", {}).items(): - span.set_data(k, v) - if curr_pipeline: - span.set_data(SPANDATA.GEN_AI_PIPELINE_NAME, curr_pipeline) - return f(*args, **kwargs) - else: - _ai_pipeline_name.set(description) - try: - res = f(*args, **kwargs) - except Exception as e: - exc_info = sys.exc_info() - with capture_internal_exceptions(): - event, hint = sentry_sdk.utils.event_from_exception( - e, - client_options=sentry_sdk.get_client().options, - mechanism={ - "type": "ai_monitoring", - "handled": False, - }, - ) - sentry_sdk.capture_event(event, hint=hint) - reraise(*exc_info) - finally: - _ai_pipeline_name.set(None) - return res - - async def async_wrapped(*args: "Any", **kwargs: "Any") -> "Any": - client = sentry_sdk.get_client() - - curr_pipeline = _ai_pipeline_name.get() - op = span_kwargs.pop("op", "ai.run" if curr_pipeline else "ai.pipeline") - - if has_span_streaming_enabled(client.options): - with sentry_sdk.traces.start_span( - name=description, attributes={"sentry.op": op} - ) as span: - for k, v in kwargs.pop("sentry_tags", {}).items(): - span.set_attribute(k, v) - for k, v in kwargs.pop("sentry_data", {}).items(): - span.set_attribute(k, v) - - if curr_pipeline: - span.set_attribute(SPANDATA.GEN_AI_PIPELINE_NAME, curr_pipeline) - return await f(*args, **kwargs) - else: - _ai_pipeline_name.set(description) - try: - res = await f(*args, **kwargs) - except Exception as e: - exc_info = sys.exc_info() - with capture_internal_exceptions(): - event, hint = sentry_sdk.utils.event_from_exception( - e, - client_options=sentry_sdk.get_client().options, - mechanism={ - "type": "ai_monitoring", - "handled": False, - }, - ) - sentry_sdk.capture_event(event, hint=hint) - reraise(*exc_info) - finally: - _ai_pipeline_name.set(None) - return res - else: - with start_span(name=description, op=op, **span_kwargs) as span: - for k, v in kwargs.pop("sentry_tags", {}).items(): - span.set_tag(k, v) - for k, v in kwargs.pop("sentry_data", {}).items(): - span.set_data(k, v) - if curr_pipeline: - span.set_data(SPANDATA.GEN_AI_PIPELINE_NAME, curr_pipeline) - return await f(*args, **kwargs) - else: - _ai_pipeline_name.set(description) - try: - res = await f(*args, **kwargs) - except Exception as e: - exc_info = sys.exc_info() - with capture_internal_exceptions(): - event, hint = sentry_sdk.utils.event_from_exception( - e, - client_options=sentry_sdk.get_client().options, - mechanism={ - "type": "ai_monitoring", - "handled": False, - }, - ) - sentry_sdk.capture_event(event, hint=hint) - reraise(*exc_info) - finally: - _ai_pipeline_name.set(None) - return res - - if inspect.iscoroutinefunction(f): - return wraps(f)(async_wrapped) # type: ignore - else: - return wraps(f)(sync_wrapped) # type: ignore - - return decorator + F = TypeVar("F", bound=Union[Callable[..., Any], Callable[..., Awaitable[Any]]]) def record_token_usage( - span: "Union[Span, StreamedSpan]", + span: "Span", input_tokens: "Optional[int]" = None, input_tokens_cached: "Optional[int]" = None, input_tokens_cache_write: "Optional[int]" = None, @@ -192,37 +19,26 @@ def record_token_usage( output_tokens_reasoning: "Optional[int]" = None, total_tokens: "Optional[int]" = None, ) -> None: - # TODO: move pipeline name elsewhere - ai_pipeline_name = get_ai_pipeline_name() - if ai_pipeline_name: - _set_span_data_attribute(span, SPANDATA.GEN_AI_PIPELINE_NAME, ai_pipeline_name) - if input_tokens is not None: - _set_span_data_attribute(span, SPANDATA.GEN_AI_USAGE_INPUT_TOKENS, input_tokens) + span.set_attribute(SPANDATA.GEN_AI_USAGE_INPUT_TOKENS, input_tokens) if input_tokens_cached is not None: - _set_span_data_attribute( - span, - SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHED, - input_tokens_cached, + span.set_attribute( + SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS, input_tokens_cached ) if input_tokens_cache_write is not None: - _set_span_data_attribute( - span, - SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHE_WRITE, + span.set_attribute( + SPANDATA.GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS, input_tokens_cache_write, ) if output_tokens is not None: - _set_span_data_attribute( - span, SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS, output_tokens - ) + span.set_attribute(SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS, output_tokens) if output_tokens_reasoning is not None: - _set_span_data_attribute( - span, - SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS_REASONING, + span.set_attribute( + SPANDATA.GEN_AI_USAGE_REASONING_OUTPUT_TOKENS, output_tokens_reasoning, ) @@ -230,4 +46,4 @@ def record_token_usage( total_tokens = input_tokens + output_tokens if total_tokens is not None: - _set_span_data_attribute(span, SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS, total_tokens) + span.set_attribute(SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS, total_tokens) diff --git a/sentry_sdk/ai/utils.py b/sentry_sdk/ai/utils.py index 7b1ca9324b..4ec9806da8 100644 --- a/sentry_sdk/ai/utils.py +++ b/sentry_sdk/ai/utils.py @@ -1,24 +1,15 @@ import inspect import json -from copy import deepcopy from typing import TYPE_CHECKING -from sentry_sdk._types import BLOB_DATA_SUBSTITUTE -from sentry_sdk.ai.consts import DATA_URL_BASE64_REGEX - if TYPE_CHECKING: - from typing import Any, Callable, Dict, List, Optional, Tuple, Union + from typing import Any, Dict, Optional, Tuple - from sentry_sdk.tracing import Span + from sentry_sdk.traces import Span import sentry_sdk -from sentry_sdk.traces import StreamedSpan from sentry_sdk.utils import logger -MAX_GEN_AI_MESSAGE_BYTES = 20_000 # 20KB -# Maximum characters when only a single message is left after bytes truncation -MAX_SINGLE_MESSAGE_CONTENT_CHARS = 10_000 - class GEN_AI_ALLOWED_MESSAGE_ROLES: SYSTEM = "system" @@ -431,38 +422,6 @@ def transform_content_part( return None -def transform_message_content(content: "Any") -> "Any": - """ - Transform message content, handling both string content and list of content blocks. - - For list content, each item is transformed using transform_content_part(). - Items that cannot be transformed (return None) are kept as-is. - - Args: - content: Message content - can be a string, list of content blocks, or other - - Returns: - - String content: returned as-is - - List content: list with each transformable item converted to standardized format - - Other: returned as-is - """ - if isinstance(content, str): - return content - - if isinstance(content, (list, tuple)): - transformed = [] - for item in content: - if isinstance(item, dict): - result = transform_content_part(item) - # If transformation succeeded, use the result; otherwise keep original - transformed.append(result if result is not None else item) - else: - transformed.append(item) - return transformed - - return content - - def _normalize_data(data: "Any", unpack: bool = True) -> "Any": # convert pydantic data (e.g. OpenAI v1+) to json compatible format if hasattr(data, "model_dump"): @@ -489,25 +448,16 @@ def _normalize_data(data: "Any", unpack: bool = True) -> "Any": def set_data_normalized( - span: "Union[Span, StreamedSpan]", + span: "Span", key: str, value: "Any", unpack: bool = True, ) -> None: normalized = _normalize_data(value, unpack=unpack) if isinstance(normalized, (int, float, bool, str)): - _set_span_data_attribute(span, key, normalized) + span.set_attribute(key, normalized) else: - _set_span_data_attribute(span, key, json.dumps(normalized)) - - -def _set_span_data_attribute( - span: "Union[Span, StreamedSpan]", key: str, value: "Any" -) -> None: - if isinstance(span, StreamedSpan): - span.set_attribute(key, value) - else: - span.set_data(key, value) + span.set_attribute(key, json.dumps(normalized)) def normalize_message_role(role: str) -> str: @@ -536,244 +486,6 @@ def normalize_message_roles(messages: "list[dict[str, Any]]") -> "list[dict[str, return normalized_messages -def get_start_span_function() -> "Callable[..., Any]": - current_span = sentry_sdk.get_current_span() - - transaction_exists = ( - current_span is not None and current_span.containing_transaction is not None - ) - return sentry_sdk.start_span if transaction_exists else sentry_sdk.start_transaction - - -def _truncate_single_message_content_if_present( - message: "Dict[str, Any]", max_chars: int -) -> "Dict[str, Any]": - """ - Truncate a message's content to at most `max_chars` characters and append an - ellipsis if truncation occurs. - """ - if not isinstance(message, dict) or "content" not in message: - return message - content = message["content"] - - if isinstance(content, str): - if len(content) <= max_chars: - return message - message["content"] = content[:max_chars] + "..." - return message - - if isinstance(content, list): - remaining = max_chars - for item in content: - if isinstance(item, dict) and "text" in item: - text = item["text"] - if isinstance(text, str): - if len(text) > remaining: - item["text"] = text[:remaining] + "..." - remaining = 0 - else: - remaining -= len(text) - return message - - return message - - -def _find_truncation_index(messages: "List[Dict[str, Any]]", max_bytes: int) -> int: - """ - Find the index of the first message that would exceed the max bytes limit. - Compute the individual message sizes, and return the index of the first message from the back - of the list that would exceed the max bytes limit. - """ - running_sum = 0 - for idx in range(len(messages) - 1, -1, -1): - size = len(json.dumps(messages[idx], separators=(",", ":")).encode("utf-8")) - running_sum += size - if running_sum > max_bytes: - return idx + 1 - - return 0 - - -def _is_image_type_with_blob_content(item: "Dict[str, Any]") -> bool: - """ - Some content blocks contain an image_url property with base64 content as its value. - This is used to identify those while not leading to unnecessary copying of data when the image URL does not contain base64 content. - """ - if item.get("type") != "image_url": - return False - - image_url_val = item.get("image_url") - image_url = ( - image_url_val.get("url", "") - if isinstance(image_url_val, dict) - else (image_url_val or "") - ) - data_url_match = DATA_URL_BASE64_REGEX.match(image_url) - - return bool(data_url_match) - - -def redact_blob_message_parts( - messages: "List[Dict[str, Any]]", -) -> "List[Dict[str, Any]]": - """ - Redact blob message parts from the messages by replacing blob content with "[Filtered]". - - This function creates a deep copy of messages that contain blob content to avoid - mutating the original message dictionaries. Messages without blob content are - returned as-is to minimize copying overhead. - - e.g: - { - "role": "user", - "content": [ - { - "text": "How many ponies do you see in the image?", - "type": "text" - }, - { - "type": "blob", - "modality": "image", - "mime_type": "image/jpeg", - "content": "data:image/jpeg;base64,..." - } - ] - } - becomes: - { - "role": "user", - "content": [ - { - "text": "How many ponies do you see in the image?", - "type": "text" - }, - { - "type": "blob", - "modality": "image", - "mime_type": "image/jpeg", - "content": "[Filtered]" - } - ] - } - """ - - # First pass: check if any message contains blob content - has_blobs = False - for message in messages: - if not isinstance(message, dict): - continue - content = message.get("content") - if isinstance(content, list): - for item in content: - if isinstance(item, dict) and ( - item.get("type") == "blob" or _is_image_type_with_blob_content(item) - ): - has_blobs = True - break - if has_blobs: - break - - # If no blobs found, return original messages to avoid unnecessary copying - if not has_blobs: - return messages - - # Deep copy messages to avoid mutating the original - messages_copy = deepcopy(messages) - - # Second pass: redact blob content in the copy - for message in messages_copy: - if not isinstance(message, dict): - continue - - content = message.get("content") - if isinstance(content, list): - for item in content: - if isinstance(item, dict): - if item.get("type") == "blob": - item["content"] = BLOB_DATA_SUBSTITUTE - elif _is_image_type_with_blob_content(item): - if isinstance(item["image_url"], dict): - item["image_url"]["url"] = BLOB_DATA_SUBSTITUTE - else: - item["image_url"] = BLOB_DATA_SUBSTITUTE - - return messages_copy - - -def truncate_messages_by_size( - messages: "List[Dict[str, Any]]", - max_bytes: int = MAX_GEN_AI_MESSAGE_BYTES, - max_single_message_chars: int = MAX_SINGLE_MESSAGE_CONTENT_CHARS, -) -> "Tuple[List[Dict[str, Any]], int]": - """ - Returns a truncated messages list, consisting of - - the last message, with its content truncated to `max_single_message_chars` characters, - if the last message's size exceeds `max_bytes` bytes; otherwise, - - the maximum number of messages, starting from the end of the `messages` list, whose total - serialized size does not exceed `max_bytes` bytes. - - In the single message case, the serialized message size may exceed `max_bytes`, because - truncation is based only on character count in that case. - """ - serialized_json = json.dumps(messages, separators=(",", ":")) - current_size = len(serialized_json.encode("utf-8")) - - if current_size <= max_bytes: - return messages, 0 - - truncation_index = _find_truncation_index(messages, max_bytes) - if truncation_index < len(messages): - truncated_messages = messages[truncation_index:] - else: - truncation_index = len(messages) - 1 - truncated_messages = messages[-1:] - - if len(truncated_messages) == 1: - truncated_messages[0] = _truncate_single_message_content_if_present( - deepcopy(truncated_messages[0]), max_chars=max_single_message_chars - ) - - return truncated_messages, truncation_index - - -def truncate_and_annotate_messages( - messages: "Optional[List[Dict[str, Any]]]", - span: "Any", - scope: "Any", - max_single_message_chars: int = MAX_SINGLE_MESSAGE_CONTENT_CHARS, -) -> "Optional[List[Dict[str, Any]]]": - if not messages: - return None - - messages = redact_blob_message_parts(messages) - - truncated_message = _truncate_single_message_content_if_present( - deepcopy(messages[-1]), max_chars=max_single_message_chars - ) - if len(messages) > 1: - scope._gen_ai_original_message_count[span.span_id] = len(messages) - - return [truncated_message] - - -def truncate_and_annotate_embedding_inputs( - messages: "Optional[List[Dict[str, Any]]]", - span: "Any", - scope: "Any", - max_bytes: int = MAX_GEN_AI_MESSAGE_BYTES, -) -> "Optional[List[Dict[str, Any]]]": - if not messages: - return None - - messages = redact_blob_message_parts(messages) - - truncated_messages, removed_count = truncate_messages_by_size(messages, max_bytes) - if removed_count > 0: - scope._gen_ai_original_message_count[span.span_id] = len(messages) - - return truncated_messages - - def set_conversation_id(conversation_id: str) -> None: """ Set the conversation_id in the scope. diff --git a/sentry_sdk/api.py b/sentry_sdk/api.py index d5f91fa145..88dc414bd4 100644 --- a/sentry_sdk/api.py +++ b/sentry_sdk/api.py @@ -1,33 +1,24 @@ import inspect -import warnings -from contextlib import contextmanager from typing import TYPE_CHECKING -from sentry_sdk import Client, tracing_utils +from sentry_sdk import Client, traces from sentry_sdk._init_implementation import init -from sentry_sdk.consts import INSTRUMENTER from sentry_sdk.crons import monitor -from sentry_sdk.scope import Scope, _ScopeManager, isolation_scope, new_scope -from sentry_sdk.traces import StreamedSpan -from sentry_sdk.traces import get_current_span as _get_current_streamed_span -from sentry_sdk.tracing import NoOpSpan, Transaction, trace +from sentry_sdk.scope import Scope, isolation_scope, new_scope +from sentry_sdk.traces import trace if TYPE_CHECKING: from collections.abc import Mapping from typing import ( Any, Callable, - ContextManager, Dict, - Generator, Optional, TypeVar, Union, overload, ) - from typing_extensions import Unpack - from sentry_sdk._types import ( Breadcrumb, BreadcrumbHint, @@ -35,12 +26,9 @@ ExcInfo, Hint, LogLevelStr, - MeasurementUnit, - SamplingContext, ) from sentry_sdk.client import BaseClient - from sentry_sdk.traces import StreamedSpan - from sentry_sdk.tracing import Span, TransactionKwargs + from sentry_sdk.traces import Span T = TypeVar("T") F = TypeVar("F", bound=Callable[..., Any]) @@ -58,8 +46,8 @@ def overload(x: "T") -> "T": "capture_event", "capture_exception", "capture_message", - "configure_scope", "continue_trace", + "new_trace", "flush", "flush_async", "get_baggage", @@ -73,25 +61,21 @@ def overload(x: "T") -> "T": "isolation_scope", "last_event_id", "new_scope", - "push_scope", "remove_attribute", "set_attribute", "set_attributes", "set_context", "set_extra", "set_level", - "set_measurement", "set_tag", "set_tags", "set_user", "start_span", - "start_transaction", "trace", "monitor", "start_session", "end_session", "set_transaction_name", - "update_current_span", ] @@ -190,11 +174,8 @@ def add_attachment( filename: "Optional[str]" = None, path: "Optional[str]" = None, content_type: "Optional[str]" = None, - add_to_transactions: bool = False, ) -> None: - return get_isolation_scope().add_attachment( - bytes, filename, path, content_type, add_to_transactions - ) + return get_isolation_scope().add_attachment(bytes, filename, path, content_type) @scopemethod @@ -206,94 +187,6 @@ def add_breadcrumb( return get_isolation_scope().add_breadcrumb(crumb, hint, **kwargs) -@overload -def configure_scope() -> "ContextManager[Scope]": - pass - - -@overload -def configure_scope( # noqa: F811 - callback: "Callable[[Scope], None]", -) -> None: - pass - - -def configure_scope( # noqa: F811 - callback: "Optional[Callable[[Scope], None]]" = None, -) -> "Optional[ContextManager[Scope]]": - """ - Reconfigures the scope. - - :param callback: If provided, call the callback with the current scope. - - :returns: If no callback is provided, returns a context manager that returns the scope. - """ - warnings.warn( - "sentry_sdk.configure_scope is deprecated and will be removed in the next major version. " - "Please consult our migration guide to learn how to migrate to the new API: " - "https://docs.sentry.io/platforms/python/migration/1.x-to-2.x#scope-configuring", - DeprecationWarning, - stacklevel=2, - ) - - scope = get_isolation_scope() - scope.generate_propagation_context() - - if callback is not None: - # TODO: used to return None when client is None. Check if this changes behavior. - callback(scope) - - return None - - @contextmanager - def inner() -> "Generator[Scope, None, None]": - yield scope - - return inner() - - -@overload -def push_scope() -> "ContextManager[Scope]": - pass - - -@overload -def push_scope( # noqa: F811 - callback: "Callable[[Scope], None]", -) -> None: - pass - - -def push_scope( # noqa: F811 - callback: "Optional[Callable[[Scope], None]]" = None, -) -> "Optional[ContextManager[Scope]]": - """ - Pushes a new layer on the scope stack. - - :param callback: If provided, this method pushes a scope, calls - `callback`, and pops the scope again. - - :returns: If no `callback` is provided, a context manager that should - be used to pop the scope again. - """ - warnings.warn( - "sentry_sdk.push_scope is deprecated and will be removed in the next major version. " - "Please consult our migration guide to learn how to migrate to the new API: " - "https://docs.sentry.io/platforms/python/migration/1.x-to-2.x#scope-pushing", - DeprecationWarning, - stacklevel=2, - ) - - if callback is not None: - with warnings.catch_warnings(): - warnings.simplefilter("ignore", DeprecationWarning) - with push_scope() as scope: - callback(scope) - return None - - return _ScopeManager() - - @scopemethod def set_attribute(attribute: str, value: "Any") -> None: """ @@ -374,72 +267,15 @@ async def flush_async( @scopemethod -def start_span( - **kwargs: "Any", -) -> "Span": - return get_current_scope().start_span(**kwargs) - - -@scopemethod -def start_transaction( - transaction: "Optional[Transaction]" = None, - instrumenter: str = INSTRUMENTER.SENTRY, - custom_sampling_context: "Optional[SamplingContext]" = None, - **kwargs: "Unpack[TransactionKwargs]", -) -> "Union[Transaction, NoOpSpan]": - """ - Start and return a transaction on the current scope. +def start_span(**kwargs: "Any") -> "Span": + return traces.start_span(**kwargs) - Start an existing transaction if given, otherwise create and start a new - transaction with kwargs. - This is the entry point to manual tracing instrumentation. - - A tree structure can be built by adding child spans to the transaction, - and child spans to other spans. To start a new child span within the - transaction or any span, call the respective `.start_child()` method. - - Every child span must be finished before the transaction is finished, - otherwise the unfinished spans are discarded. - - When used as context managers, spans and transactions are automatically - finished at the end of the `with` block. If not using context managers, - call the `.finish()` method. - - When the transaction is finished, it will be sent to Sentry with all its - finished child spans. - - :param transaction: The transaction to start. If omitted, we create and - start a new transaction. - :param instrumenter: This parameter is meant for internal use only. It - will be removed in the next major version. - :param custom_sampling_context: The transaction's custom sampling context. - :param kwargs: Optional keyword arguments to be passed to the Transaction - constructor. See :py:class:`sentry_sdk.tracing.Transaction` for - available arguments. +def get_current_span(scope: "Optional[Scope]" = None) -> "Optional[Span]": """ - return get_current_scope().start_transaction( - transaction, instrumenter, custom_sampling_context, **kwargs - ) - - -def set_measurement(name: str, value: float, unit: "MeasurementUnit" = "") -> None: + Returns the currently active span on the scope, otherwise `None`. """ - .. deprecated:: 2.28.0 - This function is deprecated and will be removed in the next major release. - """ - transaction = get_current_scope().transaction - if transaction is not None: - transaction.set_measurement(name, value, unit) - - -def get_current_span( - scope: "Optional[Scope]" = None, -) -> "Optional[Span]": - """ - Returns the currently active span if there is one running, otherwise `None` - """ - return tracing_utils.get_current_span(scope) + return traces.get_current_span(scope) def get_traceparent() -> "Optional[str]": @@ -460,19 +296,31 @@ def get_baggage() -> "Optional[str]": return None -def continue_trace( - environ_or_headers: "Dict[str, Any]", - op: "Optional[str]" = None, - name: "Optional[str]" = None, - source: "Optional[str]" = None, - origin: str = "manual", -) -> "Transaction": +def continue_trace(incoming: "Dict[str, Any]") -> None: """ - Sets the propagation context from environment or headers and returns a transaction. + Continue a trace from headers or environment variables. + + This function sets the propagation context on the scope. Any span started + in the updated scope will belong under the trace extracted from the + provided propagation headers or environment variables. + + continue_trace() doesn't start any spans on its own. Use the start_span() + API for that. """ - return get_isolation_scope().continue_trace( - environ_or_headers, op, name, source, origin - ) + return traces.continue_trace(incoming) + + +def new_trace() -> None: + """ + Reset the propagation context, forcing a new trace. + + This function sets the propagation context on the scope. Any span started + in the updated scope will start its own trace. + + new_trace() doesn't start any spans on its own. Use the start_span() API + for that. + """ + return traces.new_trace() @scopemethod @@ -490,96 +338,3 @@ def end_session() -> None: @scopemethod def set_transaction_name(name: str, source: "Optional[str]" = None) -> None: return get_current_scope().set_transaction_name(name, source) - - -def update_current_span( - op: "Optional[str]" = None, - name: "Optional[str]" = None, - attributes: "Optional[dict[str, Union[str, int, float, bool]]]" = None, - data: "Optional[dict[str, Any]]" = None, -) -> None: - """ - Update the current active span with the provided parameters. - - This function allows you to modify properties of the currently active span. - If no span is currently active, this function will do nothing. - - :param op: The operation name for the span. This is a high-level description - of what the span represents (e.g., "http.client", "db.query"). - You can use predefined constants from :py:class:`sentry_sdk.consts.OP` - or provide your own string. If not provided, the span's operation will - remain unchanged. - :type op: str or None - - :param name: The human-readable name/description for the span. This provides - more specific details about what the span represents (e.g., "GET /api/users", - "SELECT * FROM users"). If not provided, the span's name will remain unchanged. - :type name: str or None - - :param data: A dictionary of key-value pairs to add as data to the span. This - data will be merged with any existing span data. If not provided, - no data will be added. - - .. deprecated:: 2.35.0 - Use ``attributes`` instead. The ``data`` parameter will be removed - in a future version. - :type data: dict[str, Union[str, int, float, bool]] or None - - :param attributes: A dictionary of key-value pairs to add as attributes to the span. - Attribute values must be strings, integers, floats, or booleans. These - attributes will be merged with any existing span data. If not provided, - no attributes will be added. - :type attributes: dict[str, Union[str, int, float, bool]] or None - - :returns: None - - .. versionadded:: 2.35.0 - - Example:: - - import sentry_sdk - from sentry_sdk.consts import OP - - sentry_sdk.update_current_span( - op=OP.FUNCTION, - name="process_user_data", - attributes={"user_id": 123, "batch_size": 50} - ) - """ - if isinstance(_get_current_streamed_span(), StreamedSpan): - warnings.warn( - "The `update_current_span` API isn't available in streaming mode. " - "Retrieve the current span with get_current_span() and use its API " - "directly.", - DeprecationWarning, - stacklevel=2, - ) - return - - current_span = get_current_span() - - if current_span is None: - return - - if op is not None: - current_span.op = op - - if name is not None: - # internally it is still description - current_span.description = name - - if data is not None and attributes is not None: - raise ValueError( - "Cannot provide both `data` and `attributes`. Please use only `attributes`." - ) - - if data is not None: - warnings.warn( - "The `data` parameter is deprecated. Please use `attributes` instead.", - DeprecationWarning, - stacklevel=2, - ) - attributes = data - - if attributes is not None: - current_span.update_data(attributes) diff --git a/sentry_sdk/attachments.py b/sentry_sdk/attachments.py index 4d69d3acf2..7bcf59e181 100644 --- a/sentry_sdk/attachments.py +++ b/sentry_sdk/attachments.py @@ -13,8 +13,7 @@ class Attachment: This class stores attachments that can be sent along with an event. Attachments are files or other data, e.g. config or log files, that are relevant to an event. Attachments are set on the ``Scope``, and are sent along with - all non-transaction events (or all events including transactions if ``add_to_transactions`` is ``True``) that are - captured within the ``Scope``. + all non-transaction events that are captured within the ``Scope``. To add an attachment to a ``Scope``, use :py:meth:`sentry_sdk.Scope.add_attachment`. The parameters for ``add_attachment`` are the same as the parameters for this class's constructor. @@ -25,7 +24,6 @@ class Attachment: :param path: Path to a file to attach. Must be provided unless ``bytes`` is provided. :param content_type: The content type of the attachment. If not provided, it will be guessed from the ``filename`` parameter, if available, or the ``path`` parameter if ``filename`` is ``None``. - :param add_to_transactions: Whether to add this attachment to transactions. Defaults to ``False``. """ def __init__( @@ -34,7 +32,6 @@ def __init__( filename: "Optional[str]" = None, path: "Optional[str]" = None, content_type: "Optional[str]" = None, - add_to_transactions: bool = False, ) -> None: if bytes is None and path is None: raise TypeError("path or raw bytes required for attachment") @@ -48,7 +45,6 @@ def __init__( self.filename = filename self.path = path self.content_type = content_type - self.add_to_transactions = add_to_transactions def to_envelope_item(self) -> "Item": """Returns an envelope item for this attachment.""" diff --git a/sentry_sdk/client.py b/sentry_sdk/client.py index e3c6370c9c..9114cf6b67 100644 --- a/sentry_sdk/client.py +++ b/sentry_sdk/client.py @@ -1,15 +1,12 @@ -import json import os -import platform import random import socket -import sys import uuid -import warnings -from collections.abc import Iterable, Mapping +from collections.abc import Mapping +from contextvars import ContextVar from datetime import datetime, timezone from importlib import import_module -from typing import TYPE_CHECKING, Dict, List, cast, overload +from typing import TYPE_CHECKING, Dict, cast, overload from sentry_sdk._compat import check_uwsgi_thread_support from sentry_sdk._log_batcher import LogBatcher @@ -18,9 +15,6 @@ from sentry_sdk.consts import ( DEFAULT_MAX_VALUE_LENGTH, DEFAULT_OPTIONS, - INSTRUMENTER, - SPANDATA, - SPANSTATUS, VERSION, ClientConstructor, ) @@ -28,23 +22,15 @@ _map_from_send_default_pii, _resolve_data_collection, ) -from sentry_sdk.envelope import Envelope, Item, PayloadRef -from sentry_sdk.integrations import _DEFAULT_INTEGRATIONS, setup_integrations +from sentry_sdk.envelope import Envelope, Item +from sentry_sdk.integrations import setup_integrations from sentry_sdk.integrations.dedupe import DedupeIntegration from sentry_sdk.monitor import Monitor from sentry_sdk.profiler.continuous_profiler import setup_continuous_profiler -from sentry_sdk.profiler.transaction_profiler import ( - Profile, - has_profiling_enabled, - setup_profiler, -) from sentry_sdk.scrubber import EventScrubber from sentry_sdk.serializer import serialize from sentry_sdk.sessions import SessionFlusher -from sentry_sdk.traces import SpanStatus, StreamedSpan -from sentry_sdk.traces import trace as streaming_trace -from sentry_sdk.tracing import trace as legacy_trace -from sentry_sdk.tracing_utils import has_span_streaming_enabled +from sentry_sdk.traces import Span, trace from sentry_sdk.transport import ( AsyncHttpTransport, HttpTransportCore, @@ -52,10 +38,8 @@ ) from sentry_sdk.utils import ( AnnotatedValue, - ContextVar, capture_internal_exceptions, current_stacktrace, - datetime_from_isoformat, env_to_bool, format_timestamp, get_before_send_log, @@ -81,19 +65,18 @@ Log, Metric, SDKInfo, - SerializedAttributeValue, ) from sentry_sdk.integrations import Integration from sentry_sdk.scope import Scope from sentry_sdk.session import Session from sentry_sdk.spotlight import SpotlightClient - from sentry_sdk.traces import StreamedSpan + from sentry_sdk.traces import Span from sentry_sdk.transport import Item, Transport from sentry_sdk.utils import Dsn I = TypeVar("I", bound=Integration) # noqa: E741 -_client_init_debug = ContextVar("client_init_debug") +_client_init_debug: "ContextVar[bool]" = ContextVar("client_init_debug") SDK_INFO: "SDKInfo" = { @@ -103,203 +86,6 @@ } -def _serialized_v1_attribute_to_serialized_v2_attribute( - attribute_value: "Any", -) -> "Optional[SerializedAttributeValue]": - if isinstance(attribute_value, bool): - return { - "value": attribute_value, - "type": "boolean", - } - - if isinstance(attribute_value, int): - return { - "value": attribute_value, - "type": "integer", - } - - if isinstance(attribute_value, float): - return { - "value": attribute_value, - "type": "double", - } - - if isinstance(attribute_value, str): - return { - "value": attribute_value, - "type": "string", - } - - if isinstance(attribute_value, list): - if not attribute_value: - return {"value": [], "type": "array"} - - ty = type(attribute_value[0]) - if ty in (int, str, bool, float) and all( - type(v) is ty for v in attribute_value - ): - return { - "value": attribute_value, - "type": "array", - } - - # Types returned when the serializer for V1 span attributes recurses into some container types. - if isinstance(attribute_value, (dict, list)): - return { - "value": json.dumps(attribute_value), - "type": "string", - } - - return None - - -def _serialized_v1_span_to_serialized_v2_span( - span: "dict[str, Any]", event: "Event" -) -> "dict[str, Any]": - # See SpanBatcher._to_transport_format() for analogous population of all entries except "attributes". - res: "dict[str, Any]" = { - "status": SpanStatus.OK.value, - "is_segment": False, - } - - if "trace_id" in span: - res["trace_id"] = span["trace_id"] - - if "span_id" in span: - res["span_id"] = span["span_id"] - - if "description" in span: - description = span["description"] - - if description is None and "op" in span: - description = span["op"] - - res["name"] = description - - if "start_timestamp" in span: - start_timestamp = None - try: - start_timestamp = datetime_from_isoformat(span["start_timestamp"]) - except Exception: - pass - - if start_timestamp is not None: - res["start_timestamp"] = start_timestamp.timestamp() - - if "timestamp" in span: - end_timestamp = None - try: - end_timestamp = datetime_from_isoformat(span["timestamp"]) - except Exception: - pass - - if end_timestamp is not None: - res["end_timestamp"] = end_timestamp.timestamp() - - if "parent_span_id" in span: - res["parent_span_id"] = span["parent_span_id"] - - if "status" in span and span["status"] != SPANSTATUS.OK: - res["status"] = "error" - - attributes: "Dict[str, Any]" = {} - - if "op" in span: - attributes["sentry.op"] = span["op"] - if "origin" in span: - attributes["sentry.origin"] = span["origin"] - - span_data = span.get("data") - if isinstance(span_data, dict): - attributes.update(span_data) - - span_tags = span.get("tags") - if isinstance(span_tags, dict): - attributes.update(span_tags) - - # See Scope._apply_user_attributes_to_telemetry() for user attributes. - user = event.get("user") - if isinstance(user, dict): - if "id" in user: - attributes["user.id"] = user["id"] - if "username" in user: - attributes["user.name"] = user["username"] - if "email" in user: - attributes["user.email"] = user["email"] - - # See Scope.set_global_attributes() for release, environment, and SDK metadata. - if "release" in event: - attributes["sentry.release"] = event["release"] - if "environment" in event: - attributes["sentry.environment"] = event["environment"] - if "server_name" in event: - attributes["server.address"] = event["server_name"] - if "transaction" in event: - attributes["sentry.segment.name"] = event["transaction"] - - trace_context = event.get("contexts", {}).get("trace", {}) - if "span_id" in trace_context: - attributes["sentry.segment.id"] = trace_context["span_id"] - - sdk_info = event.get("sdk") - if isinstance(sdk_info, dict): - if "name" in sdk_info: - attributes["sentry.sdk.name"] = sdk_info["name"] - if "version" in sdk_info: - attributes["sentry.sdk.version"] = sdk_info["version"] - - attributes["process.runtime.name"] = platform.python_implementation() - attributes["process.runtime.version"] = ( - f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}" - ) - - if not attributes: - return res - - res["attributes"] = {} - for key, value in attributes.items(): - converted_value = _serialized_v1_attribute_to_serialized_v2_attribute(value) - if converted_value is None: - continue - - res["attributes"][key] = converted_value - - # Remove redundant attribute, as status is stored in the status field. - if "status" in res["attributes"]: - del res["attributes"]["status"] - - return res - - -def _split_gen_ai_spans( - event_opt: "Event", -) -> "Optional[tuple[List[Dict[str, object]], List[Dict[str, object]]]]": - if "spans" not in event_opt: - return None - - spans: "Any" = event_opt["spans"] - if isinstance(spans, AnnotatedValue): - spans = spans.value - - if not isinstance(spans, Iterable): - return None - - non_gen_ai_spans = [] - gen_ai_spans = [] - for span in spans: - if not isinstance(span, dict): - non_gen_ai_spans.append(span) - continue - - span_op = span.get("op") - if isinstance(span_op, str) and span_op.startswith("gen_ai."): - gen_ai_spans.append(span) - else: - non_gen_ai_spans.append(span) - - return non_gen_ai_spans, gen_ai_spans - - def _get_options(*args: "Optional[str]", **kwargs: "Any") -> "Dict[str, Any]": if args and (isinstance(args[0], (bytes, str)) or args[0] is None): dsn: "Optional[str]" = args[0] @@ -336,9 +122,6 @@ def _get_options(*args: "Optional[str]", **kwargs: "Any") -> "Dict[str, Any]": if rv["server_name"] is None and hasattr(socket, "gethostname"): rv["server_name"] = socket.gethostname() - if rv["instrumenter"] is None: - rv["instrumenter"] = INSTRUMENTER.SENTRY - if rv["project_root"] is None: try: project_root = os.getcwd() @@ -347,9 +130,6 @@ def _get_options(*args: "Optional[str]", **kwargs: "Any") -> "Dict[str, Any]": rv["project_root"] = project_root - if rv["enable_tracing"] is True and rv["traces_sample_rate"] is None: - rv["traces_sample_rate"] = 1.0 - rv["data_collection"] = _resolve_data_collection(rv) # Do not add the event scrubber if data collection is enabled as it can remove data that's @@ -361,9 +141,8 @@ def _get_options(*args: "Optional[str]", **kwargs: "Any") -> "Dict[str, Any]": else rv["send_default_pii"] ) elif has_data_collection_enabled(rv) and rv["event_scrubber"]: - warnings.warn( + logger.warning( "Event scrubbers are not enabled when data collection configuration is provided. Ignoring event_scrubber...", - stacklevel=2, ) rv["event_scrubber"] = None @@ -378,31 +157,6 @@ def _get_options(*args: "Optional[str]", **kwargs: "Any") -> "Dict[str, Any]": env_to_bool(os.environ.get("SENTRY_KEEP_ALIVE"), strict=True) or False ) - if rv["enable_tracing"] is not None: - warnings.warn( - "The `enable_tracing` parameter is deprecated. Please use `traces_sample_rate` instead.", - DeprecationWarning, - stacklevel=2, - ) - - if rv["trace_ignore_status_codes"] and has_span_streaming_enabled(rv): - warnings.warn( - "The `trace_ignore_status_codes` parameter is ignored in span streaming mode.", - stacklevel=2, - ) - - if rv["ignore_spans"] and not has_span_streaming_enabled(rv): - warnings.warn( - "The `ignore_spans` parameter only works when `trace_lifecycle` is set to `stream`.", - stacklevel=2, - ) - - if rv["before_send_span"] and not has_span_streaming_enabled(rv): - warnings.warn( - "The `before_send_span` parameter only works when `trace_lifecycle` is set to `stream`.", - stacklevel=2, - ) - return rv @@ -461,7 +215,7 @@ def _capture_log(self, log: "Log", scope: "Scope") -> None: def _capture_metric(self, metric: "Metric", scope: "Scope") -> None: pass - def _capture_span(self, span: "StreamedSpan", scope: "Scope") -> None: + def _capture_span(self, span: "Span", scope: "Scope") -> None: pass def capture_session(self, *args: "Any", **kwargs: "Any") -> None: @@ -536,12 +290,6 @@ def _setup_instrumentation( """ Instruments the functions given in the list `functions_to_trace` with a trace decorator. """ - trace = ( - streaming_trace - if has_span_streaming_enabled(self.options) - else legacy_trace - ) - for function in functions_to_trace: class_name = None function_qualname = function["qualified_name"] @@ -638,7 +386,6 @@ def _record_lost_event( self.options["send_default_pii"] = True self.options["error_sampler"] = sample_all self.options["traces_sampler"] = sample_all - self.options["profiles_sampler"] = sample_all # data_collection was resolved in _get_options() before this # spotlight override flipped send_default_pii on. Re-derive it so # data_collection agrees with should_send_default_pii() in @@ -660,22 +407,15 @@ def _record_lost_event( record_lost_func=_record_lost_event, ) - if self.options.get("enable_metrics", True) is False: - logger.warning( - "The enable_metrics option has no effect and will be removed in the next major." - ) - self.metrics_batcher = MetricsBatcher( capture_func=_capture_envelope, record_lost_func=_record_lost_event, ) - self.span_batcher = None - if has_span_streaming_enabled(self.options): - self.span_batcher = SpanBatcher( - capture_func=_capture_envelope, - record_lost_func=_record_lost_event, - ) + self.span_batcher = SpanBatcher( + capture_func=_capture_envelope, + record_lost_func=_record_lost_event, + ) max_request_body_size = ("always", "never", "small", "medium") if self.options["max_request_body_size"] not in max_request_body_size: @@ -685,19 +425,6 @@ def _record_lost_event( ) ) - if self.options["_experiments"].get("otel_powered_performance", False): - logger.debug( - "[OTel] Enabling experimental OTel-powered performance monitoring." - ) - self.options["instrumenter"] = INSTRUMENTER.OTEL - if ( - "sentry_sdk.integrations.opentelemetry.integration.OpenTelemetryIntegration" - not in _DEFAULT_INTEGRATIONS - ): - _DEFAULT_INTEGRATIONS.append( - "sentry_sdk.integrations.opentelemetry.integration.OpenTelemetryIntegration", - ) - self.integrations = setup_integrations( self.options["integrations"], with_defaults=self.options["default_integrations"], @@ -712,20 +439,14 @@ def _record_lost_event( SDK_INFO["name"] = sdk_name logger.debug("Setting SDK name to '%s'", sdk_name) - if has_profiling_enabled(self.options): - try: - setup_profiler(self.options) - except Exception as e: - logger.debug("Can not set up profiler. (%s)", e) - else: - try: - setup_continuous_profiler( - self.options, - sdk_info=SDK_INFO, - capture_func=_capture_envelope, - ) - except Exception as e: - logger.debug("Can not set up continuous profiler. (%s)", e) + try: + setup_continuous_profiler( + self.options, + sdk_info=SDK_INFO, + capture_func=_capture_envelope, + ) + except Exception as e: + logger.debug("Can not set up continuous profiler. (%s)", e) finally: _client_init_debug.set(old_debug) @@ -737,7 +458,6 @@ def _record_lost_event( or self.log_batcher or self.metrics_batcher or self.span_batcher - or has_profiling_enabled(self.options) or isinstance(self.transport, HttpTransportCore) ): # If we have anything on that could spawn a background thread, we @@ -776,17 +496,14 @@ def _prepare_event( hint: "Hint", scope: "Optional[Scope]", ) -> "Optional[Event]": - previous_total_spans: "Optional[int]" = None previous_total_breadcrumbs: "Optional[int]" = None if event.get("timestamp") is None: event["timestamp"] = datetime.now(timezone.utc) - is_transaction = event.get("type") == "transaction" is_checkin = event.get("type") == "check_in" if scope is not None: - spans_before = len(cast(List[Dict[str, object]], event.get("spans", []))) event_ = scope.apply_to_event(event, hint, self.options) # one of the event/error processors returned None @@ -794,37 +511,12 @@ def _prepare_event( if self.transport: self.transport.record_lost_event( "event_processor", - data_category=("transaction" if is_transaction else "error"), + data_category="error", ) - if is_transaction: - self.transport.record_lost_event( - "event_processor", - data_category="span", - quantity=spans_before + 1, # +1 for the transaction itself - ) return None event = event_ - spans_delta = spans_before - len( - cast(List[Dict[str, object]], event.get("spans", [])) - ) - span_recorder_dropped_spans: int = event.pop("_dropped_spans", 0) - if is_transaction and self.transport is not None: - if spans_delta > 0: - self.transport.record_lost_event( - "event_processor", data_category="span", quantity=spans_delta - ) - if span_recorder_dropped_spans > 0: - self.transport.record_lost_event( - "buffer_overflow", - data_category="span", - quantity=span_recorder_dropped_spans, - ) - - dropped_spans: int = span_recorder_dropped_spans + spans_delta - if dropped_spans > 0: - previous_total_spans = spans_before + dropped_spans if scope._n_breadcrumbs_truncated > 0: breadcrumbs = event.get("breadcrumbs", {}) values = ( @@ -837,8 +529,7 @@ def _prepare_event( ) if ( - not is_transaction - and not is_checkin + not is_checkin and self.options["attach_stacktrace"] and "exception" not in event and "stacktrace" not in event @@ -885,25 +576,6 @@ def _prepare_event( if event_scrubber: event_scrubber.scrub_event(event) - if scope is not None and scope._gen_ai_original_message_count: - spans: "List[Dict[str, Any]] | AnnotatedValue" = event.get("spans", []) - if isinstance(spans, list): - for span in spans: - span_id = span.get("span_id", None) - span_data = span.get("data", {}) - if ( - span_id - and span_id in scope._gen_ai_original_message_count - and SPANDATA.GEN_AI_REQUEST_MESSAGES in span_data - ): - span_data[SPANDATA.GEN_AI_REQUEST_MESSAGES] = AnnotatedValue( - span_data[SPANDATA.GEN_AI_REQUEST_MESSAGES], - {"len": scope._gen_ai_original_message_count[span_id]}, - ) - if previous_total_spans is not None: - event["spans"] = AnnotatedValue( - event.get("spans", []), {"len": previous_total_spans} - ) if previous_total_breadcrumbs is not None: event["breadcrumbs"] = AnnotatedValue( event.get("breadcrumbs", {"values": []}), @@ -924,11 +596,7 @@ def _prepare_event( ) before_send = self.options["before_send"] - if ( - before_send is not None - and event is not None - and event.get("type") != "transaction" - ): + if before_send is not None and event is not None: new_event = None with capture_internal_exceptions(): new_event = before_send(event, hint or {}) @@ -948,36 +616,6 @@ def _prepare_event( event = new_event - before_send_transaction = self.options["before_send_transaction"] - if ( - before_send_transaction is not None - and event is not None - and event.get("type") == "transaction" - ): - new_event = None - spans_before = len(cast(List[Dict[str, object]], event.get("spans", []))) - with capture_internal_exceptions(): - new_event = before_send_transaction(event, hint or {}) - if new_event is None: - logger.info("before send transaction dropped event") - if self.transport: - self.transport.record_lost_event( - reason="before_send", data_category="transaction" - ) - self.transport.record_lost_event( - reason="before_send", - data_category="span", - quantity=spans_before + 1, # +1 for the transaction itself - ) - else: - spans_delta = spans_before - len(new_event.get("spans", [])) - if spans_delta > 0 and self.transport is not None: - self.transport.record_lost_event( - reason="before_send", data_category="span", quantity=spans_delta - ) - - event = new_event - return event def _is_ignored_error(self, event: "Event", hint: "Hint") -> bool: @@ -1007,11 +645,6 @@ def _should_capture( hint: "Hint", scope: "Optional[Scope]" = None, ) -> bool: - # Transactions are sampled independent of error events. - is_transaction = event.get("type") == "transaction" - if is_transaction: - return True - ignoring_prevents_recursion = scope is not None and not scope._should_capture if ignoring_prevents_recursion: return False @@ -1127,13 +760,10 @@ def capture_event( if not self._should_capture(event, hint, scope): return None - profile = event.pop("profile", None) - event_id = event.get("event_id") if event_id is None: event["event_id"] = event_id = uuid.uuid4().hex - span_recorder_has_gen_ai_span = event.pop("_has_gen_ai_span", False) event_opt = self._prepare_event(event, hint, scope) if event_opt is None: return None @@ -1144,14 +774,9 @@ def capture_event( if session: self._update_session_from_event(session, event) - is_transaction = event_opt.get("type") == "transaction" is_checkin = event_opt.get("type") == "check_in" - if ( - not is_transaction - and not is_checkin - and not self._should_sample_error(event, hint) - ): + if not is_checkin and not self._should_sample_error(event, hint): return None attachments = hint.get("attachments") @@ -1169,44 +794,7 @@ def capture_event( envelope = Envelope(headers=headers) - if is_transaction and isinstance(profile, Profile): - envelope.add_profile(profile.to_json(event_opt, self.options)) - - if is_transaction and not span_recorder_has_gen_ai_span: - envelope.add_transaction(event_opt) - elif is_transaction: - split_spans = _split_gen_ai_spans(event_opt) - if split_spans is None or not split_spans[1]: - envelope.add_transaction(event_opt) - else: - non_gen_ai_spans, gen_ai_spans = split_spans - - event_opt["spans"] = non_gen_ai_spans - envelope.add_transaction(event_opt) - - converted_gen_ai_spans = [ - _serialized_v1_span_to_serialized_v2_span(span, event_opt) - for span in gen_ai_spans - if isinstance(span, dict) - ] - - envelope.add_item( - Item( - type=SpanBatcher.TYPE, - content_type=SpanBatcher.CONTENT_TYPE, - headers={ - "item_count": len(converted_gen_ai_spans), - }, - payload=PayloadRef( - json={ - "version": 2, - "items": converted_gen_ai_spans, - }, - ), - ) - ) - - elif is_checkin: + if is_checkin: envelope.add_checkin(event_opt) else: envelope.add_event(event_opt) @@ -1227,7 +815,7 @@ def capture_event( def _capture_telemetry( self, - telemetry: "Optional[Union[Log, Metric, StreamedSpan]]", + telemetry: "Optional[Union[Log, Metric, Span]]", ty: str, scope: "Scope", ) -> None: @@ -1276,7 +864,7 @@ def _capture_telemetry( if serialized is None: return - elif ty == "span" and isinstance(telemetry, StreamedSpan): + elif ty == "span" and isinstance(telemetry, Span): # Reset the span to its original value before we attempted # to call the `before_send_span` callback if exception_raised_in_before_send_func: @@ -1320,7 +908,7 @@ def _capture_log(self, log: "Optional[Log]", scope: "Scope") -> None: def _capture_metric(self, metric: "Optional[Metric]", scope: "Scope") -> None: self._capture_telemetry(metric, "metric", scope) - def _capture_span(self, span: "Optional[StreamedSpan]", scope: "Scope") -> None: + def _capture_span(self, span: "Optional[Span]", scope: "Scope") -> None: self._capture_telemetry(span, "span", scope) def capture_session( @@ -1393,9 +981,8 @@ def close( """ if self.transport is not None: if self._has_async_transport(): - warnings.warn( + logger.warning( "close() used with AsyncHttpTransport. Use close_async() instead.", - stacklevel=2, ) self._flush_components() else: @@ -1440,9 +1027,8 @@ def flush( """ if self.transport is not None: if self._has_async_transport(): - warnings.warn( + logger.warning( "flush() used with AsyncHttpTransport. Use flush_async() instead.", - stacklevel=2, ) return if timeout is None: diff --git a/sentry_sdk/consts.py b/sentry_sdk/consts.py index a1613bfbd7..75b5cb7c92 100644 --- a/sentry_sdk/consts.py +++ b/sentry_sdk/consts.py @@ -29,7 +29,6 @@ class CompressionAlgo(Enum): if TYPE_CHECKING: from typing import ( - AbstractSet, Any, Callable, Dict, @@ -54,10 +53,8 @@ class CompressionAlgo(Enum): IgnoreSpansConfig, Log, Metric, - ProfilerMode, SpanJSON, TracesSampler, - TransactionProcessor, ) # Experiments are feature flags to enable and disable certain unstable SDK @@ -67,28 +64,15 @@ class CompressionAlgo(Enum): Experiments = TypedDict( "Experiments", { - "max_spans": Optional[int], "max_flags": Optional[int], "record_sql_params": Optional[bool], "continuous_profiling_auto_start": Optional[bool], - "continuous_profiling_mode": Optional[ContinuousProfilerMode], - "otel_powered_performance": Optional[bool], "transport_zlib_compression_level": Optional[int], "transport_compression_level": Optional[int], "transport_compression_algo": Optional[CompressionAlgo], "transport_num_pools": Optional[int], "transport_http2": Optional[bool], "transport_async": Optional[bool], - "enable_logs": Optional[bool], - "before_send_log": Optional[Callable[[Log, Hint], Optional[Log]]], - "enable_metrics": Optional[bool], - "before_send_metric": Optional[Callable[[Metric, Hint], Optional[Metric]]], - "trace_lifecycle": Optional[Literal["static", "stream"]], - "ignore_spans": Optional[IgnoreSpansConfig], - "before_send_span": Optional[ - Callable[[SpanJSON, Hint], Optional[SpanJSON]] - ], - "suppress_asgi_chained_exceptions": Optional[bool], "data_collection": Optional[DataCollectionUserOptions], }, total=False, @@ -107,21 +91,6 @@ class CompressionAlgo(Enum): ] -class SPANTEMPLATE(str, Enum): - DEFAULT = "default" - AI_AGENT = "ai_agent" - AI_TOOL = "ai_tool" - AI_CHAT = "ai_chat" - - def __str__(self) -> str: - return self.value - - -class INSTRUMENTER: - SENTRY = "sentry" - OTEL = "otel" - - class SPANNAME: DB_COMMIT = "COMMIT" DB_ROLLBACK = "ROLLBACK" @@ -622,6 +591,12 @@ class SPANDATA: Example: [{"role": "assistant", "parts": [{"type": "text", "content": "The weather in Paris is currently rainy with a temperature of 57°F."}], "finish_reason": "stop"}] """ + GEN_AI_RESPONSE_TIME_TO_FIRST_CHUNK = "gen_ai.response.time_to_first_chunk" + """ + Time in seconds when the first response content chunk arrived in streaming responses. + Example: 0.6853435 + """ + GEN_AI_RESPONSE_TIME_TO_FIRST_TOKEN = "gen_ai.response.time_to_first_token" """ The time it took to receive the first token from the model. @@ -1195,32 +1170,6 @@ class SPANDATA: """ -class SPANSTATUS: - """ - The status of a Sentry span. - - See: https://develop.sentry.dev/sdk/event-payloads/contexts/#trace-context - """ - - ABORTED = "aborted" - ALREADY_EXISTS = "already_exists" - CANCELLED = "cancelled" - DATA_LOSS = "data_loss" - DEADLINE_EXCEEDED = "deadline_exceeded" - FAILED_PRECONDITION = "failed_precondition" - INTERNAL_ERROR = "internal_error" - INVALID_ARGUMENT = "invalid_argument" - NOT_FOUND = "not_found" - OK = "ok" - OUT_OF_RANGE = "out_of_range" - PERMISSION_DENIED = "permission_denied" - RESOURCE_EXHAUSTED = "resource_exhausted" - UNAUTHENTICATED = "unauthenticated" - UNAVAILABLE = "unavailable" - UNIMPLEMENTED = "unimplemented" - UNKNOWN_ERROR = "unknown_error" - - class OP: ANTHROPIC_MESSAGES_CREATE = "ai.messages.create.anthropic" CACHE_GET = "cache.get" @@ -1312,7 +1261,7 @@ def __init__( in_app_exclude: "List[str]" = [], # noqa: B006 default_integrations: bool = True, dist: "Optional[str]" = None, - transport: "Optional[Union[sentry_sdk.transport.Transport, Type[sentry_sdk.transport.Transport], Callable[[Event], None]]]" = None, + transport: "Optional[Union[sentry_sdk.transport.Transport, Type[sentry_sdk.transport.Transport], None]]" = None, transport_queue_size: int = DEFAULT_QUEUE_SIZE, sample_rate: float = 1.0, send_default_pii: "Optional[bool]" = None, @@ -1326,15 +1275,11 @@ def __init__( before_send: "Optional[EventProcessor]" = None, before_breadcrumb: "Optional[BreadcrumbProcessor]" = None, debug: "Optional[bool]" = None, - attach_stacktrace: bool = False, + attach_stacktrace: bool = True, ca_certs: "Optional[str]" = None, - propagate_traces: bool = True, traces_sample_rate: "Optional[float]" = None, - trace_lifecycle: "Optional[Literal['static', 'stream']]" = None, traces_sampler: "Optional[TracesSampler]" = None, - profiles_sample_rate: "Optional[float]" = None, - profiles_sampler: "Optional[TracesSampler]" = None, - profiler_mode: "Optional[ProfilerMode]" = None, + profiler_mode: "Optional[ContinuousProfilerMode]" = None, profile_lifecycle: 'Literal["manual", "trace"]' = "manual", profile_session_sample_rate: "Optional[float]" = None, auto_enabling_integrations: bool = True, @@ -1343,10 +1288,7 @@ def __init__( send_client_reports: bool = True, _experiments: "Experiments" = {}, # noqa: B006 proxy_headers: "Optional[Dict[str, str]]" = None, - instrumenter: "Optional[str]" = INSTRUMENTER.SENTRY, - before_send_transaction: "Optional[TransactionProcessor]" = None, project_root: "Optional[str]" = None, - enable_tracing: "Optional[bool]" = None, include_local_variables: "Optional[bool]" = True, include_source_context: "Optional[bool]" = True, trace_propagation_targets: "Optional[Sequence[str]]" = [ # noqa: B006 @@ -1367,15 +1309,11 @@ def __init__( custom_repr: "Optional[Callable[..., Optional[str]]]" = None, add_full_stack: bool = DEFAULT_ADD_FULL_STACK, max_stack_frames: "Optional[int]" = DEFAULT_MAX_STACK_FRAMES, - enable_logs: bool = False, before_send_log: "Optional[Callable[[Log, Hint], Optional[Log]]]" = None, - trace_ignore_status_codes: "AbstractSet[int]" = frozenset(), - enable_metrics: bool = True, before_send_metric: "Optional[Callable[[Metric, Hint], Optional[Metric]]]" = None, before_send_span: "Optional[Callable[[SpanJSON, Hint], Optional[SpanJSON]]]" = None, org_id: "Optional[str]" = None, strict_trace_continuation: bool = False, - stream_gen_ai_spans: bool = True, ) -> None: """Initialize the Sentry SDK with the given parameters. All parameters described here can be used in a call to `sentry_sdk.init()`. @@ -1603,11 +1541,6 @@ def __init__( By the time `before_send` is executed, all scope data has already been applied to the event. Further modification of the scope won't have any effect. - :param before_send_transaction: This function is called with an SDK-specific transaction event object, and can - return a modified transaction event object, or `null` to skip reporting the event. - - One way this might be used is for manual PII stripping before sending. - :param before_breadcrumb: This function is called with an SDK-specific breadcrumb object before the breadcrumb is added to the scope. @@ -1671,28 +1604,28 @@ def __init__( If provided, the options will override the default `urllib3` `socket options `_. - :param traces_sample_rate: A number between `0` and `1`, controlling the percentage chance a given transaction + :param traces_sample_rate: A number between `0` and `1`, controlling the percentage chance a given service span will be sent to Sentry. - (`0` represents 0% while `1` represents 100%.) Applies equally to all transactions created in the app. + (`0` represents 0% while `1` represents 100%.) Applies equally to all service spans created in the app. Either this or `traces_sampler` must be defined to enable tracing. If `traces_sample_rate` is `0`, this means that no new traces will be created. However, if you have another service (for example a JS frontend) that makes requests to your service that include trace - information, those traces will be continued and thus transactions will be sent to Sentry. + information, those traces will be continued and thus spans will be sent to Sentry. If you want to disable all tracing you need to set `traces_sample_rate=None`. In this case, no new traces will be started and no incoming traces will be continued. - :param traces_sampler: A function responsible for determining the percentage chance a given transaction will be + :param traces_sampler: A function responsible for determining the percentage chance a given service span will be sent to Sentry. - It will automatically be passed information about the transaction and the context in which it's being + It will automatically be passed information about the service span and the context in which it's being created, and must return a number between `0` (0% chance of being sent) and `1` (100% chance of being sent). - Can also be used for filtering transactions, by returning `0` for those that are unwanted. + Can also be used for filtering service spans, by returning `0` for those that are unwanted. Either this or `traces_sample_rate` must be defined to enable tracing. @@ -1753,50 +1686,21 @@ def __init__( Return a string for that repr value to be used or `None` to continue serializing how Sentry would have done it anyway. - :param profiles_sample_rate: A number between `0` and `1`, controlling the percentage chance a given sampled - transaction will be profiled. - - (`0` represents 0% while `1` represents 100%.) Applies equally to all transactions created in the app. - - This is relative to the tracing sample rate - e.g. `0.5` means 50% of sampled transactions will be - profiled. - - :param profiles_sampler: - :param profiler_mode: :param profile_lifecycle: :param profile_session_sample_rate: - :param enable_tracing: - - :param propagate_traces: - :param auto_session_tracking: :param spotlight: - :param instrumenter: - - :param enable_logs: Set `enable_logs` to True to enable the SDK to emit - Sentry logs. Defaults to False. - :param before_send_log: An optional function to modify or filter out logs before they're sent to Sentry. Any modifications to the log in this function will be retained. If the function returns None, the log will not be sent to Sentry. - :param trace_ignore_status_codes: An optional property that disables tracing for - HTTP requests with certain status codes. - - Requests are not traced if the status code is contained in the provided set. - - If `trace_ignore_status_codes` is not provided, requests with any status code - may be traced. - - This option has no effect in span streaming mode (`trace_lifecycle="stream"`). - :param strict_trace_continuation: If set to `True`, the SDK will only continue a trace if the `org_id` of the incoming trace found in the `baggage` header matches the `org_id` of the current Sentry client and only if BOTH are present. @@ -1812,17 +1716,9 @@ def __init__( :param before_send_span: An optional function to modify spans before they're sent to Sentry. Modifications to the span's attributes and name will be retained. Unlike ``before_send_log`` - and ``before_send_metric``, spans cannot be dropped by returning None. Only works when - ``trace_lifecycle="stream"`` is enabled. - - :param stream_gen_ai_spans: When set, generative AI spans are sent in a new transport format to - reduce downstream data loss. - - :param trace_lifecycle: Controls how traces are sent. Set to `"stream"` to send spans as they - finish, or `"static"` to send a completed trace as a transaction event. + and ``before_send_metric``, spans cannot be dropped by returning None. - :param ignore_spans: A sequence of span-matching rules. Matching spans are ignored when - `trace_lifecycle="stream"` is enabled. + :param ignore_spans: A sequence of span-matching rules. Matching spans are ignored. :param _experiments: Dictionary of experimental, opt-in features that are not yet stable. """ diff --git a/sentry_sdk/data_collection.py b/sentry_sdk/data_collection.py index 2491e55623..1cc92a2763 100644 --- a/sentry_sdk/data_collection.py +++ b/sentry_sdk/data_collection.py @@ -22,7 +22,6 @@ ``DeprecationWarning`` is emitted for ``send_default_pii``. """ -import warnings from typing import TYPE_CHECKING, Any, Dict, List, Mapping, Optional, Union, cast from urllib.parse import parse_qs, urlencode @@ -298,6 +297,8 @@ def _resolve_data_collection(options: "Dict[str, Any]") -> "DataCollection": overwrites ``options["data_collection"]`` with the resolved result. Feeding an already-resolved dict back in would flip ``provided_by_user`` to ``True``. """ + from sentry_sdk.utils import deprecation_warning + user_dc = options.get("data_collection") if user_dc is None: user_dc = options.get("_experiments", {}).get("data_collection") @@ -323,11 +324,9 @@ def _resolve_data_collection(options: "Dict[str, Any]") -> "DataCollection": ) ) if send_default_pii is not None: - warnings.warn( + deprecation_warning( "`send_default_pii` is deprecated and ignored when " "`data_collection` is set.", - DeprecationWarning, - stacklevel=2, ) return _resolve_explicit( user_dc, diff --git a/sentry_sdk/debug.py b/sentry_sdk/debug.py index 795882e9ef..466f680528 100644 --- a/sentry_sdk/debug.py +++ b/sentry_sdk/debug.py @@ -1,6 +1,5 @@ import logging import sys -import warnings from logging import LogRecord from sentry_sdk import get_client @@ -27,11 +26,3 @@ def configure_logger() -> None: logger.addHandler(_handler) logger.setLevel(logging.DEBUG) logger.addFilter(_DebugFilter()) - - -def configure_debug_hub() -> None: - warnings.warn( - "configure_debug_hub is deprecated. Please remove calls to it, as it is a no-op.", - DeprecationWarning, - stacklevel=2, - ) diff --git a/sentry_sdk/envelope.py b/sentry_sdk/envelope.py index d2d4aae31a..85a5a4c18f 100644 --- a/sentry_sdk/envelope.py +++ b/sentry_sdk/envelope.py @@ -23,7 +23,7 @@ class Envelope: """ Represents a Sentry Envelope. The calling code is responsible for adhering to the constraints documented in the Sentry docs: https://develop.sentry.dev/sdk/envelopes/#data-model. In particular, - each envelope may have at most one Item with type "event" or "transaction" (but not both). + each envelope may have at most one Item with type "event". """ def __init__( @@ -53,18 +53,6 @@ def add_event( ) -> None: self.add_item(Item(payload=PayloadRef(json=event), type="event")) - def add_transaction( - self, - transaction: "Event", - ) -> None: - self.add_item(Item(payload=PayloadRef(json=transaction), type="transaction")) - - def add_profile( - self, - profile: "Any", - ) -> None: - self.add_item(Item(payload=PayloadRef(json=profile), type="profile")) - def add_profile_chunk( self, profile_chunk: "Any", @@ -110,13 +98,6 @@ def get_event(self) -> "Optional[Event]": return event return None - def get_transaction_event(self) -> "Optional[Event]": - for item in self.items: - event = item.get_transaction_event() - if event is not None: - return event - return None - def __iter__(self) -> "Iterator[Item]": return iter(self.items) @@ -247,8 +228,6 @@ def data_category(self) -> "EventDataCategory": return "session" elif ty == "attachment": return "attachment" - elif ty == "transaction": - return "transaction" elif ty == "span": return "span" elif ty == "event": @@ -259,8 +238,6 @@ def data_category(self) -> "EventDataCategory": return "trace_metric" elif ty == "client_report": return "internal" - elif ty == "profile": - return "profile" elif ty == "profile_chunk": return "profile_chunk" elif ty == "check_in": @@ -279,11 +256,6 @@ def get_event(self) -> "Optional[Event]": return self.payload.json return None - def get_transaction_event(self) -> "Optional[Event]": - if self.type == "transaction" and self.payload.json is not None: - return self.payload.json - return None - def serialize_into( self, f: "Any", @@ -318,7 +290,7 @@ def deserialize_from( # if no length was specified we need to read up to the end of line # and remove it (if it is present, i.e. not the very last char in an eof terminated envelope) payload = f.readline().rstrip(b"\n") - if headers.get("type") in ("event", "transaction"): + if headers.get("type") == "event": rv = cls(headers=headers, payload=PayloadRef(json=parse_json(payload))) else: rv = cls(headers=headers, payload=payload) diff --git a/sentry_sdk/feature_flags.py b/sentry_sdk/feature_flags.py index 5eaa5e440b..1baf21068a 100644 --- a/sentry_sdk/feature_flags.py +++ b/sentry_sdk/feature_flags.py @@ -4,8 +4,6 @@ import sentry_sdk from sentry_sdk._lru_cache import LRUCache -from sentry_sdk.tracing import Span -from sentry_sdk.tracing_utils import has_span_streaming_enabled if TYPE_CHECKING: from typing import TypedDict @@ -59,17 +57,10 @@ def add_feature_flag(flag: str, result: bool) -> None: Records a flag and its value to be sent on subsequent error events. We recommend you do this on flag evaluations. Flags are buffered per Sentry scope. """ - client = sentry_sdk.get_client() flags = sentry_sdk.get_isolation_scope().flags flags.set(flag, result) - if has_span_streaming_enabled(client.options): - span = sentry_sdk.traces.get_current_span() - if span and isinstance(span, sentry_sdk.traces.StreamedSpan): - span.set_attribute(f"flag.evaluation.{flag}", result) - - else: - span = sentry_sdk.get_current_span() - if span and isinstance(span, Span): - span.set_flag(f"flag.evaluation.{flag}", result) + span = sentry_sdk.get_current_span() + if span is not None: + span.set_attribute(f"flag.evaluation.{flag}", result) diff --git a/sentry_sdk/hub.py b/sentry_sdk/hub.py deleted file mode 100644 index b17444d06e..0000000000 --- a/sentry_sdk/hub.py +++ /dev/null @@ -1,741 +0,0 @@ -import warnings -from contextlib import contextmanager -from typing import TYPE_CHECKING - -from sentry_sdk import ( - get_client, - get_current_scope, - get_global_scope, - get_isolation_scope, -) -from sentry_sdk._compat import with_metaclass -from sentry_sdk.client import Client -from sentry_sdk.consts import INSTRUMENTER -from sentry_sdk.scope import _ScopeManager -from sentry_sdk.tracing import ( - NoOpSpan, - Span, - Transaction, -) -from sentry_sdk.utils import ( - ContextVar, - logger, -) - -if TYPE_CHECKING: - from typing import ( - Any, - Callable, - ContextManager, - Dict, - Generator, - List, - Optional, - Tuple, - Type, - TypeVar, - Union, - overload, - ) - - from typing_extensions import Unpack - - from sentry_sdk._types import ( - Breadcrumb, - BreadcrumbHint, - Event, - ExcInfo, - Hint, - LogLevelStr, - SamplingContext, - ) - from sentry_sdk.client import BaseClient - from sentry_sdk.integrations import Integration - from sentry_sdk.scope import Scope - from sentry_sdk.tracing import TransactionKwargs - - T = TypeVar("T") - -else: - - def overload(x: "T") -> "T": - return x - - -class SentryHubDeprecationWarning(DeprecationWarning): - """ - A custom deprecation warning to inform users that the Hub is deprecated. - """ - - _MESSAGE = ( - "`sentry_sdk.Hub` is deprecated and will be removed in a future major release. " - "Please consult our 1.x to 2.x migration guide for details on how to migrate " - "`Hub` usage to the new API: " - "https://docs.sentry.io/platforms/python/migration/1.x-to-2.x" - ) - - def __init__(self, *_: object) -> None: - super().__init__(self._MESSAGE) - - -@contextmanager -def _suppress_hub_deprecation_warning() -> "Generator[None, None, None]": - """Utility function to suppress deprecation warnings for the Hub.""" - with warnings.catch_warnings(): - warnings.filterwarnings("ignore", category=SentryHubDeprecationWarning) - yield - - -_local = ContextVar("sentry_current_hub") - - -class HubMeta(type): - @property - def current(cls) -> "Hub": - """Returns the current instance of the hub.""" - warnings.warn(SentryHubDeprecationWarning(), stacklevel=2) - rv = _local.get(None) - if rv is None: - with _suppress_hub_deprecation_warning(): - # This will raise a deprecation warning; suppress it since we already warned above. - rv = Hub(GLOBAL_HUB) - _local.set(rv) - return rv - - @property - def main(cls) -> "Hub": - """Returns the main instance of the hub.""" - warnings.warn(SentryHubDeprecationWarning(), stacklevel=2) - return GLOBAL_HUB - - -class Hub(with_metaclass(HubMeta)): # type: ignore - """ - .. deprecated:: 2.0.0 - The Hub is deprecated. Its functionality will be merged into :py:class:`sentry_sdk.scope.Scope`. - - The hub wraps the concurrency management of the SDK. Each thread has - its own hub but the hub might transfer with the flow of execution if - context vars are available. - - If the hub is used with a with statement it's temporarily activated. - """ - - _stack: "List[Tuple[Optional[Client], Scope]]" = None # type: ignore[assignment] - _scope: "Optional[Scope]" = None - - # Mypy doesn't pick up on the metaclass. - - if TYPE_CHECKING: - current: "Hub" = None # type: ignore[assignment] - main: "Optional[Hub]" = None - - def __init__( - self, - client_or_hub: "Optional[Union[Hub, Client]]" = None, - scope: "Optional[Any]" = None, - ) -> None: - warnings.warn(SentryHubDeprecationWarning(), stacklevel=2) - - current_scope = None - - if isinstance(client_or_hub, Hub): - client = get_client() - if scope is None: - # hub cloning is going on, we use a fork of the current/isolation scope for context manager - scope = get_isolation_scope().fork() - current_scope = get_current_scope().fork() - else: - client = client_or_hub - get_global_scope().set_client(client) - - if scope is None: # so there is no Hub cloning going on - # just the current isolation scope is used for context manager - scope = get_isolation_scope() - current_scope = get_current_scope() - - if current_scope is None: - # just the current current scope is used for context manager - current_scope = get_current_scope() - - self._stack = [(client, scope)] # type: ignore - self._last_event_id: "Optional[str]" = None - self._old_hubs: "List[Hub]" = [] - - self._old_current_scopes: "List[Scope]" = [] - self._old_isolation_scopes: "List[Scope]" = [] - self._current_scope: "Scope" = current_scope - self._scope: "Scope" = scope - - def __enter__(self) -> "Hub": - self._old_hubs.append(Hub.current) - _local.set(self) - - current_scope = get_current_scope() - self._old_current_scopes.append(current_scope) - scope._current_scope.set(self._current_scope) - - isolation_scope = get_isolation_scope() - self._old_isolation_scopes.append(isolation_scope) - scope._isolation_scope.set(self._scope) - - return self - - def __exit__( - self, - exc_type: "Optional[type]", - exc_value: "Optional[BaseException]", - tb: "Optional[Any]", - ) -> None: - old = self._old_hubs.pop() - _local.set(old) - - old_current_scope = self._old_current_scopes.pop() - scope._current_scope.set(old_current_scope) - - old_isolation_scope = self._old_isolation_scopes.pop() - scope._isolation_scope.set(old_isolation_scope) - - def run( - self, - callback: "Callable[[], T]", - ) -> "T": - """ - .. deprecated:: 2.0.0 - This function is deprecated and will be removed in a future release. - - Runs a callback in the context of the hub. Alternatively the - with statement can be used on the hub directly. - """ - with self: - return callback() - - def get_integration( - self, - name_or_class: "Union[str, Type[Integration]]", - ) -> "Any": - """ - .. deprecated:: 2.0.0 - This function is deprecated and will be removed in a future release. - Please use :py:meth:`sentry_sdk.client._Client.get_integration` instead. - - Returns the integration for this hub by name or class. If there - is no client bound or the client does not have that integration - then `None` is returned. - - If the return value is not `None` the hub is guaranteed to have a - client attached. - """ - return get_client().get_integration(name_or_class) - - @property - def client(self) -> "Optional[BaseClient]": - """ - .. deprecated:: 2.0.0 - This property is deprecated and will be removed in a future release. - Please use :py:func:`sentry_sdk.api.get_client` instead. - - Returns the current client on the hub. - """ - client = get_client() - - if not client.is_active(): - return None - - return client - - @property - def scope(self) -> "Scope": - """ - .. deprecated:: 2.0.0 - This property is deprecated and will be removed in a future release. - Returns the current scope on the hub. - """ - return get_isolation_scope() - - def last_event_id(self) -> "Optional[str]": - """ - Returns the last event ID. - - .. deprecated:: 1.40.5 - This function is deprecated and will be removed in a future release. The functions `capture_event`, `capture_message`, and `capture_exception` return the event ID directly. - """ - logger.warning( - "Deprecated: last_event_id is deprecated. This will be removed in the future. The functions `capture_event`, `capture_message`, and `capture_exception` return the event ID directly." - ) - return self._last_event_id - - def bind_client( - self, - new: "Optional[BaseClient]", - ) -> None: - """ - .. deprecated:: 2.0.0 - This function is deprecated and will be removed in a future release. - Please use :py:meth:`sentry_sdk.Scope.set_client` instead. - - Binds a new client to the hub. - """ - get_global_scope().set_client(new) - - def capture_event( - self, - event: "Event", - hint: "Optional[Hint]" = None, - scope: "Optional[Scope]" = None, - **scope_kwargs: "Any", - ) -> "Optional[str]": - """ - .. deprecated:: 2.0.0 - This function is deprecated and will be removed in a future release. - Please use :py:meth:`sentry_sdk.Scope.capture_event` instead. - - Captures an event. - - Alias of :py:meth:`sentry_sdk.Scope.capture_event`. - - :param event: A ready-made event that can be directly sent to Sentry. - - :param hint: Contains metadata about the event that can be read from `before_send`, such as the original exception object or a HTTP request object. - - :param scope: An optional :py:class:`sentry_sdk.Scope` to apply to events. - The `scope` and `scope_kwargs` parameters are mutually exclusive. - - :param scope_kwargs: Optional data to apply to event. - For supported `**scope_kwargs` see :py:meth:`sentry_sdk.Scope.update_from_kwargs`. - The `scope` and `scope_kwargs` parameters are mutually exclusive. - """ - last_event_id = get_current_scope().capture_event( - event, hint, scope=scope, **scope_kwargs - ) - - is_transaction = event.get("type") == "transaction" - if last_event_id is not None and not is_transaction: - self._last_event_id = last_event_id - - return last_event_id - - def capture_message( - self, - message: str, - level: "Optional[LogLevelStr]" = None, - scope: "Optional[Scope]" = None, - **scope_kwargs: "Any", - ) -> "Optional[str]": - """ - .. deprecated:: 2.0.0 - This function is deprecated and will be removed in a future release. - Please use :py:meth:`sentry_sdk.Scope.capture_message` instead. - - Captures a message. - - Alias of :py:meth:`sentry_sdk.Scope.capture_message`. - - :param message: The string to send as the message to Sentry. - - :param level: If no level is provided, the default level is `info`. - - :param scope: An optional :py:class:`sentry_sdk.Scope` to apply to events. - The `scope` and `scope_kwargs` parameters are mutually exclusive. - - :param scope_kwargs: Optional data to apply to event. - For supported `**scope_kwargs` see :py:meth:`sentry_sdk.Scope.update_from_kwargs`. - The `scope` and `scope_kwargs` parameters are mutually exclusive. - - :returns: An `event_id` if the SDK decided to send the event (see :py:meth:`sentry_sdk.client._Client.capture_event`). - """ - last_event_id = get_current_scope().capture_message( - message, level=level, scope=scope, **scope_kwargs - ) - - if last_event_id is not None: - self._last_event_id = last_event_id - - return last_event_id - - def capture_exception( - self, - error: "Optional[Union[BaseException, ExcInfo]]" = None, - scope: "Optional[Scope]" = None, - **scope_kwargs: "Any", - ) -> "Optional[str]": - """ - .. deprecated:: 2.0.0 - This function is deprecated and will be removed in a future release. - Please use :py:meth:`sentry_sdk.Scope.capture_exception` instead. - - Captures an exception. - - Alias of :py:meth:`sentry_sdk.Scope.capture_exception`. - - :param error: An exception to capture. If `None`, `sys.exc_info()` will be used. - - :param scope: An optional :py:class:`sentry_sdk.Scope` to apply to events. - The `scope` and `scope_kwargs` parameters are mutually exclusive. - - :param scope_kwargs: Optional data to apply to event. - For supported `**scope_kwargs` see :py:meth:`sentry_sdk.Scope.update_from_kwargs`. - The `scope` and `scope_kwargs` parameters are mutually exclusive. - - :returns: An `event_id` if the SDK decided to send the event (see :py:meth:`sentry_sdk.client._Client.capture_event`). - """ - last_event_id = get_current_scope().capture_exception( - error, scope=scope, **scope_kwargs - ) - - if last_event_id is not None: - self._last_event_id = last_event_id - - return last_event_id - - def add_breadcrumb( - self, - crumb: "Optional[Breadcrumb]" = None, - hint: "Optional[BreadcrumbHint]" = None, - **kwargs: "Any", - ) -> None: - """ - .. deprecated:: 2.0.0 - This function is deprecated and will be removed in a future release. - Please use :py:meth:`sentry_sdk.Scope.add_breadcrumb` instead. - - Adds a breadcrumb. - - :param crumb: Dictionary with the data as the sentry v7/v8 protocol expects. - - :param hint: An optional value that can be used by `before_breadcrumb` - to customize the breadcrumbs that are emitted. - """ - get_isolation_scope().add_breadcrumb(crumb, hint, **kwargs) - - def start_span( - self, instrumenter: str = INSTRUMENTER.SENTRY, **kwargs: "Any" - ) -> "Span": - """ - .. deprecated:: 2.0.0 - This function is deprecated and will be removed in a future release. - Please use :py:meth:`sentry_sdk.Scope.start_span` instead. - - Start a span whose parent is the currently active span or transaction, if any. - - The return value is a :py:class:`sentry_sdk.tracing.Span` instance, - typically used as a context manager to start and stop timing in a `with` - block. - - Only spans contained in a transaction are sent to Sentry. Most - integrations start a transaction at the appropriate time, for example - for every incoming HTTP request. Use - :py:meth:`sentry_sdk.start_transaction` to start a new transaction when - one is not already in progress. - - For supported `**kwargs` see :py:class:`sentry_sdk.tracing.Span`. - """ - scope = get_current_scope() - return scope.start_span(instrumenter=instrumenter, **kwargs) - - def start_transaction( - self, - transaction: "Optional[Transaction]" = None, - instrumenter: str = INSTRUMENTER.SENTRY, - custom_sampling_context: "Optional[SamplingContext]" = None, - **kwargs: "Unpack[TransactionKwargs]", - ) -> "Union[Transaction, NoOpSpan]": - """ - .. deprecated:: 2.0.0 - This function is deprecated and will be removed in a future release. - Please use :py:meth:`sentry_sdk.Scope.start_transaction` instead. - - Start and return a transaction. - - Start an existing transaction if given, otherwise create and start a new - transaction with kwargs. - - This is the entry point to manual tracing instrumentation. - - A tree structure can be built by adding child spans to the transaction, - and child spans to other spans. To start a new child span within the - transaction or any span, call the respective `.start_child()` method. - - Every child span must be finished before the transaction is finished, - otherwise the unfinished spans are discarded. - - When used as context managers, spans and transactions are automatically - finished at the end of the `with` block. If not using context managers, - call the `.finish()` method. - - When the transaction is finished, it will be sent to Sentry with all its - finished child spans. - - For supported `**kwargs` see :py:class:`sentry_sdk.tracing.Transaction`. - """ - scope = get_current_scope() - - # For backwards compatibility, we allow passing the scope as the hub. - # We need a major release to make this nice. (if someone searches the code: deprecated) - # Type checking disabled for this line because deprecated keys are not allowed in the type signature. - kwargs["hub"] = scope # type: ignore - - return scope.start_transaction( - transaction, instrumenter, custom_sampling_context, **kwargs - ) - - def continue_trace( - self, - environ_or_headers: "Dict[str, Any]", - op: "Optional[str]" = None, - name: "Optional[str]" = None, - source: "Optional[str]" = None, - ) -> "Transaction": - """ - .. deprecated:: 2.0.0 - This function is deprecated and will be removed in a future release. - Please use :py:meth:`sentry_sdk.Scope.continue_trace` instead. - - Sets the propagation context from environment or headers and returns a transaction. - """ - return get_isolation_scope().continue_trace( - environ_or_headers=environ_or_headers, op=op, name=name, source=source - ) - - @overload - def push_scope( - self, - callback: "Optional[None]" = None, - ) -> "ContextManager[Scope]": - pass - - @overload - def push_scope( # noqa: F811 - self, - callback: "Callable[[Scope], None]", - ) -> None: - pass - - def push_scope( # noqa - self, - callback: "Optional[Callable[[Scope], None]]" = None, - continue_trace: bool = True, - ) -> "Optional[ContextManager[Scope]]": - """ - .. deprecated:: 2.0.0 - This function is deprecated and will be removed in a future release. - - Pushes a new layer on the scope stack. - - :param callback: If provided, this method pushes a scope, calls - `callback`, and pops the scope again. - - :returns: If no `callback` is provided, a context manager that should - be used to pop the scope again. - """ - if callback is not None: - with self.push_scope() as scope: - callback(scope) - return None - - return _ScopeManager(self) - - def pop_scope_unsafe(self) -> "Tuple[Optional[Client], Scope]": - """ - .. deprecated:: 2.0.0 - This function is deprecated and will be removed in a future release. - - Pops a scope layer from the stack. - - Try to use the context manager :py:meth:`push_scope` instead. - """ - rv = self._stack.pop() - assert self._stack, "stack must have at least one layer" - return rv - - @overload - def configure_scope( - self, - callback: "Optional[None]" = None, - ) -> "ContextManager[Scope]": - pass - - @overload - def configure_scope( # noqa: F811 - self, - callback: "Callable[[Scope], None]", - ) -> None: - pass - - def configure_scope( # noqa - self, - callback: "Optional[Callable[[Scope], None]]" = None, - continue_trace: bool = True, - ) -> "Optional[ContextManager[Scope]]": - """ - .. deprecated:: 2.0.0 - This function is deprecated and will be removed in a future release. - - Reconfigures the scope. - - :param callback: If provided, call the callback with the current scope. - - :returns: If no callback is provided, returns a context manager that returns the scope. - """ - scope = get_isolation_scope() - - if continue_trace: - scope.generate_propagation_context() - - if callback is not None: - # TODO: used to return None when client is None. Check if this changes behavior. - callback(scope) - - return None - - @contextmanager - def inner() -> "Generator[Scope, None, None]": - yield scope - - return inner() - - def start_session( - self, - session_mode: str = "application", - ) -> None: - """ - .. deprecated:: 2.0.0 - This function is deprecated and will be removed in a future release. - Please use :py:meth:`sentry_sdk.Scope.start_session` instead. - - Starts a new session. - """ - get_isolation_scope().start_session( - session_mode=session_mode, - ) - - def end_session(self) -> None: - """ - .. deprecated:: 2.0.0 - This function is deprecated and will be removed in a future release. - Please use :py:meth:`sentry_sdk.Scope.end_session` instead. - - Ends the current session if there is one. - """ - get_isolation_scope().end_session() - - def stop_auto_session_tracking(self) -> None: - """ - .. deprecated:: 2.0.0 - This function is deprecated and will be removed in a future release. - Please use :py:meth:`sentry_sdk.Scope.stop_auto_session_tracking` instead. - - Stops automatic session tracking. - - This temporarily session tracking for the current scope when called. - To resume session tracking call `resume_auto_session_tracking`. - """ - get_isolation_scope().stop_auto_session_tracking() - - def resume_auto_session_tracking(self) -> None: - """ - .. deprecated:: 2.0.0 - This function is deprecated and will be removed in a future release. - Please use :py:meth:`sentry_sdk.Scope.resume_auto_session_tracking` instead. - - Resumes automatic session tracking for the current scope if - disabled earlier. This requires that generally automatic session - tracking is enabled. - """ - get_isolation_scope().resume_auto_session_tracking() - - def flush( - self, - timeout: "Optional[float]" = None, - callback: "Optional[Callable[[int, float], None]]" = None, - ) -> None: - """ - .. deprecated:: 2.0.0 - This function is deprecated and will be removed in a future release. - Please use :py:meth:`sentry_sdk.client._Client.flush` instead. - - Alias for :py:meth:`sentry_sdk.client._Client.flush` - """ - return get_client().flush(timeout=timeout, callback=callback) - - def get_traceparent(self) -> "Optional[str]": - """ - .. deprecated:: 2.0.0 - This function is deprecated and will be removed in a future release. - Please use :py:meth:`sentry_sdk.Scope.get_traceparent` instead. - - Returns the traceparent either from the active span or from the scope. - """ - current_scope = get_current_scope() - traceparent = current_scope.get_traceparent() - - if traceparent is None: - isolation_scope = get_isolation_scope() - traceparent = isolation_scope.get_traceparent() - - return traceparent - - def get_baggage(self) -> "Optional[str]": - """ - .. deprecated:: 2.0.0 - This function is deprecated and will be removed in a future release. - Please use :py:meth:`sentry_sdk.Scope.get_baggage` instead. - - Returns Baggage either from the active span or from the scope. - """ - current_scope = get_current_scope() - baggage = current_scope.get_baggage() - - if baggage is None: - isolation_scope = get_isolation_scope() - baggage = isolation_scope.get_baggage() - - if baggage is not None: - return baggage.serialize() - - return None - - def iter_trace_propagation_headers( - self, span: "Optional[Span]" = None - ) -> "Generator[Tuple[str, str], None, None]": - """ - .. deprecated:: 2.0.0 - This function is deprecated and will be removed in a future release. - Please use :py:meth:`sentry_sdk.Scope.iter_trace_propagation_headers` instead. - - Return HTTP headers which allow propagation of trace data. Data taken - from the span representing the request, if available, or the current - span on the scope if not. - """ - return get_current_scope().iter_trace_propagation_headers( - span=span, - ) - - def trace_propagation_meta(self, span: "Optional[Span]" = None) -> str: - """ - .. deprecated:: 2.0.0 - This function is deprecated and will be removed in a future release. - Please use :py:meth:`sentry_sdk.Scope.trace_propagation_meta` instead. - - Return meta tags which should be injected into HTML templates - to allow propagation of trace information. - """ - if span is not None: - logger.warning( - "The parameter `span` in trace_propagation_meta() is deprecated and will be removed in the future." - ) - - return get_current_scope().trace_propagation_meta( - span=span, - ) - - -with _suppress_hub_deprecation_warning(): - # Suppress deprecation warning for the Hub here, since we still always - # import this module. - GLOBAL_HUB = Hub() -_local.set(GLOBAL_HUB) - - -# Circular imports -from sentry_sdk import scope diff --git a/sentry_sdk/integrations/__init__.py b/sentry_sdk/integrations/__init__.py index ce6b86e15f..da6fc9608b 100644 --- a/sentry_sdk/integrations/__init__.py +++ b/sentry_sdk/integrations/__init__.py @@ -1,3 +1,4 @@ +import sys from abc import ABC, abstractmethod from itertools import zip_longest from threading import Lock @@ -59,12 +60,16 @@ def iter_default_integrations( "sentry_sdk.integrations.atexit.AtexitIntegration", "sentry_sdk.integrations.dedupe.DedupeIntegration", "sentry_sdk.integrations.excepthook.ExcepthookIntegration", - "sentry_sdk.integrations.logging.LoggingIntegration", "sentry_sdk.integrations.modules.ModulesIntegration", "sentry_sdk.integrations.stdlib.StdlibIntegration", "sentry_sdk.integrations.threading.ThreadingIntegration", ] +if sys.version_info >= (3, 8): + _DEFAULT_INTEGRATIONS.append( + "sentry_sdk.integrations.unraisablehook.UnraisablehookIntegration" + ) + _AUTO_ENABLING_INTEGRATIONS = [ "sentry_sdk.integrations.aiohttp.AioHttpIntegration", "sentry_sdk.integrations.anthropic.AnthropicIntegration", @@ -91,7 +96,6 @@ def iter_default_integrations( "sentry_sdk.integrations.langchain.LangchainIntegration", "sentry_sdk.integrations.langgraph.LanggraphIntegration", "sentry_sdk.integrations.litestar.LitestarIntegration", - "sentry_sdk.integrations.loguru.LoguruIntegration", "sentry_sdk.integrations.mcp.MCPIntegration", "sentry_sdk.integrations.openai.OpenAIIntegration", "sentry_sdk.integrations.openai_agents.OpenAIAgentsIntegration", @@ -105,7 +109,6 @@ def iter_default_integrations( "sentry_sdk.integrations.sqlalchemy.SqlalchemyIntegration", "sentry_sdk.integrations.starlette.StarletteIntegration", "sentry_sdk.integrations.starlite.StarliteIntegration", - "sentry_sdk.integrations.strawberry.StrawberryIntegration", "sentry_sdk.integrations.tornado.TornadoIntegration", ] @@ -118,7 +121,7 @@ def iter_default_integrations( _MIN_VERSIONS = { - "aiohttp": (3, 4), + "aiohttp": (3, 7), "aiomysql": (0, 3, 0), "anthropic": (0, 16), "ariadne": (0, 20), @@ -127,58 +130,57 @@ def iter_default_integrations( "beam": (2, 12), "boto3": (1, 16), # botocore "bottle": (0, 12), - "celery": (4, 4, 7), - "chalice": (1, 16, 0), + "celery": (5, 0, 0), + "chalice": (1, 22, 0), "clickhouse_driver": (0, 2, 0), "cohere": (5, 4, 0), - "django": (1, 8), + "django": (2, 0), "dramatiq": (1, 9), - "falcon": (1, 4), - "fastapi": (0, 79, 0), - "flask": (1, 1, 4), + "falcon": (3, 0), + "fastapi": (0, 85, 0), + "flask": (2, 0, 0), "gql": (3, 4, 1), "graphene": (3, 3), "google_genai": (1, 29, 0), # google-genai "grpc": (1, 32, 0), # grpcio "httpx": (0, 16, 0), "httpx2": (2, 0, 0), + "huey": (2, 0), "huggingface_hub": (0, 24, 7), "langchain": (0, 1, 0), "langgraph": (0, 6, 6), "launchdarkly": (9, 8, 0), + "litestar": (2, 0, 0), "litellm": (1, 77, 5), "loguru": (0, 7, 0), - "mcp": (1, 15, 0), + "mcp": (2, 0), "mistral": (2, 0, 5), "openai": (1, 0, 0), - "openai_agents": (0, 0, 19), + "openai_agents": (0, 10, 3), "openfeature": (0, 7, 1), - "pydantic_ai": (1, 0, 0), + "pydantic_ai": (1, 76, 0), "pymongo": (3, 5, 0), + "pyramid": (2, 0), "pyreqwest": (0, 11, 6), - "quart": (0, 16, 0), + "quart": (0, 19, 0), "ray": (2, 7, 0), - "requests": (2, 0, 0), - "rq": (0, 6), - "sanic": (0, 8), - "sqlalchemy": (1, 2), - "starlette": (0, 16), + "redis": (4, 2, 0), + "requests": (2, 30, 0), + "rq": (1, 0), + "sanic": (22, 0), + "spark": (3, 0), # pyspark + "sqlalchemy": (1, 4), + "starlette": (0, 20), "starlite": (1, 48), "statsig": (0, 55, 3), "strawberry": (0, 209, 5), "tornado": (6, 0), + "trytond_wsgi": (5, 4), "typer": (0, 15), "unleash": (6, 0, 1), } -_INTEGRATION_DEACTIVATES = { - "langchain": {"openai", "anthropic", "google_genai"}, - "openai_agents": {"openai"}, - "pydantic_ai": {"openai", "anthropic"}, -} - - def setup_integrations( integrations: "Sequence[Integration]", with_defaults: bool = True, @@ -194,15 +196,6 @@ def setup_integrations( `disabled_integrations` takes precedence over `with_defaults` and `with_auto_enabling_integrations`. - - Some integrations are designed to automatically deactivate other integrations - in order to avoid conflicts and prevent duplicate telemetry from being collected. - For example, enabling the `langchain` integration will auto-deactivate both the - `openai` and `anthropic` integrations. - - Users can override this behavior by: - - Explicitly providing an integration in the `integrations=[]` list, or - - Disabling the higher-level integration via the `disabled_integrations` option. """ integrations = dict( (integration.identifier, integration) for integration in integrations or () @@ -210,8 +203,6 @@ def setup_integrations( logger.debug("Setting up integrations (with default = %s)", with_defaults) - user_provided_integrations = set(integrations.keys()) - # Integrations that will not be enabled disabled_integrations = [ integration if isinstance(integration, type) else type(integration) @@ -230,27 +221,6 @@ def setup_integrations( integrations[instance.identifier] = instance used_as_default_integration.add(instance.identifier) - disabled_integration_identifiers = { - integration.identifier for integration in disabled_integrations - } - - for integration, targets_to_deactivate in _INTEGRATION_DEACTIVATES.items(): - if ( - integration in integrations - and integration not in disabled_integration_identifiers - ): - for target in targets_to_deactivate: - if target not in user_provided_integrations: - for cls in iter_default_integrations(True): - if cls.identifier == target: - if cls not in disabled_integrations: - disabled_integrations.append(cls) - logger.debug( - "Auto-deactivating %s integration because %s integration is active", - target, - integration, - ) - for identifier, integration in integrations.items(): with _installer_lock: if identifier not in _processed_integrations: diff --git a/sentry_sdk/integrations/_wsgi_common.py b/sentry_sdk/integrations/_wsgi_common.py index 3ccf029964..eaf764fb4b 100644 --- a/sentry_sdk/integrations/_wsgi_common.py +++ b/sentry_sdk/integrations/_wsgi_common.py @@ -5,7 +5,7 @@ from sentry_sdk._types import SENSITIVE_DATA_SUBSTITUTE from sentry_sdk.data_collection import _apply_key_value_collection_filtering from sentry_sdk.scope import should_send_default_pii -from sentry_sdk.utils import AnnotatedValue, has_data_collection_enabled, logger +from sentry_sdk.utils import AnnotatedValue, has_data_collection_enabled try: from django.http.request import RawPostDataException @@ -20,7 +20,7 @@ if TYPE_CHECKING: from typing import Any, Dict, Mapping, MutableMapping, Optional, Union - from sentry_sdk._types import Event, HttpStatusCodeRange + from sentry_sdk._types import Event SENSITIVE_ENV_KEYS = ( @@ -256,36 +256,3 @@ def _filter_headers( ) for k, v in headers.items() } - - -def _in_http_status_code_range( - code: object, code_ranges: "list[HttpStatusCodeRange]" -) -> bool: - for target in code_ranges: - if isinstance(target, int): - if code == target: - return True - continue - - try: - if code in target: - return True - except TypeError: - logger.warning( - "failed_request_status_codes has to be a list of integers or containers" - ) - - return False - - -class HttpCodeRangeContainer: - """ - Wrapper to make it possible to use list[HttpStatusCodeRange] as a Container[int]. - Used for backwards compatibility with the old `failed_request_status_codes` option. - """ - - def __init__(self, code_ranges: "list[HttpStatusCodeRange]") -> None: - self._code_ranges = code_ranges - - def __contains__(self, item: object) -> bool: - return _in_http_status_code_range(item, self._code_ranges) diff --git a/sentry_sdk/integrations/aiohttp.py b/sentry_sdk/integrations/aiohttp.py index 4f7b421357..5c05a5b08b 100644 --- a/sentry_sdk/integrations/aiohttp.py +++ b/sentry_sdk/integrations/aiohttp.py @@ -3,8 +3,7 @@ from functools import wraps import sentry_sdk -from sentry_sdk.api import continue_trace -from sentry_sdk.consts import _SENTRY_HEADER_NAMES, OP, SPANDATA, SPANSTATUS +from sentry_sdk.consts import _SENTRY_HEADER_NAMES, OP, SPANDATA from sentry_sdk.data_collection import ( _apply_data_collection_filtering_to_query_string, ) @@ -18,30 +17,23 @@ _filter_headers, request_body_within_bounds, ) -from sentry_sdk.integrations.logging import ignore_logger -from sentry_sdk.scope import Scope, should_send_default_pii +from sentry_sdk.integrations.logging import ignore_logger_for_events +from sentry_sdk.scope import Scope from sentry_sdk.sessions import track_session from sentry_sdk.traces import ( - NoOpStreamedSpan, - SegmentNameSource, - SpanStatus, - StreamedSpan, -) -from sentry_sdk.tracing import ( BAGGAGE_HEADER_NAME, SENTRY_TRACE_HEADER_NAME, SOURCE_FOR_STYLE, - TransactionSource, + SegmentNameSource, + Span, + SpanStatus, ) from sentry_sdk.tracing_utils import ( add_http_breadcrumb, add_http_request_source, - has_span_streaming_enabled, should_propagate_trace, ) from sentry_sdk.utils import ( - CONTEXTVARS_ERROR_MESSAGE, - HAS_REAL_CONTEXTVARS, SENSITIVE_DATA_SUBSTITUTE, AnnotatedValue, _get_aws_sigv4_signed_headers_from_authorization_header, @@ -50,7 +42,6 @@ capture_internal_exceptions, ensure_integration_enabled, event_from_exception, - has_data_collection_enabled, logger, parse_url, parse_version, @@ -65,21 +56,20 @@ from aiohttp import __version__ as AIOHTTP_VERSION from aiohttp.web import Application, HTTPException, UrlDispatcher except ImportError: - raise DidNotEnable("AIOHTTP not installed") + raise DidNotEnable("AIOHTTP not installed or incompatible") from typing import TYPE_CHECKING if TYPE_CHECKING: from collections.abc import Set from types import SimpleNamespace - from typing import Any, ContextManager, Optional, Tuple, Union + from typing import Any, Optional, Tuple, Union from aiohttp import TraceRequestEndParams, TraceRequestStartParams from aiohttp.web_request import Request from aiohttp.web_urldispatcher import UrlMappingMatchInfo from sentry_sdk._types import Attributes, Event, EventProcessor - from sentry_sdk.tracing import Span from sentry_sdk.utils import ExcInfo @@ -109,21 +99,13 @@ def setup_once() -> None: version = parse_version(AIOHTTP_VERSION) _check_minimum_version(AioHttpIntegration, version) - if not HAS_REAL_CONTEXTVARS: - # We better have contextvars or we're going to leak state between - # requests. - raise DidNotEnable( - "The aiohttp integration for Sentry requires Python 3.7+ " - " or aiocontextvars package." + CONTEXTVARS_ERROR_MESSAGE - ) - # In the aiohttp integration, all of their HTTP responses are Exceptions. # Because they have to be raised and handled by the framework, we need to # register the exceptions as control flow exceptions so that we don't # accidentally overwrite a status of "ok" with "error". _register_control_flow_exception(HTTPException) - ignore_logger("aiohttp.server") + ignore_logger_for_events("aiohttp.server") old_handle = Application._handle @@ -136,7 +118,6 @@ async def sentry_app_handle( return await old_handle(self, request, *args, **kwargs) weak_request = weakref.ref(request) - is_span_streaming_enabled = has_span_streaming_enabled(client.options) with sentry_sdk.isolation_scope() as scope: with track_session(scope, session_mode="request"): @@ -148,130 +129,78 @@ async def sentry_app_handle( headers = dict(request.headers) - span_ctx: "ContextManager[Union[Span, StreamedSpan]]" - if is_span_streaming_enabled: - sentry_sdk.traces.continue_trace(headers) - Scope.set_custom_sampling_context({"aiohttp_request": request}) - - header_attributes: "dict[str, Any]" = {} - for header, header_value in _filter_headers( - headers, - use_annotated_value=False, - ).items(): - header_attributes[ - f"http.request.header.{header.lower()}" - ] = ( - # header_value will always be a string because we set `use_annotated_value` to false above - header_value - ) + sentry_sdk.continue_trace(headers) + Scope.set_custom_sampling_context({"aiohttp_request": request}) + + header_attributes: "dict[str, Any]" = {} + for header, header_value in _filter_headers( + headers, + use_annotated_value=False, + ).items(): + header_attributes[f"http.request.header.{header.lower()}"] = ( + # header_value will always be a string because we set `use_annotated_value` to false above + header_value + ) - url_attributes = {} - client_address_attributes = {} + url_attributes = {} + client_address_attributes = {} - if has_data_collection_enabled(client.options): - url_attributes["url.full"] = "%s://%s%s" % ( - request.scheme, - request.host, - request.path, - ) - url_attributes["url.path"] = request.path - - if request.query_string: - filtered_query_string = ( - _apply_data_collection_filtering_to_query_string( - query_string=request.query_string, - behaviour=client.options["data_collection"][ - "url_query_params" - ], - ) - ) - if filtered_query_string: - url_attributes["url.query"] = filtered_query_string - url_attributes["url.full"] += ( - "?" + filtered_query_string - ) - - if request.remote: - if client.options["data_collection"]["user_info"]: - client_address_attributes["client.address"] = ( - request.remote - ) - scope.set_attribute( - SPANDATA.USER_IP_ADDRESS, request.remote - ) - - elif should_send_default_pii(): - url_full = "%s://%s%s" % ( - request.scheme, - request.host, - request.path, + url_attributes["url.full"] = "%s://%s%s" % ( + request.scheme, + request.host, + request.path, + ) + url_attributes["url.path"] = request.path + + if request.query_string: + filtered_query_string = ( + _apply_data_collection_filtering_to_query_string( + query_string=request.query_string, + behaviour=client.options["data_collection"][ + "url_query_params" + ], ) - if request.query_string: - url_full += "?" + request.query_string - url_attributes["url.query"] = request.query_string - - url_attributes["url.full"] = url_full - url_attributes["url.path"] = request.path - - if request.remote: - client_address_attributes["client.address"] = ( - request.remote - ) - scope.set_attribute( - SPANDATA.USER_IP_ADDRESS, request.remote - ) - - span_ctx = sentry_sdk.traces.start_span( - # If this name makes it to the UI, AIOHTTP's URL - # resolver did not find a route or died trying. - name="generic AIOHTTP request", - attributes={ - "sentry.op": OP.HTTP_SERVER, - "sentry.origin": AioHttpIntegration.origin, - "sentry.segment.name.source": SegmentNameSource.ROUTE.value, - "http.request.method": request.method, - **url_attributes, - **client_address_attributes, - **header_attributes, - }, - parent_span=None, - ) - scope.get_current_scope()._server_segment_span = span_ctx - else: - transaction = continue_trace( - headers, - op=OP.HTTP_SERVER, - # If this transaction name makes it to the UI, AIOHTTP's - # URL resolver did not find a route or died trying. - name="generic AIOHTTP request", - source=TransactionSource.ROUTE, - origin=AioHttpIntegration.origin, - ) - span_ctx = sentry_sdk.start_transaction( - transaction, - custom_sampling_context={"aiohttp_request": request}, ) + if filtered_query_string: + url_attributes["url.query"] = filtered_query_string + url_attributes["url.full"] += "?" + filtered_query_string + + if request.remote: + if client.options["data_collection"]["user_info"]: + client_address_attributes["client.address"] = request.remote + scope.set_attribute( + SPANDATA.USER_IP_ADDRESS, request.remote + ) - with span_ctx as span: + span = sentry_sdk.start_span( + # If this name makes it to the UI, AIOHTTP's URL + # resolver did not find a route or died trying. + name="generic AIOHTTP request", + attributes={ + "sentry.op": OP.HTTP_SERVER, + "sentry.origin": AioHttpIntegration.origin, + "sentry.segment.name.source": SegmentNameSource.ROUTE.value, + "http.request.method": request.method, + **url_attributes, + **client_address_attributes, + **header_attributes, + }, + parent_span=None, + ) + scope.get_current_scope()._server_segment_span = span + + with span: try: response = await old_handle(self, request) except HTTPException as e: - if isinstance(span, StreamedSpan) and not isinstance( - span, NoOpStreamedSpan - ): - span.set_attribute( - "http.response.status_code", e.status_code - ) - - if e.status_code >= 400: - span.status = SpanStatus.ERROR.value - else: - span.status = SpanStatus.OK.value + span.set_attribute( + "http.response.status_code", e.status_code + ) + + if e.status_code >= 400: + span.status = SpanStatus.ERROR.value else: - # Since a NoOpStreamedSpan can end up here, we have to guard against it - # so this only gets set in the legacy transaction approach. - if not isinstance(span, NoOpStreamedSpan): - span.set_http_status(e.status_code) + span.status = SpanStatus.OK.value if ( e.status_code @@ -280,10 +209,7 @@ async def sentry_app_handle( _capture_exception() raise except (asyncio.CancelledError, ConnectionResetError): - if isinstance(span, StreamedSpan): - span.status = SpanStatus.ERROR.value - else: - span.set_status(SPANSTATUS.CANCELLED) + span.status = SpanStatus.ERROR.value raise except Exception: # This will probably map to a 500 but seems like we @@ -299,17 +225,14 @@ async def sentry_app_handle( except AttributeError: pass else: - if isinstance(span, StreamedSpan): - span.set_attribute( - "http.response.status_code", response_status - ) - span.status = ( - SpanStatus.ERROR.value - if response_status >= 400 - else SpanStatus.OK.value - ) - else: - span.set_http_status(response_status) + span.set_attribute( + "http.response.status_code", response_status + ) + span.status = ( + SpanStatus.ERROR.value + if response_status >= 400 + else SpanStatus.OK.value + ) return response @@ -392,79 +315,36 @@ async def on_request_start( parsed_url.url if parsed_url else SENSITIVE_DATA_SUBSTITUTE, ) - span: "Union[Span, StreamedSpan, None]" = None - if has_span_streaming_enabled(client.options): - attributes: "Attributes" = { - "sentry.op": OP.HTTP_CLIENT, - "sentry.origin": AioHttpIntegration.origin, - "http.request.method": method, - } - if parsed_url is not None: - if has_data_collection_enabled(client.options): - url_full = parsed_url.url - attributes["url.path"] = params.url.path - - if parsed_url.query: - filtered_query = ( - _apply_data_collection_filtering_to_query_string( - query_string=parsed_url.query, - behaviour=client.options["data_collection"][ - "url_query_params" - ], - ) - ) - if filtered_query: - attributes["url.query"] = filtered_query - url_full += "?" + filtered_query - breadcrumb[SPANDATA.HTTP_QUERY] = filtered_query - - if parsed_url.fragment: - attributes["url.fragment"] = parsed_url.fragment - url_full += "#" + parsed_url.fragment - breadcrumb[SPANDATA.HTTP_FRAGMENT] = parsed_url.fragment - - attributes["url.full"] = url_full - breadcrumb["url"] = url_full - - elif should_send_default_pii(): - url_full = parsed_url.url - attributes["url.path"] = params.url.path - - if parsed_url.query: - url_full += "?" + parsed_url.query - attributes["url.query"] = parsed_url.query - breadcrumb[SPANDATA.HTTP_QUERY] = parsed_url.query - if parsed_url.fragment: - url_full += "#" + parsed_url.fragment - attributes["url.fragment"] = parsed_url.fragment - breadcrumb[SPANDATA.HTTP_FRAGMENT] = parsed_url.fragment - - attributes["url.full"] = url_full - breadcrumb["url"] = url_full - - if sentry_sdk.traces.get_current_span() is not None: - span = sentry_sdk.traces.start_span( - name=span_name, attributes=attributes + span: "Optional[Span]" = None + attributes: "Attributes" = { + "sentry.op": OP.HTTP_CLIENT, + "sentry.origin": AioHttpIntegration.origin, + "http.request.method": method, + } + if parsed_url is not None: + url_full = parsed_url.url + attributes["url.path"] = params.url.path + + if parsed_url.query: + filtered_query = _apply_data_collection_filtering_to_query_string( + query_string=parsed_url.query, + behaviour=client.options["data_collection"]["url_query_params"], ) - else: - legacy_span = sentry_sdk.start_span( - op=OP.HTTP_CLIENT, - name=span_name, - origin=AioHttpIntegration.origin, - ) - legacy_span.set_data(SPANDATA.HTTP_METHOD, method) - if parsed_url is not None: - legacy_span.set_data("url", parsed_url.url) - legacy_span.set_data(SPANDATA.HTTP_QUERY, parsed_url.query) - legacy_span.set_data(SPANDATA.HTTP_FRAGMENT, parsed_url.fragment) - breadcrumb.update( - { - SPANDATA.HTTP_QUERY: parsed_url.query, - SPANDATA.HTTP_FRAGMENT: parsed_url.fragment, - "url": parsed_url.url, - } - ) - span = legacy_span + if filtered_query: + attributes["url.query"] = filtered_query + url_full += "?" + filtered_query + breadcrumb[SPANDATA.HTTP_QUERY] = filtered_query + + if parsed_url.fragment: + attributes["url.fragment"] = parsed_url.fragment + url_full += "#" + parsed_url.fragment + breadcrumb[SPANDATA.HTTP_FRAGMENT] = parsed_url.fragment + + attributes["url.full"] = url_full + breadcrumb["url"] = url_full + + if sentry_sdk.get_current_span() is not None: + span = sentry_sdk.start_span(name=span_name, attributes=attributes) if should_propagate_trace(client, str(params.url)): # existing `sentry-trace`: skip so it is not duplicated. @@ -553,21 +433,13 @@ async def on_request_end( if span is None: return - if isinstance(span, StreamedSpan): - span.set_attribute("http.response.status_code", status) - span.status = ( - SpanStatus.ERROR.value if status >= 400 else SpanStatus.OK.value - ) + span.set_attribute("http.response.status_code", status) + span.status = SpanStatus.ERROR.value if status >= 400 else SpanStatus.OK.value - with capture_internal_exceptions(): - add_http_request_source(span) - span.end() - else: - span.set_http_status(status) - span.set_data("reason", params.response.reason) - span.finish() - with capture_internal_exceptions(): - add_http_request_source(span) + with capture_internal_exceptions(): + add_http_request_source(span) + + span.end() trace_config = TraceConfig() @@ -598,44 +470,26 @@ def aiohttp_processor( request.path, ) - if has_data_collection_enabled(client_options): - if request.query_string: - filtered_query_string = ( - _apply_data_collection_filtering_to_query_string( - query_string=request.query_string, - behaviour=client_options["data_collection"][ - "url_query_params" - ], - ) + if request.query_string: + filtered_query_string = ( + _apply_data_collection_filtering_to_query_string( + query_string=request.query_string, + behaviour=client_options["data_collection"]["url_query_params"], ) - if filtered_query_string: - request_info["query_string"] = filtered_query_string - else: - request_info["query_string"] = request.query_string + ) + if filtered_query_string: + request_info["query_string"] = filtered_query_string request_info["method"] = request.method + request_info["headers"] = _filter_headers(dict(request.headers)) - # REMOTE_ADDR was unconditionally set pre-data collection, so it - # continues to be set when data collection is not enabled. - if ( - not has_data_collection_enabled(client_options) - or client_options["data_collection"]["user_info"] - ): + if client_options["data_collection"]["user_info"]: request_info["env"] = {"REMOTE_ADDR": request.remote} - request_info["headers"] = _filter_headers(dict(request.headers)) # Just attach raw data here if it is within bounds, if available. # Unfortunately there's no way to get structured data from aiohttp # without awaiting on some coroutine. - if has_data_collection_enabled(client_options): - if ( - "incoming_request" - in client_options["data_collection"]["http_bodies"] - ): - request_info["data"] = get_aiohttp_request_data(request) - else: - # We never gated this prior to data collection, so it should be attached - # when data collection is not enabled. + if "incoming_request" in client_options["data_collection"]["http_bodies"]: request_info["data"] = get_aiohttp_request_data(request) return event diff --git a/sentry_sdk/integrations/aiomysql.py b/sentry_sdk/integrations/aiomysql.py index 459214da0e..687759fcdd 100644 --- a/sentry_sdk/integrations/aiomysql.py +++ b/sentry_sdk/integrations/aiomysql.py @@ -6,10 +6,9 @@ import sentry_sdk from sentry_sdk.consts import OP, SPANDATA from sentry_sdk.integrations import DidNotEnable, Integration, _check_minimum_version -from sentry_sdk.traces import StreamedSpan +from sentry_sdk.traces import Span from sentry_sdk.tracing_utils import ( add_query_source, - has_span_streaming_enabled, record_sql_queries, ) from sentry_sdk.utils import ( @@ -23,7 +22,7 @@ from aiomysql.connection import Connection # type: ignore[import-not-found] from aiomysql.cursors import Cursor # type: ignore[import-not-found] except ImportError: - raise DidNotEnable("aiomysql not installed.") + raise DidNotEnable("aiomysql not installed or incompatible") class AioMySQLIntegration(Integration): @@ -106,11 +105,11 @@ async def _inner(*args: Any, **kwargs: Any) -> T: if conn: _set_db_data(span, conn) res = await f(*args, **kwargs) - if isinstance(span, StreamedSpan): + if isinstance(span, Span): with capture_internal_exceptions(): add_query_source(span) - if not isinstance(span, StreamedSpan): + if not isinstance(span, Span): with capture_internal_exceptions(): add_query_source(span) @@ -159,11 +158,11 @@ async def _inner(*args: Any, **kwargs: Any) -> T: if conn: _set_db_data(span, conn) res = await f(*args, **kwargs) - if isinstance(span, StreamedSpan): + if isinstance(span, Span): with capture_internal_exceptions(): add_query_source(span) - if not isinstance(span, StreamedSpan): + if not isinstance(span, Span): with capture_internal_exceptions(): add_query_source(span) @@ -187,42 +186,22 @@ async def _inner(self: "Connection") -> T: if client.get_integration(AioMySQLIntegration) is None: return await f(self) - if has_span_streaming_enabled(client.options): - breadcrumb_data = _get_connect_data(self, use_streaming_keys=True) + breadcrumb_data = _get_connect_data(self, use_streaming_keys=True) - with capture_internal_exceptions(): - sentry_sdk.add_breadcrumb( - message="connect", category="query", data=breadcrumb_data - ) - - if sentry_sdk.traces.get_current_span() is None: - return await f(self) - - span_attributes: dict[str, Any] = { - "sentry.op": OP.DB, - "sentry.origin": AioMySQLIntegration.origin, - } | breadcrumb_data - - with sentry_sdk.traces.start_span( - name="connect", attributes=span_attributes - ): - return await f(self) + with capture_internal_exceptions(): + sentry_sdk.add_breadcrumb( + message="connect", category="query", data=breadcrumb_data + ) - connect_data = _get_connect_data(self) + if sentry_sdk.get_current_span() is None: + return await f(self) - with sentry_sdk.start_span( - op=OP.DB, - name="connect", - origin=AioMySQLIntegration.origin, - ) as span: - _set_db_data(span, self) + span_attributes: dict[str, Any] = { + "sentry.op": OP.DB, + "sentry.origin": AioMySQLIntegration.origin, + } | breadcrumb_data - with capture_internal_exceptions(): - sentry_sdk.add_breadcrumb( - message="connect", - category="query", - data=connect_data, - ) + with sentry_sdk.start_span(name="connect", attributes=span_attributes): return await f(self) return _inner @@ -262,32 +241,21 @@ def _get_connect_data(conn: Any, *, use_streaming_keys: bool = False) -> dict[st def _set_db_data(span: Any, conn: Any) -> None: """Set database-related span data from connection object.""" - if isinstance(span, StreamedSpan): - set_value = span.set_attribute - db_system = SPANDATA.DB_SYSTEM_NAME - db_name = SPANDATA.DB_NAMESPACE - else: - # Remove this else block once we've completely migrated to streamed spans - # The use of deprecated attributes here is to ensure backwards compatibility - set_value = span.set_data - db_system = SPANDATA.DB_SYSTEM - db_name = SPANDATA.DB_NAME - - set_value(db_system, "mysql") - set_value(SPANDATA.DB_DRIVER_NAME, "aiomysql") + span.set_attribute(SPANDATA.DB_SYSTEM_NAME, "mysql") + span.set_attribute(SPANDATA.DB_DRIVER_NAME, "aiomysql") host = getattr(conn, "host", None) if host is not None: - set_value(SPANDATA.SERVER_ADDRESS, host) + span.set_attribute(SPANDATA.SERVER_ADDRESS, host) port = getattr(conn, "port", None) if port is not None: - set_value(SPANDATA.SERVER_PORT, port) + span.set_attribute(SPANDATA.SERVER_PORT, port) database = getattr(conn, "db", None) if database is not None: - set_value(db_name, database) + span.set_attribute(SPANDATA.DB_NAMESPACE, database) user = getattr(conn, "user", None) if user is not None: - set_value(SPANDATA.DB_USER, user) + span.set_attribute(SPANDATA.DB_USER, user) diff --git a/sentry_sdk/integrations/anthropic.py b/sentry_sdk/integrations/anthropic.py index 23bdbbb06e..47ade3f99e 100644 --- a/sentry_sdk/integrations/anthropic.py +++ b/sentry_sdk/integrations/anthropic.py @@ -8,26 +8,19 @@ from sentry_sdk.ai.monitoring import record_token_usage from sentry_sdk.ai.utils import ( GEN_AI_ALLOWED_MESSAGE_ROLES, - get_start_span_function, normalize_message_roles, set_data_normalized, transform_anthropic_content_part, - truncate_and_annotate_messages, ) from sentry_sdk.consts import OP, SPANDATA from sentry_sdk.integrations import DidNotEnable, Integration, _check_minimum_version from sentry_sdk.scope import should_send_default_pii -from sentry_sdk.traces import StreamedSpan -from sentry_sdk.tracing import Span -from sentry_sdk.tracing_utils import ( - has_span_streaming_enabled, - should_truncate_gen_ai_input, -) +from sentry_sdk.traces import Span from sentry_sdk.utils import ( capture_internal_exceptions, event_from_exception, has_data_collection_enabled, - package_version, + parse_version, reraise, safe_serialize, ) @@ -44,6 +37,7 @@ Omit = None # type: ignore[misc,assignment] from anthropic import AsyncStream, Stream + from anthropic import __version__ as ANTHROPIC_VERSION from anthropic.lib.streaming import ( AsyncMessageStream, AsyncMessageStreamManager, @@ -63,7 +57,7 @@ if TYPE_CHECKING: from anthropic.types import MessageStreamEvent, TextBlockParam except ImportError: - raise DidNotEnable("Anthropic not installed") + raise DidNotEnable("Anthropic not installed or incompatible") if TYPE_CHECKING: from typing import ( @@ -89,7 +83,7 @@ from sentry_sdk._types import TextPart class _PatchedRawMessageStream(Stream[RawMessageStreamEvent]): - _span: Union[Span, StreamedSpan] + _span: Span _integration: "AnthropicIntegration" _model: Optional[ModelParam] @@ -99,7 +93,7 @@ class _PatchedRawMessageStream(Stream[RawMessageStreamEvent]): _finish_reason: Optional[str] class _PatchedMessageStream(MessageStream): - _span: Union[Span, StreamedSpan] + _span: Span _integration: "AnthropicIntegration" _model: Optional[ModelParam] @@ -109,7 +103,7 @@ class _PatchedMessageStream(MessageStream): _finish_reason: Optional[str] class _PatchedRawAsyncMessageStream(AsyncStream[RawMessageStreamEvent]): - _span: Union[Span, StreamedSpan] + _span: Span _integration: "AnthropicIntegration" _model: Optional[ModelParam] @@ -119,7 +113,7 @@ class _PatchedRawAsyncMessageStream(AsyncStream[RawMessageStreamEvent]): _finish_reason: Optional[str] class _PatchedAsyncMessageStream(AsyncMessageStream): - _span: Union[Span, StreamedSpan] + _span: Span _integration: "AnthropicIntegration" _model: Optional[ModelParam] @@ -129,7 +123,7 @@ class _PatchedAsyncMessageStream(AsyncMessageStream): _finish_reason: Optional[str] class _PatchedMessageStreamManager(MessageStreamManager): - _span: Union[Span, StreamedSpan] + _span: Span _integration: "AnthropicIntegration" _max_tokens: int @@ -142,7 +136,7 @@ class _PatchedMessageStreamManager(MessageStreamManager): _tools: Optional[Iterable[ToolUnionParam]] class _PatchedAsyncMessageStreamManager(AsyncMessageStreamManager[Any]): - _span: Union[Span, StreamedSpan] + _span: Span _integration: "AnthropicIntegration" _max_tokens: int @@ -222,12 +216,9 @@ class AnthropicIntegration(Integration): identifier = "anthropic" origin = f"auto.ai.{identifier}" - def __init__(self: "AnthropicIntegration", include_prompts: bool = True) -> None: - self.include_prompts = include_prompts - @staticmethod def setup_once() -> None: - version = package_version("anthropic") + version = parse_version(ANTHROPIC_VERSION) _check_minimum_version(AnthropicIntegration, version) """ @@ -447,7 +438,7 @@ def _transform_system_instructions( def _set_common_input_data( - span: "Union[Span, StreamedSpan]", + span: "Span", integration: "AnthropicIntegration", max_tokens: "int", messages: "Iterable[MessageParam]", @@ -461,36 +452,35 @@ def _set_common_input_data( """ Set input data for the span based on the provided keyword arguments for the anthropic message creation. """ - set_on_span = ( - span.set_attribute if isinstance(span, StreamedSpan) else span.set_data - ) - set_on_span(SPANDATA.GEN_AI_SYSTEM, "anthropic") - set_on_span(SPANDATA.GEN_AI_OPERATION_NAME, "chat") + span.set_attribute(SPANDATA.GEN_AI_PROVIDER_NAME, "anthropic") + span.set_attribute(SPANDATA.GEN_AI_OPERATION_NAME, "chat") if max_tokens is not None and _is_given(max_tokens): - set_on_span(SPANDATA.GEN_AI_REQUEST_MAX_TOKENS, max_tokens) + span.set_attribute(SPANDATA.GEN_AI_REQUEST_MAX_TOKENS, max_tokens) if model is not None and _is_given(model): - set_on_span(SPANDATA.GEN_AI_REQUEST_MODEL, model) + span.set_attribute(SPANDATA.GEN_AI_REQUEST_MODEL, model) if temperature is not None and _is_given(temperature): - set_on_span(SPANDATA.GEN_AI_REQUEST_TEMPERATURE, temperature) + span.set_attribute(SPANDATA.GEN_AI_REQUEST_TEMPERATURE, temperature) if top_k is not None and _is_given(top_k): - set_on_span(SPANDATA.GEN_AI_REQUEST_TOP_K, top_k) + span.set_attribute(SPANDATA.GEN_AI_REQUEST_TOP_K, top_k) if top_p is not None and _is_given(top_p): - set_on_span(SPANDATA.GEN_AI_REQUEST_TOP_P, top_p) + span.set_attribute(SPANDATA.GEN_AI_REQUEST_TOP_P, top_p) client = sentry_sdk.get_client() if has_data_collection_enabled(client.options): if client.options["data_collection"]["gen_ai"]["inputs"]: if tools is not None and _is_given(tools) and len(tools) > 0: # type: ignore - set_on_span( + span.set_attribute( SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS, safe_serialize(tools) ) else: # Tools were unconditionally added pre-data collection configuration. # This can be removed once data collection is fully rolled out if tools is not None and _is_given(tools) and len(tools) > 0: # type: ignore - set_on_span(SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS, safe_serialize(tools)) + span.set_attribute( + SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS, safe_serialize(tools) + ) if messages is None or len(messages) == 0: # type: ignore return @@ -499,12 +489,12 @@ def _set_common_input_data( if has_data_collection_enabled(client.options): if client.options["data_collection"]["gen_ai"]["inputs"]: record_inputs = True - elif should_send_default_pii() and integration.include_prompts: + elif should_send_default_pii(): record_inputs = True if record_inputs: if isinstance(system, str) or isinstance(system, Iterable): - set_on_span( + span.set_attribute( SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS, json.dumps(_transform_system_instructions(system)), ) @@ -554,35 +544,23 @@ def _set_common_input_data( role_normalized_messages = normalize_message_roles(normalized_messages) - scope = sentry_sdk.get_current_scope() - messages_data = ( - truncate_and_annotate_messages(role_normalized_messages, span, scope) - if should_truncate_gen_ai_input(client.options) - else role_normalized_messages + set_data_normalized( + span, + SPANDATA.GEN_AI_REQUEST_MESSAGES, + role_normalized_messages, + unpack=False, ) - if messages_data is not None: - set_data_normalized( - span, - SPANDATA.GEN_AI_REQUEST_MESSAGES, - messages_data, - unpack=False, - ) def _set_create_input_data( - span: "Union[Span, StreamedSpan]", + span: "Span", kwargs: "dict[str, Any]", integration: "AnthropicIntegration", ) -> None: """ Set input data for the span based on the provided keyword arguments for the anthropic message creation. """ - if isinstance(span, StreamedSpan): - span.set_attribute( - SPANDATA.GEN_AI_RESPONSE_STREAMING, kwargs.get("stream", False) - ) - else: - span.set_data(SPANDATA.GEN_AI_RESPONSE_STREAMING, kwargs.get("stream", False)) + span.set_attribute(SPANDATA.GEN_AI_RESPONSE_STREAMING, kwargs.get("stream", False)) _set_common_input_data( span=span, @@ -659,7 +637,7 @@ async def _wrap_asynchronous_message_iterator( def _set_output_data( - span: "Union[Span, StreamedSpan]", + span: "Span", integration: "AnthropicIntegration", model: "str | None", input_tokens: "int | None", @@ -672,21 +650,18 @@ def _set_output_data( ) -> None: """ Set output data for the span based on the AI response.""" - set_on_span = ( - span.set_attribute if isinstance(span, StreamedSpan) else span.set_data - ) if model is not None: - set_on_span(SPANDATA.GEN_AI_RESPONSE_MODEL, model) + span.set_attribute(SPANDATA.GEN_AI_RESPONSE_MODEL, model) if response_id is not None: - set_on_span(SPANDATA.GEN_AI_RESPONSE_ID, response_id) + span.set_attribute(SPANDATA.GEN_AI_RESPONSE_ID, response_id) if finish_reason is not None: - set_on_span(SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS, [finish_reason]) + span.set_attribute(SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS, [finish_reason]) client = sentry_sdk.get_client() record_outputs = False if has_data_collection_enabled(client.options): record_outputs = client.options["data_collection"]["gen_ai"]["outputs"] - elif should_send_default_pii() and integration.include_prompts: + elif should_send_default_pii(): record_outputs = True if record_outputs: @@ -731,6 +706,9 @@ def _sentry_patched_create_sync(f: "Any", *args: "Any", **kwargs: "Any") -> "Any if integration is None: return f(*args, **kwargs) + if sentry_sdk.get_current_scope()._agent_framework_chat_generation_entered: + return f(*args, **kwargs) + if "messages" not in kwargs: return f(*args, **kwargs) @@ -741,22 +719,13 @@ def _sentry_patched_create_sync(f: "Any", *args: "Any", **kwargs: "Any") -> "Any model = kwargs.get("model", "") - span_streaming = has_span_streaming_enabled(sentry_sdk.get_client().options) - if span_streaming: - span = sentry_sdk.traces.start_span( - name=f"chat {model}".strip(), - attributes={ - "sentry.op": OP.GEN_AI_CHAT, - "sentry.origin": AnthropicIntegration.origin, - }, - ) - else: - span = get_start_span_function()( - op=OP.GEN_AI_CHAT, - name=f"chat {model}".strip(), - origin=AnthropicIntegration.origin, - ) - span.__enter__() + span = sentry_sdk.start_span( + name=f"chat {model}".strip(), + attributes={ + "sentry.op": OP.GEN_AI_CHAT, + "sentry.origin": AnthropicIntegration.origin, + }, + ) _set_create_input_data(span, kwargs, integration) @@ -811,8 +780,6 @@ def _sentry_patched_create_sync(f: "Any", *args: "Any", **kwargs: "Any") -> "Any response_id=getattr(result, "id", None), finish_reason=getattr(result, "stop_reason", None), ) - elif isinstance(span, Span): - span.set_data("unknown_response", True) span.__exit__(None, None, None) @@ -829,6 +796,9 @@ async def _sentry_patched_create_async( if integration is None: return await f(*args, **kwargs) + if sentry_sdk.get_current_scope()._agent_framework_chat_generation_entered: + return await f(*args, **kwargs) + if "messages" not in kwargs: return await f(*args, **kwargs) @@ -839,22 +809,13 @@ async def _sentry_patched_create_async( model = kwargs.get("model", "") - span_streaming = has_span_streaming_enabled(sentry_sdk.get_client().options) - if span_streaming: - span = sentry_sdk.traces.start_span( - name=f"chat {model}".strip(), - attributes={ - "sentry.op": OP.GEN_AI_CHAT, - "sentry.origin": AnthropicIntegration.origin, - }, - ) - else: - span = get_start_span_function()( - op=OP.GEN_AI_CHAT, - name=f"chat {model}".strip(), - origin=AnthropicIntegration.origin, - ) - span.__enter__() + span = sentry_sdk.start_span( + name=f"chat {model}".strip(), + attributes={ + "sentry.op": OP.GEN_AI_CHAT, + "sentry.origin": AnthropicIntegration.origin, + }, + ) _set_create_input_data(span, kwargs, integration) @@ -909,8 +870,6 @@ async def _sentry_patched_create_async( response_id=getattr(result, "id", None), finish_reason=getattr(result, "stop_reason", None), ) - elif isinstance(span, Span): - span.set_data("unknown_response", True) span.__exit__(None, None, None) @@ -966,7 +925,7 @@ def _accumulate_event_data( def _set_streaming_output_data( - span: "Union[Span, StreamedSpan]", + span: "Span", integration: "AnthropicIntegration", model: "Optional[str]", usage: "_RecordedUsage", @@ -1046,6 +1005,9 @@ def _wrap_message_stream(f: "Any") -> "Any": @wraps(f) def _sentry_patched_stream(*args: "Any", **kwargs: "Any") -> "MessageStreamManager": + if sentry_sdk.get_current_scope()._agent_framework_chat_generation_entered: + return f(*args, **kwargs) + stream_manager = f(*args, **kwargs) stream_manager._max_tokens = kwargs.get("max_tokens") @@ -1088,28 +1050,16 @@ def _sentry_patched_enter(self: "MessageStreamManager") -> "MessageStream": except TypeError: return f(self) - if has_span_streaming_enabled(client.options): - span = sentry_sdk.traces.start_span( - name="chat" - if patched_self._model is None - else f"chat {patched_self._model}".strip(), - attributes={ - "sentry.op": OP.GEN_AI_CHAT, - "sentry.origin": AnthropicIntegration.origin, - SPANDATA.GEN_AI_RESPONSE_STREAMING: True, - }, - ) - else: - span = get_start_span_function()( - op=OP.GEN_AI_CHAT, - name="chat" - if patched_self._model is None - else f"chat {patched_self._model}".strip(), - origin=AnthropicIntegration.origin, - ) - span.__enter__() - - span.set_data(SPANDATA.GEN_AI_RESPONSE_STREAMING, True) + span = sentry_sdk.start_span( + name="chat" + if patched_self._model is None + else f"chat {patched_self._model}".strip(), + attributes={ + "sentry.op": OP.GEN_AI_CHAT, + "sentry.origin": AnthropicIntegration.origin, + SPANDATA.GEN_AI_RESPONSE_STREAMING: True, + }, + ) _set_common_input_data( span=span, @@ -1157,6 +1107,9 @@ def _wrap_async_message_stream(f: "Any") -> "Any": def _sentry_patched_stream( *args: "Any", **kwargs: "Any" ) -> "AsyncMessageStreamManager": + if sentry_sdk.get_current_scope()._agent_framework_chat_generation_entered: + return f(*args, **kwargs) + stream_manager = f(*args, **kwargs) stream_manager._max_tokens = kwargs.get("max_tokens") @@ -1201,28 +1154,16 @@ async def _sentry_patched_aenter( except TypeError: return await f(self) - if has_span_streaming_enabled(client.options): - span = sentry_sdk.traces.start_span( - name="chat" - if patched_self._model is None - else f"chat {patched_self._model}".strip(), - attributes={ - "sentry.op": OP.GEN_AI_CHAT, - "sentry.origin": AnthropicIntegration.origin, - SPANDATA.GEN_AI_RESPONSE_STREAMING: True, - }, - ) - else: - span = get_start_span_function()( - op=OP.GEN_AI_CHAT, - name="chat" - if patched_self._model is None - else f"chat {patched_self._model}".strip(), - origin=AnthropicIntegration.origin, - ) - span.__enter__() - - span.set_data(SPANDATA.GEN_AI_RESPONSE_STREAMING, True) + span = sentry_sdk.start_span( + name="chat" + if patched_self._model is None + else f"chat {patched_self._model}".strip(), + attributes={ + "sentry.op": OP.GEN_AI_CHAT, + "sentry.origin": AnthropicIntegration.origin, + SPANDATA.GEN_AI_RESPONSE_STREAMING: True, + }, + ) _set_common_input_data( span=span, diff --git a/sentry_sdk/integrations/ariadne.py b/sentry_sdk/integrations/ariadne.py index 2a3c405514..e52ca76505 100644 --- a/sentry_sdk/integrations/ariadne.py +++ b/sentry_sdk/integrations/ariadne.py @@ -4,13 +4,11 @@ from sentry_sdk import capture_event, get_client from sentry_sdk.integrations import DidNotEnable, Integration, _check_minimum_version from sentry_sdk.integrations._wsgi_common import request_body_within_bounds -from sentry_sdk.integrations.logging import ignore_logger -from sentry_sdk.scope import should_send_default_pii +from sentry_sdk.integrations.logging import ignore_logger_for_events from sentry_sdk.utils import ( capture_internal_exceptions, ensure_integration_enabled, event_from_exception, - has_data_collection_enabled, package_version, ) @@ -19,7 +17,7 @@ # (ariadne.graphql is also a function) ariadne_graphql = import_module("ariadne.graphql") except ImportError: - raise DidNotEnable("ariadne is not installed") + raise DidNotEnable("ariadne is not installed or incompatible") from typing import TYPE_CHECKING @@ -45,7 +43,7 @@ def setup_once() -> None: version = package_version("ariadne") _check_minimum_version(AriadneIntegration, version) - ignore_logger("ariadne") + ignore_logger_for_events("ariadne") _patch_graphql() @@ -138,32 +136,21 @@ def inner(event: "Event", hint: "dict[str, Any]") -> "Event": return event client_options = sentry_sdk.get_client().options - if has_data_collection_enabled(client_options): - dc_graphql = client_options["data_collection"]["graphql"] - collect_variables = dc_graphql["variables"] - collect_document = dc_graphql[ - "document" - ] and request_body_within_bounds(get_client(), content_length) - - if collect_document or collect_variables: - request_info = event.setdefault("request", {}) - request_info["api_target"] = "graphql" - request_info["data"] = { - key: value - for key, value in data.items() - if (key != "query" or collect_document) - and (key != "variables" or collect_variables) - } - elif event.get("request", {}).get("data"): - del event["request"]["data"] - - elif should_send_default_pii() and request_body_within_bounds( + dc_graphql = client_options["data_collection"]["graphql"] + collect_variables = dc_graphql["variables"] + collect_document = dc_graphql["document"] and request_body_within_bounds( get_client(), content_length - ): + ) + + if collect_document or collect_variables: request_info = event.setdefault("request", {}) request_info["api_target"] = "graphql" - request_info["data"] = data - + request_info["data"] = { + key: value + for key, value in data.items() + if (key != "query" or collect_document) + and (key != "variables" or collect_variables) + } elif event.get("request", {}).get("data"): del event["request"]["data"] @@ -178,13 +165,9 @@ def _make_response_event_processor(response: "Dict[str, Any]") -> "EventProcesso def inner(event: "Event", hint: "dict[str, Any]") -> "Event": client_options = sentry_sdk.get_client().options with capture_internal_exceptions(): - if has_data_collection_enabled(client_options): - collect_response = ( - "outgoing_response" - in client_options["data_collection"]["http_bodies"] - ) - else: - collect_response = should_send_default_pii() + collect_response = ( + "outgoing_response" in client_options["data_collection"]["http_bodies"] + ) if collect_response and response.get("errors"): contexts = event.setdefault("contexts", {}) diff --git a/sentry_sdk/integrations/arq.py b/sentry_sdk/integrations/arq.py index 9d6497f03a..295c3eff0e 100644 --- a/sentry_sdk/integrations/arq.py +++ b/sentry_sdk/integrations/arq.py @@ -1,20 +1,15 @@ import sys import sentry_sdk -from sentry_sdk.consts import OP, SPANDATA, SPANSTATUS +from sentry_sdk.consts import OP, SPANDATA from sentry_sdk.integrations import DidNotEnable, Integration, _check_minimum_version -from sentry_sdk.integrations.logging import ignore_logger -from sentry_sdk.scope import should_send_default_pii +from sentry_sdk.integrations.logging import ignore_logger_for_events from sentry_sdk.traces import SegmentNameSource -from sentry_sdk.tracing import Transaction, TransactionSource -from sentry_sdk.tracing_utils import has_span_streaming_enabled from sentry_sdk.utils import ( - SENSITIVE_DATA_SUBSTITUTE, _register_control_flow_exception, capture_internal_exceptions, ensure_integration_enabled, event_from_exception, - has_data_collection_enabled, parse_version, reraise, ) @@ -25,7 +20,7 @@ from arq.version import VERSION as ARQ_VERSION from arq.worker import JobExecutionFailed, Retry, RetryJob, Worker except ImportError: - raise DidNotEnable("Arq is not installed") + raise DidNotEnable("Arq is not installed or incompatible") from typing import TYPE_CHECKING @@ -65,7 +60,7 @@ def setup_once() -> None: _register_control_flow_exception(ARQ_CONTROL_FLOW_EXCEPTIONS) # type: ignore - ignore_logger("arq.worker") + ignore_logger_for_events("arq.worker") def patch_enqueue_job() -> None: @@ -79,21 +74,15 @@ async def _sentry_enqueue_job( if client.get_integration(ArqIntegration) is None: return await old_enqueue_job(self, function, *args, **kwargs) - if has_span_streaming_enabled(client.options): - if sentry_sdk.traces.get_current_span() is None: - return await old_enqueue_job(self, function, *args, **kwargs) - - with sentry_sdk.traces.start_span( - name=function, - attributes={ - "sentry.op": OP.QUEUE_SUBMIT_ARQ, - "sentry.origin": ArqIntegration.origin, - }, - ): - return await old_enqueue_job(self, function, *args, **kwargs) + if sentry_sdk.get_current_span() is None: + return await old_enqueue_job(self, function, *args, **kwargs) with sentry_sdk.start_span( - op=OP.QUEUE_SUBMIT_ARQ, name=function, origin=ArqIntegration.origin + name=function, + attributes={ + "sentry.op": OP.QUEUE_SUBMIT_ARQ, + "sentry.origin": ArqIntegration.origin, + }, ): return await old_enqueue_job(self, function, *args, **kwargs) @@ -113,49 +102,26 @@ async def _sentry_run_job(self: "Worker", job_id: str, score: int) -> None: scope._name = "arq" scope.clear_breadcrumbs() - if has_span_streaming_enabled(client.options): - with sentry_sdk.traces.start_span( - name="unknown arq task", - attributes={ - "sentry.op": OP.QUEUE_TASK_ARQ, - "sentry.origin": ArqIntegration.origin, - "sentry.segment.name.source": SegmentNameSource.TASK, - SPANDATA.MESSAGING_MESSAGE_ID: job_id, - }, - parent_span=None, - ) as span: - if self.queue_name is not None: - span.set_attribute( - SPANDATA.MESSAGING_DESTINATION_NAME, self.queue_name - ) - return await old_run_job(self, job_id, score) - - transaction = Transaction( + with sentry_sdk.start_span( name="unknown arq task", - status="ok", - op=OP.QUEUE_TASK_ARQ, - source=TransactionSource.TASK, - origin=ArqIntegration.origin, - ) - - with sentry_sdk.start_transaction(transaction) as span: + attributes={ + "sentry.op": OP.QUEUE_TASK_ARQ, + "sentry.origin": ArqIntegration.origin, + "sentry.segment.name.source": SegmentNameSource.TASK, + SPANDATA.MESSAGING_MESSAGE_ID: job_id, + }, + parent_span=None, + ) as span: if self.queue_name is not None: - span.set_data(SPANDATA.MESSAGING_DESTINATION_NAME, self.queue_name) + span.set_attribute( + SPANDATA.MESSAGING_DESTINATION_NAME, self.queue_name + ) return await old_run_job(self, job_id, score) Worker.run_job = _sentry_run_job def _capture_exception(exc_info: "ExcInfo") -> None: - scope = sentry_sdk.get_current_scope() - - if scope.transaction is not None: - if exc_info[0] in ARQ_CONTROL_FLOW_EXCEPTIONS: - scope.transaction.set_status(SPANSTATUS.ABORTED) - return - - scope.transaction.set_status(SPANSTATUS.INTERNAL_ERROR) - if exc_info[0] in ARQ_CONTROL_FLOW_EXCEPTIONS: return @@ -172,11 +138,6 @@ def _make_event_processor( ) -> "EventProcessor": def event_processor(event: "Event", hint: "Hint") -> "Optional[Event]": with capture_internal_exceptions(): - scope = sentry_sdk.get_current_scope() - if scope.transaction is not None: - scope.transaction.name = ctx["job_name"] - event["transaction"] = ctx["job_name"] - tags = event.setdefault("tags", {}) tags["arq_task_id"] = ctx["job_id"] tags["arq_task_retry"] = ctx["job_try"] > 1 @@ -188,16 +149,9 @@ def event_processor(event: "Event", hint: "Hint") -> "Optional[Event]": } client_options = sentry_sdk.get_client().options - if has_data_collection_enabled(client_options): - if client_options["data_collection"]["queues"]: - arq_job_dict["args"] = args - arq_job_dict["kwargs"] = kwargs - elif should_send_default_pii(): + if client_options["data_collection"]["queues"]: arq_job_dict["args"] = args arq_job_dict["kwargs"] = kwargs - else: - arq_job_dict["args"] = SENSITIVE_DATA_SUBSTITUTE - arq_job_dict["kwargs"] = SENSITIVE_DATA_SUBSTITUTE extra["arq-job"] = arq_job_dict @@ -215,13 +169,12 @@ async def _sentry_coroutine( if integration is None: return await coroutine(ctx, *args, **kwargs) - if has_span_streaming_enabled(client.options): - scope = sentry_sdk.get_current_scope() - span = scope.streamed_span - if span is not None: - span.name = name + scope = sentry_sdk.get_current_scope() + span = scope.span + if span is not None: + span.name = name - scope.set_transaction_name(name) + scope.set_transaction_name(name) sentry_sdk.get_isolation_scope().add_event_processor( _make_event_processor({**ctx, "job_name": name}, *args, **kwargs) diff --git a/sentry_sdk/integrations/asgi.py b/sentry_sdk/integrations/asgi.py index 17ffbaacf7..3214cf4584 100644 --- a/sentry_sdk/integrations/asgi.py +++ b/sentry_sdk/integrations/asgi.py @@ -6,12 +6,13 @@ import inspect import sys +from contextlib import nullcontext +from contextvars import ContextVar from copy import deepcopy from functools import partial from typing import TYPE_CHECKING import sentry_sdk -from sentry_sdk.api import continue_trace from sentry_sdk.consts import OP, SPANDATA from sentry_sdk.integrations._asgi_common import ( _get_headers, @@ -28,41 +29,30 @@ from sentry_sdk.scope import Scope, should_send_default_pii from sentry_sdk.sessions import track_session from sentry_sdk.traces import ( - SOURCE_FOR_STYLE as SEGMENT_SOURCE_FOR_STYLE, -) -from sentry_sdk.traces import ( - SegmentNameSource, - StreamedSpan, -) -from sentry_sdk.tracing import ( SOURCE_FOR_STYLE, - Transaction, - TransactionSource, + SegmentNameSource, + Span, ) -from sentry_sdk.tracing_utils import has_span_streaming_enabled from sentry_sdk.utils import ( - CONTEXTVARS_ERROR_MESSAGE, - HAS_REAL_CONTEXTVARS, - ContextVar, _get_installed_modules, capture_internal_exceptions, event_from_exception, has_data_collection_enabled, logger, - nullcontext, qualname_from_function, reraise, transaction_from_function, ) if TYPE_CHECKING: - from typing import Any, ContextManager, Dict, Optional, Tuple, Union + from typing import Any, ContextManager, Dict, Optional, Tuple from sentry_sdk._types import Attributes, Event, Hint - from sentry_sdk.tracing import Span -_asgi_middleware_applied = ContextVar("sentry_asgi_middleware_applied") +_asgi_middleware_applied: "ContextVar[bool]" = ContextVar( + "sentry_asgi_middleware_applied" +) _DEFAULT_TRANSACTION_NAME = "generic ASGI request" @@ -114,7 +104,6 @@ class SentryAsgiMiddleware: def __init__( self, app: "Any", - unsafe_context_data: bool = False, transaction_style: str = "endpoint", mechanism_type: str = "asgi", span_origin: str = "manual", @@ -127,15 +116,7 @@ def __init__( data to sent events and basic handling for exceptions bubbling up through the middleware. - :param unsafe_context_data: Disable errors when a proper contextvars installation could not be found. We do not recommend changing this from the default. """ - if not unsafe_context_data and not HAS_REAL_CONTEXTVARS: - # We better have contextvars or we're going to leak state between - # requests. - raise RuntimeError( - "The ASGI middleware for Sentry requires Python 3.7+ " - "or the aiocontextvars package." + CONTEXTVARS_ERROR_MESSAGE - ) if transaction_style not in TRANSACTION_STYLE_VALUES: raise ValueError( "Invalid value for transaction_style: %s (must be in %s)" @@ -206,23 +187,11 @@ async def _run_app( return await self.app(scope, receive, send) except Exception as exc: - suppress_chained_exceptions = ( - sentry_sdk.get_client() - .options.get("_experiments", {}) - .get("suppress_asgi_chained_exceptions", True) - ) - if suppress_chained_exceptions: - self._capture_lifespan_exception(exc) - raise exc from None - exc_info = sys.exc_info() with capture_internal_exceptions(): self._capture_lifespan_exception(exc) reraise(*exc_info) - client = sentry_sdk.get_client() - span_streaming = has_span_streaming_enabled(client.options) - _asgi_middleware_applied.set(True) try: with sentry_sdk.isolation_scope() as sentry_scope: @@ -243,98 +212,55 @@ async def _run_app( method = scope.get("method", "").upper() - span_ctx: "ContextManager[Union[Span, StreamedSpan, None]]" - if span_streaming: - segment: "Optional[StreamedSpan]" = None - attributes: "Attributes" = { - "sentry.segment.name.source": getattr( - transaction_source, "value", transaction_source - ), - "sentry.origin": self.span_origin, - "network.protocol.name": ty, - } - - if scope.get("client"): - client_options = sentry_sdk.get_client().options - if has_data_collection_enabled(client_options): - if client_options["data_collection"]["user_info"]: - sentry_scope.set_attribute( - SPANDATA.USER_IP_ADDRESS, _get_ip(scope) - ) - elif should_send_default_pii(): + span: "Optional[ContextManager[Optional[Span]]]" = None + attributes: "Attributes" = { + "sentry.segment.name.source": getattr( + transaction_source, "value", transaction_source + ), + "sentry.origin": self.span_origin, + "network.protocol.name": ty, + } + + if scope.get("client"): + client_options = sentry_sdk.get_client().options + if has_data_collection_enabled(client_options): + if client_options["data_collection"]["user_info"]: sentry_scope.set_attribute( SPANDATA.USER_IP_ADDRESS, _get_ip(scope) ) + elif should_send_default_pii(): + sentry_scope.set_attribute( + SPANDATA.USER_IP_ADDRESS, _get_ip(scope) + ) - if ty in ("http", "websocket"): - if ( - ty == "websocket" - or method in self.http_methods_to_capture - ): - sentry_sdk.traces.continue_trace(_get_headers(scope)) - - Scope.set_custom_sampling_context({"asgi_scope": scope}) - - attributes["sentry.op"] = f"{ty}.server" - segment = sentry_sdk.traces.start_span( - name=transaction_name, - attributes=attributes, - parent_span=None, - ) - sentry_scope.get_current_scope()._server_segment_span = segment - else: - sentry_sdk.traces.new_trace() + if ty in ("http", "websocket"): + if ty == "websocket" or method in self.http_methods_to_capture: + sentry_sdk.continue_trace(_get_headers(scope)) Scope.set_custom_sampling_context({"asgi_scope": scope}) - attributes["sentry.op"] = OP.HTTP_SERVER - segment = sentry_sdk.traces.start_span( + attributes["sentry.op"] = f"{ty}.server" + span = sentry_sdk.start_span( name=transaction_name, attributes=attributes, parent_span=None, ) - sentry_scope.get_current_scope()._server_segment_span = ( - segment - ) - - span_ctx = segment or nullcontext() - + sentry_scope.get_current_scope()._server_segment_span = span else: - transaction = None - if ty in ("http", "websocket"): - if ( - ty == "websocket" - or method in self.http_methods_to_capture - ): - transaction = continue_trace( - _get_headers(scope), - op="{}.server".format(ty), - name=transaction_name, - source=transaction_source, - origin=self.span_origin, - ) - else: - transaction = Transaction( - op=OP.HTTP_SERVER, - name=transaction_name, - source=transaction_source, - origin=self.span_origin, - ) + sentry_sdk.new_trace() - if transaction: - transaction.set_tag("asgi.type", ty) + Scope.set_custom_sampling_context({"asgi_scope": scope}) - span_ctx = ( - sentry_sdk.start_transaction( - transaction, - custom_sampling_context={"asgi_scope": scope}, - ) - if transaction is not None - else nullcontext() + attributes["sentry.op"] = OP.HTTP_SERVER + span = sentry_sdk.start_span( + name=transaction_name, + attributes=attributes, + parent_span=None, ) + sentry_scope.get_current_scope()._server_segment_span = span - with span_ctx as span: - if isinstance(span, StreamedSpan): + with span or nullcontext() as span: + if span is not None: for attribute, value in _get_request_attributes( scope, root_path_in_path=self.root_path_in_path, @@ -352,18 +278,13 @@ async def _sentry_wrapped_send( and "status" in event ) if is_http_response: - if isinstance(span, StreamedSpan): - span.status = ( - "error" - if event["status"] >= 400 - else "ok" - ) - span.set_attribute( - "http.response.status_code", - event["status"], - ) - else: - span.set_http_status(event["status"]) + span.status = ( + "error" if event["status"] >= 400 else "ok" + ) + span.set_attribute( + "http.response.status_code", + event["status"], + ) return await send(event) @@ -377,22 +298,13 @@ async def _sentry_wrapped_send( ) except Exception as exc: - suppress_chained_exceptions = ( - sentry_sdk.get_client() - .options.get("_experiments", {}) - .get("suppress_asgi_chained_exceptions", True) - ) - if suppress_chained_exceptions: - self._capture_request_exception(exc) - raise exc from None - exc_info = sys.exc_info() with capture_internal_exceptions(): self._capture_request_exception(exc) reraise(*exc_info) finally: - if isinstance(span, StreamedSpan): + if span is not None: already_set = ( span is not None and span.name != _DEFAULT_TRANSACTION_NAME @@ -436,9 +348,9 @@ def event_processor( and transaction != _DEFAULT_TRANSACTION_NAME and transaction_source in [ - TransactionSource.COMPONENT, - TransactionSource.ROUTE, - TransactionSource.CUSTOM, + SegmentNameSource.COMPONENT, + SegmentNameSource.ROUTE, + SegmentNameSource.CUSTOM, ] ) if not already_set: @@ -479,7 +391,7 @@ def _get_transaction_name_and_source( asgi_scope=asgi_scope, root_path_in_path=self.root_path_in_path ), ) - source = TransactionSource.URL + source = SegmentNameSource.URL elif transaction_style == "url": # FastAPI includes the route object in the scope to let Sentry extract the @@ -498,11 +410,11 @@ def _get_transaction_name_and_source( asgi_scope=asgi_scope, root_path_in_path=self.root_path_in_path ), ) - source = TransactionSource.URL + source = SegmentNameSource.URL if name is None: name = _DEFAULT_TRANSACTION_NAME - source = TransactionSource.ROUTE + source = SegmentNameSource.ROUTE return name, source return name, source @@ -511,7 +423,7 @@ def _get_segment_name_and_source( self: "SentryAsgiMiddleware", segment_style: str, asgi_scope: "Any" ) -> "Tuple[str, str]": name = None - source = SEGMENT_SOURCE_FOR_STYLE[segment_style].value + source = SOURCE_FOR_STYLE[segment_style].value ty = asgi_scope.get("type") if segment_style == "endpoint": diff --git a/sentry_sdk/integrations/asyncio.py b/sentry_sdk/integrations/asyncio.py index 4fc600d36f..2443808f23 100644 --- a/sentry_sdk/integrations/asyncio.py +++ b/sentry_sdk/integrations/asyncio.py @@ -1,18 +1,15 @@ import functools import sys +from contextlib import nullcontext import sentry_sdk from sentry_sdk.consts import OP from sentry_sdk.integrations import DidNotEnable, Integration -from sentry_sdk.traces import StreamedSpan -from sentry_sdk.tracing import Span -from sentry_sdk.tracing_utils import has_span_streaming_enabled from sentry_sdk.transport import AsyncHttpTransport from sentry_sdk.utils import ( event_from_exception, is_internal_task, logger, - nullcontext, reraise, ) @@ -22,7 +19,7 @@ except ImportError: raise DidNotEnable("asyncio not available") -from typing import TYPE_CHECKING, Optional, Union +from typing import TYPE_CHECKING if TYPE_CHECKING: from collections.abc import Coroutine @@ -149,32 +146,22 @@ async def _task_with_sentry_span_creation() -> "Any": integration = client.get_integration(AsyncioIntegration) task_spans = integration.task_spans if integration else False - span_ctx: "Optional[Union[StreamedSpan, Span]]" = None - is_span_streaming_enabled = has_span_streaming_enabled(client.options) - with sentry_sdk.isolation_scope(): - if task_spans: - if is_span_streaming_enabled: - if sentry_sdk.traces.get_current_span() is not None: - span_ctx = sentry_sdk.traces.start_span( - name=get_name(coro), - attributes={ - "sentry.op": OP.FUNCTION, - "sentry.origin": AsyncioIntegration.origin, - }, - ) - else: - span_ctx = sentry_sdk.start_span( - op=OP.FUNCTION, - name=get_name(coro), - origin=AsyncioIntegration.origin, - ) - - with span_ctx if span_ctx else nullcontext(): + span_ctx = nullcontext() + if task_spans and sentry_sdk.get_current_span() is not None: + span_ctx = sentry_sdk.start_span( + name=get_name(coro), + attributes={ + "sentry.op": OP.FUNCTION, + "sentry.origin": AsyncioIntegration.origin, + }, + ) + + with span_ctx: try: result = await coro - except StopAsyncIteration as e: - raise e from None + except StopAsyncIteration: + raise except Exception: reraise(*_capture_exception()) diff --git a/sentry_sdk/integrations/asyncpg.py b/sentry_sdk/integrations/asyncpg.py index 5354078ca2..f4e7724510 100644 --- a/sentry_sdk/integrations/asyncpg.py +++ b/sentry_sdk/integrations/asyncpg.py @@ -2,16 +2,14 @@ import contextlib import re -from typing import Any, Awaitable, Callable, Iterator, TypeVar, Union +from typing import Any, Awaitable, Callable, Iterator, TypeVar import sentry_sdk from sentry_sdk.consts import OP, SPANDATA from sentry_sdk.integrations import DidNotEnable, Integration, _check_minimum_version -from sentry_sdk.traces import StreamedSpan -from sentry_sdk.tracing import Span +from sentry_sdk.traces import Span from sentry_sdk.tracing_utils import ( add_query_source, - has_span_streaming_enabled, record_sql_queries, ) from sentry_sdk.utils import ( @@ -28,7 +26,7 @@ ) except ImportError: - raise DidNotEnable("asyncpg not installed.") + raise DidNotEnable("asyncpg not installed or incompatible") class AsyncPGIntegration(Integration): @@ -95,11 +93,6 @@ async def _inner(*args: "Any", **kwargs: "Any") -> "T": span_origin=AsyncPGIntegration.origin, ) as span: res = await f(*args, **kwargs) - if isinstance(span, StreamedSpan): - with capture_internal_exceptions(): - add_query_source(span) - - if not isinstance(span, StreamedSpan): with capture_internal_exceptions(): add_query_source(span) @@ -118,7 +111,7 @@ def _record( params_list: "tuple[Any, ...] | None", *, executemany: bool = False, -) -> "Iterator[Union[Span, StreamedSpan]]": +) -> "Iterator[Span]": client = sentry_sdk.get_client() integration = client.get_integration(AsyncPGIntegration) if integration is not None and not integration._record_params: @@ -152,11 +145,6 @@ async def _inner(*args: "Any", **kwargs: "Any") -> "T": res = await f(*args, **kwargs) - if isinstance(span, StreamedSpan): - with capture_internal_exceptions(): - add_query_source(span) - - if not isinstance(span, StreamedSpan): with capture_internal_exceptions(): add_query_source(span) @@ -194,11 +182,6 @@ async def _inner(*args: "Any", **kwargs: "Any") -> "T": _set_db_data(span, cursor._connection) res = await f(*args, **kwargs) - if isinstance(span, StreamedSpan): - with capture_internal_exceptions(): - add_query_source(span) - - if not isinstance(span, StreamedSpan): with capture_internal_exceptions(): add_query_source(span) @@ -219,95 +202,51 @@ async def _inner(*args: "Any", **kwargs: "Any") -> "T": database = kwargs["params"].database addr = kwargs.get("addr") - if has_span_streaming_enabled(client.options): - span_attributes = { - "sentry.op": OP.DB, - "sentry.origin": AsyncPGIntegration.origin, - SPANDATA.DB_SYSTEM_NAME: "postgresql", - SPANDATA.DB_USER: user, - SPANDATA.DB_NAMESPACE: database, - SPANDATA.DB_DRIVER_NAME: "asyncpg", - } - if addr: - try: - span_attributes[SPANDATA.SERVER_ADDRESS] = addr[0] - span_attributes[SPANDATA.SERVER_PORT] = addr[1] - except IndexError: - pass + span_attributes = { + "sentry.op": OP.DB, + "sentry.origin": AsyncPGIntegration.origin, + SPANDATA.DB_SYSTEM_NAME: "postgresql", + SPANDATA.DB_USER: user, + SPANDATA.DB_NAMESPACE: database, + SPANDATA.DB_DRIVER_NAME: "asyncpg", + } + if addr: + try: + span_attributes[SPANDATA.SERVER_ADDRESS] = addr[0] + span_attributes[SPANDATA.SERVER_PORT] = addr[1] + except IndexError: + pass + + with capture_internal_exceptions(): + sentry_sdk.add_breadcrumb( + message="connect", category="query", data=span_attributes + ) - with capture_internal_exceptions(): - sentry_sdk.add_breadcrumb( - message="connect", category="query", data=span_attributes - ) - - if sentry_sdk.traces.get_current_span() is None: - return await f(*args, **kwargs) - - with sentry_sdk.traces.start_span( - name="connect", attributes=span_attributes - ): - return await f(*args, **kwargs) - - with sentry_sdk.start_span( - op=OP.DB, - name="connect", - origin=AsyncPGIntegration.origin, - ) as span: - span.set_data(SPANDATA.DB_SYSTEM, "postgresql") - if addr: - try: - span.set_data(SPANDATA.SERVER_ADDRESS, addr[0]) - span.set_data(SPANDATA.SERVER_PORT, addr[1]) - except IndexError: - pass - span.set_data(SPANDATA.DB_NAME, database) - span.set_data(SPANDATA.DB_USER, user) - span.set_data(SPANDATA.DB_DRIVER_NAME, "asyncpg") + if sentry_sdk.get_current_span() is None: + return await f(*args, **kwargs) - with capture_internal_exceptions(): - sentry_sdk.add_breadcrumb( - message="connect", category="query", data=span._data - ) + with sentry_sdk.start_span(name="connect", attributes=span_attributes): return await f(*args, **kwargs) return _inner -def _set_db_data(span: "Union[Span, StreamedSpan]", conn: "Any") -> None: +def _set_db_data(span: "Span", conn: "Any") -> None: addr = conn._addr database = conn._params.database user = conn._params.user - if isinstance(span, StreamedSpan): - span.set_attribute(SPANDATA.DB_SYSTEM_NAME, "postgresql") - span.set_attribute(SPANDATA.DB_DRIVER_NAME, "asyncpg") - if addr: - try: - span.set_attribute(SPANDATA.SERVER_ADDRESS, addr[0]) - span.set_attribute(SPANDATA.SERVER_PORT, addr[1]) - except IndexError: - pass - - if database: - span.set_attribute(SPANDATA.DB_NAMESPACE, database) - - if user: - span.set_attribute(SPANDATA.DB_USER, user) - else: - # Remove this else block once we've completely migrated to streamed spans - # The use of deprecated attributes here is to ensure backwards compatibility - span.set_data(SPANDATA.DB_SYSTEM, "postgresql") - span.set_data(SPANDATA.DB_DRIVER_NAME, "asyncpg") - - if addr: - try: - span.set_data(SPANDATA.SERVER_ADDRESS, addr[0]) - span.set_data(SPANDATA.SERVER_PORT, addr[1]) - except IndexError: - pass + span.set_attribute(SPANDATA.DB_SYSTEM_NAME, "postgresql") + span.set_attribute(SPANDATA.DB_DRIVER_NAME, "asyncpg") + if addr: + try: + span.set_attribute(SPANDATA.SERVER_ADDRESS, addr[0]) + span.set_attribute(SPANDATA.SERVER_PORT, addr[1]) + except IndexError: + pass - if database: - span.set_data(SPANDATA.DB_NAME, database) + if database: + span.set_attribute(SPANDATA.DB_NAMESPACE, database) - if user: - span.set_data(SPANDATA.DB_USER, user) + if user: + span.set_attribute(SPANDATA.DB_USER, user) diff --git a/sentry_sdk/integrations/aws_lambda.py b/sentry_sdk/integrations/aws_lambda.py index d8bf35ef7e..6fdd209c01 100644 --- a/sentry_sdk/integrations/aws_lambda.py +++ b/sentry_sdk/integrations/aws_lambda.py @@ -9,7 +9,6 @@ from urllib.parse import urlencode import sentry_sdk -from sentry_sdk.api import continue_trace from sentry_sdk.consts import OP from sentry_sdk.data_collection import _apply_key_value_collection_filtering from sentry_sdk.integrations import Integration @@ -18,17 +17,14 @@ CLOUD_PLATFORM, CLOUD_PROVIDER, ) -from sentry_sdk.scope import Scope, should_send_default_pii +from sentry_sdk.scope import Scope from sentry_sdk.traces import SegmentNameSource -from sentry_sdk.tracing import TransactionSource -from sentry_sdk.tracing_utils import has_span_streaming_enabled from sentry_sdk.utils import ( AnnotatedValue, TimeoutThread, capture_internal_exceptions, ensure_integration_enabled, event_from_exception, - has_data_collection_enabled, logger, reraise, ) @@ -142,10 +138,6 @@ def sentry_handler( request_data, aws_context, configured_time ) ) - scope.set_tag("aws_region", aws_region) - if batch_size > 1: - scope.set_tag("batch_request", True) - scope.set_tag("batch_size", batch_size) # Starting the Timeout thread only if the configured time is greater than Timeout warning # buffer and timeout_warning parameter is set True. @@ -187,31 +179,21 @@ def sentry_handler( "httpMethod" ] + data_collection = client.options["data_collection"] if "queryStringParameters" in request_data: qs = request_data["queryStringParameters"] if qs: - if has_data_collection_enabled(client.options): - filtered_qs = _apply_key_value_collection_filtering( - items=qs, - behaviour=client.options["data_collection"][ - "url_query_params" - ], - ) - if filtered_qs: - additional_attributes["url.query"] = urlencode(filtered_qs) - elif should_send_default_pii(): - additional_attributes["url.query"] = urlencode(qs) - - if not scope._user: - if has_data_collection_enabled(client.options): - if client.options["data_collection"]["user_info"]: - user_info = _get_user_from_event(request_data) - if user_info: - scope.set_user(user_info) - elif should_send_default_pii(): - user_info = _get_user_from_event(request_data) - if user_info: - scope.set_user(user_info) + filtered_qs = _apply_key_value_collection_filtering( + items=qs, + behaviour=data_collection["url_query_params"], + ) + if filtered_qs: + additional_attributes["url.query"] = urlencode(filtered_qs) + + if not scope._user and data_collection["user_info"]: + user_info = _get_user_from_event(request_data) + if user_info: + scope.set_user(user_info) sampling_context = { "aws_event": aws_event, @@ -220,45 +202,31 @@ def sentry_handler( function_name = aws_context.function_name - if has_span_streaming_enabled(client.options): - sentry_sdk.traces.continue_trace(headers) - Scope.set_custom_sampling_context(sampling_context) - span_ctx = sentry_sdk.traces.start_span( - name=function_name, - parent_span=None, - attributes={ - "sentry.op": OP.FUNCTION_AWS, - "sentry.origin": AwsLambdaIntegration.origin, - "sentry.segment.name.source": SegmentNameSource.COMPONENT, - "cloud.region": aws_region, - "cloud.resource_id": aws_context.invoked_function_arn, - "cloud.platform": CLOUD_PLATFORM.AWS_LAMBDA, - "cloud.provider": CLOUD_PROVIDER.AWS, - "faas.name": function_name, - "faas.invocation_id": aws_context.aws_request_id, - "faas.version": aws_context.function_version, - "aws.lambda.invoked_arn": aws_context.invoked_function_arn, - "aws.log.group.names": [aws_context.log_group_name], - "aws.log.stream.names": [aws_context.log_stream_name], - "messaging.batch.message_count": batch_size, - **header_attributes, - **additional_attributes, - }, - ) - else: - transaction = continue_trace( - headers, - op=OP.FUNCTION_AWS, - name=function_name, - source=TransactionSource.COMPONENT, - origin=AwsLambdaIntegration.origin, - ) - - span_ctx = sentry_sdk.start_transaction( - transaction, custom_sampling_context=sampling_context - ) - - with span_ctx: + sentry_sdk.continue_trace(headers) + Scope.set_custom_sampling_context(sampling_context) + + with sentry_sdk.start_span( + name=function_name, + parent_span=None, + attributes={ + "sentry.op": OP.FUNCTION_AWS, + "sentry.origin": AwsLambdaIntegration.origin, + "sentry.segment.name.source": SegmentNameSource.COMPONENT, + "cloud.region": aws_region, + "cloud.resource_id": aws_context.invoked_function_arn, + "cloud.platform": CLOUD_PLATFORM.AWS_LAMBDA, + "cloud.provider": CLOUD_PROVIDER.AWS, + "faas.name": function_name, + "faas.invocation_id": aws_context.aws_request_id, + "faas.version": aws_context.function_version, + "aws.lambda.invoked_arn": aws_context.invoked_function_arn, + "aws.log.group.names": [aws_context.log_group_name], + "aws.log.stream.names": [aws_context.log_stream_name], + "messaging.batch.message_count": batch_size, + **header_attributes, + **additional_attributes, + }, + ): try: return handler(aws_event, aws_context, *args, **kwargs) except Exception: @@ -311,76 +279,42 @@ def setup_once() -> None: ) return - pre_37 = hasattr(lambda_bootstrap, "handle_http_request") # Python 3.6 - - if pre_37: - old_handle_event_request = lambda_bootstrap.handle_event_request - - def sentry_handle_event_request( - request_handler: "Any", *args: "Any", **kwargs: "Any" - ) -> "Any": - request_handler = _wrap_handler(request_handler) - return old_handle_event_request(request_handler, *args, **kwargs) - - lambda_bootstrap.handle_event_request = sentry_handle_event_request - - old_handle_http_request = lambda_bootstrap.handle_http_request + lambda_bootstrap.LambdaRuntimeClient.post_init_error = _wrap_init_error( + lambda_bootstrap.LambdaRuntimeClient.post_init_error + ) - def sentry_handle_http_request( - request_handler: "Any", *args: "Any", **kwargs: "Any" - ) -> "Any": - request_handler = _wrap_handler(request_handler) - return old_handle_http_request(request_handler, *args, **kwargs) - - lambda_bootstrap.handle_http_request = sentry_handle_http_request - - # Patch to_json to drain the queue. This should work even when the - # SDK is initialized inside of the handler - - old_to_json = lambda_bootstrap.to_json - - def sentry_to_json(*args: "Any", **kwargs: "Any") -> "Any": - _drain_queue() - return old_to_json(*args, **kwargs) + old_handle_event_request = lambda_bootstrap.handle_event_request - lambda_bootstrap.to_json = sentry_to_json - else: - lambda_bootstrap.LambdaRuntimeClient.post_init_error = _wrap_init_error( - lambda_bootstrap.LambdaRuntimeClient.post_init_error - ) - - old_handle_event_request = lambda_bootstrap.handle_event_request - - def sentry_handle_event_request( # type: ignore + def sentry_handle_event_request( # type: ignore + lambda_runtime_client, request_handler, *args, **kwargs + ): + request_handler = _wrap_handler(request_handler) + return old_handle_event_request( lambda_runtime_client, request_handler, *args, **kwargs - ): - request_handler = _wrap_handler(request_handler) - return old_handle_event_request( - lambda_runtime_client, request_handler, *args, **kwargs - ) + ) - lambda_bootstrap.handle_event_request = sentry_handle_event_request + lambda_bootstrap.handle_event_request = sentry_handle_event_request - # Patch the runtime client to drain the queue. This should work - # even when the SDK is initialized inside of the handler + # Patch the runtime client to drain the queue. This should work + # even when the SDK is initialized inside of the handler - def _wrap_post_function(f: "F") -> "F": - def inner(*args: "Any", **kwargs: "Any") -> "Any": - _drain_queue() - return f(*args, **kwargs) + def _wrap_post_function(f: "F") -> "F": + def inner(*args: "Any", **kwargs: "Any") -> "Any": + _drain_queue() + return f(*args, **kwargs) - return inner # type: ignore + return inner # type: ignore - lambda_bootstrap.LambdaRuntimeClient.post_invocation_result = ( - _wrap_post_function( - lambda_bootstrap.LambdaRuntimeClient.post_invocation_result - ) + lambda_bootstrap.LambdaRuntimeClient.post_invocation_result = ( + _wrap_post_function( + lambda_bootstrap.LambdaRuntimeClient.post_invocation_result ) - lambda_bootstrap.LambdaRuntimeClient.post_invocation_error = ( - _wrap_post_function( - lambda_bootstrap.LambdaRuntimeClient.post_invocation_error - ) + ) + lambda_bootstrap.LambdaRuntimeClient.post_invocation_error = ( + _wrap_post_function( + lambda_bootstrap.LambdaRuntimeClient.post_invocation_error ) + ) def get_lambda_bootstrap() -> "Optional[Any]": @@ -452,50 +386,36 @@ def event_processor( request["url"] = _get_url(aws_event, aws_context) + client_options = sentry_sdk.get_client().options + data_collection = client_options["data_collection"] + if "queryStringParameters" in aws_event: query_string = aws_event["queryStringParameters"] - client_options = sentry_sdk.get_client().options - if has_data_collection_enabled(client_options): - if query_string: - filtered_qs = _apply_key_value_collection_filtering( - items=query_string, - behaviour=client_options["data_collection"]["url_query_params"], - ) - if filtered_qs: - request["query_string"] = filtered_qs - else: - request["query_string"] = query_string + if query_string: + filtered_qs = _apply_key_value_collection_filtering( + items=query_string, + behaviour=data_collection["url_query_params"], + ) + if filtered_qs: + request["query_string"] = filtered_qs if "headers" in aws_event: request["headers"] = _filter_headers(aws_event["headers"]) - client_options = sentry_sdk.get_client().options - if has_data_collection_enabled(client_options): - if client_options["data_collection"]["user_info"]: - extracted_user = _get_user_from_event(aws_event) - if extracted_user: - user_info = sentry_event.setdefault("user", {}) - for key, value in extracted_user.items(): - user_info.setdefault(key, value) - - if "incoming_request" in client_options["data_collection"]["http_bodies"]: - if "body" in aws_event: - request["data"] = aws_event.get("body", "") - - elif should_send_default_pii(): + if data_collection["user_info"]: extracted_user = _get_user_from_event(aws_event) if extracted_user: user_info = sentry_event.setdefault("user", {}) for key, value in extracted_user.items(): user_info.setdefault(key, value) + if "incoming_request" in data_collection["http_bodies"]: if "body" in aws_event: request["data"] = aws_event.get("body", "") - else: - if aws_event.get("body", None): - # Unfortunately couldn't find a way to get structured body from AWS - # event. Meaning every body is unstructured to us. - request["data"] = AnnotatedValue.removed_because_raw_data() + elif aws_event.get("body", None): + # Unfortunately couldn't find a way to get structured body from AWS + # event. Meaning every body is unstructured to us. + request["data"] = AnnotatedValue.removed_because_raw_data() sentry_event["request"] = deepcopy(request) diff --git a/sentry_sdk/integrations/beam.py b/sentry_sdk/integrations/beam.py index 31f45f73de..4bce445075 100644 --- a/sentry_sdk/integrations/beam.py +++ b/sentry_sdk/integrations/beam.py @@ -4,12 +4,13 @@ from typing import TYPE_CHECKING import sentry_sdk -from sentry_sdk.integrations import Integration -from sentry_sdk.integrations.logging import ignore_logger +from sentry_sdk.integrations import Integration, _check_minimum_version +from sentry_sdk.integrations.logging import ignore_logger_for_events from sentry_sdk.utils import ( capture_internal_exceptions, ensure_integration_enabled, event_from_exception, + parse_version, reraise, ) @@ -32,10 +33,14 @@ class BeamIntegration(Integration): @staticmethod def setup_once() -> None: + from apache_beam import __version__ as BEAM_VERSION # type: ignore from apache_beam.transforms.core import DoFn, ParDo # type: ignore - ignore_logger("root") - ignore_logger("bundle_processor.create") + version = parse_version(BEAM_VERSION) + _check_minimum_version(BeamIntegration, version) + + ignore_logger_for_events("root") + ignore_logger_for_events("bundle_processor.create") function_patches = ["process", "start_bundle", "finish_bundle", "setup"] for func_name in function_patches: diff --git a/sentry_sdk/integrations/boto3.py b/sentry_sdk/integrations/boto3.py index 18d7accf6d..63719b124d 100644 --- a/sentry_sdk/integrations/boto3.py +++ b/sentry_sdk/integrations/boto3.py @@ -4,13 +4,11 @@ import sentry_sdk from sentry_sdk.consts import OP, SPANDATA from sentry_sdk.integrations import DidNotEnable, Integration, _check_minimum_version -from sentry_sdk.traces import StreamedSpan -from sentry_sdk.tracing import BAGGAGE_HEADER_NAME, Span +from sentry_sdk.traces import BAGGAGE_HEADER_NAME, Span from sentry_sdk.tracing_utils import ( add_http_breadcrumb, add_sentry_baggage_to_headers, get_url_attributes, - has_span_streaming_enabled, should_propagate_trace, ) from sentry_sdk.utils import ( @@ -20,7 +18,7 @@ ) if TYPE_CHECKING: - from typing import Any, Dict, Optional, Type, Union + from typing import Any, Dict, Optional, Type from botocore.model import ServiceId @@ -31,7 +29,7 @@ from botocore.client import BaseClient from botocore.response import StreamingBody except ImportError: - raise DidNotEnable("botocore is not installed") + raise DidNotEnable("botocore is not installed or incompatible") class Boto3Integration(Integration): @@ -79,56 +77,27 @@ def _sentry_request_created( breadcrumb: "dict[str, Any]" = {} - is_span_streaming_enabled = has_span_streaming_enabled(client.options) - span: "Union[Span, StreamedSpan, None]" = None - if is_span_streaming_enabled: - url_attributes = get_url_attributes(client, parsed_url) - breadcrumb.update(url_attributes) + span: "Optional[Span]" = None - if request.method is not None: - breadcrumb[SPANDATA.HTTP_REQUEST_METHOD] = request.method - - if sentry_sdk.traces.get_current_span() is not None: - span = sentry_sdk.traces.start_span( - name=description, - attributes={ - "sentry.op": OP.HTTP_CLIENT, - "sentry.origin": Boto3Integration.origin, - SPANDATA.RPC_METHOD: f"{service_id}/{operation_name}", - }, - ) - span.set_attributes(url_attributes) + url_attributes = get_url_attributes(client, parsed_url) + breadcrumb.update(url_attributes) + + if request.method is not None: + breadcrumb[SPANDATA.HTTP_REQUEST_METHOD] = request.method - if request.method is not None: - span.set_attribute(SPANDATA.HTTP_REQUEST_METHOD, request.method) - else: + if sentry_sdk.get_current_span() is not None: span = sentry_sdk.start_span( - op=OP.HTTP_CLIENT, name=description, - origin=Boto3Integration.origin, + attributes={ + "sentry.op": OP.HTTP_CLIENT, + "sentry.origin": Boto3Integration.origin, + SPANDATA.RPC_METHOD: f"{service_id}/{operation_name}", + }, ) + span.set_attributes(url_attributes) - if parsed_url: - span.set_data("aws.request.url", parsed_url.url) - span.set_data(SPANDATA.HTTP_QUERY, parsed_url.query) - span.set_data(SPANDATA.HTTP_FRAGMENT, parsed_url.fragment) - breadcrumb.update( - { - "aws.request.url": parsed_url.url, - SPANDATA.HTTP_QUERY: parsed_url.query, - SPANDATA.HTTP_FRAGMENT: parsed_url.fragment, - } - ) - - span.set_tag("aws.service_id", service_id.hyphenize()) - span.set_tag("aws.operation_name", operation_name) if request.method is not None: - span.set_data(SPANDATA.HTTP_METHOD, request.method) - breadcrumb[SPANDATA.HTTP_METHOD] = request.method - - # We do it in order for subsequent http calls/retries be - # attached to this span. - span.__enter__() + span.set_attribute(SPANDATA.HTTP_REQUEST_METHOD, request.method) add_http_breadcrumb(None, breadcrumb) @@ -195,7 +164,7 @@ def _replace_header(request: "AWSRequest", key: str, value: str) -> None: def _sentry_after_call( context: "Dict[str, Any]", parsed: "Dict[str, Any]", **kwargs: "Any" ) -> None: - span: "Optional[Union[Span, StreamedSpan]]" = context.pop("_sentrysdk_span", None) + span: "Optional[Span]" = context.pop("_sentrysdk_span", None) # Span could be absent if the integration is disabled. if span is None: @@ -207,22 +176,14 @@ def _sentry_after_call( if not isinstance(body, StreamingBody): return - streaming_span: "Union[Span, StreamedSpan]" - if isinstance(span, StreamedSpan): - streaming_span = sentry_sdk.traces.start_span( - name=span.name, - parent_span=span, - attributes={ - "sentry.op": OP.HTTP_CLIENT_STREAM, - "sentry.origin": Boto3Integration.origin, - }, - ) - else: - streaming_span = span.start_child( - op=OP.HTTP_CLIENT_STREAM, - name=span.description, - origin=Boto3Integration.origin, - ) + streaming_span = sentry_sdk.start_span( + name=span.name, + parent_span=span, + attributes={ + "sentry.op": OP.HTTP_CLIENT_STREAM, + "sentry.origin": Boto3Integration.origin, + }, + ) orig_read = body.read orig_close = body.close @@ -233,25 +194,16 @@ def sentry_streaming_body_read(*args: "Any", **kwargs: "Any") -> bytes: if ret: return ret - if isinstance(streaming_span, StreamedSpan): - streaming_span.end() - else: - streaming_span.finish() + streaming_span.end() return ret except Exception: - if isinstance(streaming_span, StreamedSpan): - streaming_span.end() - else: - streaming_span.finish() + streaming_span.end() raise body.read = sentry_streaming_body_read # type: ignore def sentry_streaming_body_close(*args: "Any", **kwargs: "Any") -> None: - if isinstance(streaming_span, StreamedSpan): - streaming_span.end() - else: - streaming_span.finish() + streaming_span.end() orig_close(*args, **kwargs) body.close = sentry_streaming_body_close # type: ignore @@ -260,7 +212,7 @@ def sentry_streaming_body_close(*args: "Any", **kwargs: "Any") -> None: def _sentry_after_call_error( context: "Dict[str, Any]", exception: "Type[BaseException]", **kwargs: "Any" ) -> None: - span: "Optional[Union[Span, StreamedSpan]]" = context.pop("_sentrysdk_span", None) + span: "Optional[Span]" = context.pop("_sentrysdk_span", None) # Span could be absent if the integration is disabled. if span is None: diff --git a/sentry_sdk/integrations/bottle.py b/sentry_sdk/integrations/bottle.py index 68df00cfde..51c9ba6d2e 100644 --- a/sentry_sdk/integrations/bottle.py +++ b/sentry_sdk/integrations/bottle.py @@ -12,8 +12,6 @@ from sentry_sdk.integrations._wsgi_common import RequestExtractor from sentry_sdk.integrations.wsgi import SentryWsgiMiddleware from sentry_sdk.traces import SOURCE_FOR_STYLE as SEGMENT_SOURCE_FOR_STYLE -from sentry_sdk.tracing import SOURCE_FOR_STYLE as TRANSACTION_SOURCE_FOR_STYLE -from sentry_sdk.tracing_utils import has_span_streaming_enabled from sentry_sdk.utils import ( capture_internal_exceptions, ensure_integration_enabled, @@ -44,7 +42,7 @@ request as bottle_request, ) except ImportError: - raise DidNotEnable("Bottle not installed") + raise DidNotEnable("Bottle not installed or incompatible") TRANSACTION_STYLE_VALUES = ("endpoint", "url") @@ -129,10 +127,9 @@ def _patched_handle(self: "Bottle", environ: "Dict[str, Any]") -> "Any": if route_path is not None: server_span.set_attribute(SPANDATA.HTTP_ROUTE, route_path) - if has_span_streaming_enabled(sentry_sdk.get_client().options): - _set_segment_name_and_source( - transaction_style=integration.transaction_style - ) + _set_segment_name_and_source( + transaction_style=integration.transaction_style + ) return res @@ -195,57 +192,38 @@ def size_of_file(self, file: "FileUpload") -> int: return file.content_length -def _set_segment_name_and_source(transaction_style: str) -> None: +def _get_transaction_name(transaction_style: str, request: "Any") -> str: try: if transaction_style == "url": - name = bottle_request.route.rule or "bottle request" + return request.route.rule or "bottle request" else: - name = ( - bottle_request.route.name - or transaction_from_function(bottle_request.route.callback) + return ( + request.route.name + or transaction_from_function(request.route.callback) or "bottle request" ) + except RuntimeError: + return "bottle request" + +def _set_segment_name_and_source(transaction_style: str) -> None: + name = _get_transaction_name(transaction_style, bottle_request) + if name: sentry_sdk.get_current_scope().set_transaction_name( name, source=SEGMENT_SOURCE_FOR_STYLE[transaction_style], ) - except RuntimeError: - pass - - -def _set_transaction_name_and_source( - event: "Event", transaction_style: str, request: "Any" -) -> None: - name = "" - - if transaction_style == "url": - try: - name = request.route.rule or "" - except RuntimeError: - pass - - elif transaction_style == "endpoint": - try: - name = ( - request.route.name - or transaction_from_function(request.route.callback) - or "" - ) - except RuntimeError: - pass - - event["transaction"] = name - event["transaction_info"] = { - "source": TRANSACTION_SOURCE_FOR_STYLE[transaction_style] - } def _make_request_event_processor( app: "Bottle", request: "LocalRequest", integration: "BottleIntegration" ) -> "EventProcessor": def event_processor(event: "Event", hint: "dict[str, Any]") -> "Event": - _set_transaction_name_and_source(event, integration.transaction_style, request) + name = _get_transaction_name(integration.transaction_style, request) + event["transaction"] = name + event["transaction_info"] = { + "source": SEGMENT_SOURCE_FOR_STYLE[integration.transaction_style] + } with capture_internal_exceptions(): BottleRequestExtractor(request).extract_into_event(event) diff --git a/sentry_sdk/integrations/celery/__init__.py b/sentry_sdk/integrations/celery/__init__.py index b81e622003..0338a8499e 100644 --- a/sentry_sdk/integrations/celery/__init__.py +++ b/sentry_sdk/integrations/celery/__init__.py @@ -1,12 +1,12 @@ import sys from collections.abc import Mapping +from contextlib import nullcontext from functools import wraps from typing import TYPE_CHECKING import sentry_sdk from sentry_sdk import isolation_scope -from sentry_sdk.api import continue_trace -from sentry_sdk.consts import OP, SPANDATA, SPANSTATUS +from sentry_sdk.consts import OP, SPANDATA from sentry_sdk.integrations import DidNotEnable, Integration, _check_minimum_version from sentry_sdk.integrations.celery.beat import ( _patch_beat_apply_entry, @@ -14,22 +14,19 @@ _setup_celery_beat_signals, ) from sentry_sdk.integrations.celery.utils import _now_seconds_since_epoch -from sentry_sdk.integrations.logging import ignore_logger -from sentry_sdk.scope import Scope, should_send_default_pii -from sentry_sdk.traces import SegmentNameSource, StreamedSpan, get_current_span -from sentry_sdk.tracing import BAGGAGE_HEADER_NAME, Span, TransactionSource -from sentry_sdk.tracing_utils import Baggage, has_span_streaming_enabled +from sentry_sdk.integrations.logging import ignore_logger_for_events +from sentry_sdk.scope import Scope +from sentry_sdk.traces import BAGGAGE_HEADER_NAME, SegmentNameSource, Span +from sentry_sdk.tracing_utils import Baggage from sentry_sdk.utils import ( - SENSITIVE_DATA_SUBSTITUTE, capture_internal_exceptions, event_from_exception, - has_data_collection_enabled, parse_version, reraise, ) if TYPE_CHECKING: - from typing import Any, Callable, List, Optional, TypeVar, Union + from typing import Any, Callable, List, Optional, TypeVar from sentry_sdk._types import Event, EventProcessor, ExcInfo, Hint @@ -85,25 +82,20 @@ def setup_once() -> None: # This logger logs every status of every task that ran on the worker. # Meaning that every task's breadcrumbs are full of stuff like "Task # raised unexpected ". - ignore_logger("celery.worker.job") - ignore_logger("celery.app.trace") + ignore_logger_for_events("celery.worker.job") + ignore_logger_for_events("celery.app.trace") # This is stdout/err redirected to a logger, can't deal with this # (need event_level=logging.WARN to reproduce) - ignore_logger("celery.redirected") + ignore_logger_for_events("celery.redirected") def _set_status(status: str) -> None: - client = sentry_sdk.get_client() - span_streaming = has_span_streaming_enabled(client.options) - with capture_internal_exceptions(): - scope = sentry_sdk.get_current_scope() + span = sentry_sdk.get_current_span() - if span_streaming and scope.streamed_span is not None: - scope.streamed_span.status = "ok" if status == "ok" else "error" - elif not span_streaming and scope.span is not None: - scope.span.set_status(status) + if span is not None: + span.status = "ok" if status == "ok" else "error" def _capture_exception(task: "Any", exc_info: "ExcInfo") -> None: @@ -146,16 +138,9 @@ def event_processor(event: "Event", hint: "Hint") -> "Optional[Event]": celery_job = {"task_name": task.name} client_options = sentry_sdk.get_client().options - if has_data_collection_enabled(client_options): - if client_options["data_collection"]["queues"]: - celery_job["args"] = args - celery_job["kwargs"] = kwargs - elif should_send_default_pii(): + if client_options["data_collection"]["queues"]: celery_job["args"] = args celery_job["kwargs"] = kwargs - else: - celery_job["args"] = SENSITIVE_DATA_SUBSTITUTE - celery_job["kwargs"] = SENSITIVE_DATA_SUBSTITUTE extra["celery-job"] = celery_job @@ -175,7 +160,7 @@ def event_processor(event: "Event", hint: "Hint") -> "Optional[Event]": def _update_celery_task_headers( original_headers: "dict[str, Any]", - span: "Optional[Union[StreamedSpan, Span]]", + span: "Optional[Span]", monitor_beat_tasks: bool, ) -> "dict[str, Any]": """ @@ -256,14 +241,6 @@ def _update_celery_task_headers( return updated_headers -class NoOpMgr: - def __enter__(self) -> None: - return None - - def __exit__(self, exc_type: "Any", exc_value: "Any", traceback: "Any") -> None: - return None - - def _wrap_task_run(f: "F") -> "F": @wraps(f) def apply_async(*args: "Any", **kwargs: "Any") -> "Any": @@ -289,30 +266,19 @@ def apply_async(*args: "Any", **kwargs: "Any") -> "Any": else: task_name = "" - span_streaming = has_span_streaming_enabled(client.options) - task_started_from_beat = sentry_sdk.get_isolation_scope()._name == "celery-beat" - span_mgr: "Union[StreamedSpan, Span, NoOpMgr]" = NoOpMgr() - if span_streaming: - if not task_started_from_beat and get_current_span() is not None: - span_mgr = sentry_sdk.traces.start_span( - name=task_name, - attributes={ - "sentry.op": OP.QUEUE_SUBMIT_CELERY, - "sentry.origin": CeleryIntegration.origin, - }, - ) - - else: - if not task_started_from_beat: - span_mgr = sentry_sdk.start_span( - op=OP.QUEUE_SUBMIT_CELERY, - name=task_name, - origin=CeleryIntegration.origin, - ) + span = None + if not task_started_from_beat and sentry_sdk.get_current_span() is not None: + span = sentry_sdk.start_span( + name=task_name, + attributes={ + "sentry.op": OP.QUEUE_SUBMIT_CELERY, + "sentry.origin": CeleryIntegration.origin, + }, + ) - with span_mgr as span: + with span if span else nullcontext(): kwargs["headers"] = _update_celery_task_headers( kwarg_headers, span, integration.monitor_beat_tasks ) @@ -334,8 +300,6 @@ def _inner(*args: "Any", **kwargs: "Any") -> "Any": if client.get_integration(CeleryIntegration) is None: return f(*args, **kwargs) - span_streaming = has_span_streaming_enabled(client.options) - with isolation_scope() as scope: scope._name = "celery" scope.clear_breadcrumbs() @@ -355,52 +319,33 @@ def _inner(*args: "Any", **kwargs: "Any") -> "Any": } } - span: "Union[Span, StreamedSpan]" - span_ctx: "Union[StreamedSpan, Span, NoOpMgr]" = NoOpMgr() + span = None # Celery task objects are not a thing to be trusted. Even # something such as attribute access can fail. with capture_internal_exceptions(): headers = args[3].get("headers") or {} - if span_streaming: - sentry_sdk.traces.continue_trace(headers) - Scope.set_custom_sampling_context(custom_sampling_context) - span = sentry_sdk.traces.start_span( - name=task_name, - parent_span=None, # make this a segment - attributes={ - "sentry.origin": CeleryIntegration.origin, - "sentry.segment.name.source": SegmentNameSource.TASK.value, - "sentry.op": OP.QUEUE_TASK_CELERY, - }, - ) + sentry_sdk.continue_trace(headers) - span_ctx = span + Scope.set_custom_sampling_context(custom_sampling_context) - else: - span = continue_trace( - headers, - op=OP.QUEUE_TASK_CELERY, - name=task_name, - source=TransactionSource.TASK, - origin=CeleryIntegration.origin, - ) - span.set_status(SPANSTATUS.OK) - - span_ctx = sentry_sdk.start_transaction( - span, - custom_sampling_context=custom_sampling_context, - ) + span = sentry_sdk.start_span( + name=task_name, + parent_span=None, # make this a segment + attributes={ + "sentry.origin": CeleryIntegration.origin, + "sentry.segment.name.source": SegmentNameSource.TASK.value, + "sentry.op": OP.QUEUE_TASK_CELERY, + }, + ) - with span_ctx: + with span if span else nullcontext(): return f(*args, **kwargs) return _inner # type: ignore -def _set_messaging_destination_name( - task: "Any", span: "Union[StreamedSpan, Span]" -) -> None: +def _set_messaging_destination_name(task: "Any", span: "Span") -> None: """Set "messaging.destination.name" tag for span""" with capture_internal_exceptions(): delivery_info = task.request.delivery_info @@ -409,10 +354,7 @@ def _set_messaging_destination_name( if delivery_info.get("exchange") == "" and routing_key is not None: # Empty exchange indicates the default exchange, meaning the tasks # are sent to the queue with the same name as the routing key. - if isinstance(span, StreamedSpan): - span.set_attribute(SPANDATA.MESSAGING_DESTINATION_NAME, routing_key) - else: - span.set_data(SPANDATA.MESSAGING_DESTINATION_NAME, routing_key) + span.set_attribute(SPANDATA.MESSAGING_DESTINATION_NAME, routing_key) def _wrap_task_call(task: "Any", f: "F") -> "F": @@ -425,34 +367,17 @@ def _inner(*args: "Any", **kwargs: "Any") -> "Any": if client.get_integration(CeleryIntegration) is None: return f(*args, **kwargs) - span_streaming = has_span_streaming_enabled(client.options) - try: - if span_streaming and get_current_span() is None: + if sentry_sdk.get_current_span() is None: return f(*args, **kwargs) - span: "Union[Span, StreamedSpan]" - if span_streaming: - span = sentry_sdk.traces.start_span( - name=task.name, - attributes={ - "sentry.op": OP.QUEUE_PROCESS, - "sentry.origin": CeleryIntegration.origin, - }, - ) - else: - span = sentry_sdk.start_span( - op=OP.QUEUE_PROCESS, - name=task.name, - origin=CeleryIntegration.origin, - ) - - with span: - if isinstance(span, StreamedSpan): - set_on_span = span.set_attribute - else: - set_on_span = span.set_data - + with sentry_sdk.start_span( + name=task.name, + attributes={ + "sentry.op": OP.QUEUE_PROCESS, + "sentry.origin": CeleryIntegration.origin, + }, + ) as span: _set_messaging_destination_name(task, span) latency = None @@ -467,25 +392,28 @@ def _inner(*args: "Any", **kwargs: "Any") -> "Any": if latency is not None: latency *= 1000 # milliseconds - set_on_span(SPANDATA.MESSAGING_MESSAGE_RECEIVE_LATENCY, latency) + span.set_attribute( + SPANDATA.MESSAGING_MESSAGE_RECEIVE_LATENCY, latency + ) with capture_internal_exceptions(): - set_on_span(SPANDATA.MESSAGING_MESSAGE_ID, task.request.id) + span.set_attribute(SPANDATA.MESSAGING_MESSAGE_ID, task.request.id) with capture_internal_exceptions(): - set_on_span( + span.set_attribute( SPANDATA.MESSAGING_MESSAGE_RETRY_COUNT, task.request.retries, ) with capture_internal_exceptions(): with task.app.connection() as conn: - set_on_span( + span.set_attribute( SPANDATA.MESSAGING_SYSTEM, conn.transport.driver_type, ) return f(*args, **kwargs) + except Exception: exc_info = sys.exc_info() with capture_internal_exceptions(): @@ -560,8 +488,6 @@ def sentry_publish(self: "Producer", *args: "Any", **kwargs: "Any") -> "Any": if client.get_integration(CeleryIntegration) is None: return original_publish(self, *args, **kwargs) - span_streaming = has_span_streaming_enabled(client.options) - kwargs_headers = kwargs.get("headers", {}) if not isinstance(kwargs_headers, Mapping): # Ensure kwargs_headers is a Mapping, so we can safely call get(). @@ -578,45 +504,29 @@ def sentry_publish(self: "Producer", *args: "Any", **kwargs: "Any") -> "Any": routing_key = kwargs.get("routing_key") exchange = kwargs.get("exchange") - span: "Union[StreamedSpan, Span, None]" = None - if span_streaming: - if get_current_span() is not None: - span = sentry_sdk.traces.start_span( - name=task_name, - attributes={ - "sentry.op": OP.QUEUE_PUBLISH, - "sentry.origin": CeleryIntegration.origin, - }, - ) - else: - span = sentry_sdk.start_span( - op=OP.QUEUE_PUBLISH, - name=task_name, - origin=CeleryIntegration.origin, - ) - - if span is None: + if sentry_sdk.get_current_span() is None: return original_publish(self, *args, **kwargs) - with span: - if isinstance(span, StreamedSpan): - set_on_span = span.set_attribute - else: - set_on_span = span.set_data - + with sentry_sdk.start_span( + name=task_name, + attributes={ + "sentry.op": OP.QUEUE_PUBLISH, + "sentry.origin": CeleryIntegration.origin, + }, + ) as span: if task_id is not None: - set_on_span(SPANDATA.MESSAGING_MESSAGE_ID, task_id) + span.set_attribute(SPANDATA.MESSAGING_MESSAGE_ID, task_id) if exchange == "" and routing_key is not None: # Empty exchange indicates the default exchange, meaning messages are # routed to the queue with the same name as the routing key. - set_on_span(SPANDATA.MESSAGING_DESTINATION_NAME, routing_key) + span.set_attribute(SPANDATA.MESSAGING_DESTINATION_NAME, routing_key) if retries is not None: - set_on_span(SPANDATA.MESSAGING_MESSAGE_RETRY_COUNT, retries) + span.set_attribute(SPANDATA.MESSAGING_MESSAGE_RETRY_COUNT, retries) with capture_internal_exceptions(): - set_on_span( + span.set_attribute( SPANDATA.MESSAGING_SYSTEM, self.connection.transport.driver_type ) diff --git a/sentry_sdk/integrations/chalice.py b/sentry_sdk/integrations/chalice.py index 9baa0e5cdd..cfe2c13634 100644 --- a/sentry_sdk/integrations/chalice.py +++ b/sentry_sdk/integrations/chalice.py @@ -2,16 +2,14 @@ from functools import wraps import sentry_sdk -from sentry_sdk.integrations import DidNotEnable, Integration +from sentry_sdk.integrations import DidNotEnable, Integration, _check_minimum_version from sentry_sdk.integrations._wsgi_common import _filter_headers from sentry_sdk.integrations.aws_lambda import _make_request_event_processor from sentry_sdk.traces import ( + SegmentNameSource, + Span, SpanStatus, - StreamedSpan, - get_current_span, ) -from sentry_sdk.tracing import TransactionSource -from sentry_sdk.tracing_utils import has_span_streaming_enabled from sentry_sdk.utils import ( capture_internal_exceptions, event_from_exception, @@ -21,13 +19,14 @@ try: import chalice # type: ignore - from chalice import Chalice, ChaliceViewError + from chalice import ChaliceViewError from chalice import __version__ as CHALICE_VERSION from chalice.app import ( # type: ignore EventSourceHandler as ChaliceEventSourceHandler, ) + from chalice.app import RestAPIEventHandler except ImportError: - raise DidNotEnable("Chalice is not installed") + raise DidNotEnable("Chalice is not installed or incompatible") from typing import TYPE_CHECKING @@ -78,73 +77,58 @@ def wrapped_view_function(**function_args: "Any") -> "Any": ) ) - if has_span_streaming_enabled(client.options): - current_span = get_current_span() - segment = None - if type(current_span) is StreamedSpan: - # A segment already exists (created by the AWS Lambda - # integration), so decorate it with Chalice attributes - # The AWS Lambda integration owns the span lifecycle - # (end + flush), but Chalice converts unhandled view exceptions - # into 500 responses, so the error must be captured here. - request_dict = app.current_request.to_dict() - headers = request_dict.get("headers", {}) - - header_attrs: "Dict[str, Any]" = {} - for header, value in _filter_headers( - headers, use_annotated_value=False - ).items(): - header_attrs[f"http.request.header.{header.lower()}"] = value - - additional_attrs: "Dict[str, Any]" = {} - if "method" in request_dict: - additional_attrs["http.request.method"] = request_dict["method"] - - attributes = { - "sentry.origin": ChaliceIntegration.origin, - **header_attrs, - **additional_attrs, - } - - segment = current_span._segment - segment.set_attributes(attributes) - - try: - return view_function(**function_args) - except Exception as exc: - if isinstance(exc, ChaliceViewError): - raise - exc_info = sys.exc_info() - if segment: - segment.status = SpanStatus.ERROR.value - sentry_event, hint = event_from_exception( - exc_info, - client_options=client.options, - mechanism={"type": "chalice", "handled": False}, - ) - sentry_sdk.capture_event(sentry_event, hint=hint) - if segment is None: - client.flush() + scope.set_transaction_name( + app.lambda_context.function_name, + source=SegmentNameSource.COMPONENT, + ) + + current_span = sentry_sdk.get_current_span() + segment = None + if type(current_span) is Span: + # A segment already exists (created by the AWS Lambda + # integration), so decorate it with Chalice attributes + # The AWS Lambda integration owns the span lifecycle + # (end + flush), but Chalice converts unhandled view exceptions + # into 500 responses, so the error must be captured here. + request_dict = app.current_request.to_dict() + headers = request_dict.get("headers", {}) + + header_attrs: "Dict[str, Any]" = {} + for header, value in _filter_headers( + headers, use_annotated_value=False + ).items(): + header_attrs[f"http.request.header.{header.lower()}"] = value + + additional_attrs: "Dict[str, Any]" = {} + if "method" in request_dict: + additional_attrs["http.request.method"] = request_dict["method"] + + attributes = { + "sentry.origin": ChaliceIntegration.origin, + **header_attrs, + **additional_attrs, + } + + segment = current_span._segment + segment.set_attributes(attributes) + + try: + return view_function(**function_args) + except Exception as exc: + if isinstance(exc, ChaliceViewError): raise - else: - scope.set_transaction_name( - app.lambda_context.function_name, - source=TransactionSource.COMPONENT, + exc_info = sys.exc_info() + if segment: + segment.status = SpanStatus.ERROR.value + sentry_event, hint = event_from_exception( + exc_info, + client_options=client.options, + mechanism={"type": "chalice", "handled": False}, ) - try: - return view_function(**function_args) - except Exception as exc: - if isinstance(exc, ChaliceViewError): - raise - exc_info = sys.exc_info() - sentry_event, hint = event_from_exception( - exc_info, - client_options=client.options, - mechanism={"type": "chalice", "handled": False}, - ) - sentry_sdk.capture_event(sentry_event, hint=hint) + sentry_sdk.capture_event(sentry_event, hint=hint) + if segment is None: client.flush() - raise + raise return wrapped_view_function # type: ignore @@ -156,18 +140,11 @@ class ChaliceIntegration(Integration): @staticmethod def setup_once() -> None: version = parse_version(CHALICE_VERSION) - + _check_minimum_version(ChaliceIntegration, version) if version is None: - raise DidNotEnable("Unparsable Chalice version: {}".format(CHALICE_VERSION)) + return - if version < (1, 20): - old_get_view_function_response = Chalice._get_view_function_response - else: - from chalice.app import RestAPIEventHandler - - old_get_view_function_response = ( - RestAPIEventHandler._get_view_function_response - ) + old_get_view_function_response = RestAPIEventHandler._get_view_function_response def sentry_event_response( app: "Any", view_function: "F", function_args: "Dict[str, Any]" @@ -180,9 +157,7 @@ def sentry_event_response( app, wrapped_view_function, function_args ) - if version < (1, 20): - Chalice._get_view_function_response = sentry_event_response - else: - RestAPIEventHandler._get_view_function_response = sentry_event_response + RestAPIEventHandler._get_view_function_response = sentry_event_response + # for everything else (like events) chalice.app.EventSourceHandler = EventSourceHandler diff --git a/sentry_sdk/integrations/clickhouse_driver.py b/sentry_sdk/integrations/clickhouse_driver.py index 576c6fadd6..457ec3d626 100644 --- a/sentry_sdk/integrations/clickhouse_driver.py +++ b/sentry_sdk/integrations/clickhouse_driver.py @@ -4,18 +4,13 @@ import sentry_sdk from sentry_sdk.consts import OP, SPANDATA from sentry_sdk.integrations import DidNotEnable, Integration, _check_minimum_version -from sentry_sdk.scope import should_send_default_pii -from sentry_sdk.traces import StreamedSpan -from sentry_sdk.tracing import Span -from sentry_sdk.tracing_utils import has_span_streaming_enabled -from sentry_sdk.utils import capture_internal_exceptions, has_data_collection_enabled +from sentry_sdk.traces import Span # Hack to get new Python features working in older versions # without introducing a hard dependency on `typing_extensions` # from: https://stackoverflow.com/a/71944042/300572 if TYPE_CHECKING: - from collections.abc import Iterator - from typing import Any, Callable, Optional, ParamSpec, Union + from typing import Any, Callable, Optional, ParamSpec else: # Fake ParamSpec class ParamSpec: @@ -40,7 +35,7 @@ def __getitem__(self, _): ) except ImportError: - raise DidNotEnable("clickhouse-driver not installed.") + raise DidNotEnable("clickhouse-driver not installed or incompatible") class ClickhouseDriverIntegration(Integration): @@ -81,48 +76,27 @@ def _inner(*args: "P.args", **kwargs: "P.kwargs") -> "T": connection: "Connection" = args[0] query = args[1] - query_id = args[2] if len(args) > 2 else kwargs.get("query_id") - params = args[3] if len(args) > 3 else kwargs.get("params") - - if has_span_streaming_enabled(client.options): - span = None - if sentry_sdk.traces.get_current_span() is not None: - span = sentry_sdk.traces.start_span( - name=query, # type: ignore - attributes={ - "sentry.op": OP.DB, - "sentry.origin": ClickhouseDriverIntegration.origin, - SPANDATA.DB_QUERY_TEXT: str(query), - }, - ) - - connection._query = query - connection._breadcrumb_data = { - SPANDATA.DB_SYSTEM: "clickhouse", - SPANDATA.DB_NAME: connection.database, - SPANDATA.DB_DRIVER_NAME: "clickhouse-driver", - SPANDATA.SERVER_ADDRESS: connection.host, - SPANDATA.SERVER_PORT: connection.port, - SPANDATA.DB_USER: connection.user, - } - else: + + span = None + if sentry_sdk.get_current_span() is not None: span = sentry_sdk.start_span( - op=OP.DB, name=query, - origin=ClickhouseDriverIntegration.origin, + attributes={ + "sentry.op": OP.DB, + "sentry.origin": ClickhouseDriverIntegration.origin, + SPANDATA.DB_QUERY_TEXT: str(query), + }, ) - span.set_data("query", query) - - if query_id: - span.set_data("db.query_id", query_id) - - if params: - if has_data_collection_enabled(client.options): - if client.options["data_collection"]["database_query_data"]: - span.set_data("db.params", params) - elif should_send_default_pii(): - span.set_data("db.params", params) + connection._query = query + connection._breadcrumb_data = { + SPANDATA.DB_SYSTEM: "clickhouse", + SPANDATA.DB_NAME: connection.database, + SPANDATA.DB_DRIVER_NAME: "clickhouse-driver", + SPANDATA.SERVER_ADDRESS: connection.host, + SPANDATA.SERVER_PORT: connection.port, + SPANDATA.DB_USER: connection.user, + } connection._sentry_span = span @@ -149,13 +123,7 @@ def _inner_end(*args: "P.args", **kwargs: "P.kwargs") -> "T": if query is not None and breadcrumb_data is not None: client_options = sentry_sdk.get_client().options - if ( - has_data_collection_enabled(client_options) - and client_options["data_collection"]["database_query_data"] - ) or ( - not has_data_collection_enabled(client_options) - and should_send_default_pii() - ): + if client_options["data_collection"]["database_query_data"]: breadcrumb_data = {"db.result": res, **breadcrumb_data} sentry_sdk.get_isolation_scope().add_breadcrumb( @@ -169,23 +137,7 @@ def _inner_end(*args: "P.args", **kwargs: "P.kwargs") -> "T": if span is None: return res - if isinstance(span, StreamedSpan): - span.end() - else: - if res is not None: - client_options = sentry_sdk.get_client().options - if has_data_collection_enabled(client_options): - if client_options["data_collection"]["database_query_data"]: - span.set_data("db.result", res) - elif should_send_default_pii(): - span.set_data("db.result", res) - - with capture_internal_exceptions(): - span.scope.add_breadcrumb( - message=span._data.pop("query"), category="query", data=span._data - ) - - span.finish() + span.end() return res @@ -198,61 +150,9 @@ def _wrap_send_data() -> None: def _inner_send_data( # type: ignore[no-untyped-def] # clickhouse-driver does not type send_data self, sample_block, data, types_check=False, columnar=False, *args, **kwargs ): - span = getattr(self.connection, "_sentry_span", None) - - if isinstance(span, StreamedSpan): - _set_db_data(span, self.connection) - return original_send_data( - self, sample_block, data, types_check, columnar, *args, **kwargs - ) - - if span is not None: - _set_db_data(span, self.connection) - - client_options = sentry_sdk.get_client().options - if has_data_collection_enabled(client_options): - if client_options["data_collection"]["database_query_data"]: - db_params = span._data.get("db.params", []) - if isinstance(data, (list, tuple)): - db_params.extend(data) - - else: # data is a generic iterator - orig_data = data - - # Wrap the generator to add items to db.params as they are yielded. - # This allows us to send the params to Sentry without needing to allocate - # memory for the entire generator at once. - def wrapped_generator() -> "Iterator[Any]": - for item in orig_data: - db_params.append(item) - yield item - - # Replace the original iterator with the wrapped one. - data = wrapped_generator() - - span.set_data("db.params", db_params) - elif should_send_default_pii(): - db_params = span._data.get("db.params", []) - - if isinstance(data, (list, tuple)): - db_params.extend(data) - - else: # data is a generic iterator - orig_data = data - - # Wrap the generator to add items to db.params as they are yielded. - # This allows us to send the params to Sentry without needing to allocate - # memory for the entire generator at once. - def wrapped_generator() -> "Iterator[Any]": - for item in orig_data: - db_params.append(item) - yield item - - # Replace the original iterator with the wrapped one. - data = wrapped_generator() - - span.set_data("db.params", db_params) + span: "Optional[Span]" = getattr(self.connection, "_sentry_span", None) + _set_db_data(span, self.connection) return original_send_data( self, sample_block, data, types_check, columnar, *args, **kwargs ) @@ -260,19 +160,13 @@ def wrapped_generator() -> "Iterator[Any]": Client.send_data = _inner_send_data -def _set_db_data(span: "Union[Span, StreamedSpan]", connection: "Connection") -> None: - if isinstance(span, StreamedSpan): - span.set_attribute(SPANDATA.DB_SYSTEM_NAME, "clickhouse") - span.set_attribute(SPANDATA.DB_NAMESPACE, connection.database) - - set_on_span = span.set_attribute - else: - span.set_data(SPANDATA.DB_SYSTEM, "clickhouse") - span.set_data(SPANDATA.DB_NAME, connection.database) - - set_on_span = span.set_data +def _set_db_data(span: "Optional[Span]", connection: "Connection") -> None: + if span is None: + return - set_on_span(SPANDATA.DB_DRIVER_NAME, "clickhouse-driver") - set_on_span(SPANDATA.SERVER_ADDRESS, connection.host) - set_on_span(SPANDATA.SERVER_PORT, connection.port) - set_on_span(SPANDATA.DB_USER, connection.user) + span.set_attribute(SPANDATA.DB_SYSTEM_NAME, "clickhouse") + span.set_attribute(SPANDATA.DB_NAMESPACE, connection.database) + span.set_attribute(SPANDATA.DB_DRIVER_NAME, "clickhouse-driver") + span.set_attribute(SPANDATA.SERVER_ADDRESS, connection.host) + span.set_attribute(SPANDATA.SERVER_PORT, connection.port) + span.set_attribute(SPANDATA.DB_USER, connection.user) diff --git a/sentry_sdk/integrations/cohere.py b/sentry_sdk/integrations/cohere.py index 9cac912a2b..4fbb21e68e 100644 --- a/sentry_sdk/integrations/cohere.py +++ b/sentry_sdk/integrations/cohere.py @@ -4,23 +4,22 @@ from sentry_sdk import consts from sentry_sdk.ai.monitoring import record_token_usage -from sentry_sdk.ai.utils import get_start_span_function, set_data_normalized +from sentry_sdk.ai.utils import set_data_normalized from sentry_sdk.consts import SPANDATA -from sentry_sdk.traces import StreamedSpan -from sentry_sdk.tracing_utils import has_span_streaming_enabled +from sentry_sdk.traces import Span if TYPE_CHECKING: - from typing import Any, Callable, Iterator, Union + from typing import Any, Callable, Iterator - from sentry_sdk.tracing import Span import sentry_sdk -from sentry_sdk.integrations import DidNotEnable, Integration +from sentry_sdk.integrations import DidNotEnable, Integration, _check_minimum_version from sentry_sdk.scope import should_send_default_pii from sentry_sdk.utils import ( capture_internal_exceptions, event_from_exception, has_data_collection_enabled, + parse_version, reraise, ) @@ -29,13 +28,16 @@ ChatStreamEndEvent, NonStreamedChatResponse, ) + from cohere import ( + __version__ as COHERE_VERSION, + ) from cohere.base_client import BaseCohere from cohere.client import Client if TYPE_CHECKING: from cohere import StreamedChatResponse except ImportError: - raise DidNotEnable("Cohere not installed") + raise DidNotEnable("Cohere not installed or incompatible") try: # cohere 5.9.3+ @@ -78,22 +80,22 @@ class CohereIntegration(Integration): identifier = "cohere" origin = f"auto.ai.{identifier}" - def __init__(self: "CohereIntegration", include_prompts: bool = True) -> None: - self.include_prompts = include_prompts - @staticmethod def setup_once() -> None: + version = parse_version(COHERE_VERSION) + _check_minimum_version(CohereIntegration, version) + BaseCohere.chat = _wrap_chat(BaseCohere.chat, streaming=False) Client.embed = _wrap_embed(Client.embed) BaseCohere.chat_stream = _wrap_chat(BaseCohere.chat_stream, streaming=True) -def _should_record(integration: "CohereIntegration", category: str) -> bool: +def _should_record(category: str) -> bool: client = sentry_sdk.get_client() if has_data_collection_enabled(client.options): return bool(client.options["data_collection"]["gen_ai"][category]) - return should_send_default_pii() and integration.include_prompts + return should_send_default_pii() def _capture_exception(exc: "Any") -> None: @@ -105,16 +107,9 @@ def _capture_exception(exc: "Any") -> None: sentry_sdk.capture_event(event, hint=hint) -def _end_span(span: "Any") -> None: - if isinstance(span, StreamedSpan): - span.end() - else: - span.__exit__(None, None, None) - - def _wrap_chat(f: "Callable[..., Any]", streaming: bool) -> "Callable[..., Any]": def collect_chat_response_fields( - span: "Union[Span, StreamedSpan]", + span: "Span", res: "NonStreamedChatResponse", include_pii: bool, ) -> None: @@ -153,9 +148,6 @@ def collect_chat_response_fields( @wraps(f) def new_chat(*args: "Any", **kwargs: "Any") -> "Any": integration = sentry_sdk.get_client().get_integration(CohereIntegration) - is_span_streaming_enabled = has_span_streaming_enabled( - sentry_sdk.get_client().options - ) if ( integration is None @@ -166,21 +158,14 @@ def new_chat(*args: "Any", **kwargs: "Any") -> "Any": message = kwargs.get("message") - if is_span_streaming_enabled: - span = sentry_sdk.traces.start_span( - name="cohere.client.Chat", - attributes={ - "sentry.op": consts.OP.COHERE_CHAT_COMPLETIONS_CREATE, - "sentry.origin": CohereIntegration.origin, - }, - ) - else: - span = get_start_span_function()( - op=consts.OP.COHERE_CHAT_COMPLETIONS_CREATE, - name="cohere.client.Chat", - origin=CohereIntegration.origin, - ) - span.__enter__() + span = sentry_sdk.start_span( + name="cohere.client.Chat", + attributes={ + "sentry.op": consts.OP.COHERE_CHAT_COMPLETIONS_CREATE, + "sentry.origin": CohereIntegration.origin, + }, + ) + try: res = f(*args, **kwargs) except Exception as e: @@ -192,7 +177,7 @@ def new_chat(*args: "Any", **kwargs: "Any") -> "Any": reraise(*exc_info) with capture_internal_exceptions(): - if _should_record(integration, "inputs"): + if _should_record("inputs"): set_data_normalized( span, SPANDATA.AI_INPUT_MESSAGES, @@ -228,22 +213,22 @@ def new_iterator() -> "Iterator[StreamedChatResponse]": collect_chat_response_fields( span, x.response, - include_pii=_should_record(integration, "outputs"), + include_pii=_should_record("outputs"), ) yield x - _end_span(span) + span.end() return new_iterator() elif isinstance(res, NonStreamedChatResponse): collect_chat_response_fields( span, res, - include_pii=_should_record(integration, "outputs"), + include_pii=_should_record("outputs"), ) - _end_span(span) + span.end() else: set_data_normalized(span, "unknown_response", True) - _end_span(span) + span.end() return res return new_chat @@ -256,27 +241,14 @@ def new_embed(*args: "Any", **kwargs: "Any") -> "Any": if integration is None: return f(*args, **kwargs) - is_span_streaming_enabled = has_span_streaming_enabled( - sentry_sdk.get_client().options - ) - - if is_span_streaming_enabled: - span_ctx = sentry_sdk.traces.start_span( - name="Cohere Embedding Creation", - attributes={ - "sentry.op": consts.OP.COHERE_EMBEDDINGS_CREATE, - "sentry.origin": CohereIntegration.origin, - }, - ) - else: - span_ctx = get_start_span_function()( - op=consts.OP.COHERE_EMBEDDINGS_CREATE, - name="Cohere Embedding Creation", - origin=CohereIntegration.origin, - ) - - with span_ctx as span: - if "texts" in kwargs and _should_record(integration, "inputs"): + with sentry_sdk.start_span( + name="Cohere Embedding Creation", + attributes={ + "sentry.op": consts.OP.COHERE_EMBEDDINGS_CREATE, + "sentry.origin": CohereIntegration.origin, + }, + ) as span: + if "texts" in kwargs and _should_record("inputs"): if isinstance(kwargs["texts"], str): set_data_normalized(span, SPANDATA.AI_TEXTS, [kwargs["texts"]]) elif ( diff --git a/sentry_sdk/integrations/dedupe.py b/sentry_sdk/integrations/dedupe.py index a0e9014666..a0cc88081f 100644 --- a/sentry_sdk/integrations/dedupe.py +++ b/sentry_sdk/integrations/dedupe.py @@ -1,13 +1,14 @@ import weakref +from contextvars import ContextVar from typing import TYPE_CHECKING import sentry_sdk from sentry_sdk.integrations import Integration from sentry_sdk.scope import add_global_event_processor -from sentry_sdk.utils import ContextVar, logger +from sentry_sdk.utils import logger if TYPE_CHECKING: - from typing import Optional + from typing import Any, Optional from sentry_sdk._types import Event, Hint @@ -16,7 +17,7 @@ class DedupeIntegration(Integration): identifier = "dedupe" def __init__(self) -> None: - self._last_seen = ContextVar("last-seen") + self._last_seen: "ContextVar[Any]" = ContextVar("last-seen") @staticmethod def setup_once() -> None: diff --git a/sentry_sdk/integrations/django/__init__.py b/sentry_sdk/integrations/django/__init__.py index bff2982d35..c362277038 100644 --- a/sentry_sdk/integrations/django/__init__.py +++ b/sentry_sdk/integrations/django/__init__.py @@ -17,27 +17,22 @@ DEFAULT_HTTP_METHODS_TO_CAPTURE, RequestExtractor, ) -from sentry_sdk.integrations.logging import ignore_logger +from sentry_sdk.integrations.logging import ignore_logger_for_events from sentry_sdk.integrations.wsgi import SentryWsgiMiddleware from sentry_sdk.scope import add_global_event_processor, should_send_default_pii from sentry_sdk.serializer import add_global_repr_processor, add_repr_sequence_type -from sentry_sdk.traces import StreamedSpan -from sentry_sdk.tracing import SOURCE_FOR_STYLE, TransactionSource +from sentry_sdk.traces import SOURCE_FOR_STYLE, SegmentNameSource from sentry_sdk.tracing_utils import ( add_query_source, - has_span_streaming_enabled, record_sql_queries, ) from sentry_sdk.utils import ( - CONTEXTVARS_ERROR_MESSAGE, - HAS_REAL_CONTEXTVARS, SENSITIVE_DATA_SUBSTITUTE, AnnotatedValue, capture_internal_exceptions, ensure_integration_enabled, event_from_exception, has_data_collection_enabled, - logger, transaction_from_function, walk_exception_chain, ) @@ -45,20 +40,10 @@ try: from django import VERSION as DJANGO_VERSION from django.conf import settings - from django.conf import settings as django_settings from django.core import signals + from django.urls import Resolver404, resolve from django.utils.functional import SimpleLazyObject - try: - from django.urls import resolve - except ImportError: - from django.core.urlresolvers import resolve - - try: - from django.urls import Resolver404 - except ImportError: - from django.core.urlresolvers import Resolver404 - # Only available in Django 3.0+ try: from django.core.handlers.asgi import ASGIRequest @@ -68,6 +53,9 @@ except ImportError: raise DidNotEnable("Django not installed") +from typing import TYPE_CHECKING + +from sentry_sdk.integrations.django.caching import patch_caching from sentry_sdk.integrations.django.middleware import patch_django_middlewares from sentry_sdk.integrations.django.signals_handlers import patch_signals from sentry_sdk.integrations.django.tasks import patch_tasks @@ -78,13 +66,6 @@ from sentry_sdk.integrations.django.transactions import LEGACY_RESOLVER from sentry_sdk.integrations.django.views import patch_views -if DJANGO_VERSION[:2] > (1, 8): - from sentry_sdk.integrations.django.caching import patch_caching -else: - patch_caching = None # type: ignore - -from typing import TYPE_CHECKING - if TYPE_CHECKING: from collections.abc import Set from typing import Any, Callable, Dict, List, Optional, Union @@ -102,19 +83,7 @@ NotImplementedType, ) from sentry_sdk.integrations.wsgi import _ScopedResponse - from sentry_sdk.traces import StreamedSpan - from sentry_sdk.tracing import Span - - -if DJANGO_VERSION < (1, 10): - - def is_authenticated(request_user: "Any") -> bool: - return request_user.is_authenticated() - -else: - - def is_authenticated(request_user: "Any") -> bool: - return request_user.is_authenticated + from sentry_sdk.traces import Span TRANSACTION_STYLE_VALUES = ("function_name", "url") @@ -128,7 +97,7 @@ class DjangoIntegration(Integration): :param middleware_spans: Whether to create spans for middleware. Defaults to `False`. :param signals_spans: Whether to create spans for signals. Defaults to `True`. :param signals_denylist: A list of signals to ignore when creating spans. - :param cache_spans: Whether to create spans for cache operations. Defaults to `False`. + :param cache_spans: Whether to create spans for cache operations. Defaults to `True`. :param failed_request_status_codes: Which HTTP error responses to report to Sentry. Django answers some exceptions itself instead of failing: `raise Http404` gets the user a 404 page, `PermissionDenied` a 403. Those are reported only if their @@ -151,7 +120,7 @@ def __init__( transaction_style: str = "url", middleware_spans: bool = False, signals_spans: bool = True, - cache_spans: bool = False, + cache_spans: bool = True, db_transaction_spans: bool = False, signals_denylist: "Optional[list[signals.Signal]]" = None, http_methods_to_capture: "tuple[str, ...]" = DEFAULT_HTTP_METHODS_TO_CAPTURE, @@ -184,8 +153,8 @@ def setup_once() -> None: # Patch in our custom middleware. # logs an error for every 500 - ignore_logger("django.server") - ignore_logger("django.request") + ignore_logger_for_events("django.server") + ignore_logger_for_events("django.request") from django.core.handlers.wsgi import WSGIHandler @@ -300,9 +269,7 @@ def _django_queryset_repr( patch_signals() patch_tasks() add_template_context_repr_sequence() - - if patch_caching is not None: - patch_caching() + patch_caching() _DRF_PATCHED = False @@ -380,27 +347,21 @@ def sentry_patched_drf_authenticate(self: "Request") -> "Any": integration = client.get_integration(DjangoIntegration) # Nothing to time if there are no authenticators configured # for this view. - if integration is None or not getattr(self, "authenticators", None): + if ( + integration is None + or not getattr(self, "authenticators", None) + or sentry_sdk.get_current_span() is None + ): return old_drf_authenticate(self) - if has_span_streaming_enabled(client.options): - if sentry_sdk.traces.get_current_span() is None: - return old_drf_authenticate(self) - with sentry_sdk.traces.start_span( - name="authenticate", - attributes={ - "sentry.op": OP.VIEW_AUTHENTICATE, - "sentry.origin": DjangoIntegration.origin, - }, - ): - return old_drf_authenticate(self) - else: - with sentry_sdk.start_span( - op=OP.VIEW_AUTHENTICATE, - name="authenticate", - origin=DjangoIntegration.origin, - ): - return old_drf_authenticate(self) + with sentry_sdk.start_span( + name="authenticate", + attributes={ + "sentry.op": OP.VIEW_AUTHENTICATE, + "sentry.origin": DjangoIntegration.origin, + }, + ): + return old_drf_authenticate(self) Request._authenticate = sentry_patched_drf_authenticate @@ -411,19 +372,6 @@ def _patch_channels() -> None: except ImportError: return - if not HAS_REAL_CONTEXTVARS: - # We better have contextvars or we're going to leak state between - # requests. - # - # We cannot hard-raise here because channels may not be used at all in - # the current process. That is the case when running traditional WSGI - # workers in gunicorn+gevent and the websocket stuff in a separate - # process. - logger.warning( - "We detected that you are using Django channels 2.0." - + CONTEXTVARS_ERROR_MESSAGE - ) - from sentry_sdk.integrations.django.asgi import patch_channels_asgi_handler_impl patch_channels_asgi_handler_impl(AsgiHandler) @@ -435,16 +383,6 @@ def _patch_django_asgi_handler() -> None: except ImportError: return - if not HAS_REAL_CONTEXTVARS: - # We better have contextvars or we're going to leak state between - # requests. - # - # We cannot hard-raise here because Django's ASGI stuff may not be used - # at all. - logger.warning( - "We detected that you are using Django 3." + CONTEXTVARS_ERROR_MESSAGE - ) - from sentry_sdk.integrations.django.asgi import patch_django_asgi_handler_impl patch_django_asgi_handler_impl(ASGIHandler) @@ -467,7 +405,7 @@ def _set_transaction_name_and_source( if transaction_name is None: transaction_name = request.path_info - source = TransactionSource.URL + source = SegmentNameSource.URL else: source = SOURCE_FOR_STYLE[transaction_style] @@ -487,11 +425,13 @@ def _set_transaction_name_and_source( if hasattr(urlconf, "handler404"): handler = urlconf.handler404 if isinstance(handler, str): - scope.transaction = handler + scope.set_transaction_name(handler) else: - scope.transaction = transaction_from_function( + name = transaction_from_function( getattr(handler, "view_class", handler) ) + if name: + scope.set_transaction_name(name) except Exception: pass @@ -578,7 +518,7 @@ def _get_user_from_request_and_set_on_scope(request: "WSGIRequest") -> None: elif is_lazy: return - if user is None or not is_authenticated(user): + if user is None or not user.is_authenticated: return user_info = {} @@ -610,13 +550,11 @@ def _after_get_response(request: "WSGIRequest") -> None: scope = sentry_sdk.get_current_scope() _attempt_resolve_again(request, scope, integration.transaction_style) - span_streaming = has_span_streaming_enabled(client.options) - if span_streaming: - if has_data_collection_enabled(client.options): - if client.options["data_collection"]["user_info"]: - _get_user_from_request_and_set_on_scope(request) - elif should_send_default_pii(): + if has_data_collection_enabled(client.options): + if client.options["data_collection"]["user_info"]: _get_user_from_request_and_set_on_scope(request) + elif should_send_default_pii(): + _get_user_from_request_and_set_on_scope(request) def _patch_get_response() -> None: @@ -780,8 +718,8 @@ def env(self) -> "Dict[str, str]": def cookies(self) -> "Dict[str, Union[str, AnnotatedValue]]": privacy_cookies = [ - django_settings.CSRF_COOKIE_NAME, - django_settings.SESSION_COOKIE_NAME, + settings.CSRF_COOKIE_NAME, + settings.SESSION_COOKIE_NAME, ] clean_cookies: "Dict[str, Union[str, AnnotatedValue]]" = {} @@ -817,7 +755,7 @@ def _set_user_info(request: "WSGIRequest", event: "Event") -> None: user = getattr(request, "user", None) - if user is None or not is_authenticated(user): + if user is None or not user.is_authenticated: return try: @@ -838,27 +776,14 @@ def _set_user_info(request: "WSGIRequest", event: "Event") -> None: def install_sql_hook() -> None: """If installed this causes Django's queries to be captured.""" - try: - from django.db.backends.utils import CursorWrapper - except ImportError: - from django.db.backends.util import CursorWrapper + from django.db.backends.base.base import BaseDatabaseWrapper + from django.db.backends.utils import CursorWrapper - try: - # django 1.6 and 1.7 compatability - from django.db.backends import BaseDatabaseWrapper - except ImportError: - # django 1.8 or later - from django.db.backends.base.base import BaseDatabaseWrapper - - try: - real_execute = CursorWrapper.execute - real_executemany = CursorWrapper.executemany - real_connect = BaseDatabaseWrapper.connect - real_commit = BaseDatabaseWrapper._commit - real_rollback = BaseDatabaseWrapper._rollback - except AttributeError: - # This won't work on Django versions < 1.6 - return + real_execute = CursorWrapper.execute + real_executemany = CursorWrapper.executemany + real_connect = BaseDatabaseWrapper.connect + real_commit = BaseDatabaseWrapper._commit + real_rollback = BaseDatabaseWrapper._rollback @ensure_integration_enabled(DjangoIntegration, real_execute) def execute( @@ -875,11 +800,6 @@ def execute( _set_db_data(span, self) result = real_execute(self, sql, params) - if isinstance(span, StreamedSpan): - with capture_internal_exceptions(): - add_query_source(span) - - if not isinstance(span, StreamedSpan): with capture_internal_exceptions(): add_query_source(span) @@ -901,11 +821,6 @@ def executemany( result = real_executemany(self, sql, param_list) - if isinstance(span, StreamedSpan): - with capture_internal_exceptions(): - add_query_source(span) - - if not isinstance(span, StreamedSpan): with capture_internal_exceptions(): add_query_source(span) @@ -916,27 +831,17 @@ def connect(self: "BaseDatabaseWrapper") -> None: with capture_internal_exceptions(): sentry_sdk.add_breadcrumb(message="connect", category="query") - span_streaming = has_span_streaming_enabled(sentry_sdk.get_client().options) - if span_streaming: - if sentry_sdk.traces.get_current_span() is None: - return real_connect(self) - with sentry_sdk.traces.start_span( - name="connect", - attributes={ - "sentry.op": OP.DB, - "sentry.origin": DjangoIntegration.origin_db, - }, - ) as span: - _set_db_data(span, self) - return real_connect(self) - else: - with sentry_sdk.start_span( - op=OP.DB, - name="connect", - origin=DjangoIntegration.origin_db, - ) as span: - _set_db_data(span, self) - return real_connect(self) + if sentry_sdk.get_current_span() is None: + return real_connect(self) + with sentry_sdk.start_span( + name="connect", + attributes={ + "sentry.op": OP.DB, + "sentry.origin": DjangoIntegration.origin_db, + }, + ) as span: + _set_db_data(span, self) + return real_connect(self) def _commit(self: "BaseDatabaseWrapper") -> None: integration = sentry_sdk.get_client().get_integration(DjangoIntegration) @@ -944,27 +849,18 @@ def _commit(self: "BaseDatabaseWrapper") -> None: if integration is None or not integration.db_transaction_spans: return real_commit(self) - span_streaming = has_span_streaming_enabled(sentry_sdk.get_client().options) - if span_streaming: - if sentry_sdk.traces.get_current_span() is None: - return real_commit(self) - with sentry_sdk.traces.start_span( - name=SPANNAME.DB_COMMIT, - attributes={ - "sentry.op": OP.DB, - "sentry.origin": DjangoIntegration.origin_db, - }, - ) as span: - _set_db_data(span, self, SPANNAME.DB_COMMIT) - return real_commit(self) - else: - with sentry_sdk.start_span( - op=OP.DB, - name=SPANNAME.DB_COMMIT, - origin=DjangoIntegration.origin_db, - ) as span: - _set_db_data(span, self, SPANNAME.DB_COMMIT) - return real_commit(self) + if sentry_sdk.get_current_span() is None: + return real_commit(self) + + with sentry_sdk.start_span( + name=SPANNAME.DB_COMMIT, + attributes={ + "sentry.op": OP.DB, + "sentry.origin": DjangoIntegration.origin_db, + }, + ) as span: + _set_db_data(span, self, SPANNAME.DB_COMMIT) + return real_commit(self) def _rollback(self: "BaseDatabaseWrapper") -> None: integration = sentry_sdk.get_client().get_integration(DjangoIntegration) @@ -972,53 +868,38 @@ def _rollback(self: "BaseDatabaseWrapper") -> None: if integration is None or not integration.db_transaction_spans: return real_rollback(self) - span_streaming = has_span_streaming_enabled(sentry_sdk.get_client().options) - if span_streaming: - if sentry_sdk.traces.get_current_span() is None: - return real_rollback(self) - with sentry_sdk.traces.start_span( - name=SPANNAME.DB_ROLLBACK, - attributes={ - "sentry.op": OP.DB, - "sentry.origin": DjangoIntegration.origin_db, - }, - ) as span: - _set_db_data(span, self, SPANNAME.DB_ROLLBACK) - return real_rollback(self) - else: - with sentry_sdk.start_span( - op=OP.DB, - name=SPANNAME.DB_ROLLBACK, - origin=DjangoIntegration.origin_db, - ) as span: - _set_db_data(span, self, SPANNAME.DB_ROLLBACK) - return real_rollback(self) + if sentry_sdk.get_current_span() is None: + return real_rollback(self) + + with sentry_sdk.start_span( + name=SPANNAME.DB_ROLLBACK, + attributes={ + "sentry.op": OP.DB, + "sentry.origin": DjangoIntegration.origin_db, + }, + ) as span: + _set_db_data(span, self, SPANNAME.DB_ROLLBACK) + return real_rollback(self) CursorWrapper.execute = execute CursorWrapper.executemany = executemany BaseDatabaseWrapper.connect = connect BaseDatabaseWrapper._commit = _commit BaseDatabaseWrapper._rollback = _rollback - ignore_logger("django.db.backends") + ignore_logger_for_events("django.db.backends") def _set_db_data( - span: "Union[Span, StreamedSpan]", + span: "Span", cursor_or_db: "Any", db_operation: "Optional[str]" = None, ) -> None: db = cursor_or_db.db if hasattr(cursor_or_db, "db") else cursor_or_db vendor = db.vendor - if isinstance(span, StreamedSpan): - span.set_attribute(SPANDATA.DB_SYSTEM_NAME, vendor) - - if db_operation is not None: - span.set_attribute(SPANDATA.DB_OPERATION_NAME, db_operation) - else: - span.set_data(SPANDATA.DB_SYSTEM, vendor) + span.set_attribute(SPANDATA.DB_SYSTEM_NAME, vendor) - if db_operation is not None: - span.set_data(SPANDATA.DB_OPERATION, db_operation) + if db_operation is not None: + span.set_attribute(SPANDATA.DB_OPERATION_NAME, db_operation) # Some custom backends override `__getattr__`, making it look like `cursor_or_db` # actually has a `connection` and the `connection` has a `get_dsn_parameters` @@ -1051,28 +932,20 @@ def _set_db_data( db_name = connection_params.get("dbname") or connection_params.get("database") - if isinstance(span, StreamedSpan): - if db_name is not None: - span.set_attribute(SPANDATA.DB_NAMESPACE, db_name) - - set_on_span = span.set_attribute - else: - if db_name is not None: - span.set_data(SPANDATA.DB_NAME, db_name) - - set_on_span = span.set_data + if db_name is not None: + span.set_attribute(SPANDATA.DB_NAMESPACE, db_name) server_address = connection_params.get("host") if server_address is not None: - set_on_span(SPANDATA.SERVER_ADDRESS, server_address) + span.set_attribute(SPANDATA.SERVER_ADDRESS, server_address) server_port = connection_params.get("port") if server_port is not None: - set_on_span(SPANDATA.SERVER_PORT, str(server_port)) + span.set_attribute(SPANDATA.SERVER_PORT, str(server_port)) server_socket_address = connection_params.get("unix_socket") if server_socket_address is not None: - set_on_span(SPANDATA.SERVER_SOCKET_ADDRESS, server_socket_address) + span.set_attribute(SPANDATA.SERVER_SOCKET_ADDRESS, server_socket_address) def add_template_context_repr_sequence() -> None: diff --git a/sentry_sdk/integrations/django/asgi.py b/sentry_sdk/integrations/django/asgi.py index df287e6436..d237c4d946 100644 --- a/sentry_sdk/integrations/django/asgi.py +++ b/sentry_sdk/integrations/django/asgi.py @@ -17,8 +17,7 @@ from sentry_sdk.consts import OP from sentry_sdk.integrations.asgi import SentryAsgiMiddleware from sentry_sdk.scope import should_send_default_pii -from sentry_sdk.traces import StreamedSpan -from sentry_sdk.tracing_utils import has_span_streaming_enabled +from sentry_sdk.traces import Span from sentry_sdk.utils import ( capture_internal_exceptions, ensure_integration_enabled, @@ -99,7 +98,6 @@ async def sentry_patched_asgi_handler( middleware = SentryAsgiMiddleware( old_app.__get__(self, cls), - unsafe_context_data=True, span_origin=DjangoIntegration.origin, http_methods_to_capture=integration.http_methods_to_capture, )._run_asgi3 @@ -154,7 +152,6 @@ async def sentry_patched_asgi_handler( middleware = SentryAsgiMiddleware( lambda _scope: old_app.__get__(self, cls), - unsafe_context_data=True, span_origin=DjangoIntegration.origin, http_methods_to_capture=integration.http_methods_to_capture, ) @@ -177,43 +174,26 @@ async def sentry_wrapped_callback( request: "Any", *args: "Any", **kwargs: "Any" ) -> "Any": client = sentry_sdk.get_client() - span_streaming = has_span_streaming_enabled(client.options) - current_scope = sentry_sdk.get_current_scope() - if span_streaming: - current_span = current_scope.streamed_span - if type(current_span) is StreamedSpan: - segment = current_span._segment - segment._update_active_thread() - else: - if current_scope.transaction is not None: - current_scope.transaction.update_active_thread() - - sentry_scope = sentry_sdk.get_isolation_scope() - if sentry_scope.profile is not None: - sentry_scope.profile.update_active_thread_id() + current_span = sentry_sdk.get_current_span() + if type(current_span) is Span: + segment = current_span._segment + segment._update_active_thread() integration = client.get_integration(DjangoIntegration) if not integration or not integration.middleware_spans: return await callback(request, *args, **kwargs) - if span_streaming: - if sentry_sdk.traces.get_current_span() is None: - return await callback(request, *args, **kwargs) - with sentry_sdk.traces.start_span( - name=request.resolver_match.view_name, - attributes={ - "sentry.op": OP.VIEW_RENDER, - "sentry.origin": DjangoIntegration.origin, - }, - ): - return await callback(request, *args, **kwargs) - else: - with sentry_sdk.start_span( - op=OP.VIEW_RENDER, - name=request.resolver_match.view_name, - origin=DjangoIntegration.origin, - ): - return await callback(request, *args, **kwargs) + if current_span is None: + return await callback(request, *args, **kwargs) + + with sentry_sdk.start_span( + name=request.resolver_match.view_name, + attributes={ + "sentry.op": OP.VIEW_RENDER, + "sentry.origin": DjangoIntegration.origin, + }, + ): + return await callback(request, *args, **kwargs) return sentry_wrapped_callback diff --git a/sentry_sdk/integrations/django/caching.py b/sentry_sdk/integrations/django/caching.py index 2cfc0cd2e1..24bf8a6c08 100644 --- a/sentry_sdk/integrations/django/caching.py +++ b/sentry_sdk/integrations/django/caching.py @@ -8,7 +8,6 @@ import sentry_sdk from sentry_sdk.consts import OP, SPANDATA from sentry_sdk.integrations.redis.utils import _get_safe_key, _key_as_string -from sentry_sdk.tracing_utils import has_span_streaming_enabled from sentry_sdk.utils import ( capture_internal_exceptions, ensure_integration_enabled, @@ -59,113 +58,61 @@ def _instrument_call( op = OP.CACHE_PUT if is_set_operation else OP.CACHE_GET description = _get_span_description(method_name, args, kwargs) - span_streaming = has_span_streaming_enabled(sentry_sdk.get_client().options) - if span_streaming: - if sentry_sdk.traces.get_current_span() is None: - return original_method(*args, **kwargs) - with sentry_sdk.traces.start_span( - name=description, - attributes={ - "sentry.op": op, - "sentry.origin": DjangoIntegration.origin, - }, - ) as span: - value = original_method(*args, **kwargs) - - with capture_internal_exceptions(): - if address is not None: - span.set_attribute(SPANDATA.NETWORK_PEER_ADDRESS, address) - - if port is not None: - span.set_attribute(SPANDATA.NETWORK_PEER_PORT, port) - - key = _get_safe_key(method_name, args, kwargs) - if key is not None: - span.set_attribute(SPANDATA.CACHE_KEY, key) - - item_size = None - if is_get_many_method: - if value != {}: - item_size = len(str(value)) - span.set_attribute(SPANDATA.CACHE_HIT, True) - else: - span.set_attribute(SPANDATA.CACHE_HIT, False) - elif is_get_method: - default_value = None - if len(args) >= 2: - default_value = args[1] - elif "default" in kwargs: - default_value = kwargs["default"] - - if value != default_value: - item_size = len(str(value)) - span.set_attribute(SPANDATA.CACHE_HIT, True) - else: - span.set_attribute(SPANDATA.CACHE_HIT, False) - else: # TODO: We don't handle `get_or_set` which we should - arg_count = len(args) - if arg_count >= 2: - # 'set' command - item_size = len(str(args[1])) - elif arg_count == 1: - # 'set_many' command - item_size = len(str(args[0])) - - if item_size is not None: - span.set_attribute(SPANDATA.CACHE_ITEM_SIZE, item_size) - - return value - else: - with sentry_sdk.start_span( - op=op, - name=description, - origin=DjangoIntegration.origin, - ) as span: - value = original_method(*args, **kwargs) - - with capture_internal_exceptions(): - if address is not None: - span.set_data(SPANDATA.NETWORK_PEER_ADDRESS, address) - - if port is not None: - span.set_data(SPANDATA.NETWORK_PEER_PORT, port) - - key = _get_safe_key(method_name, args, kwargs) - if key is not None: - span.set_data(SPANDATA.CACHE_KEY, key) - - item_size = None - if is_get_many_method: - if value != {}: - item_size = len(str(value)) - span.set_data(SPANDATA.CACHE_HIT, True) - else: - span.set_data(SPANDATA.CACHE_HIT, False) - elif is_get_method: - default_value = None - if len(args) >= 2: - default_value = args[1] - elif "default" in kwargs: - default_value = kwargs["default"] - - if value != default_value: - item_size = len(str(value)) - span.set_data(SPANDATA.CACHE_HIT, True) - else: - span.set_data(SPANDATA.CACHE_HIT, False) - else: # TODO: We don't handle `get_or_set` which we should - arg_count = len(args) - if arg_count >= 2: - # 'set' command - item_size = len(str(args[1])) - elif arg_count == 1: - # 'set_many' command - item_size = len(str(args[0])) - - if item_size is not None: - span.set_data(SPANDATA.CACHE_ITEM_SIZE, item_size) - - return value + if sentry_sdk.get_current_span() is None: + return original_method(*args, **kwargs) + + with sentry_sdk.start_span( + name=description, + attributes={ + "sentry.op": op, + "sentry.origin": DjangoIntegration.origin, + }, + ) as span: + value = original_method(*args, **kwargs) + + with capture_internal_exceptions(): + if address is not None: + span.set_attribute(SPANDATA.NETWORK_PEER_ADDRESS, address) + + if port is not None: + span.set_attribute(SPANDATA.NETWORK_PEER_PORT, port) + + key = _get_safe_key(method_name, args, kwargs) + if key is not None: + span.set_attribute(SPANDATA.CACHE_KEY, key) + + item_size = None + if is_get_many_method: + if value != {}: + item_size = len(str(value)) + span.set_attribute(SPANDATA.CACHE_HIT, True) + else: + span.set_attribute(SPANDATA.CACHE_HIT, False) + elif is_get_method: + default_value = None + if len(args) >= 2: + default_value = args[1] + elif "default" in kwargs: + default_value = kwargs["default"] + + if value != default_value: + item_size = len(str(value)) + span.set_attribute(SPANDATA.CACHE_HIT, True) + else: + span.set_attribute(SPANDATA.CACHE_HIT, False) + else: # TODO: We don't handle `get_or_set` which we should + arg_count = len(args) + if arg_count >= 2: + # 'set' command + item_size = len(str(args[1])) + elif arg_count == 1: + # 'set_many' command + item_size = len(str(args[0])) + + if item_size is not None: + span.set_attribute(SPANDATA.CACHE_ITEM_SIZE, item_size) + + return value @functools.wraps(original_method) def sentry_method(*args: "Any", **kwargs: "Any") -> "Any": @@ -215,14 +162,9 @@ def _get_address_port( def should_enable_cache_spans() -> bool: from sentry_sdk.integrations.django import DjangoIntegration - client = sentry_sdk.get_client() - integration = client.get_integration(DjangoIntegration) - from django.conf import settings + integration = sentry_sdk.get_client().get_integration(DjangoIntegration) - return integration is not None and ( - (client.spotlight is not None and settings.DEBUG is True) - or integration.cache_spans is True - ) + return integration is not None and integration.cache_spans is True def patch_caching() -> None: diff --git a/sentry_sdk/integrations/django/middleware.py b/sentry_sdk/integrations/django/middleware.py index 01ed8962e0..af4ac249e8 100644 --- a/sentry_sdk/integrations/django/middleware.py +++ b/sentry_sdk/integrations/django/middleware.py @@ -2,6 +2,7 @@ Create spans from Django middleware invocations """ +from contextvars import ContextVar from functools import wraps from typing import TYPE_CHECKING @@ -9,22 +10,18 @@ import sentry_sdk from sentry_sdk.consts import OP, SPANDATA -from sentry_sdk.tracing_utils import has_span_streaming_enabled from sentry_sdk.utils import ( - ContextVar, capture_internal_exceptions, - transaction_from_function, ) if TYPE_CHECKING: - from typing import Any, Callable, Optional, TypeVar, Union + from typing import Any, Callable, Optional, TypeVar - from sentry_sdk.traces import StreamedSpan - from sentry_sdk.tracing import Span + from sentry_sdk.traces import Span F = TypeVar("F", bound=Callable[..., Any]) -_import_string_should_wrap_middleware = ContextVar( +_import_string_should_wrap_middleware: "ContextVar[bool]" = ContextVar( "import_string_should_wrap_middleware" ) @@ -69,39 +66,27 @@ def _wrap_middleware(middleware: "Any", middleware_name: str) -> "Any": def _check_middleware_span( old_method: "Callable[..., Any]", - ) -> "Optional[Union[Span, StreamedSpan]]": + ) -> "Optional[Span]": integration = sentry_sdk.get_client().get_integration(DjangoIntegration) if integration is None or not integration.middleware_spans: return None - function_name = transaction_from_function(old_method) - description = middleware_name function_basename = getattr(old_method, "__name__", None) if function_basename: description = "{}.{}".format(description, function_basename) - span_streaming = has_span_streaming_enabled(sentry_sdk.get_client().options) - middleware_span: "Union[Span, StreamedSpan]" - if span_streaming: - if sentry_sdk.traces.get_current_span() is None: - return None - middleware_span = sentry_sdk.traces.start_span( - name=description, - attributes={ - "sentry.op": OP.MIDDLEWARE_DJANGO, - "sentry.origin": DjangoIntegration.origin, - SPANDATA.MIDDLEWARE_NAME: middleware_name, - }, - ) - else: - middleware_span = sentry_sdk.start_span( - op=OP.MIDDLEWARE_DJANGO, - name=description, - origin=DjangoIntegration.origin, - ) - middleware_span.set_tag("django.function_name", function_name) - middleware_span.set_tag("django.middleware_name", middleware_name) + if sentry_sdk.get_current_span() is None: + return None + + middleware_span = sentry_sdk.start_span( + name=description, + attributes={ + "sentry.op": OP.MIDDLEWARE_DJANGO, + "sentry.origin": DjangoIntegration.origin, + SPANDATA.MIDDLEWARE_NAME: middleware_name, + }, + ) return middleware_span diff --git a/sentry_sdk/integrations/django/signals_handlers.py b/sentry_sdk/integrations/django/signals_handlers.py index 711e74b441..bbc76c9b4f 100644 --- a/sentry_sdk/integrations/django/signals_handlers.py +++ b/sentry_sdk/integrations/django/signals_handlers.py @@ -6,7 +6,6 @@ import sentry_sdk from sentry_sdk.consts import OP, SPANDATA from sentry_sdk.integrations.django import DJANGO_VERSION -from sentry_sdk.tracing_utils import has_span_streaming_enabled if TYPE_CHECKING: from collections.abc import Callable @@ -64,29 +63,18 @@ def sentry_sync_receiver_wrapper( def wrapper(*args: "Any", **kwargs: "Any") -> "Any": signal_name = _get_receiver_name(receiver) - span_streaming = has_span_streaming_enabled( - sentry_sdk.get_client().options - ) - if span_streaming: - if sentry_sdk.traces.get_current_span() is None: - return receiver(*args, **kwargs) - with sentry_sdk.traces.start_span( - name=signal_name, - attributes={ - "sentry.op": OP.EVENT_DJANGO, - "sentry.origin": DjangoIntegration.origin, - SPANDATA.CODE_FUNCTION_NAME: signal_name, - }, - ): - return receiver(*args, **kwargs) - else: - with sentry_sdk.start_span( - op=OP.EVENT_DJANGO, - name=signal_name, - origin=DjangoIntegration.origin, - ) as span: - span.set_data("signal", signal_name) - return receiver(*args, **kwargs) + if sentry_sdk.get_current_span() is None: + return receiver(*args, **kwargs) + + with sentry_sdk.start_span( + name=signal_name, + attributes={ + "sentry.op": OP.EVENT_DJANGO, + "sentry.origin": DjangoIntegration.origin, + SPANDATA.CODE_FUNCTION_NAME: signal_name, + }, + ): + return receiver(*args, **kwargs) return wrapper diff --git a/sentry_sdk/integrations/django/tasks.py b/sentry_sdk/integrations/django/tasks.py index 303040d042..d1fdc72854 100644 --- a/sentry_sdk/integrations/django/tasks.py +++ b/sentry_sdk/integrations/django/tasks.py @@ -2,7 +2,6 @@ import sentry_sdk from sentry_sdk.consts import OP -from sentry_sdk.tracing_utils import has_span_streaming_enabled from sentry_sdk.utils import qualname_from_function try: @@ -33,22 +32,16 @@ def _sentry_enqueue(self: "Any", *args: "Any", **kwargs: "Any") -> "Any": name = qualname_from_function(self.func) or "" - span_streaming = has_span_streaming_enabled(sentry_sdk.get_client().options) - if span_streaming: - if sentry_sdk.traces.get_current_span() is None: - return old_task_enqueue(self, *args, **kwargs) - with sentry_sdk.traces.start_span( - name=name, - attributes={ - "sentry.op": OP.QUEUE_SUBMIT_DJANGO, - "sentry.origin": DjangoIntegration.origin, - }, - ): - return old_task_enqueue(self, *args, **kwargs) - else: - with sentry_sdk.start_span( - op=OP.QUEUE_SUBMIT_DJANGO, name=name, origin=DjangoIntegration.origin - ): - return old_task_enqueue(self, *args, **kwargs) + if sentry_sdk.get_current_span() is None: + return old_task_enqueue(self, *args, **kwargs) + + with sentry_sdk.start_span( + name=name, + attributes={ + "sentry.op": OP.QUEUE_SUBMIT_DJANGO, + "sentry.origin": DjangoIntegration.origin, + }, + ): + return old_task_enqueue(self, *args, **kwargs) Task.enqueue = _sentry_enqueue diff --git a/sentry_sdk/integrations/django/templates.py b/sentry_sdk/integrations/django/templates.py index 1c0986dd9e..db0efb4c7d 100644 --- a/sentry_sdk/integrations/django/templates.py +++ b/sentry_sdk/integrations/django/templates.py @@ -1,25 +1,17 @@ import functools from typing import TYPE_CHECKING -from django import VERSION as DJANGO_VERSION from django.template import TemplateSyntaxError +from django.template.base import Origin from django.utils.safestring import mark_safe import sentry_sdk from sentry_sdk.consts import OP -from sentry_sdk.tracing_utils import has_span_streaming_enabled from sentry_sdk.utils import ensure_integration_enabled if TYPE_CHECKING: from typing import Any, Dict, Iterator, Optional, Tuple -try: - # support Django 1.9 - from django.template.base import Origin -except ImportError: - # backward compatibility - from django.template.loader import LoaderOrigin as Origin - def get_template_frame_from_exception( exc_value: "Optional[BaseException]", @@ -62,31 +54,20 @@ def patch_templates() -> None: @property # type: ignore @ensure_integration_enabled(DjangoIntegration, real_rendered_content.fget) def rendered_content(self: "SimpleTemplateResponse") -> str: - span_streaming = has_span_streaming_enabled(sentry_sdk.get_client().options) - if span_streaming: - if sentry_sdk.traces.get_current_span() is None: - return real_rendered_content.fget(self) - with sentry_sdk.traces.start_span( - name=_get_template_name_description(self.template_name), - attributes={ - "sentry.op": OP.TEMPLATE_RENDER, - "sentry.origin": DjangoIntegration.origin, - }, - ): - return real_rendered_content.fget(self) - else: - with sentry_sdk.start_span( - op=OP.TEMPLATE_RENDER, - name=_get_template_name_description(self.template_name), - origin=DjangoIntegration.origin, - ) as span: - span.set_data("context", self.context_data) - return real_rendered_content.fget(self) + if sentry_sdk.get_current_span() is None: + return real_rendered_content.fget(self) + + with sentry_sdk.start_span( + name=_get_template_name_description(self.template_name), + attributes={ + "sentry.op": OP.TEMPLATE_RENDER, + "sentry.origin": DjangoIntegration.origin, + }, + ): + return real_rendered_content.fget(self) SimpleTemplateResponse.rendered_content = rendered_content - if DJANGO_VERSION < (1, 7): - return import django.shortcuts real_render = django.shortcuts.render @@ -107,28 +88,17 @@ def render( sentry_sdk.get_current_scope().trace_propagation_meta() ) - client = sentry_sdk.get_client() - span_streaming = has_span_streaming_enabled(client.options) - - if span_streaming: - if sentry_sdk.traces.get_current_span() is None: - return real_render(request, template_name, context, *args, **kwargs) - with sentry_sdk.traces.start_span( - name=_get_template_name_description(template_name), - attributes={ - "sentry.op": OP.TEMPLATE_RENDER, - "sentry.origin": DjangoIntegration.origin, - }, - ): - return real_render(request, template_name, context, *args, **kwargs) - else: - with sentry_sdk.start_span( - op=OP.TEMPLATE_RENDER, - name=_get_template_name_description(template_name), - origin=DjangoIntegration.origin, - ) as span: - span.set_data("context", context) - return real_render(request, template_name, context, *args, **kwargs) + if sentry_sdk.get_current_span() is None: + return real_render(request, template_name, context, *args, **kwargs) + + with sentry_sdk.start_span( + name=_get_template_name_description(template_name), + attributes={ + "sentry.op": OP.TEMPLATE_RENDER, + "sentry.origin": DjangoIntegration.origin, + }, + ): + return real_render(request, template_name, context, *args, **kwargs) django.shortcuts.render = render diff --git a/sentry_sdk/integrations/django/transactions.py b/sentry_sdk/integrations/django/transactions.py index 192f0765e6..7f1157bd3b 100644 --- a/sentry_sdk/integrations/django/transactions.py +++ b/sentry_sdk/integrations/django/transactions.py @@ -8,24 +8,20 @@ import re from typing import TYPE_CHECKING +from sentry_sdk.integrations import DidNotEnable + +try: + from django.urls import get_resolver + from django.urls.resolvers import RoutePattern +except ImportError: + raise DidNotEnable("Supported version of Django not installed") + if TYPE_CHECKING: from re import Pattern from typing import Dict, List, Optional, Tuple, Union from django.urls.resolvers import URLPattern, URLResolver -from django import VERSION as DJANGO_VERSION - -if DJANGO_VERSION >= (2, 0): - from django.urls.resolvers import RoutePattern -else: - RoutePattern = None - -try: - from django.urls import get_resolver -except ImportError: - from django.core.urlresolvers import get_resolver - def get_regex(resolver_or_pattern: "Union[URLPattern, URLResolver]") -> "Pattern[str]": """Utility method for django's deprecated resolver.regex""" @@ -61,11 +57,7 @@ def _simplify(self, pattern: "Union[URLPattern, URLResolver]") -> str: """ # "new-style" path patterns can be parsed directly without turning them # into regexes first - if ( - RoutePattern is not None - and hasattr(pattern, "pattern") - and isinstance(pattern.pattern, RoutePattern) - ): + if hasattr(pattern, "pattern") and isinstance(pattern.pattern, RoutePattern): return self._new_style_group_matcher.sub( lambda m: "{%s}" % m.group(2), str(pattern.pattern._route) ) diff --git a/sentry_sdk/integrations/django/views.py b/sentry_sdk/integrations/django/views.py index d37d54117d..54833d0ccd 100644 --- a/sentry_sdk/integrations/django/views.py +++ b/sentry_sdk/integrations/django/views.py @@ -3,8 +3,7 @@ import sentry_sdk from sentry_sdk.consts import OP -from sentry_sdk.traces import StreamedSpan -from sentry_sdk.tracing_utils import has_span_streaming_enabled +from sentry_sdk.traces import Span if TYPE_CHECKING: from typing import Any @@ -22,25 +21,17 @@ def patch_views() -> None: old_render = SimpleTemplateResponse.render def sentry_patched_render(self: "SimpleTemplateResponse") -> "Any": - span_streaming = has_span_streaming_enabled(sentry_sdk.get_client().options) - if span_streaming: - if sentry_sdk.traces.get_current_span() is None: - return old_render(self) - with sentry_sdk.traces.start_span( - name="serialize response", - attributes={ - "sentry.op": OP.VIEW_RESPONSE_RENDER, - "sentry.origin": DjangoIntegration.origin, - }, - ): - return old_render(self) - else: - with sentry_sdk.start_span( - op=OP.VIEW_RESPONSE_RENDER, - name="serialize response", - origin=DjangoIntegration.origin, - ): - return old_render(self) + if sentry_sdk.get_current_span() is None: + return old_render(self) + + with sentry_sdk.start_span( + name="serialize response", + attributes={ + "sentry.op": OP.VIEW_RESPONSE_RENDER, + "sentry.origin": DjangoIntegration.origin, + }, + ): + return old_render(self) @functools.wraps(old_make_view_atomic) def sentry_patched_make_view_atomic( @@ -70,44 +61,26 @@ def _wrap_sync_view(callback: "Any") -> "Any": @functools.wraps(callback) def sentry_wrapped_callback(request: "Any", *args: "Any", **kwargs: "Any") -> "Any": client = sentry_sdk.get_client() - span_streaming = has_span_streaming_enabled(client.options) - current_scope = sentry_sdk.get_current_scope() - if span_streaming: - current_span = current_scope.streamed_span - if type(current_span) is StreamedSpan: - segment = current_span._segment - segment._update_active_thread() - else: - if current_scope.transaction is not None: - current_scope.transaction.update_active_thread() - - sentry_scope = sentry_sdk.get_isolation_scope() - # set the active thread id to the handler thread for sync views - # this isn't necessary for async views since that runs on main - if sentry_scope.profile is not None: - sentry_scope.profile.update_active_thread_id() + + current_span = sentry_sdk.get_current_span() + if type(current_span) is Span: + segment = current_span._segment + segment._update_active_thread() integration = client.get_integration(DjangoIntegration) if not integration or not integration.middleware_spans: return callback(request, *args, **kwargs) - if span_streaming: - if sentry_sdk.traces.get_current_span() is None: - return callback(request, *args, **kwargs) - with sentry_sdk.traces.start_span( - name=request.resolver_match.view_name, - attributes={ - "sentry.op": OP.VIEW_RENDER, - "sentry.origin": DjangoIntegration.origin, - }, - ): - return callback(request, *args, **kwargs) - else: - with sentry_sdk.start_span( - op=OP.VIEW_RENDER, - name=request.resolver_match.view_name, - origin=DjangoIntegration.origin, - ): - return callback(request, *args, **kwargs) + if sentry_sdk.get_current_span() is None: + return callback(request, *args, **kwargs) + + with sentry_sdk.start_span( + name=request.resolver_match.view_name, + attributes={ + "sentry.op": OP.VIEW_RENDER, + "sentry.origin": DjangoIntegration.origin, + }, + ): + return callback(request, *args, **kwargs) return sentry_wrapped_callback diff --git a/sentry_sdk/integrations/dramatiq.py b/sentry_sdk/integrations/dramatiq.py index 01ad4e1b28..2ac023bb63 100644 --- a/sentry_sdk/integrations/dramatiq.py +++ b/sentry_sdk/integrations/dramatiq.py @@ -2,33 +2,33 @@ from typing import TypeVar import sentry_sdk -from sentry_sdk.api import continue_trace, get_baggage, get_traceparent -from sentry_sdk.consts import OP, SPANDATA, SPANSTATUS -from sentry_sdk.integrations import DidNotEnable, Integration +from sentry_sdk.api import get_baggage, get_traceparent +from sentry_sdk.consts import OP, SPANDATA +from sentry_sdk.integrations import DidNotEnable, Integration, _check_minimum_version from sentry_sdk.integrations._wsgi_common import request_body_within_bounds -from sentry_sdk.traces import SegmentNameSource -from sentry_sdk.tracing import ( +from sentry_sdk.traces import ( BAGGAGE_HEADER_NAME, SENTRY_TRACE_HEADER_NAME, - TransactionSource, + SegmentNameSource, ) -from sentry_sdk.tracing_utils import has_span_streaming_enabled from sentry_sdk.utils import ( AnnotatedValue, capture_internal_exceptions, event_from_exception, has_data_collection_enabled, + parse_version, ) R = TypeVar("R") try: + from dramatiq import __version__ as DRAMATIQ_VERSION from dramatiq.broker import Broker from dramatiq.errors import Retry from dramatiq.message import Message from dramatiq.middleware import Middleware, default_middleware except ImportError: - raise DidNotEnable("Dramatiq is not installed") + raise DidNotEnable("Dramatiq is not installed or incompatible") from typing import TYPE_CHECKING @@ -55,6 +55,9 @@ class DramatiqIntegration(Integration): @staticmethod def setup_once() -> None: + version = parse_version(DRAMATIQ_VERSION) + _check_minimum_version(DramatiqIntegration, version) + _patch_dramatiq_broker() @@ -133,39 +136,20 @@ def before_process_message(self, broker: "Broker", message: "Message[R]") -> Non # start new trace in case of retrying sentry_headers = {} - if has_span_streaming_enabled(client.options): - sentry_sdk.traces.continue_trace(sentry_headers) - span = sentry_sdk.traces.start_span( - name=message.actor_name, - attributes={ - "sentry.op": OP.QUEUE_TASK_DRAMATIQ, - "sentry.origin": DramatiqIntegration.origin, - "sentry.segment.name.source": SegmentNameSource.TASK.value, - SPANDATA.MESSAGING_DESTINATION_NAME: message.queue_name, - }, - parent_span=None, - ) - message._sentry_span_ctx = span - else: - transaction = continue_trace( - sentry_headers, - name=message.actor_name, - op=OP.QUEUE_TASK_DRAMATIQ, - source=TransactionSource.TASK, - origin=DramatiqIntegration.origin, - ) - transaction.set_status(SPANSTATUS.OK) - sentry_sdk.start_transaction( - transaction, - name=message.actor_name, - op=OP.QUEUE_TASK_DRAMATIQ, - source=TransactionSource.TASK, - ) - transaction.__enter__() - transaction.set_data( - SPANDATA.MESSAGING_DESTINATION_NAME, message.queue_name - ) - message._sentry_span_ctx = transaction + scope.set_transaction_name(message.actor_name, source=SegmentNameSource.TASK) + + sentry_sdk.continue_trace(sentry_headers) + span = sentry_sdk.start_span( + name=message.actor_name, + attributes={ + "sentry.op": OP.QUEUE_TASK_DRAMATIQ, + "sentry.origin": DramatiqIntegration.origin, + "sentry.segment.name.source": SegmentNameSource.TASK.value, + SPANDATA.MESSAGING_DESTINATION_NAME: message.queue_name, + }, + parent_span=None, + ) + message._sentry_span = span def after_process_message( self, @@ -183,8 +167,8 @@ def after_process_message( throws = message.options.get("throws") or actor.options.get("throws") scope_manager = message._scope_manager - span_ctx = getattr(message, "_sentry_span_ctx", None) - if span_ctx is None: + span = getattr(message, "_sentry_span", None) + if span is None: return None is_event_capture_required = ( @@ -194,7 +178,7 @@ def after_process_message( ) if not is_event_capture_required: # normal transaction finish - span_ctx.__exit__(None, None, None) + span.end() scope_manager.__exit__(None, None, None) return @@ -208,7 +192,7 @@ def after_process_message( ) sentry_sdk.capture_event(event, hint=hint) # transaction error - span_ctx.__exit__(type(exception), exception, None) + span.__exit__(type(exception), exception, None) scope_manager.__exit__(type(exception), exception, None) after_skip_message = after_process_message diff --git a/sentry_sdk/integrations/executing.py b/sentry_sdk/integrations/executing.py index 4473fcc435..ce66491e74 100644 --- a/sentry_sdk/integrations/executing.py +++ b/sentry_sdk/integrations/executing.py @@ -13,7 +13,7 @@ try: from executing import Source except ImportError: - raise DidNotEnable("executing is not installed") + raise DidNotEnable("executing is not installed or incompatible") class ExecutingIntegration(Integration): diff --git a/sentry_sdk/integrations/falcon.py b/sentry_sdk/integrations/falcon.py index 7f360544ba..a1a0df9fcd 100644 --- a/sentry_sdk/integrations/falcon.py +++ b/sentry_sdk/integrations/falcon.py @@ -5,8 +5,6 @@ from sentry_sdk.integrations import DidNotEnable, Integration, _check_minimum_version from sentry_sdk.integrations._wsgi_common import RequestExtractor from sentry_sdk.integrations.wsgi import SentryWsgiMiddleware -from sentry_sdk.tracing import SOURCE_FOR_STYLE -from sentry_sdk.tracing_utils import has_span_streaming_enabled from sentry_sdk.utils import ( capture_internal_exceptions, ensure_integration_enabled, @@ -24,30 +22,11 @@ try: import falcon # type: ignore + from falcon import App, app_helpers from falcon import __version__ as FALCON_VERSION + from falcon.request import _UNSET as _FALCON_UNSET # type: ignore except ImportError: - raise DidNotEnable("Falcon not installed") - -try: - import falcon.app_helpers # type: ignore - - falcon_helpers = falcon.app_helpers - falcon_app_class = falcon.App - FALCON3 = True -except ImportError: - import falcon.api_helpers # type: ignore - - falcon_helpers = falcon.api_helpers - falcon_app_class = falcon.API - FALCON3 = False - - -_FALCON_UNSET: "Optional[object]" = None -if FALCON3: # falcon.request._UNSET is only available in Falcon 3.0+ - with capture_internal_exceptions(): - from falcon.request import ( # type: ignore[import-not-found, no-redef] - _UNSET as _FALCON_UNSET, - ) + raise DidNotEnable("Falcon not installed or incompatible") class FalconRequestExtractor(RequestExtractor): @@ -114,7 +93,7 @@ def process_resource( """ client = sentry_sdk.get_client() integration = client.get_integration(FalconIntegration) - if integration is None or not has_span_streaming_enabled(client.options): + if integration is None: return server_span = sentry_sdk.get_current_scope()._server_segment_span @@ -142,15 +121,14 @@ class FalconIntegration(Integration): def __init__(self, transaction_style: str = "uri_template") -> None: if transaction_style not in TRANSACTION_STYLE_VALUES: raise ValueError( - "Invalid value for transaction_style: %s (must be in %s)" - % (transaction_style, TRANSACTION_STYLE_VALUES) + f"Invalid value for transaction_style: {transaction_style} " + f"(must be in {TRANSACTION_STYLE_VALUES})" ) self.transaction_style = transaction_style @staticmethod def setup_once() -> None: - version = parse_version(FALCON_VERSION) - _check_minimum_version(FalconIntegration, version) + _check_minimum_version(FalconIntegration, parse_version(FALCON_VERSION)) _patch_wsgi_app() _patch_handle_exception() @@ -158,7 +136,7 @@ def setup_once() -> None: def _patch_wsgi_app() -> None: - original_wsgi_app = falcon_app_class.__call__ + original_wsgi_app = App.__call__ def sentry_patched_wsgi_app( self: "falcon.API", env: "Any", start_response: "Any" @@ -174,11 +152,11 @@ def sentry_patched_wsgi_app( return sentry_wrapped(env, start_response) - falcon_app_class.__call__ = sentry_patched_wsgi_app + App.__call__ = sentry_patched_wsgi_app def _patch_handle_exception() -> None: - original_handle_exception = falcon_app_class._handle_exception + original_handle_exception = App._handle_exception @ensure_integration_enabled(FalconIntegration, original_handle_exception) def sentry_patched_handle_exception(self: "falcon.API", *args: "Any") -> "Any": @@ -210,11 +188,11 @@ def sentry_patched_handle_exception(self: "falcon.API", *args: "Any") -> "Any": return was_handled - falcon_app_class._handle_exception = sentry_patched_handle_exception + App._handle_exception = sentry_patched_handle_exception def _patch_prepare_middleware() -> None: - original_prepare_middleware = falcon_helpers.prepare_middleware + original_prepare_middleware = app_helpers.prepare_middleware def sentry_patched_prepare_middleware( middleware: "Any" = None, @@ -229,11 +207,9 @@ def sentry_patched_prepare_middleware( if integration is not None: middleware = [SentryFalconMiddleware()] + (middleware or []) - # We intentionally omit the asgi argument here, since the default is False anyways, - # and this way, we remain backwards-compatible with pre-3.0.0 Falcon versions. - return original_prepare_middleware(middleware, independent_middleware) + return original_prepare_middleware(middleware, independent_middleware, asgi) - falcon_helpers.prepare_middleware = sentry_patched_prepare_middleware + app_helpers.prepare_middleware = sentry_patched_prepare_middleware def _exception_leads_to_http_5xx(ex: Exception, response: "falcon.Response") -> bool: @@ -244,37 +220,17 @@ def _exception_leads_to_http_5xx(ex: Exception, response: "falcon.Response") -> ex, (falcon.HTTPError, falcon.http_status.HTTPStatus) ) - # We only check the HTTP status on Falcon 3 because in Falcon 2, the status on the response - # at the stage where we capture it is listed as 200, even though we would expect to see a 500 - # status. Since at the time of this change, Falcon 2 is ca. 4 years old, we have decided to - # only perform this check on Falcon 3+, despite the risk that some handled errors might be - # reported to Sentry as unhandled on Falcon 2. - return (is_server_error or is_unhandled_error) and ( - not FALCON3 or _has_http_5xx_status(response) - ) + return (is_server_error or is_unhandled_error) and _has_http_5xx_status(response) def _has_http_5xx_status(response: "falcon.Response") -> bool: return response.status.startswith("5") -def _set_transaction_name_and_source( - event: "Event", transaction_style: str, request: "falcon.Request" -) -> None: - name_for_style = { - "uri_template": request.uri_template, - "path": request.path, - } - event["transaction"] = name_for_style[transaction_style] - event["transaction_info"] = {"source": SOURCE_FOR_STYLE[transaction_style]} - - def _make_request_event_processor( req: "falcon.Request", integration: "FalconIntegration" ) -> "EventProcessor": def event_processor(event: "Event", hint: "dict[str, Any]") -> "Event": - _set_transaction_name_and_source(event, integration.transaction_style, req) - with capture_internal_exceptions(): FalconRequestExtractor(req).extract_into_event(event) diff --git a/sentry_sdk/integrations/fastapi.py b/sentry_sdk/integrations/fastapi.py index 6a7c543c8c..064776d268 100644 --- a/sentry_sdk/integrations/fastapi.py +++ b/sentry_sdk/integrations/fastapi.py @@ -5,11 +5,18 @@ import sentry_sdk from sentry_sdk.consts import SPANDATA -from sentry_sdk.integrations import DidNotEnable -from sentry_sdk.traces import StreamedSpan, get_current_span -from sentry_sdk.tracing import SOURCE_FOR_STYLE, TransactionSource -from sentry_sdk.tracing_utils import has_span_streaming_enabled -from sentry_sdk.utils import has_data_collection_enabled, transaction_from_function +from sentry_sdk.integrations import DidNotEnable, _check_minimum_version +from sentry_sdk.traces import ( + SOURCE_FOR_STYLE, + SegmentNameSource, + Span, + get_current_span, +) +from sentry_sdk.utils import ( + has_data_collection_enabled, + parse_version, + transaction_from_function, +) if TYPE_CHECKING: from typing import Any, Awaitable, Callable, Dict, Optional @@ -23,12 +30,13 @@ _get_cached_request_body_attribute, ) except DidNotEnable: - raise DidNotEnable("Starlette is not installed") + raise DidNotEnable("Starlette is not installed or incompatible") try: import fastapi # type: ignore + from fastapi import __version__ as FASTAPI_VERSION except ImportError: - raise DidNotEnable("FastAPI is not installed") + raise DidNotEnable("FastAPI is not installed or incompatible") _DEFAULT_TRANSACTION_NAME = "generic FastAPI request" @@ -46,6 +54,9 @@ class FastApiIntegration(StarletteIntegration): @staticmethod def setup_once() -> None: + version = parse_version(FASTAPI_VERSION) + _check_minimum_version(FastApiIntegration, version) + patch_get_request_handler() @@ -65,7 +76,7 @@ def _set_transaction_name_and_source( if not name: name = _DEFAULT_TRANSACTION_NAME - source = TransactionSource.ROUTE + source = SegmentNameSource.ROUTE else: source = SOURCE_FOR_STYLE[transaction_style] @@ -119,7 +130,6 @@ async def _wrap_async_handler( ) sentry_scope = sentry_sdk.get_isolation_scope() extractor = StarletteRequestExtractor(request) - info = await extractor.extract_request_info() def _make_request_event_processor( req: "Any", integration: "Any" @@ -127,6 +137,8 @@ def _make_request_event_processor( def event_processor(event: "Event", hint: "Dict[str, Any]") -> "Event": # Extract information from request request_info = event.get("request", {}) + + info = extractor.extract_request_info() if info: if "cookies" in info: request_info["cookies"] = info["cookies"] @@ -156,7 +168,7 @@ def event_processor(event: "Event", hint: "Dict[str, Any]") -> "Event": finally: current_span = get_current_span() - if type(current_span) is StreamedSpan: + if type(current_span) is Span: attach_request_data = True if has_data_collection_enabled(client.options): attach_request_data = ( @@ -195,22 +207,11 @@ def _sentry_get_request_handler(*args: "Any", **kwargs: "Any") -> "Any": @wraps(old_call) def _sentry_call(*args: "Any", **kwargs: "Any") -> "Any": - current_scope = sentry_sdk.get_current_scope() - - client = sentry_sdk.get_client() - if has_span_streaming_enabled(client.options): - current_span = current_scope.streamed_span - - if type(current_span) is StreamedSpan: - segment = current_span._segment - segment._update_active_thread() - - elif current_scope.transaction is not None: - current_scope.transaction.update_active_thread() + current_span = sentry_sdk.get_current_span() - sentry_scope = sentry_sdk.get_isolation_scope() - if sentry_scope.profile is not None: - sentry_scope.profile.update_active_thread_id() + if type(current_span) is Span: + segment = current_span._segment + segment._update_active_thread() return old_call(*args, **kwargs) diff --git a/sentry_sdk/integrations/flask.py b/sentry_sdk/integrations/flask.py index b99a3b49eb..bff656bbb8 100644 --- a/sentry_sdk/integrations/flask.py +++ b/sentry_sdk/integrations/flask.py @@ -9,7 +9,7 @@ ) from sentry_sdk.integrations.wsgi import SentryWsgiMiddleware from sentry_sdk.scope import should_send_default_pii -from sentry_sdk.tracing import SOURCE_FOR_STYLE +from sentry_sdk.traces import SOURCE_FOR_STYLE from sentry_sdk.utils import ( capture_internal_exceptions, ensure_integration_enabled, @@ -42,12 +42,12 @@ ) from markupsafe import Markup except ImportError: - raise DidNotEnable("Flask is not installed") + raise DidNotEnable("Flask is not installed or incompatible") try: import blinker # noqa except ImportError: - raise DidNotEnable("blinker is not installed") + raise DidNotEnable("blinker is not installed or incompatible") TRANSACTION_STYLE_VALUES = ("endpoint", "url") diff --git a/sentry_sdk/integrations/gcp.py b/sentry_sdk/integrations/gcp.py index c0debc8094..1b53889a25 100644 --- a/sentry_sdk/integrations/gcp.py +++ b/sentry_sdk/integrations/gcp.py @@ -6,7 +6,6 @@ from typing import TYPE_CHECKING import sentry_sdk -from sentry_sdk.api import continue_trace from sentry_sdk.consts import OP from sentry_sdk.data_collection import _apply_data_collection_filtering_to_query_string from sentry_sdk.integrations import Integration @@ -14,8 +13,6 @@ from sentry_sdk.integrations.cloud_resource_context import CLOUD_PROVIDER from sentry_sdk.scope import Scope, should_send_default_pii from sentry_sdk.traces import SegmentNameSource -from sentry_sdk.tracing import TransactionSource -from sentry_sdk.tracing_utils import has_span_streaming_enabled from sentry_sdk.utils import ( AnnotatedValue, TimeoutThread, @@ -68,7 +65,6 @@ def sentry_func( gcp_event, configured_time, initial_time ) ) - scope.set_tag("gcp_region", environ.get("FUNCTION_REGION")) timeout_thread = None if ( integration.timeout_warning @@ -141,36 +137,22 @@ def sentry_func( if environ.get("ENTRY_POINT"): additional_attributes["faas.entry_point"] = environ.get("ENTRY_POINT") - if has_span_streaming_enabled(client.options): - sentry_sdk.traces.continue_trace(headers) - Scope.set_custom_sampling_context(sampling_context) - span_ctx = sentry_sdk.traces.start_span( - name=function_name, - parent_span=None, - attributes={ - "sentry.op": OP.FUNCTION_GCP, - "sentry.origin": GcpIntegration.origin, - "sentry.segment.name.source": SegmentNameSource.COMPONENT, - "cloud.provider": CLOUD_PROVIDER.GCP, - "faas.name": function_name, - **header_attributes, - **additional_attributes, - }, - ) - else: - transaction = continue_trace( - headers, - op=OP.FUNCTION_GCP, - name=environ.get("FUNCTION_NAME", ""), - source=TransactionSource.COMPONENT, - origin=GcpIntegration.origin, - ) - - span_ctx = sentry_sdk.start_transaction( - transaction, custom_sampling_context=sampling_context - ) - - with span_ctx: + sentry_sdk.continue_trace(headers) + Scope.set_custom_sampling_context(sampling_context) + + with sentry_sdk.start_span( + name=function_name, + parent_span=None, + attributes={ + "sentry.op": OP.FUNCTION_GCP, + "sentry.origin": GcpIntegration.origin, + "sentry.segment.name.source": SegmentNameSource.COMPONENT, + "cloud.provider": CLOUD_PROVIDER.GCP, + "faas.name": function_name, + **header_attributes, + **additional_attributes, + }, + ): try: return func(functionhandler, gcp_event, *args, **kwargs) except Exception: diff --git a/sentry_sdk/integrations/google_genai/__init__.py b/sentry_sdk/integrations/google_genai/__init__.py index 8e3871595d..f7a67d6625 100644 --- a/sentry_sdk/integrations/google_genai/__init__.py +++ b/sentry_sdk/integrations/google_genai/__init__.py @@ -8,14 +8,13 @@ ) import sentry_sdk -from sentry_sdk.ai.utils import get_start_span_function from sentry_sdk.consts import OP, SPANDATA -from sentry_sdk.integrations import DidNotEnable, Integration -from sentry_sdk.traces import SpanStatus, StreamedSpan -from sentry_sdk.tracing import SPANSTATUS -from sentry_sdk.tracing_utils import has_span_streaming_enabled +from sentry_sdk.integrations import DidNotEnable, Integration, _check_minimum_version +from sentry_sdk.traces import SpanStatus +from sentry_sdk.utils import parse_version try: + from google.genai import __version__ as GOOGLE_GENAI_VERSION from google.genai.models import AsyncModels, Models except ImportError: raise DidNotEnable("google-genai not installed") @@ -41,11 +40,11 @@ class GoogleGenAIIntegration(Integration): identifier = IDENTIFIER origin = ORIGIN - def __init__(self: "GoogleGenAIIntegration", include_prompts: bool = True) -> None: - self.include_prompts = include_prompts - @staticmethod def setup_once() -> None: + version = parse_version(GOOGLE_GENAI_VERSION) + _check_minimum_version(GoogleGenAIIntegration, version) + # Patch sync methods Models.generate_content = _wrap_generate_content(Models.generate_content) # type: ignore[method-assign] Models.generate_content_stream = _wrap_generate_content_stream( # type: ignore[method-assign] @@ -73,32 +72,22 @@ def new_generate_content_stream( if integration is None: return f(self, *args, **kwargs) - _model, contents, model_name = prepare_generate_content_args(args, kwargs) + if sentry_sdk.get_current_scope()._agent_framework_chat_generation_entered: + return f(self, *args, **kwargs) - if has_span_streaming_enabled(client.options): - chat_span = sentry_sdk.traces.start_span( - name=f"chat {model_name}", - attributes={ - "sentry.op": OP.GEN_AI_CHAT, - "sentry.origin": ORIGIN, - SPANDATA.GEN_AI_OPERATION_NAME: "chat", - SPANDATA.GEN_AI_SYSTEM: GEN_AI_SYSTEM, - SPANDATA.GEN_AI_REQUEST_MODEL: model_name, - SPANDATA.GEN_AI_RESPONSE_STREAMING: True, - }, - ) - else: - chat_span = get_start_span_function()( - op=OP.GEN_AI_CHAT, - name=f"chat {model_name}", - origin=ORIGIN, - ) - chat_span.__enter__() + _model, contents, model_name = prepare_generate_content_args(args, kwargs) - chat_span.set_data(SPANDATA.GEN_AI_OPERATION_NAME, "chat") - chat_span.set_data(SPANDATA.GEN_AI_SYSTEM, GEN_AI_SYSTEM) - chat_span.set_data(SPANDATA.GEN_AI_REQUEST_MODEL, model_name) - chat_span.set_data(SPANDATA.GEN_AI_RESPONSE_STREAMING, True) + chat_span = sentry_sdk.start_span( + name=f"chat {model_name}", + attributes={ + "sentry.op": OP.GEN_AI_CHAT, + "sentry.origin": ORIGIN, + SPANDATA.GEN_AI_OPERATION_NAME: "chat", + SPANDATA.GEN_AI_PROVIDER_NAME: GEN_AI_SYSTEM, + SPANDATA.GEN_AI_REQUEST_MODEL: model_name, + SPANDATA.GEN_AI_RESPONSE_STREAMING: True, + }, + ) set_span_data_for_request(chat_span, integration, model_name, contents, kwargs) @@ -114,10 +103,7 @@ def new_iterator() -> "Iterator[Any]": yield chunk except Exception as exc: _capture_exception(exc) - if isinstance(chat_span, StreamedSpan): - chat_span.status = SpanStatus.ERROR - else: - chat_span.set_status(SPANSTATUS.INTERNAL_ERROR) + chat_span.status = SpanStatus.ERROR raise finally: # Accumulate all chunks and set final response data on spans @@ -150,32 +136,22 @@ async def new_async_generate_content_stream( if integration is None: return await f(self, *args, **kwargs) - _model, contents, model_name = prepare_generate_content_args(args, kwargs) + if sentry_sdk.get_current_scope()._agent_framework_chat_generation_entered: + return f(self, *args, **kwargs) - if has_span_streaming_enabled(client.options): - chat_span = sentry_sdk.traces.start_span( - name=f"chat {model_name}", - attributes={ - "sentry.op": OP.GEN_AI_CHAT, - "sentry.origin": ORIGIN, - SPANDATA.GEN_AI_OPERATION_NAME: "chat", - SPANDATA.GEN_AI_SYSTEM: GEN_AI_SYSTEM, - SPANDATA.GEN_AI_REQUEST_MODEL: model_name, - SPANDATA.GEN_AI_RESPONSE_STREAMING: True, - }, - ) - else: - chat_span = get_start_span_function()( - op=OP.GEN_AI_CHAT, - name=f"chat {model_name}", - origin=ORIGIN, - ) - chat_span.__enter__() + _model, contents, model_name = prepare_generate_content_args(args, kwargs) - chat_span.set_data(SPANDATA.GEN_AI_OPERATION_NAME, "chat") - chat_span.set_data(SPANDATA.GEN_AI_SYSTEM, GEN_AI_SYSTEM) - chat_span.set_data(SPANDATA.GEN_AI_REQUEST_MODEL, model_name) - chat_span.set_data(SPANDATA.GEN_AI_RESPONSE_STREAMING, True) + chat_span = sentry_sdk.start_span( + name=f"chat {model_name}", + attributes={ + "sentry.op": OP.GEN_AI_CHAT, + "sentry.origin": ORIGIN, + SPANDATA.GEN_AI_OPERATION_NAME: "chat", + SPANDATA.GEN_AI_PROVIDER_NAME: GEN_AI_SYSTEM, + SPANDATA.GEN_AI_REQUEST_MODEL: model_name, + SPANDATA.GEN_AI_RESPONSE_STREAMING: True, + }, + ) set_span_data_for_request(chat_span, integration, model_name, contents, kwargs) @@ -191,10 +167,7 @@ async def new_async_iterator() -> "AsyncIterator[Any]": yield chunk except Exception as exc: _capture_exception(exc) - if isinstance(chat_span, StreamedSpan): - chat_span.status = SpanStatus.ERROR - else: - chat_span.set_status(SPANSTATUS.INTERNAL_ERROR) + chat_span.status = SpanStatus.ERROR raise finally: # Accumulate all chunks and set final response data on spans @@ -223,56 +196,35 @@ def new_generate_content(self: "Any", *args: "Any", **kwargs: "Any") -> "Any": if integration is None: return f(self, *args, **kwargs) - model, contents, model_name = prepare_generate_content_args(args, kwargs) - - if has_span_streaming_enabled(client.options): - with sentry_sdk.traces.start_span( - name=f"chat {model_name}", - attributes={ - "sentry.op": OP.GEN_AI_CHAT, - "sentry.origin": ORIGIN, - SPANDATA.GEN_AI_OPERATION_NAME: "chat", - SPANDATA.GEN_AI_SYSTEM: GEN_AI_SYSTEM, - SPANDATA.GEN_AI_REQUEST_MODEL: model_name, - }, - ) as chat_span: - set_span_data_for_request( - chat_span, integration, model_name, contents, kwargs - ) + if sentry_sdk.get_current_scope()._agent_framework_chat_generation_entered: + return f(self, *args, **kwargs) - try: - response = f(self, *args, **kwargs) - except Exception as exc: - _capture_exception(exc) - chat_span.status = SpanStatus.ERROR - raise + model, contents, model_name = prepare_generate_content_args(args, kwargs) - set_span_data_for_response(chat_span, integration, response) - - return response - else: - with get_start_span_function()( - op=OP.GEN_AI_CHAT, - name=f"chat {model_name}", - origin=ORIGIN, - ) as chat_span: - chat_span.set_data(SPANDATA.GEN_AI_OPERATION_NAME, "chat") - chat_span.set_data(SPANDATA.GEN_AI_SYSTEM, GEN_AI_SYSTEM) - chat_span.set_data(SPANDATA.GEN_AI_REQUEST_MODEL, model_name) - set_span_data_for_request( - chat_span, integration, model_name, contents, kwargs - ) + with sentry_sdk.start_span( + name=f"chat {model_name}", + attributes={ + "sentry.op": OP.GEN_AI_CHAT, + "sentry.origin": ORIGIN, + SPANDATA.GEN_AI_OPERATION_NAME: "chat", + SPANDATA.GEN_AI_PROVIDER_NAME: GEN_AI_SYSTEM, + SPANDATA.GEN_AI_REQUEST_MODEL: model_name, + }, + ) as chat_span: + set_span_data_for_request( + chat_span, integration, model_name, contents, kwargs + ) - try: - response = f(self, *args, **kwargs) - except Exception as exc: - _capture_exception(exc) - chat_span.set_status(SPANSTATUS.INTERNAL_ERROR) - raise + try: + response = f(self, *args, **kwargs) + except Exception as exc: + _capture_exception(exc) + chat_span.status = SpanStatus.ERROR + raise - set_span_data_for_response(chat_span, integration, response) + set_span_data_for_response(chat_span, integration, response) - return response + return response return new_generate_content @@ -287,54 +239,34 @@ async def new_async_generate_content( if integration is None: return await f(self, *args, **kwargs) - model, contents, model_name = prepare_generate_content_args(args, kwargs) + if sentry_sdk.get_current_scope()._agent_framework_chat_generation_entered: + return f(self, *args, **kwargs) - if has_span_streaming_enabled(client.options): - with sentry_sdk.traces.start_span( - name=f"chat {model_name}", - attributes={ - "sentry.op": OP.GEN_AI_CHAT, - "sentry.origin": ORIGIN, - SPANDATA.GEN_AI_OPERATION_NAME: "chat", - SPANDATA.GEN_AI_SYSTEM: GEN_AI_SYSTEM, - SPANDATA.GEN_AI_REQUEST_MODEL: model_name, - }, - ) as chat_span: - set_span_data_for_request( - chat_span, integration, model_name, contents, kwargs - ) - try: - response = await f(self, *args, **kwargs) - except Exception as exc: - _capture_exception(exc) - chat_span.status = SpanStatus.ERROR - raise + model, contents, model_name = prepare_generate_content_args(args, kwargs) - set_span_data_for_response(chat_span, integration, response) - - return response - else: - with get_start_span_function()( - op=OP.GEN_AI_CHAT, - name=f"chat {model_name}", - origin=ORIGIN, - ) as chat_span: - chat_span.set_data(SPANDATA.GEN_AI_OPERATION_NAME, "chat") - chat_span.set_data(SPANDATA.GEN_AI_SYSTEM, GEN_AI_SYSTEM) - chat_span.set_data(SPANDATA.GEN_AI_REQUEST_MODEL, model_name) - set_span_data_for_request( - chat_span, integration, model_name, contents, kwargs - ) - try: - response = await f(self, *args, **kwargs) - except Exception as exc: - _capture_exception(exc) - chat_span.set_status(SPANSTATUS.INTERNAL_ERROR) - raise + with sentry_sdk.start_span( + name=f"chat {model_name}", + attributes={ + "sentry.op": OP.GEN_AI_CHAT, + "sentry.origin": ORIGIN, + SPANDATA.GEN_AI_OPERATION_NAME: "chat", + SPANDATA.GEN_AI_PROVIDER_NAME: GEN_AI_SYSTEM, + SPANDATA.GEN_AI_REQUEST_MODEL: model_name, + }, + ) as chat_span: + set_span_data_for_request( + chat_span, integration, model_name, contents, kwargs + ) + try: + response = await f(self, *args, **kwargs) + except Exception as exc: + _capture_exception(exc) + chat_span.status = SpanStatus.ERROR + raise - set_span_data_for_response(chat_span, integration, response) + set_span_data_for_response(chat_span, integration, response) - return response + return response return new_async_generate_content @@ -349,50 +281,28 @@ def new_embed_content(self: "Any", *args: "Any", **kwargs: "Any") -> "Any": model_name, contents = prepare_embed_content_args(args, kwargs) - if has_span_streaming_enabled(client.options): - with sentry_sdk.traces.start_span( - name=f"embeddings {model_name}", - attributes={ - "sentry.op": OP.GEN_AI_EMBEDDINGS, - "sentry.origin": ORIGIN, - SPANDATA.GEN_AI_OPERATION_NAME: "embeddings", - SPANDATA.GEN_AI_SYSTEM: GEN_AI_SYSTEM, - SPANDATA.GEN_AI_REQUEST_MODEL: model_name, - }, - ) as span: - set_span_data_for_embed_request(span, integration, contents, kwargs) - - try: - response = f(self, *args, **kwargs) - except Exception as exc: - _capture_exception(exc) - span.status = SpanStatus.ERROR - raise - - set_span_data_for_embed_response(span, integration, response) - - return response - else: - with get_start_span_function()( - op=OP.GEN_AI_EMBEDDINGS, - name=f"embeddings {model_name}", - origin=ORIGIN, - ) as span: - span.set_data(SPANDATA.GEN_AI_OPERATION_NAME, "embeddings") - span.set_data(SPANDATA.GEN_AI_SYSTEM, GEN_AI_SYSTEM) - span.set_data(SPANDATA.GEN_AI_REQUEST_MODEL, model_name) - set_span_data_for_embed_request(span, integration, contents, kwargs) - - try: - response = f(self, *args, **kwargs) - except Exception as exc: - _capture_exception(exc) - span.set_status(SPANSTATUS.INTERNAL_ERROR) - raise - - set_span_data_for_embed_response(span, integration, response) - - return response + with sentry_sdk.start_span( + name=f"embeddings {model_name}", + attributes={ + "sentry.op": OP.GEN_AI_EMBEDDINGS, + "sentry.origin": ORIGIN, + SPANDATA.GEN_AI_OPERATION_NAME: "embeddings", + SPANDATA.GEN_AI_PROVIDER_NAME: GEN_AI_SYSTEM, + SPANDATA.GEN_AI_REQUEST_MODEL: model_name, + }, + ) as span: + set_span_data_for_embed_request(span, integration, contents, kwargs) + + try: + response = f(self, *args, **kwargs) + except Exception as exc: + _capture_exception(exc) + span.status = SpanStatus.ERROR + raise + + set_span_data_for_embed_response(span, integration, response) + + return response return new_embed_content @@ -409,49 +319,27 @@ async def new_async_embed_content( model_name, contents = prepare_embed_content_args(args, kwargs) - if has_span_streaming_enabled(client.options): - with sentry_sdk.traces.start_span( - name=f"embeddings {model_name}", - attributes={ - "sentry.op": OP.GEN_AI_EMBEDDINGS, - "sentry.origin": ORIGIN, - SPANDATA.GEN_AI_OPERATION_NAME: "embeddings", - SPANDATA.GEN_AI_SYSTEM: GEN_AI_SYSTEM, - SPANDATA.GEN_AI_REQUEST_MODEL: model_name, - }, - ) as span: - set_span_data_for_embed_request(span, integration, contents, kwargs) - - try: - response = await f(self, *args, **kwargs) - except Exception as exc: - _capture_exception(exc) - span.status = SpanStatus.ERROR - raise - - set_span_data_for_embed_response(span, integration, response) - - return response - else: - with get_start_span_function()( - op=OP.GEN_AI_EMBEDDINGS, - name=f"embeddings {model_name}", - origin=ORIGIN, - ) as span: - span.set_data(SPANDATA.GEN_AI_OPERATION_NAME, "embeddings") - span.set_data(SPANDATA.GEN_AI_SYSTEM, GEN_AI_SYSTEM) - span.set_data(SPANDATA.GEN_AI_REQUEST_MODEL, model_name) - set_span_data_for_embed_request(span, integration, contents, kwargs) - - try: - response = await f(self, *args, **kwargs) - except Exception as exc: - _capture_exception(exc) - span.set_status(SPANSTATUS.INTERNAL_ERROR) - raise - - set_span_data_for_embed_response(span, integration, response) - - return response + with sentry_sdk.start_span( + name=f"embeddings {model_name}", + attributes={ + "sentry.op": OP.GEN_AI_EMBEDDINGS, + "sentry.origin": ORIGIN, + SPANDATA.GEN_AI_OPERATION_NAME: "embeddings", + SPANDATA.GEN_AI_PROVIDER_NAME: GEN_AI_SYSTEM, + SPANDATA.GEN_AI_REQUEST_MODEL: model_name, + }, + ) as span: + set_span_data_for_embed_request(span, integration, contents, kwargs) + + try: + response = await f(self, *args, **kwargs) + except Exception as exc: + _capture_exception(exc) + span.status = SpanStatus.ERROR + raise + + set_span_data_for_embed_response(span, integration, response) + + return response return new_async_embed_content diff --git a/sentry_sdk/integrations/google_genai/streaming.py b/sentry_sdk/integrations/google_genai/streaming.py index 86cdcf29ba..cde266780c 100644 --- a/sentry_sdk/integrations/google_genai/streaming.py +++ b/sentry_sdk/integrations/google_genai/streaming.py @@ -1,10 +1,10 @@ -from typing import TYPE_CHECKING, Any, List, Optional, TypedDict, Union +from typing import TYPE_CHECKING, Any, List, Optional, TypedDict import sentry_sdk from sentry_sdk.ai.utils import set_data_normalized from sentry_sdk.consts import SPANDATA from sentry_sdk.scope import should_send_default_pii -from sentry_sdk.traces import StreamedSpan +from sentry_sdk.traces import Span from sentry_sdk.utils import ( has_data_collection_enabled, safe_serialize, @@ -21,8 +21,6 @@ if TYPE_CHECKING: from google.genai.types import GenerateContentResponse - from sentry_sdk.tracing import Span - class AccumulatedResponse(TypedDict): id: "Optional[str]" @@ -100,14 +98,11 @@ def accumulate_streaming_response( def set_span_data_for_streaming_response( - span: "Union[Span, StreamedSpan]", + span: "Span", integration: "Any", accumulated_response: "AccumulatedResponse", ) -> None: """Set span data for accumulated streaming response.""" - set_on_span = ( - span.set_attribute if isinstance(span, StreamedSpan) else span.set_data - ) client = sentry_sdk.get_client() if accumulated_response.get("finish_reasons"): @@ -119,41 +114,41 @@ def set_span_data_for_streaming_response( response_id = accumulated_response.get("id") if response_id is not None: - set_on_span(SPANDATA.GEN_AI_RESPONSE_ID, response_id) + span.set_attribute(SPANDATA.GEN_AI_RESPONSE_ID, response_id) response_model = accumulated_response.get("model") if response_model is not None: - set_on_span(SPANDATA.GEN_AI_RESPONSE_MODEL, response_model) + span.set_attribute(SPANDATA.GEN_AI_RESPONSE_MODEL, response_model) if accumulated_response["usage_metadata"] is None: return if accumulated_response["usage_metadata"]["input_tokens"]: - set_on_span( + span.set_attribute( SPANDATA.GEN_AI_USAGE_INPUT_TOKENS, accumulated_response["usage_metadata"]["input_tokens"], ) if accumulated_response["usage_metadata"]["input_tokens_cached"]: - set_on_span( - SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHED, + span.set_attribute( + SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS, accumulated_response["usage_metadata"]["input_tokens_cached"], ) if accumulated_response["usage_metadata"]["output_tokens"]: - set_on_span( + span.set_attribute( SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS, accumulated_response["usage_metadata"]["output_tokens"], ) if accumulated_response["usage_metadata"]["output_tokens_reasoning"]: - set_on_span( - SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS_REASONING, + span.set_attribute( + SPANDATA.GEN_AI_USAGE_REASONING_OUTPUT_TOKENS, accumulated_response["usage_metadata"]["output_tokens_reasoning"], ) if accumulated_response["usage_metadata"]["total_tokens"]: - set_on_span( + span.set_attribute( SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS, accumulated_response["usage_metadata"]["total_tokens"], ) @@ -161,13 +156,13 @@ def set_span_data_for_streaming_response( if accumulated_response.get("tool_calls"): if has_data_collection_enabled(client.options): if client.options["data_collection"]["gen_ai"]["outputs"]: - set_on_span( + span.set_attribute( SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS, safe_serialize(accumulated_response["tool_calls"]), ) else: # Before data collection was introduced this was unconditionally set - set_on_span( + span.set_attribute( SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS, safe_serialize(accumulated_response["tool_calls"]), ) @@ -175,13 +170,13 @@ def set_span_data_for_streaming_response( if accumulated_response.get("text"): if has_data_collection_enabled(client.options): if client.options["data_collection"]["gen_ai"]["outputs"]: - set_on_span( + span.set_attribute( SPANDATA.GEN_AI_RESPONSE_TEXT, safe_serialize([accumulated_response["text"]]), ) - elif should_send_default_pii() and integration.include_prompts: - set_on_span( + elif should_send_default_pii(): + span.set_attribute( SPANDATA.GEN_AI_RESPONSE_TEXT, safe_serialize([accumulated_response["text"]]), ) diff --git a/sentry_sdk/integrations/google_genai/utils.py b/sentry_sdk/integrations/google_genai/utils.py index e56d55033e..03081d908b 100644 --- a/sentry_sdk/integrations/google_genai/utils.py +++ b/sentry_sdk/integrations/google_genai/utils.py @@ -25,15 +25,9 @@ normalize_message_roles, set_data_normalized, transform_google_content_part, - truncate_and_annotate_messages, ) from sentry_sdk.consts import OP, SPANDATA from sentry_sdk.scope import should_send_default_pii -from sentry_sdk.traces import StreamedSpan -from sentry_sdk.tracing_utils import ( - has_span_streaming_enabled, - should_truncate_gen_ai_input, -) from sentry_sdk.utils import ( capture_internal_exceptions, event_from_exception, @@ -57,7 +51,7 @@ ) from sentry_sdk._types import TextPart - from sentry_sdk.tracing import Span + from sentry_sdk.traces import Span _is_PIL_available = False try: @@ -685,32 +679,18 @@ def _capture_tool_input( return tool_input -def _create_tool_span( - tool_name: str, tool_doc: "Optional[str]" -) -> "Union[Span, StreamedSpan]": +def _create_tool_span(tool_name: str, tool_doc: "Optional[str]") -> "Span": """Create a span for tool execution.""" - span_streaming = has_span_streaming_enabled(sentry_sdk.get_client().options) - if span_streaming: - span = sentry_sdk.traces.start_span( - name=f"execute_tool {tool_name}", - attributes={ - "sentry.op": OP.GEN_AI_EXECUTE_TOOL, - "sentry.origin": ORIGIN, - SPANDATA.GEN_AI_TOOL_NAME: tool_name, - }, - ) - if tool_doc: - span.set_attribute(SPANDATA.GEN_AI_TOOL_DESCRIPTION, tool_doc) - return span - span = sentry_sdk.start_span( - op=OP.GEN_AI_EXECUTE_TOOL, name=f"execute_tool {tool_name}", - origin=ORIGIN, + attributes={ + "sentry.op": OP.GEN_AI_EXECUTE_TOOL, + "sentry.origin": ORIGIN, + SPANDATA.GEN_AI_TOOL_NAME: tool_name, + }, ) - span.set_data(SPANDATA.GEN_AI_TOOL_NAME, tool_name) if tool_doc: - span.set_data(SPANDATA.GEN_AI_TOOL_DESCRIPTION, tool_doc) + span.set_attribute(SPANDATA.GEN_AI_TOOL_DESCRIPTION, tool_doc) return span @@ -728,22 +708,21 @@ def wrapped_tool(tool: "Tool | Callable[..., Any]") -> "Tool | Callable[..., Any @wraps(tool) async def async_wrapped(*args: "Any", **kwargs: "Any") -> "Any": with _create_tool_span(tool_name, tool_doc) as span: - set_on_span = ( - span.set_attribute - if isinstance(span, StreamedSpan) - else span.set_data - ) # Capture tool input tool_input = _capture_tool_input(args, kwargs, tool) with capture_internal_exceptions(): - set_on_span(SPANDATA.GEN_AI_TOOL_INPUT, safe_serialize(tool_input)) + span.set_attribute( + SPANDATA.GEN_AI_TOOL_INPUT, safe_serialize(tool_input) + ) try: result = await tool(*args, **kwargs) # Capture tool output with capture_internal_exceptions(): - set_on_span(SPANDATA.GEN_AI_TOOL_OUTPUT, safe_serialize(result)) + span.set_attribute( + SPANDATA.GEN_AI_TOOL_OUTPUT, safe_serialize(result) + ) return result except Exception as exc: @@ -756,22 +735,21 @@ async def async_wrapped(*args: "Any", **kwargs: "Any") -> "Any": @wraps(tool) def sync_wrapped(*args: "Any", **kwargs: "Any") -> "Any": with _create_tool_span(tool_name, tool_doc) as span: - set_on_span = ( - span.set_attribute - if isinstance(span, StreamedSpan) - else span.set_data - ) # Capture tool input tool_input = _capture_tool_input(args, kwargs, tool) with capture_internal_exceptions(): - set_on_span(SPANDATA.GEN_AI_TOOL_INPUT, safe_serialize(tool_input)) + span.set_attribute( + SPANDATA.GEN_AI_TOOL_INPUT, safe_serialize(tool_input) + ) try: result = tool(*args, **kwargs) # Capture tool output with capture_internal_exceptions(): - set_on_span(SPANDATA.GEN_AI_TOOL_OUTPUT, safe_serialize(result)) + span.set_attribute( + SPANDATA.GEN_AI_TOOL_OUTPUT, safe_serialize(result) + ) return result except Exception as exc: @@ -919,7 +897,7 @@ def _transform_system_instructions( def set_span_data_for_request( - span: "Union[Span, StreamedSpan]", + span: "Span", integration: "Any", model: str, contents: "ContentListUnion", @@ -927,14 +905,11 @@ def set_span_data_for_request( ) -> None: """Set span data for the request.""" client = sentry_sdk.get_client() - set_on_span = ( - span.set_attribute if isinstance(span, StreamedSpan) else span.set_data - ) - set_on_span(SPANDATA.GEN_AI_SYSTEM, GEN_AI_SYSTEM) - set_on_span(SPANDATA.GEN_AI_REQUEST_MODEL, model) + span.set_attribute(SPANDATA.GEN_AI_PROVIDER_NAME, GEN_AI_SYSTEM) + span.set_attribute(SPANDATA.GEN_AI_REQUEST_MODEL, model) if kwargs.get("stream", False): - set_on_span(SPANDATA.GEN_AI_RESPONSE_STREAMING, True) + span.set_attribute(SPANDATA.GEN_AI_RESPONSE_STREAMING, True) config: "Optional[GenerateContentConfig]" = kwargs.get("config") @@ -965,7 +940,7 @@ def set_span_data_for_request( if has_data_collection_enabled(client.options): if client.options["data_collection"]["gen_ai"]["inputs"]: record_inputs = True - elif should_send_default_pii() and integration.include_prompts: + elif should_send_default_pii(): record_inputs = True if record_inputs: @@ -979,7 +954,7 @@ def set_span_data_for_request( system_instructions = config.get("system_instruction") if system_instructions is not None: - set_on_span( + span.set_attribute( SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS, json.dumps(_transform_system_instructions(system_instructions)), ) @@ -990,20 +965,12 @@ def set_span_data_for_request( if messages: normalized_messages = normalize_message_roles(messages) - client = sentry_sdk.get_client() - scope = sentry_sdk.get_current_scope() - messages_data = ( - truncate_and_annotate_messages(normalized_messages, span, scope) - if should_truncate_gen_ai_input(client.options) - else normalized_messages + set_data_normalized( + span, + SPANDATA.GEN_AI_REQUEST_MESSAGES, + normalized_messages, + unpack=False, ) - if messages_data is not None: - set_data_normalized( - span, - SPANDATA.GEN_AI_REQUEST_MESSAGES, - messages_data, - unpack=False, - ) # Extract parameters directly from config (not nested under generation_config) for param, span_key in [ @@ -1018,11 +985,11 @@ def set_span_data_for_request( if hasattr(config, param): value = getattr(config, param) if value is not None: - set_on_span(span_key, value) + span.set_attribute(span_key, value) def set_span_data_for_response( - span: "Union[Span, StreamedSpan]", + span: "Span", integration: "Any", response: "GenerateContentResponse", ) -> None: @@ -1030,9 +997,6 @@ def set_span_data_for_response( return client = sentry_sdk.get_client() - set_on_span = ( - span.set_attribute if isinstance(span, StreamedSpan) else span.set_data - ) finish_reasons = extract_finish_reasons(response) if finish_reasons: @@ -1042,59 +1006,69 @@ def set_span_data_for_response( response_id = getattr(response, "response_id", None) if response_id is not None: - set_on_span(SPANDATA.GEN_AI_RESPONSE_ID, response_id) + span.set_attribute(SPANDATA.GEN_AI_RESPONSE_ID, response_id) model_version = getattr(response, "model_version", None) if model_version is not None: - set_on_span(SPANDATA.GEN_AI_RESPONSE_MODEL, model_version) + span.set_attribute(SPANDATA.GEN_AI_RESPONSE_MODEL, model_version) usage_data = extract_usage_data(response) if usage_data["input_tokens"]: - set_on_span(SPANDATA.GEN_AI_USAGE_INPUT_TOKENS, usage_data["input_tokens"]) + span.set_attribute( + SPANDATA.GEN_AI_USAGE_INPUT_TOKENS, usage_data["input_tokens"] + ) if usage_data["input_tokens_cached"]: - set_on_span( - SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHED, + span.set_attribute( + SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS, usage_data["input_tokens_cached"], ) if usage_data["output_tokens"]: - set_on_span(SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS, usage_data["output_tokens"]) + span.set_attribute( + SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS, usage_data["output_tokens"] + ) if usage_data["output_tokens_reasoning"]: - set_on_span( - SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS_REASONING, + span.set_attribute( + SPANDATA.GEN_AI_USAGE_REASONING_OUTPUT_TOKENS, usage_data["output_tokens_reasoning"], ) if usage_data["total_tokens"]: - set_on_span(SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS, usage_data["total_tokens"]) + span.set_attribute( + SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS, usage_data["total_tokens"] + ) tool_calls = extract_tool_calls(response) if tool_calls: if has_data_collection_enabled(client.options): if client.options["data_collection"]["gen_ai"]["outputs"]: - set_on_span( + span.set_attribute( SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS, safe_serialize(tool_calls) ) else: # Before data collection was introduced, this was set unconditionally - set_on_span(SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS, safe_serialize(tool_calls)) + span.set_attribute( + SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS, safe_serialize(tool_calls) + ) if has_data_collection_enabled(client.options): if client.options["data_collection"]["gen_ai"]["outputs"]: response_texts = _extract_response_text(response) if response_texts: - set_on_span( + span.set_attribute( SPANDATA.GEN_AI_RESPONSE_TEXT, safe_serialize(response_texts) ) - elif should_send_default_pii() and integration.include_prompts: + elif should_send_default_pii(): # TODO: Delete this block once data collection has been completely rolled out response_texts = _extract_response_text(response) if response_texts: # Format as JSON string array as per documentation - set_on_span(SPANDATA.GEN_AI_RESPONSE_TEXT, safe_serialize(response_texts)) + span.set_attribute( + SPANDATA.GEN_AI_RESPONSE_TEXT, safe_serialize(response_texts) + ) def prepare_generate_content_args( @@ -1129,7 +1103,7 @@ def prepare_embed_content_args( def set_span_data_for_embed_request( - span: "Union[Span, StreamedSpan]", + span: "Span", integration: "Any", contents: "Any", kwargs: "dict[str, Any]", @@ -1141,7 +1115,7 @@ def set_span_data_for_embed_request( if has_data_collection_enabled(client.options): if client.options["data_collection"]["gen_ai"]["inputs"]: record_inputs = True - elif should_send_default_pii() and integration.include_prompts: + elif should_send_default_pii(): record_inputs = True if record_inputs: @@ -1172,7 +1146,7 @@ def set_span_data_for_embed_request( def set_span_data_for_embed_response( - span: "Union[Span, StreamedSpan]", + span: "Span", integration: "Any", response: "EmbedContentResponse", ) -> None: @@ -1193,7 +1167,4 @@ def set_span_data_for_embed_response( # Set token count if we found any if total_tokens > 0: - if isinstance(span, StreamedSpan): - span.set_attribute(SPANDATA.GEN_AI_USAGE_INPUT_TOKENS, total_tokens) - else: - span.set_data(SPANDATA.GEN_AI_USAGE_INPUT_TOKENS, total_tokens) + span.set_attribute(SPANDATA.GEN_AI_USAGE_INPUT_TOKENS, total_tokens) diff --git a/sentry_sdk/integrations/gql.py b/sentry_sdk/integrations/gql.py index 95dbb5c1a0..30b4af6ad5 100644 --- a/sentry_sdk/integrations/gql.py +++ b/sentry_sdk/integrations/gql.py @@ -31,7 +31,7 @@ GraphQLRequest = None except ImportError: - raise DidNotEnable("gql is not installed") + raise DidNotEnable("gql is not installed or incompatible") from typing import TYPE_CHECKING diff --git a/sentry_sdk/integrations/graphene.py b/sentry_sdk/integrations/graphene.py index 7f567a5407..54a2f4baa3 100644 --- a/sentry_sdk/integrations/graphene.py +++ b/sentry_sdk/integrations/graphene.py @@ -4,19 +4,19 @@ from sentry_sdk.consts import OP from sentry_sdk.integrations import DidNotEnable, Integration, _check_minimum_version from sentry_sdk.scope import should_send_default_pii -from sentry_sdk.tracing_utils import has_span_streaming_enabled from sentry_sdk.utils import ( capture_internal_exceptions, ensure_integration_enabled, event_from_exception, has_data_collection_enabled, - package_version, + parse_version, ) try: + from graphene import __version__ as GRAPHENE_VERSION # type: ignore from graphene.types import schema as graphene_schema # type: ignore except ImportError: - raise DidNotEnable("graphene is not installed") + raise DidNotEnable("graphene is not installed or incompatible") from typing import TYPE_CHECKING @@ -36,7 +36,7 @@ class GrapheneIntegration(Integration): @staticmethod def setup_once() -> None: - version = package_version("graphene") + version = parse_version(GRAPHENE_VERSION) _check_minimum_version(GrapheneIntegration, version) _patch_graphql() @@ -153,47 +153,29 @@ def graphql_span( ) client_options = sentry_sdk.get_client().options - is_span_streaming_enabled = has_span_streaming_enabled(client_options) - - if is_span_streaming_enabled: - if sentry_sdk.traces.get_current_span() is None: - yield - return - - additional_attributes = {} - if has_data_collection_enabled(client_options): - if client_options["data_collection"]["graphql"]["document"]: - additional_attributes["graphql.document"] = source - elif should_send_default_pii(): - additional_attributes["graphql.document"] = source - - _graphql_span = sentry_sdk.traces.start_span( - name=operation_name, - attributes={ - "sentry.op": op, - "graphql.operation.name": operation_name, - "graphql.operation.type": operation_type, - **additional_attributes, - }, - ) - else: - _graphql_span = sentry_sdk.start_span(op=op, name=operation_name) - if has_data_collection_enabled(client_options): - if client_options["data_collection"]["graphql"]["document"]: - _graphql_span.set_data("graphql.document", source) - elif should_send_default_pii(): - _graphql_span.set_data("graphql.document", source) - - _graphql_span.set_data("graphql.operation.name", operation_name) - _graphql_span.set_data("graphql.operation.type", operation_type) + if sentry_sdk.get_current_span() is None: + yield + return - _graphql_span.__enter__() + additional_attributes = {} + if has_data_collection_enabled(client_options): + if client_options["data_collection"]["graphql"]["document"]: + additional_attributes["graphql.document"] = source + elif should_send_default_pii(): + additional_attributes["graphql.document"] = source + + _graphql_span = sentry_sdk.start_span( + name=operation_name, + attributes={ + "sentry.op": op, + "graphql.operation.name": operation_name, + "graphql.operation.type": operation_type, + **additional_attributes, + }, + ) try: yield finally: - if is_span_streaming_enabled: - _graphql_span.end() # type: ignore - else: - _graphql_span.__exit__(None, None, None) + _graphql_span.end() diff --git a/sentry_sdk/integrations/grpc/__init__.py b/sentry_sdk/integrations/grpc/__init__.py index bf74ff1351..8d94e1f6b5 100644 --- a/sentry_sdk/integrations/grpc/__init__.py +++ b/sentry_sdk/integrations/grpc/__init__.py @@ -1,7 +1,7 @@ from functools import wraps from typing import TYPE_CHECKING, Any, Optional, Sequence -from sentry_sdk.integrations import DidNotEnable, Integration +from sentry_sdk.integrations import DidNotEnable, Integration, _check_minimum_version from sentry_sdk.utils import parse_version from .client import ClientInterceptor @@ -175,6 +175,8 @@ class GRPCIntegration(Integration): @staticmethod def setup_once() -> None: + _check_minimum_version(GRPCIntegration, GRPC_VERSION) + import grpc grpc.insecure_channel = _wrap_channel_sync(grpc.insecure_channel) diff --git a/sentry_sdk/integrations/grpc/aio/client.py b/sentry_sdk/integrations/grpc/aio/client.py index 97e9d828c0..67f85ef167 100644 --- a/sentry_sdk/integrations/grpc/aio/client.py +++ b/sentry_sdk/integrations/grpc/aio/client.py @@ -4,7 +4,6 @@ from sentry_sdk.consts import OP, SPANDATA from sentry_sdk.integrations import DidNotEnable from sentry_sdk.integrations.grpc.consts import SPAN_ORIGIN -from sentry_sdk.tracing_utils import has_span_streaming_enabled try: from google.protobuf.message import Message @@ -50,54 +49,29 @@ async def intercept_unary_unary( ) -> "Union[UnaryUnaryCall, Message]": method = client_call_details.method - span_streaming = has_span_streaming_enabled(sentry_sdk.get_client().options) - if span_streaming: - if sentry_sdk.traces.get_current_span() is None: - client_call_details = ( - self._update_client_call_details_metadata_from_scope( - client_call_details - ) - ) - return await continuation(client_call_details, request) - with sentry_sdk.traces.start_span( - name="unary unary call to %s" % method.decode(), - attributes={ - "sentry.op": OP.GRPC_CLIENT, - "sentry.origin": SPAN_ORIGIN, - SPANDATA.RPC_METHOD: method.decode(), - }, - ) as span: - client_call_details = ( - self._update_client_call_details_metadata_from_scope( - client_call_details - ) - ) - - response = await continuation(client_call_details, request) - status_code = await response.code() - span.set_attribute(SPANDATA.RPC_RESPONSE_STATUS_CODE, status_code.name) - - return response - else: - with sentry_sdk.start_span( - op=OP.GRPC_CLIENT, - name="unary unary call to %s" % method.decode(), - origin=SPAN_ORIGIN, - ) as span: - span.set_data("type", "unary unary") - span.set_data("method", method) - - client_call_details = ( - self._update_client_call_details_metadata_from_scope( - client_call_details - ) - ) + if sentry_sdk.get_current_span() is None: + client_call_details = self._update_client_call_details_metadata_from_scope( + client_call_details + ) + return await continuation(client_call_details, request) + + with sentry_sdk.start_span( + name="unary unary call to %s" % method.decode(), + attributes={ + "sentry.op": OP.GRPC_CLIENT, + "sentry.origin": SPAN_ORIGIN, + SPANDATA.RPC_METHOD: method.decode(), + }, + ) as span: + client_call_details = self._update_client_call_details_metadata_from_scope( + client_call_details + ) - response = await continuation(client_call_details, request) - status_code = await response.code() - span.set_data("code", status_code.name) + response = await continuation(client_call_details, request) + status_code = await response.code() + span.set_attribute(SPANDATA.RPC_RESPONSE_STATUS_CODE, status_code.name) - return response + return response class SentryUnaryStreamClientInterceptor( @@ -112,49 +86,23 @@ async def intercept_unary_stream( ) -> "Union[AsyncIterable[Any], UnaryStreamCall]": method = client_call_details.method - span_streaming = has_span_streaming_enabled(sentry_sdk.get_client().options) - if span_streaming: - if sentry_sdk.traces.get_current_span() is None: - client_call_details = ( - self._update_client_call_details_metadata_from_scope( - client_call_details - ) - ) - return await continuation(client_call_details, request) - with sentry_sdk.traces.start_span( - name="unary stream call to %s" % method.decode(), - attributes={ - "sentry.op": OP.GRPC_CLIENT, - "sentry.origin": SPAN_ORIGIN, - SPANDATA.RPC_METHOD: method.decode(), - }, - ) as span: - client_call_details = ( - self._update_client_call_details_metadata_from_scope( - client_call_details - ) - ) - - response = await continuation(client_call_details, request) - - return response - else: - with sentry_sdk.start_span( - op=OP.GRPC_CLIENT, - name="unary stream call to %s" % method.decode(), - origin=SPAN_ORIGIN, - ) as span: - span.set_data("type", "unary stream") - span.set_data("method", method) - - client_call_details = ( - self._update_client_call_details_metadata_from_scope( - client_call_details - ) - ) - - response = await continuation(client_call_details, request) - # status_code = await response.code() - # span.set_data("code", status_code) + if sentry_sdk.get_current_span() is None: + client_call_details = self._update_client_call_details_metadata_from_scope( + client_call_details + ) + return await continuation(client_call_details, request) + + with sentry_sdk.start_span( + name="unary stream call to %s" % method.decode(), + attributes={ + "sentry.op": OP.GRPC_CLIENT, + "sentry.origin": SPAN_ORIGIN, + SPANDATA.RPC_METHOD: method.decode(), + }, + ): + client_call_details = self._update_client_call_details_metadata_from_scope( + client_call_details + ) - return response + response = await continuation(client_call_details, request) + return response diff --git a/sentry_sdk/integrations/grpc/aio/server.py b/sentry_sdk/integrations/grpc/aio/server.py index 15dcacab59..153430bd31 100644 --- a/sentry_sdk/integrations/grpc/aio/server.py +++ b/sentry_sdk/integrations/grpc/aio/server.py @@ -5,8 +5,6 @@ from sentry_sdk.integrations import DidNotEnable from sentry_sdk.integrations.grpc.consts import SPAN_ORIGIN from sentry_sdk.traces import SegmentNameSource -from sentry_sdk.tracing import TransactionSource -from sentry_sdk.tracing_utils import has_span_streaming_enabled from sentry_sdk.utils import event_from_exception if TYPE_CHECKING: @@ -54,57 +52,29 @@ async def wrapped(request: "Any", context: "ServicerContext") -> "Any": if not name: return await handler(request, context) - span_streaming = has_span_streaming_enabled( - sentry_sdk.get_client().options - ) - if span_streaming: - # What if the headers are empty? - sentry_sdk.traces.continue_trace( - dict(context.invocation_metadata()) - ) - - with sentry_sdk.traces.start_span( - name=name, - attributes={ - "sentry.op": OP.GRPC_SERVER, - "sentry.segment.name.source": SegmentNameSource.CUSTOM.value, - "sentry.origin": SPAN_ORIGIN, - }, - parent_span=None, - ): - try: - return await handler.unary_unary(request, context) - except AbortError: - raise - except Exception as exc: - event, hint = event_from_exception( - exc, - mechanism={"type": "grpc", "handled": False}, - ) - sentry_sdk.capture_event(event, hint=hint) - raise - else: - # What if the headers are empty? - transaction = sentry_sdk.continue_trace( - dict(context.invocation_metadata()), - op=OP.GRPC_SERVER, - name=name, - source=TransactionSource.CUSTOM, - origin=SPAN_ORIGIN, - ) - - with sentry_sdk.start_transaction(transaction=transaction): - try: - return await handler.unary_unary(request, context) - except AbortError: - raise - except Exception as exc: - event, hint = event_from_exception( - exc, - mechanism={"type": "grpc", "handled": False}, - ) - sentry_sdk.capture_event(event, hint=hint) - raise + # What if the headers are empty? + sentry_sdk.continue_trace(dict(context.invocation_metadata())) + + with sentry_sdk.start_span( + name=name, + attributes={ + "sentry.op": OP.GRPC_SERVER, + "sentry.segment.name.source": SegmentNameSource.CUSTOM.value, + "sentry.origin": SPAN_ORIGIN, + }, + parent_span=None, + ): + try: + return await handler.unary_unary(request, context) + except AbortError: + raise + except Exception as exc: + event, hint = event_from_exception( + exc, + mechanism={"type": "grpc", "handled": False}, + ) + sentry_sdk.capture_event(event, hint=hint) + raise elif not handler.request_streaming and handler.response_streaming: handler_factory = grpc.unary_stream_rpc_method_handler diff --git a/sentry_sdk/integrations/grpc/client.py b/sentry_sdk/integrations/grpc/client.py index fe9954445e..82e2190f40 100644 --- a/sentry_sdk/integrations/grpc/client.py +++ b/sentry_sdk/integrations/grpc/client.py @@ -4,7 +4,6 @@ from sentry_sdk.consts import OP, SPANDATA from sentry_sdk.integrations import DidNotEnable from sentry_sdk.integrations.grpc.consts import SPAN_ORIGIN -from sentry_sdk.tracing_utils import has_span_streaming_enabled if TYPE_CHECKING: from typing import Any, Callable, Iterable, Iterator, Union @@ -31,54 +30,27 @@ def intercept_unary_unary( ) -> "_UnaryOutcome": method = client_call_details.method - span_streaming = has_span_streaming_enabled(sentry_sdk.get_client().options) - if span_streaming: - if sentry_sdk.traces.get_current_span() is None: - client_call_details = ( - self._update_client_call_details_metadata_from_scope( - client_call_details - ) - ) - return continuation(client_call_details, request) - with sentry_sdk.traces.start_span( - name="unary unary call to %s" % method, - attributes={ - "sentry.op": OP.GRPC_CLIENT, - "sentry.origin": SPAN_ORIGIN, - SPANDATA.RPC_METHOD: method, - }, - ) as span: - client_call_details = ( - self._update_client_call_details_metadata_from_scope( - client_call_details - ) - ) - - response = continuation(client_call_details, request) - span.set_attribute( - SPANDATA.RPC_RESPONSE_STATUS_CODE, response.code().name - ) - - return response - else: - with sentry_sdk.start_span( - op=OP.GRPC_CLIENT, - name="unary unary call to %s" % method, - origin=SPAN_ORIGIN, - ) as span: - span.set_data("type", "unary unary") - span.set_data("method", method) - - client_call_details = ( - self._update_client_call_details_metadata_from_scope( - client_call_details - ) - ) - - response = continuation(client_call_details, request) - span.set_data("code", response.code().name) - - return response + if sentry_sdk.get_current_span() is None: + client_call_details = self._update_client_call_details_metadata_from_scope( + client_call_details + ) + return continuation(client_call_details, request) + with sentry_sdk.start_span( + name="unary unary call to %s" % method, + attributes={ + "sentry.op": OP.GRPC_CLIENT, + "sentry.origin": SPAN_ORIGIN, + SPANDATA.RPC_METHOD: method, + }, + ) as span: + client_call_details = self._update_client_call_details_metadata_from_scope( + client_call_details + ) + + response = continuation(client_call_details, request) + span.set_attribute(SPANDATA.RPC_RESPONSE_STATUS_CODE, response.code().name) + + return response def intercept_unary_stream( self: "ClientInterceptor", @@ -88,55 +60,25 @@ def intercept_unary_stream( ) -> "Union[Iterator[Message], Call]": method = client_call_details.method - span_streaming = has_span_streaming_enabled(sentry_sdk.get_client().options) - response: "UnaryStreamCall" - if span_streaming: - if sentry_sdk.traces.get_current_span() is None: - client_call_details = ( - self._update_client_call_details_metadata_from_scope( - client_call_details - ) - ) - return continuation(client_call_details, request) - with sentry_sdk.traces.start_span( - name="unary stream call to %s" % method, - attributes={ - "sentry.op": OP.GRPC_CLIENT, - "sentry.origin": SPAN_ORIGIN, - SPANDATA.RPC_METHOD: method, - }, - ) as span: - client_call_details = ( - self._update_client_call_details_metadata_from_scope( - client_call_details - ) - ) - - response = continuation(client_call_details, request) - # Setting code on unary-stream leads to execution getting stuck - # span.set_data("code", response.code().name) - - return response - else: - with sentry_sdk.start_span( - op=OP.GRPC_CLIENT, - name="unary stream call to %s" % method, - origin=SPAN_ORIGIN, - ) as span: - span.set_data("type", "unary stream") - span.set_data("method", method) - - client_call_details = ( - self._update_client_call_details_metadata_from_scope( - client_call_details - ) - ) - - response = continuation(client_call_details, request) - # Setting code on unary-stream leads to execution getting stuck - # span.set_data("code", response.code().name) - - return response + if sentry_sdk.get_current_span() is None: + client_call_details = self._update_client_call_details_metadata_from_scope( + client_call_details + ) + return continuation(client_call_details, request) + + with sentry_sdk.start_span( + name="unary stream call to %s" % method, + attributes={ + "sentry.op": OP.GRPC_CLIENT, + "sentry.origin": SPAN_ORIGIN, + SPANDATA.RPC_METHOD: method, + }, + ): + client_call_details = self._update_client_call_details_metadata_from_scope( + client_call_details + ) + + return continuation(client_call_details, request) @staticmethod def _update_client_call_details_metadata_from_scope( diff --git a/sentry_sdk/integrations/grpc/server.py b/sentry_sdk/integrations/grpc/server.py index 9b091c258d..79b05cb275 100644 --- a/sentry_sdk/integrations/grpc/server.py +++ b/sentry_sdk/integrations/grpc/server.py @@ -5,8 +5,6 @@ from sentry_sdk.integrations import DidNotEnable from sentry_sdk.integrations.grpc.consts import SPAN_ORIGIN from sentry_sdk.traces import SegmentNameSource -from sentry_sdk.tracing import TransactionSource -from sentry_sdk.tracing_utils import has_span_streaming_enabled if TYPE_CHECKING: from typing import Callable, Optional @@ -48,39 +46,22 @@ def behavior(request: "Message", context: "ServicerContext") -> "Message": if name: metadata = dict(context.invocation_metadata()) - span_streaming = has_span_streaming_enabled( - sentry_sdk.get_client().options - ) - if span_streaming: - sentry_sdk.traces.continue_trace(metadata) + sentry_sdk.continue_trace(metadata) - with sentry_sdk.traces.start_span( - name=name, - attributes={ - "sentry.op": OP.GRPC_SERVER, - "sentry.segment.name.source": SegmentNameSource.CUSTOM.value, - "sentry.origin": SPAN_ORIGIN, - }, - parent_span=None, - ): - try: - return handler.unary_unary(request, context) - except BaseException as e: - raise e - else: - transaction = sentry_sdk.continue_trace( - metadata, - op=OP.GRPC_SERVER, - name=name, - source=TransactionSource.CUSTOM, - origin=SPAN_ORIGIN, - ) + with sentry_sdk.start_span( + name=name, + attributes={ + "sentry.op": OP.GRPC_SERVER, + "sentry.segment.name.source": SegmentNameSource.CUSTOM.value, + "sentry.origin": SPAN_ORIGIN, + }, + parent_span=None, + ): + try: + return handler.unary_unary(request, context) + except BaseException as e: + raise e - with sentry_sdk.start_transaction(transaction=transaction): - try: - return handler.unary_unary(request, context) - except BaseException as e: - raise e else: return handler.unary_unary(request, context) diff --git a/sentry_sdk/integrations/httpx.py b/sentry_sdk/integrations/httpx.py index a6f9267b2d..4286b84aa9 100644 --- a/sentry_sdk/integrations/httpx.py +++ b/sentry_sdk/integrations/httpx.py @@ -1,33 +1,32 @@ +from contextlib import nullcontext from typing import TYPE_CHECKING import sentry_sdk from sentry_sdk.consts import OP, SPANDATA -from sentry_sdk.integrations import DidNotEnable, Integration +from sentry_sdk.integrations import DidNotEnable, Integration, _check_minimum_version from sentry_sdk.tracing_utils import ( add_http_breadcrumb, add_http_request_source, - get_url_attributes, - has_span_streaming_enabled, + get_url_attributes_legacy, propagate_trace_headers, ) from sentry_sdk.utils import ( SENSITIVE_DATA_SUBSTITUTE, capture_internal_exceptions, ensure_integration_enabled, - nullcontext, parse_url, + parse_version, ) if TYPE_CHECKING: from typing import Any - from sentry_sdk._types import Attributes - try: from httpx import AsyncClient, Client, Request, Response + from httpx import __version__ as HTTPX_VERSION except ImportError: - raise DidNotEnable("httpx is not installed") + raise DidNotEnable("httpx is not installed or incompatible") __all__ = ["HttpxIntegration"] @@ -42,6 +41,9 @@ def setup_once() -> None: httpx has its own transport layer and can be customized when needed, so patch Client.send and AsyncClient.send to support both synchronous and async interfaces. """ + version = parse_version(HTTPX_VERSION) + _check_minimum_version(HttpxIntegration, version) + _install_httpx_client() _install_httpx_async_client() @@ -52,81 +54,47 @@ def _install_httpx_client() -> None: @ensure_integration_enabled(HttpxIntegration, real_send) def send(self: "Client", request: "Request", **kwargs: "Any") -> "Response": client = sentry_sdk.get_client() - is_span_streaming_enabled = has_span_streaming_enabled(client.options) parsed_url = None with capture_internal_exceptions(): parsed_url = parse_url(str(request.url), sanitize=False) - url_attributes: "Attributes" = {} - - if is_span_streaming_enabled: - if sentry_sdk.traces.get_current_span() is None: - span_ctx = nullcontext() - else: - span_ctx = sentry_sdk.traces.start_span( - name="%s %s" - % ( - request.method, - parsed_url.url if parsed_url else SENSITIVE_DATA_SUBSTITUTE, - ), - attributes={ - "sentry.op": OP.HTTP_CLIENT, - "sentry.origin": HttpxIntegration.origin, - "http.request.method": request.method, - }, - ) - - url_attributes = get_url_attributes(client, parsed_url) - - with span_ctx as streamed_span: - propagate_trace_headers(client, request) - - try: - rv = real_send(self, request, **kwargs) - - if streamed_span is not None: - streamed_span.status = ( - "error" if rv.status_code >= 400 else "ok" - ) - streamed_span.set_attribute( - "http.response.status_code", rv.status_code - ) - finally: - if streamed_span is not None: - streamed_span.set_attributes(url_attributes) - - if streamed_span is not None: - # Needs to happen within the context manager as we want to attach the - # final data before the span finishes and is sent for ingesting. - with capture_internal_exceptions(): - add_http_request_source(streamed_span) + url_attributes = get_url_attributes_legacy(client, parsed_url) + if sentry_sdk.get_current_span() is None: + span_ctx = nullcontext() else: - with sentry_sdk.start_span( - op=OP.HTTP_CLIENT, + span_ctx = sentry_sdk.start_span( name="%s %s" % ( request.method, parsed_url.url if parsed_url else SENSITIVE_DATA_SUBSTITUTE, ), - origin=HttpxIntegration.origin, - ) as span: - span.set_data(SPANDATA.HTTP_METHOD, request.method) - if parsed_url is not None: - span.set_data("url", parsed_url.url) - span.set_data(SPANDATA.HTTP_QUERY, parsed_url.query) - span.set_data(SPANDATA.HTTP_FRAGMENT, parsed_url.fragment) + attributes={ + "sentry.op": OP.HTTP_CLIENT, + "sentry.origin": HttpxIntegration.origin, + "http.request.method": request.method, + }, + ) - propagate_trace_headers(client, request) + with span_ctx as span: + propagate_trace_headers(client, request) + try: rv = real_send(self, request, **kwargs) - span.set_http_status(rv.status_code) - span.set_data("reason", rv.reason_phrase) + if span is not None: + span.status = "error" if rv.status_code >= 400 else "ok" + span.set_attribute("http.response.status_code", rv.status_code) + finally: + if span is not None: + span.set_attributes(url_attributes) - with capture_internal_exceptions(): - add_http_request_source(span) + if span is not None: + # Needs to happen within the context manager as we want to attach the + # final data before the span finishes and is sent for ingesting. + with capture_internal_exceptions(): + add_http_request_source(span) breadcrumb_data = { SPANDATA.HTTP_METHOD: request.method, @@ -134,23 +102,14 @@ def send(self: "Client", request: "Request", **kwargs: "Any") -> "Response": "reason": rv.reason_phrase, } - if parsed_url: - if not is_span_streaming_enabled: - breadcrumb_data.update( - { - "url": parsed_url.url, - SPANDATA.HTTP_QUERY: parsed_url.query, - SPANDATA.HTTP_FRAGMENT: parsed_url.fragment, - } - ) - elif url_attributes: - breadcrumb_data.update( - { - "url": url_attributes.get("url.full", ""), - SPANDATA.HTTP_QUERY: url_attributes.get("url.query", ""), - SPANDATA.HTTP_FRAGMENT: url_attributes.get("url.fragment", ""), - } - ) + if parsed_url and url_attributes: + breadcrumb_data.update( + { + "url": url_attributes.get("url.full", ""), + SPANDATA.HTTP_QUERY: url_attributes.get("url.query", ""), + SPANDATA.HTTP_FRAGMENT: url_attributes.get("url.fragment", ""), + } + ) add_http_breadcrumb(rv.status_code, breadcrumb_data) @@ -169,102 +128,60 @@ async def send( if client.get_integration(HttpxIntegration) is None: return await real_send(self, request, **kwargs) - is_span_streaming_enabled = has_span_streaming_enabled(client.options) parsed_url = None with capture_internal_exceptions(): parsed_url = parse_url(str(request.url), sanitize=False) - url_attributes: "Attributes" = {} - - if is_span_streaming_enabled: - if sentry_sdk.traces.get_current_span() is None: - span_ctx = nullcontext() - else: - span_ctx = sentry_sdk.traces.start_span( - name="%s %s" - % ( - request.method, - parsed_url.url if parsed_url else SENSITIVE_DATA_SUBSTITUTE, - ), - attributes={ - "sentry.op": OP.HTTP_CLIENT, - "sentry.origin": HttpxIntegration.origin, - "http.request.method": request.method, - }, - ) - - url_attributes = get_url_attributes(client, parsed_url) - - with span_ctx as streamed_span: - propagate_trace_headers(client, request) - - try: - rv = await real_send(self, request, **kwargs) - - if streamed_span is not None: - streamed_span.status = ( - "error" if rv.status_code >= 400 else "ok" - ) - streamed_span.set_attribute( - "http.response.status_code", rv.status_code - ) - finally: - if streamed_span is not None: - streamed_span.set_attributes(url_attributes) - - if streamed_span is not None: - # Needs to happen within the context manager as we want to attach the - # final data before the span finishes and is sent for ingesting. - with capture_internal_exceptions(): - add_http_request_source(streamed_span) + if sentry_sdk.get_current_span() is None: + span_ctx = nullcontext() else: - with sentry_sdk.start_span( - op=OP.HTTP_CLIENT, + span_ctx = sentry_sdk.start_span( name="%s %s" % ( request.method, parsed_url.url if parsed_url else SENSITIVE_DATA_SUBSTITUTE, ), - origin=HttpxIntegration.origin, - ) as span: - span.set_data(SPANDATA.HTTP_METHOD, request.method) - if parsed_url is not None: - span.set_data("url", parsed_url.url) - span.set_data(SPANDATA.HTTP_QUERY, parsed_url.query) - span.set_data(SPANDATA.HTTP_FRAGMENT, parsed_url.fragment) + attributes={ + "sentry.op": OP.HTTP_CLIENT, + "sentry.origin": HttpxIntegration.origin, + "http.request.method": request.method, + }, + ) + + url_attributes = get_url_attributes_legacy(client, parsed_url) - propagate_trace_headers(client, request) + with span_ctx as span: + propagate_trace_headers(client, request) + try: rv = await real_send(self, request, **kwargs) - span.set_http_status(rv.status_code) - span.set_data("reason", rv.reason_phrase) + if span is not None: + span.status = "error" if rv.status_code >= 400 else "ok" + span.set_attribute("http.response.status_code", rv.status_code) + finally: + if span is not None: + span.set_attributes(url_attributes) - with capture_internal_exceptions(): - add_http_request_source(span) + if span is not None: + # Needs to happen within the context manager as we want to attach the + # final data before the span finishes and is sent for ingesting. + with capture_internal_exceptions(): + add_http_request_source(span) breadcrumb_data = { SPANDATA.HTTP_METHOD: request.method, SPANDATA.HTTP_STATUS_CODE: rv.status_code, "reason": rv.reason_phrase, } - if parsed_url: - if not is_span_streaming_enabled: - breadcrumb_data.update( - { - "url": parsed_url.url, - SPANDATA.HTTP_QUERY: parsed_url.query, - SPANDATA.HTTP_FRAGMENT: parsed_url.fragment, - } - ) - elif url_attributes: - breadcrumb_data.update( - { - "url": url_attributes.get("url.full", ""), - SPANDATA.HTTP_QUERY: url_attributes.get("url.query", ""), - SPANDATA.HTTP_FRAGMENT: url_attributes.get("url.fragment", ""), - } - ) + if parsed_url and url_attributes: + breadcrumb_data.update( + { + "url": url_attributes.get("url.full", ""), + SPANDATA.HTTP_QUERY: url_attributes.get("url.query", ""), + SPANDATA.HTTP_FRAGMENT: url_attributes.get("url.fragment", ""), + } + ) add_http_breadcrumb(rv.status_code, breadcrumb_data) diff --git a/sentry_sdk/integrations/httpx2.py b/sentry_sdk/integrations/httpx2.py index 5ce2f74fb7..34804f7b03 100644 --- a/sentry_sdk/integrations/httpx2.py +++ b/sentry_sdk/integrations/httpx2.py @@ -1,33 +1,32 @@ +from contextlib import nullcontext from typing import TYPE_CHECKING import sentry_sdk from sentry_sdk.consts import OP, SPANDATA -from sentry_sdk.integrations import DidNotEnable, Integration +from sentry_sdk.integrations import DidNotEnable, Integration, _check_minimum_version from sentry_sdk.tracing_utils import ( add_http_breadcrumb, add_http_request_source, - get_url_attributes, - has_span_streaming_enabled, + get_url_attributes_legacy, propagate_trace_headers, ) from sentry_sdk.utils import ( SENSITIVE_DATA_SUBSTITUTE, capture_internal_exceptions, ensure_integration_enabled, - nullcontext, parse_url, + parse_version, ) if TYPE_CHECKING: from typing import Any - from sentry_sdk._types import Attributes - try: from httpx2 import AsyncClient, Client, Request, Response + from httpx2 import __version__ as HTTPX2_VERSION except ImportError: - raise DidNotEnable("httpx2 is not installed") + raise DidNotEnable("httpx2 is not installed or incompatible") __all__ = ["Httpx2Integration"] @@ -42,6 +41,9 @@ def setup_once() -> None: httpx2 has its own transport layer and can be customized when needed, so patch Client.send and AsyncClient.send to support both synchronous and async interfaces. """ + version = parse_version(HTTPX2_VERSION) + _check_minimum_version(Httpx2Integration, version) + _install_httpx2_client() _install_httpx2_async_client() @@ -52,80 +54,47 @@ def _install_httpx2_client() -> None: @ensure_integration_enabled(Httpx2Integration, real_send) def send(self: "Client", request: "Request", **kwargs: "Any") -> "Response": client = sentry_sdk.get_client() - is_span_streaming_enabled = has_span_streaming_enabled(client.options) parsed_url = None with capture_internal_exceptions(): parsed_url = parse_url(str(request.url), sanitize=False) - url_attributes: "Attributes" = {} - - if is_span_streaming_enabled: - if sentry_sdk.traces.get_current_span() is None: - span_ctx = nullcontext() - else: - span_ctx = sentry_sdk.traces.start_span( - name="%s %s" - % ( - request.method, - parsed_url.url if parsed_url else SENSITIVE_DATA_SUBSTITUTE, - ), - attributes={ - "sentry.op": OP.HTTP_CLIENT, - "sentry.origin": Httpx2Integration.origin, - "http.request.method": request.method, - }, - ) - - url_attributes = get_url_attributes(client, parsed_url) - - with span_ctx as streamed_span: - propagate_trace_headers(client, request) - - try: - rv = real_send(self, request, **kwargs) - - if streamed_span is not None: - streamed_span.status = ( - "error" if rv.status_code >= 400 else "ok" - ) - streamed_span.set_attribute( - "http.response.status_code", rv.status_code - ) - finally: - if streamed_span is not None: - streamed_span.set_attributes(url_attributes) - - if streamed_span is not None: - # Needs to happen within the context manager as we want to attach the - # final data before the span finishes and is sent for ingesting. - with capture_internal_exceptions(): - add_http_request_source(streamed_span) + url_attributes = get_url_attributes_legacy(client, parsed_url) + + if sentry_sdk.get_current_span() is None: + span_ctx = nullcontext() else: - with sentry_sdk.start_span( - op=OP.HTTP_CLIENT, + span_ctx = sentry_sdk.start_span( name="%s %s" % ( request.method, parsed_url.url if parsed_url else SENSITIVE_DATA_SUBSTITUTE, ), - origin=Httpx2Integration.origin, - ) as span: - span.set_data(SPANDATA.HTTP_METHOD, request.method) - if parsed_url is not None: - span.set_data("url", parsed_url.url) - span.set_data(SPANDATA.HTTP_QUERY, parsed_url.query) - span.set_data(SPANDATA.HTTP_FRAGMENT, parsed_url.fragment) + attributes={ + "sentry.op": OP.HTTP_CLIENT, + "sentry.origin": Httpx2Integration.origin, + "http.request.method": request.method, + }, + ) - propagate_trace_headers(client, request) + with span_ctx as span: + propagate_trace_headers(client, request) + try: rv = real_send(self, request, **kwargs) - span.set_http_status(rv.status_code) - span.set_data("reason", rv.reason_phrase) + if span is not None: + span.status = "error" if rv.status_code >= 400 else "ok" + span.set_attribute("http.response.status_code", rv.status_code) + finally: + if span is not None: + span.set_attributes(url_attributes) - with capture_internal_exceptions(): - add_http_request_source(span) + if span is not None: + # Needs to happen within the context manager as we want to attach the + # final data before the span finishes and is sent for ingesting. + with capture_internal_exceptions(): + add_http_request_source(span) breadcrumb_data = { SPANDATA.HTTP_METHOD: request.method, @@ -133,23 +102,14 @@ def send(self: "Client", request: "Request", **kwargs: "Any") -> "Response": "reason": rv.reason_phrase, } - if parsed_url: - if not is_span_streaming_enabled: - breadcrumb_data.update( - { - "url": parsed_url.url, - SPANDATA.HTTP_QUERY: parsed_url.query, - SPANDATA.HTTP_FRAGMENT: parsed_url.fragment, - } - ) - elif url_attributes: - breadcrumb_data.update( - { - "url": url_attributes.get("url.full", ""), - SPANDATA.HTTP_QUERY: url_attributes.get("url.query", ""), - SPANDATA.HTTP_FRAGMENT: url_attributes.get("url.fragment", ""), - } - ) + if parsed_url and url_attributes: + breadcrumb_data.update( + { + "url": url_attributes.get("url.full", ""), + SPANDATA.HTTP_QUERY: url_attributes.get("url.query", ""), + SPANDATA.HTTP_FRAGMENT: url_attributes.get("url.fragment", ""), + } + ) add_http_breadcrumb(rv.status_code, breadcrumb_data) @@ -168,102 +128,60 @@ async def send( if client.get_integration(Httpx2Integration) is None: return await real_send(self, request, **kwargs) - is_span_streaming_enabled = has_span_streaming_enabled(client.options) parsed_url = None with capture_internal_exceptions(): parsed_url = parse_url(str(request.url), sanitize=False) - url_attributes: "Attributes" = {} - - if is_span_streaming_enabled: - if sentry_sdk.traces.get_current_span() is None: - span_ctx = nullcontext() - else: - span_ctx = sentry_sdk.traces.start_span( - name="%s %s" - % ( - request.method, - parsed_url.url if parsed_url else SENSITIVE_DATA_SUBSTITUTE, - ), - attributes={ - "sentry.op": OP.HTTP_CLIENT, - "sentry.origin": Httpx2Integration.origin, - "http.request.method": request.method, - }, - ) - - url_attributes = get_url_attributes(client, parsed_url) - - with span_ctx as streamed_span: - propagate_trace_headers(client, request) - - try: - rv = await real_send(self, request, **kwargs) - - if streamed_span is not None: - streamed_span.status = ( - "error" if rv.status_code >= 400 else "ok" - ) - streamed_span.set_attribute( - "http.response.status_code", rv.status_code - ) - finally: - if streamed_span is not None: - streamed_span.set_attributes(url_attributes) - - if streamed_span is not None: - # Needs to happen within the context manager as we want to attach the - # final data before the span finishes and is sent for ingesting. - with capture_internal_exceptions(): - add_http_request_source(streamed_span) + if sentry_sdk.get_current_span() is None: + span_ctx = nullcontext() else: - with sentry_sdk.start_span( - op=OP.HTTP_CLIENT, + span_ctx = sentry_sdk.start_span( name="%s %s" % ( request.method, parsed_url.url if parsed_url else SENSITIVE_DATA_SUBSTITUTE, ), - origin=Httpx2Integration.origin, - ) as span: - span.set_data(SPANDATA.HTTP_METHOD, request.method) - if parsed_url is not None: - span.set_data("url", parsed_url.url) - span.set_data(SPANDATA.HTTP_QUERY, parsed_url.query) - span.set_data(SPANDATA.HTTP_FRAGMENT, parsed_url.fragment) + attributes={ + "sentry.op": OP.HTTP_CLIENT, + "sentry.origin": Httpx2Integration.origin, + "http.request.method": request.method, + }, + ) + + url_attributes = get_url_attributes_legacy(client, parsed_url) - propagate_trace_headers(client, request) + with span_ctx as span: + propagate_trace_headers(client, request) + try: rv = await real_send(self, request, **kwargs) - span.set_http_status(rv.status_code) - span.set_data("reason", rv.reason_phrase) + if span is not None: + span.status = "error" if rv.status_code >= 400 else "ok" + span.set_attribute("http.response.status_code", rv.status_code) + finally: + if span is not None: + span.set_attributes(url_attributes) - with capture_internal_exceptions(): - add_http_request_source(span) + if span is not None: + # Needs to happen within the context manager as we want to attach the + # final data before the span finishes and is sent for ingesting. + with capture_internal_exceptions(): + add_http_request_source(span) breadcrumb_data = { SPANDATA.HTTP_METHOD: request.method, SPANDATA.HTTP_STATUS_CODE: rv.status_code, "reason": rv.reason_phrase, } - if parsed_url: - if not is_span_streaming_enabled: - breadcrumb_data.update( - { - "url": parsed_url.url, - SPANDATA.HTTP_QUERY: parsed_url.query, - SPANDATA.HTTP_FRAGMENT: parsed_url.fragment, - } - ) - elif url_attributes: - breadcrumb_data.update( - { - "url": url_attributes.get("url.full", ""), - SPANDATA.HTTP_QUERY: url_attributes.get("url.query", ""), - SPANDATA.HTTP_FRAGMENT: url_attributes.get("url.fragment", ""), - } - ) + if parsed_url and url_attributes: + breadcrumb_data.update( + { + "url": url_attributes.get("url.full", ""), + SPANDATA.HTTP_QUERY: url_attributes.get("url.query", ""), + SPANDATA.HTTP_FRAGMENT: url_attributes.get("url.fragment", ""), + } + ) add_http_breadcrumb(rv.status_code, breadcrumb_data) diff --git a/sentry_sdk/integrations/huey.py b/sentry_sdk/integrations/huey.py index e1d34f05d7..7cfbcc2022 100644 --- a/sentry_sdk/integrations/huey.py +++ b/sentry_sdk/integrations/huey.py @@ -3,17 +3,17 @@ from typing import TYPE_CHECKING import sentry_sdk -from sentry_sdk.api import continue_trace, get_baggage, get_traceparent -from sentry_sdk.consts import OP, SPANDATA, SPANSTATUS -from sentry_sdk.integrations import DidNotEnable, Integration +from sentry_sdk.api import get_baggage, get_traceparent +from sentry_sdk.consts import OP, SPANDATA +from sentry_sdk.integrations import DidNotEnable, Integration, _check_minimum_version from sentry_sdk.scope import should_send_default_pii -from sentry_sdk.traces import SegmentNameSource, SpanStatus, StreamedSpan -from sentry_sdk.tracing import ( +from sentry_sdk.traces import ( BAGGAGE_HEADER_NAME, SENTRY_TRACE_HEADER_NAME, - TransactionSource, + SegmentNameSource, + Span, + SpanStatus, ) -from sentry_sdk.tracing_utils import has_span_streaming_enabled from sentry_sdk.utils import ( SENSITIVE_DATA_SUBSTITUTE, _register_control_flow_exception, @@ -21,6 +21,7 @@ ensure_integration_enabled, event_from_exception, has_data_collection_enabled, + parse_version, reraise, ) @@ -33,10 +34,11 @@ F = TypeVar("F", bound=Callable[..., Any]) try: + from huey import __version__ as HUEY_VERSION from huey.api import Huey, PeriodicTask, Result, ResultGroup, Task from huey.exceptions import CancelExecution, RetryTask, TaskLockedException except ImportError: - raise DidNotEnable("Huey is not installed") + raise DidNotEnable("Huey is not installed or incompatible") try: from huey.api import chord as HueyChord @@ -55,6 +57,9 @@ class HueyIntegration(Integration): @staticmethod def setup_once() -> None: + version = parse_version(HUEY_VERSION) + _check_minimum_version(HueyIntegration, version) + patch_enqueue() patch_execute() _register_control_flow_exception( @@ -76,15 +81,11 @@ def _sentry_enqueue( else: span_name = item.name - is_span_streaming_enabled = has_span_streaming_enabled( - sentry_sdk.get_client().options - ) - no_headers_types = (PeriodicTask,) + tuple( t for t in [HueyGroup, HueyChord] if t is not None ) - if is_span_streaming_enabled and sentry_sdk.traces.get_current_span() is None: + if sentry_sdk.get_current_span() is None: if not isinstance(item, no_headers_types): item.kwargs["sentry_headers"] = { BAGGAGE_HEADER_NAME: get_baggage(), @@ -92,24 +93,14 @@ def _sentry_enqueue( } return old_enqueue(self, item) - if is_span_streaming_enabled: - span_ctx = sentry_sdk.traces.start_span( - name=span_name, - attributes={ - "sentry.op": OP.QUEUE_SUBMIT_HUEY, - "sentry.origin": HueyIntegration.origin, - SPANDATA.MESSAGING_DESTINATION_NAME: self.name, - }, - ) - else: - span_ctx = sentry_sdk.start_span( - op=OP.QUEUE_SUBMIT_HUEY, - name=span_name, - origin=HueyIntegration.origin, - ) - span_ctx.set_data(SPANDATA.MESSAGING_DESTINATION_NAME, self.name) - - with span_ctx: + with sentry_sdk.start_span( + name=span_name, + attributes={ + "sentry.op": OP.QUEUE_SUBMIT_HUEY, + "sentry.origin": HueyIntegration.origin, + SPANDATA.MESSAGING_DESTINATION_NAME: self.name, + }, + ): if not isinstance(item, no_headers_types): # Attach trace propagation data to task kwargs. We do # not do this for periodic tasks, as these don't @@ -161,20 +152,12 @@ def event_processor(event: "Event", hint: "Hint") -> "Optional[Event]": def _capture_exception(exc_info: "ExcInfo") -> None: scope = sentry_sdk.get_current_scope() - is_span_streaming_enabled = has_span_streaming_enabled( - sentry_sdk.get_client().options - ) - if exc_info[0] in HUEY_CONTROL_FLOW_EXCEPTIONS: - if not is_span_streaming_enabled: - scope.transaction.set_status(SPANSTATUS.ABORTED) - elif type(scope._span) is StreamedSpan: + if type(scope._span) is Span: scope._span._segment.status = SpanStatus.OK return - if not is_span_streaming_enabled: - scope.transaction.set_status(SPANSTATUS.INTERNAL_ERROR) - elif type(scope._span) is StreamedSpan: + if type(scope._span) is Span: scope._span._segment.status = SpanStatus.ERROR event, hint = event_from_exception( @@ -214,39 +197,23 @@ def _sentry_execute( scope.add_event_processor(_make_event_processor(task)) sentry_headers = task.kwargs.pop("sentry_headers", None) - is_span_streaming_enabled = has_span_streaming_enabled( - sentry_sdk.get_client().options + headers = sentry_headers or {} + sentry_sdk.continue_trace(headers) + span_ctx = sentry_sdk.start_span( + name=task.name, + attributes={ + "sentry.op": OP.QUEUE_TASK_HUEY, + "sentry.origin": HueyIntegration.origin, + "sentry.segment.name.source": SegmentNameSource.TASK, + SPANDATA.MESSAGING_DESTINATION_NAME: self.name, + "messaging.message.id": task.id, + "messaging.message.system": "huey", + "messaging.message.retry.count": (task.default_retries or 0) + - task.retries, + }, + parent_span=None, ) - if is_span_streaming_enabled: - headers = sentry_headers or {} - sentry_sdk.traces.continue_trace(headers) - span_ctx = sentry_sdk.traces.start_span( - name=task.name, - attributes={ - "sentry.op": OP.QUEUE_TASK_HUEY, - "sentry.origin": HueyIntegration.origin, - "sentry.segment.name.source": SegmentNameSource.TASK, - SPANDATA.MESSAGING_DESTINATION_NAME: self.name, - "messaging.message.id": task.id, - "messaging.message.system": "huey", - "messaging.message.retry.count": (task.default_retries or 0) - - task.retries, - }, - parent_span=None, - ) - else: - transaction = continue_trace( - sentry_headers or {}, - name=task.name, - op=OP.QUEUE_TASK_HUEY, - source=TransactionSource.TASK, - origin=HueyIntegration.origin, - ) - transaction.set_status(SPANSTATUS.OK) - span_ctx = sentry_sdk.start_transaction(transaction) - span_ctx.set_data(SPANDATA.MESSAGING_DESTINATION_NAME, self.name) - if not getattr(task, "_sentry_is_patched", False): task.execute = _wrap_task_execute(task.execute) task._sentry_is_patched = True diff --git a/sentry_sdk/integrations/huggingface_hub.py b/sentry_sdk/integrations/huggingface_hub.py index 5980c298c0..2348f2b155 100644 --- a/sentry_sdk/integrations/huggingface_hub.py +++ b/sentry_sdk/integrations/huggingface_hub.py @@ -5,49 +5,42 @@ import sentry_sdk from sentry_sdk.ai.monitoring import record_token_usage -from sentry_sdk.ai.utils import ( - _set_span_data_attribute, - get_start_span_function, - set_data_normalized, -) +from sentry_sdk.ai.utils import set_data_normalized from sentry_sdk.consts import OP, SPANDATA -from sentry_sdk.integrations import DidNotEnable, Integration +from sentry_sdk.integrations import DidNotEnable, Integration, _check_minimum_version from sentry_sdk.scope import should_send_default_pii -from sentry_sdk.traces import StreamedSpan -from sentry_sdk.tracing_utils import has_span_streaming_enabled from sentry_sdk.utils import ( capture_internal_exceptions, event_from_exception, has_data_collection_enabled, + parse_version, reraise, ) if TYPE_CHECKING: - from typing import Any, Callable, Iterable, Union + from typing import Any, Callable, Iterable from huggingface_hub import ( ChatCompletionStreamOutput, ) - from sentry_sdk.tracing import Span try: import huggingface_hub.inference._client + from huggingface_hub import __version__ as HUGGINGFACE_HUB_VERSION except ImportError: - raise DidNotEnable("Huggingface not installed") + raise DidNotEnable("Huggingface not installed or incompatible") class HuggingfaceHubIntegration(Integration): identifier = "huggingface_hub" origin = f"auto.ai.{identifier}" - def __init__( - self: "HuggingfaceHubIntegration", include_prompts: bool = True - ) -> None: - self.include_prompts = include_prompts - @staticmethod def setup_once() -> None: + version = parse_version(HUGGINGFACE_HUB_VERSION) + _check_minimum_version(HuggingfaceHubIntegration, version) + # Other tasks that can be called: https://huggingface.co/docs/huggingface_hub/guides/inference#supported-providers-and-tasks huggingface_hub.inference._client.InferenceClient.text_generation = ( # type: ignore[method-assign] _wrap_huggingface_task( @@ -97,27 +90,18 @@ def new_huggingface_task(*args: "Any", **kwargs: "Any") -> "Any": model = hf_client.model or kwargs.get("model") or "" operation_name = op.split(".")[-1] - span: "Union[Span, StreamedSpan]" - if has_span_streaming_enabled(client.options): - span = sentry_sdk.traces.start_span( - name=f"{operation_name} {model}", - attributes={ - "sentry.op": op, - "sentry.origin": HuggingfaceHubIntegration.origin, - }, - ) - else: - span = get_start_span_function()( - op=op, - name=f"{operation_name} {model}", - origin=HuggingfaceHubIntegration.origin, - ) - span.__enter__() + span = sentry_sdk.start_span( + name=f"{operation_name} {model}", + attributes={ + "sentry.op": op, + "sentry.origin": HuggingfaceHubIntegration.origin, + }, + ) - _set_span_data_attribute(span, SPANDATA.GEN_AI_OPERATION_NAME, operation_name) + span.set_attribute(SPANDATA.GEN_AI_OPERATION_NAME, operation_name) if model: - _set_span_data_attribute(span, SPANDATA.GEN_AI_REQUEST_MODEL, model) + span.set_attribute(SPANDATA.GEN_AI_REQUEST_MODEL, model) attribute_mapping = { "frequency_penalty": SPANDATA.GEN_AI_REQUEST_FREQUENCY_PENALTY, @@ -142,7 +126,7 @@ def new_huggingface_task(*args: "Any", **kwargs: "Any") -> "Any": set_data_normalized( span, SPANDATA.GEN_AI_REQUEST_MESSAGES, prompt, unpack=False ) - elif should_send_default_pii() and integration.include_prompts: + elif should_send_default_pii(): set_data_normalized( span, SPANDATA.GEN_AI_REQUEST_MESSAGES, prompt, unpack=False ) @@ -151,7 +135,7 @@ def new_huggingface_task(*args: "Any", **kwargs: "Any") -> "Any": value = kwargs.get(attribute, None) if value is not None: if isinstance(value, (int, float, bool, str)): - _set_span_data_attribute(span, span_attribute, value) + span.set_attribute(span_attribute, value) else: set_data_normalized(span, span_attribute, value, unpack=False) @@ -212,9 +196,7 @@ def new_huggingface_task(*args: "Any", **kwargs: "Any") -> "Any": response_text_buffer.append(choice.message.content) if response_model is not None: - _set_span_data_attribute( - span, SPANDATA.GEN_AI_RESPONSE_MODEL, response_model - ) + span.set_attribute(SPANDATA.GEN_AI_RESPONSE_MODEL, response_model) if finish_reason is not None: set_data_normalized( @@ -232,7 +214,7 @@ def new_huggingface_task(*args: "Any", **kwargs: "Any") -> "Any": tool_calls, unpack=False, ) - elif should_send_default_pii() and integration.include_prompts: + elif should_send_default_pii(): set_data_normalized( span, SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS, @@ -250,7 +232,7 @@ def new_huggingface_task(*args: "Any", **kwargs: "Any") -> "Any": SPANDATA.GEN_AI_RESPONSE_TEXT, text_response, ) - elif should_send_default_pii() and integration.include_prompts: + elif should_send_default_pii(): set_data_normalized( span, SPANDATA.GEN_AI_RESPONSE_TEXT, @@ -317,7 +299,7 @@ def new_details_iterator() -> "Iterable[Any]": if has_data_collection_enabled(client.options): if client.options["data_collection"]["gen_ai"]["outputs"]: should_set_response_text = True - elif should_send_default_pii() and integration.include_prompts: + elif should_send_default_pii(): should_set_response_text = True if should_set_response_text: @@ -388,8 +370,8 @@ def new_iterator() -> "Iterable[ChatCompletionStreamOutput]": yield chunk if response_model is not None: - _set_span_data_attribute( - span, SPANDATA.GEN_AI_RESPONSE_MODEL, response_model + span.set_attribute( + SPANDATA.GEN_AI_RESPONSE_MODEL, response_model ) if finish_reason is not None: @@ -410,10 +392,7 @@ def new_iterator() -> "Iterable[ChatCompletionStreamOutput]": tool_calls, unpack=False, ) - elif ( - should_send_default_pii() - and integration.include_prompts - ): + elif should_send_default_pii(): set_data_normalized( span, SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS, @@ -433,10 +412,7 @@ def new_iterator() -> "Iterable[ChatCompletionStreamOutput]": SPANDATA.GEN_AI_RESPONSE_TEXT, text_response, ) - elif ( - should_send_default_pii() - and integration.include_prompts - ): + elif should_send_default_pii(): set_data_normalized( span, SPANDATA.GEN_AI_RESPONSE_TEXT, diff --git a/sentry_sdk/integrations/langchain.py b/sentry_sdk/integrations/langchain.py index 78242ba92c..8ab01d7801 100644 --- a/sentry_sdk/integrations/langchain.py +++ b/sentry_sdk/integrations/langchain.py @@ -1,7 +1,6 @@ import itertools import json import sys -import warnings from collections import OrderedDict from functools import wraps from typing import TYPE_CHECKING, NamedTuple @@ -9,26 +8,23 @@ import sentry_sdk from sentry_sdk.ai.utils import ( GEN_AI_ALLOWED_MESSAGE_ROLES, - get_start_span_function, normalize_message_roles, set_data_normalized, transform_content_part, - truncate_and_annotate_messages, ) from sentry_sdk.consts import OP, SPANDATA -from sentry_sdk.integrations import DidNotEnable, Integration +from sentry_sdk.integrations import DidNotEnable, Integration, _check_minimum_version from sentry_sdk.scope import should_send_default_pii -from sentry_sdk.traces import StreamedSpan +from sentry_sdk.traces import Span, _AgentFrameworkChatGenerationContext from sentry_sdk.tracing_utils import ( _get_value, - has_span_streaming_enabled, - should_truncate_gen_ai_input, ) from sentry_sdk.utils import ( capture_internal_exceptions, event_from_exception, has_data_collection_enabled, logger, + parse_version, ) if TYPE_CHECKING: @@ -45,10 +41,10 @@ from uuid import UUID from sentry_sdk._types import TextPart - from sentry_sdk.tracing import Span try: + from langchain_core import __version__ as LANGCHAIN_VERSION from langchain_core.callbacks import ( BaseCallbackHandler, BaseCallbackManager, @@ -65,7 +61,7 @@ ) except ImportError: - raise DidNotEnable("langchain not installed") + raise DidNotEnable("langchain not installed or incompatible") class TokenUsage(NamedTuple): @@ -89,54 +85,6 @@ class TokenUsage(NamedTuple): AgentExecutor = None -# Conditional imports for embeddings providers -try: - from langchain_openai import OpenAIEmbeddings # type: ignore[import-not-found] -except ImportError: - OpenAIEmbeddings = None - -try: - from langchain_openai import AzureOpenAIEmbeddings -except ImportError: - AzureOpenAIEmbeddings = None - -try: - from langchain_google_vertexai import ( # type: ignore[import-not-found] - VertexAIEmbeddings, - ) -except ImportError: - VertexAIEmbeddings = None - -try: - from langchain_aws import BedrockEmbeddings # type: ignore[import-not-found] -except ImportError: - BedrockEmbeddings = None - -try: - from langchain_cohere import CohereEmbeddings # type: ignore[import-not-found] -except ImportError: - CohereEmbeddings = None - -try: - from langchain_mistralai import ( # type: ignore[import-not-found] - MistralAIEmbeddings, - ) -except ImportError: - MistralAIEmbeddings = None - -try: - from langchain_huggingface import ( # type: ignore[import-not-found] - HuggingFaceEmbeddings, - ) -except ImportError: - HuggingFaceEmbeddings = None - -try: - from langchain_ollama import OllamaEmbeddings # type: ignore[import-not-found] -except ImportError: - OllamaEmbeddings = None - - def _get_ai_system(all_params: "Dict[str, Any]") -> "Optional[str]": ai_type = all_params.get("_type") @@ -232,40 +180,17 @@ class LangchainIntegration(Integration): _ignored_exceptions: "set[type[Exception]]" = set() - def __init__( - self: "LangchainIntegration", - include_prompts: bool = True, - max_spans: "Optional[int]" = None, - ) -> None: - self.include_prompts = include_prompts - self.max_spans = max_spans - - if max_spans is not None: - warnings.warn( - "The `max_spans` parameter of `LangchainIntegration` is " - "deprecated and will be removed in version 3.0 of sentry-sdk.", - DeprecationWarning, - stacklevel=2, - ) - @staticmethod def setup_once() -> None: + version = parse_version(LANGCHAIN_VERSION) + _check_minimum_version(LangchainIntegration, version) + manager._configure = _wrap_configure(manager._configure) if AgentExecutor is not None: AgentExecutor.invoke = _wrap_agent_executor_invoke(AgentExecutor.invoke) AgentExecutor.stream = _wrap_agent_executor_stream(AgentExecutor.stream) - # Patch embeddings providers - _patch_embeddings_provider(OpenAIEmbeddings) - _patch_embeddings_provider(AzureOpenAIEmbeddings) - _patch_embeddings_provider(VertexAIEmbeddings) - _patch_embeddings_provider(BedrockEmbeddings) - _patch_embeddings_provider(CohereEmbeddings) - _patch_embeddings_provider(MistralAIEmbeddings) - _patch_embeddings_provider(HuggingFaceEmbeddings) - _patch_embeddings_provider(OllamaEmbeddings) - def _capture_exception(exc: "Any", scope: "Optional[Any]" = None) -> None: event, hint = event_from_exception( @@ -279,18 +204,8 @@ def _capture_exception(exc: "Any", scope: "Optional[Any]" = None) -> None: class SentryLangchainCallback(BaseCallbackHandler): """Callback handler that creates Sentry spans.""" - def __init__( - self, max_span_map_size: "Optional[int]", include_prompts: bool - ) -> None: - self.span_map: "OrderedDict[UUID, Union[sentry_sdk.tracing.Span, StreamedSpan]]" = OrderedDict() - self.max_span_map_size = max_span_map_size - self.include_prompts = include_prompts - - def gc_span_map(self) -> None: - if self.max_span_map_size is not None: - while len(self.span_map) > self.max_span_map_size: - run_id, span = self.span_map.popitem(last=False) - self._exit_span(span, run_id) + def __init__(self) -> None: + self.span_map: "OrderedDict[UUID, Union[Span, _AgentFrameworkChatGenerationContext]]" = OrderedDict() def _handle_error(self, run_id: "UUID", error: "Any") -> None: is_ignored = isinstance(error, tuple(LangchainIntegration._ignored_exceptions)) @@ -299,15 +214,18 @@ def _handle_error(self, run_id: "UUID", error: "Any") -> None: if not run_id or run_id not in self.span_map: return - span = self.span_map[run_id] + context = self.span_map[run_id] if is_ignored: - span.__exit__(None, None, None) + context.__exit__(None, None, None) else: _capture_exception( - error, span._scope if isinstance(span, StreamedSpan) else span.scope + error, + context.span._scope + if isinstance(context, _AgentFrameworkChatGenerationContext) + else context._scope, ) - span.__exit__(type(error), error, error.__traceback__) + context.__exit__(type(error), error, error.__traceback__) del self.span_map[run_id] @@ -325,48 +243,76 @@ def _create_span( op: str, name: str, origin: str, - ) -> "Union[sentry_sdk.tracing.Span, StreamedSpan]": + ) -> "Span": span = None if parent_id: - parent_span: "Optional[Union[sentry_sdk.tracing.Span, StreamedSpan]]" = ( + parent: "Optional[Union[Span, _AgentFrameworkChatGenerationContext]]" = ( self.span_map.get(parent_id) ) - if parent_span: - span = ( - sentry_sdk.traces.start_span( - parent_span=parent_span, - name=name, - attributes={ - "sentry.op": op, - "sentry.origin": origin, - }, - ) - if isinstance(parent_span, StreamedSpan) - else parent_span.start_child(op=op, name=name, origin=origin) + if parent: + span = sentry_sdk.start_span( + parent_span=parent.span + if isinstance(parent, _AgentFrameworkChatGenerationContext) + else parent, + name=name, + attributes={ + "sentry.op": op, + "sentry.origin": origin, + }, ) if span is None: - span_streaming = has_span_streaming_enabled(sentry_sdk.get_client().options) - span = ( - sentry_sdk.traces.start_span( + span = sentry_sdk.start_span( + name=name, + attributes={ + "sentry.op": op, + "sentry.origin": origin, + }, + ) + + self.span_map[run_id] = span + return span + + def _create_generation_span( + self: "SentryLangchainCallback", + run_id: "UUID", + parent_id: "Optional[Any]", + op: str, + name: str, + origin: str, + ) -> "_AgentFrameworkChatGenerationContext": + context = None + if parent_id: + parent: "Optional[Union[Span, _AgentFrameworkChatGenerationContext]]" = ( + self.span_map.get(parent_id) + ) + if parent: + context = _AgentFrameworkChatGenerationContext( + parent_span=parent.span + if isinstance(parent, _AgentFrameworkChatGenerationContext) + else parent, name=name, attributes={ "sentry.op": op, "sentry.origin": origin, }, ) - if span_streaming - else sentry_sdk.start_span(op=op, name=name, origin=origin) + + if context is None: + context = _AgentFrameworkChatGenerationContext( + name=name, + attributes={ + "sentry.op": op, + "sentry.origin": origin, + }, ) - span.__enter__() - self.span_map[run_id] = span - self.gc_span_map() - return span + self.span_map[run_id] = context + return context def _exit_span( self: "SentryLangchainCallback", - span: "Union[sentry_sdk.tracing.Span, StreamedSpan]", + span: "Span", run_id: "UUID", ) -> None: span.__exit__(None, None, None) @@ -405,24 +351,21 @@ def on_llm_start( origin=LangchainIntegration.origin, ) - set_on_span = ( - span.set_attribute if isinstance(span, StreamedSpan) else span.set_data - ) - set_on_span(SPANDATA.GEN_AI_OPERATION_NAME, "text_completion") + span.set_attribute(SPANDATA.GEN_AI_OPERATION_NAME, "text_completion") run_name = kwargs.get("name") if run_name: - set_on_span(SPANDATA.GEN_AI_FUNCTION_ID, run_name) + span.set_attribute(SPANDATA.GEN_AI_FUNCTION_ID, run_name) if model: - set_on_span( + span.set_attribute( SPANDATA.GEN_AI_REQUEST_MODEL, model, ) ai_system = _get_ai_system(all_params) if ai_system: - set_on_span(SPANDATA.GEN_AI_SYSTEM, ai_system) + span.set_attribute(SPANDATA.GEN_AI_PROVIDER_NAME, ai_system) client = sentry_sdk.get_client() @@ -448,7 +391,7 @@ def on_llm_start( record_inputs = False if has_data_collection_enabled(client.options): record_inputs = client.options["data_collection"]["gen_ai"]["inputs"] - elif should_send_default_pii() and self.include_prompts: + elif should_send_default_pii(): # TODO: Remove this branch once `send_default_pii` is deprecated record_inputs = True @@ -460,20 +403,12 @@ def on_llm_start( } for prompt in prompts ] - - scope = sentry_sdk.get_current_scope() - messages_data = ( - truncate_and_annotate_messages(normalized_messages, span, scope) - if should_truncate_gen_ai_input(client.options) - else normalized_messages + set_data_normalized( + span, + SPANDATA.GEN_AI_REQUEST_MESSAGES, + normalized_messages, + unpack=False, ) - if messages_data is not None: - set_data_normalized( - span, - SPANDATA.GEN_AI_REQUEST_MESSAGES, - messages_data, - unpack=False, - ) def on_chat_model_start( self: "SentryLangchainCallback", @@ -498,32 +433,32 @@ def on_chat_model_start( or "" ) - span = self._create_span( + context = self._create_generation_span( run_id, kwargs.get("parent_run_id"), op=OP.GEN_AI_CHAT, name=f"chat {model}".strip(), origin=LangchainIntegration.origin, ) + span = context.span - set_on_span = ( - span.set_attribute if isinstance(span, StreamedSpan) else span.set_data - ) - set_on_span(SPANDATA.GEN_AI_OPERATION_NAME, "chat") + span.set_attribute(SPANDATA.GEN_AI_OPERATION_NAME, "chat") if model: - set_on_span(SPANDATA.GEN_AI_REQUEST_MODEL, model) + span.set_attribute(SPANDATA.GEN_AI_REQUEST_MODEL, model) ai_system = _get_ai_system(all_params) if ai_system: - set_on_span(SPANDATA.GEN_AI_SYSTEM, ai_system) + span.set_attribute(SPANDATA.GEN_AI_PROVIDER_NAME, ai_system) agent_metadata = kwargs.get("metadata") if isinstance(agent_metadata, dict) and "lc_agent_name" in agent_metadata: - set_on_span(SPANDATA.GEN_AI_AGENT_NAME, agent_metadata["lc_agent_name"]) + span.set_attribute( + SPANDATA.GEN_AI_AGENT_NAME, agent_metadata["lc_agent_name"] + ) run_name = kwargs.get("name") if run_name: - set_on_span( + span.set_attribute( SPANDATA.GEN_AI_FUNCTION_ID, run_name, ) @@ -551,14 +486,14 @@ def on_chat_model_start( record_inputs = False if has_data_collection_enabled(client.options): record_inputs = client.options["data_collection"]["gen_ai"]["inputs"] - elif should_send_default_pii() and self.include_prompts: + elif should_send_default_pii(): # TODO: Remove this branch once `send_default_pii` is deprecated record_inputs = True if record_inputs: system_instructions = _get_system_instructions(messages) if len(system_instructions) > 0: - set_on_span( + span.set_attribute( SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS, json.dumps(_transform_system_instructions(system_instructions)), ) @@ -573,20 +508,12 @@ def on_chat_model_start( self._normalize_langchain_message(message) ) normalized_messages = normalize_message_roles(normalized_messages) - - scope = sentry_sdk.get_current_scope() - messages_data = ( - truncate_and_annotate_messages(normalized_messages, span, scope) - if should_truncate_gen_ai_input(client.options) - else normalized_messages + set_data_normalized( + span, + SPANDATA.GEN_AI_REQUEST_MESSAGES, + normalized_messages, + unpack=False, ) - if messages_data is not None: - set_data_normalized( - span, - SPANDATA.GEN_AI_REQUEST_MESSAGES, - messages_data, - unpack=False, - ) def on_chat_model_end( self: "SentryLangchainCallback", @@ -600,14 +527,19 @@ def on_chat_model_end( if not run_id or run_id not in self.span_map: return - span = self.span_map[run_id] + context = self.span_map[run_id] + span = ( + context.span + if isinstance(context, _AgentFrameworkChatGenerationContext) + else context + ) client = sentry_sdk.get_client() record_outputs = False if has_data_collection_enabled(client.options): record_outputs = client.options["data_collection"]["gen_ai"]["outputs"] - elif should_send_default_pii() and self.include_prompts: + elif should_send_default_pii(): # TODO: Remove this branch once `send_default_pii` is deprecated record_outputs = True @@ -633,14 +565,19 @@ def on_llm_end( if not run_id or run_id not in self.span_map: return - span = self.span_map[run_id] + context = self.span_map[run_id] + span = ( + context.span + if isinstance(context, _AgentFrameworkChatGenerationContext) + else context + ) client = sentry_sdk.get_client() record_outputs = False if has_data_collection_enabled(client.options): record_outputs = client.options["data_collection"]["gen_ai"]["outputs"] - elif should_send_default_pii() and self.include_prompts: + elif should_send_default_pii(): # TODO: Remove this branch once `send_default_pii` is deprecated record_outputs = True @@ -649,14 +586,10 @@ def on_llm_end( except IndexError: generation = None - set_on_span = ( - span.set_attribute if isinstance(span, StreamedSpan) else span.set_data - ) - if generation is not None and generation.generation_info is not None: finish_reason = generation.generation_info.get("finish_reason") if finish_reason is not None: - set_on_span( + span.set_attribute( SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS, [finish_reason], ) @@ -664,7 +597,7 @@ def on_llm_end( if isinstance(generation, ChatGeneration): response_model = generation.message.response_metadata.get("model_name") if response_model is not None: - set_on_span(SPANDATA.GEN_AI_RESPONSE_MODEL, response_model) + span.set_attribute(SPANDATA.GEN_AI_RESPONSE_MODEL, response_model) if record_outputs: tool_calls = getattr(generation.message, "tool_calls", None) @@ -729,24 +662,22 @@ def on_tool_start( origin=LangchainIntegration.origin, ) - set_on_span = ( - span.set_attribute if isinstance(span, StreamedSpan) else span.set_data - ) - - set_on_span(SPANDATA.GEN_AI_OPERATION_NAME, "execute_tool") - set_on_span(SPANDATA.GEN_AI_TOOL_NAME, tool_name) + span.set_attribute(SPANDATA.GEN_AI_OPERATION_NAME, "execute_tool") + span.set_attribute(SPANDATA.GEN_AI_TOOL_NAME, tool_name) tool_description = serialized.get("description") if tool_description is not None: - set_on_span(SPANDATA.GEN_AI_TOOL_DESCRIPTION, tool_description) + span.set_attribute(SPANDATA.GEN_AI_TOOL_DESCRIPTION, tool_description) agent_metadata = kwargs.get("metadata") if isinstance(agent_metadata, dict) and "lc_agent_name" in agent_metadata: - set_on_span(SPANDATA.GEN_AI_AGENT_NAME, agent_metadata["lc_agent_name"]) + span.set_attribute( + SPANDATA.GEN_AI_AGENT_NAME, agent_metadata["lc_agent_name"] + ) run_name = kwargs.get("name") if run_name: - set_on_span( + span.set_attribute( SPANDATA.GEN_AI_FUNCTION_ID, run_name, ) @@ -756,7 +687,7 @@ def on_tool_start( record_inputs = False if has_data_collection_enabled(client.options): record_inputs = client.options["data_collection"]["gen_ai"]["inputs"] - elif should_send_default_pii() and self.include_prompts: + elif should_send_default_pii(): # TODO: Remove this branch once `send_default_pii` is deprecated record_inputs = True @@ -775,14 +706,19 @@ def on_tool_end( if not run_id or run_id not in self.span_map: return - span = self.span_map[run_id] + context = self.span_map[run_id] + span = ( + context.span + if isinstance(context, _AgentFrameworkChatGenerationContext) + else context + ) client = sentry_sdk.get_client() record_outputs = False if has_data_collection_enabled(client.options): record_outputs = client.options["data_collection"]["gen_ai"]["outputs"] - elif should_send_default_pii() and self.include_prompts: + elif should_send_default_pii(): # TODO: Remove this branch once `send_default_pii` is deprecated record_outputs = True @@ -911,9 +847,7 @@ def _get_token_usage(obj: "Any") -> "Optional[Dict[str, Any]]": return None -def _record_token_usage( - span: "Union[Span, StreamedSpan]", response: "LLMResult" -) -> None: +def _record_token_usage(span: "Span", response: "LLMResult") -> None: input_tokens = None output_tokens = None total_tokens = None @@ -942,29 +876,27 @@ def _record_token_usage( if token_usage.reasoning is not None: reasoning = token_usage.reasoning - set_on_span = ( - span.set_attribute if isinstance(span, StreamedSpan) else span.set_data - ) - if input_tokens is not None: - set_on_span(SPANDATA.GEN_AI_USAGE_INPUT_TOKENS, input_tokens) + span.set_attribute(SPANDATA.GEN_AI_USAGE_INPUT_TOKENS, input_tokens) if output_tokens is not None: - set_on_span(SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS, output_tokens) + span.set_attribute(SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS, output_tokens) if total_tokens is not None: - set_on_span(SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS, total_tokens) + span.set_attribute(SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS, total_tokens) if cache_read_tokens is not None: - set_on_span(SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS, cache_read_tokens) + span.set_attribute( + SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS, cache_read_tokens + ) if cache_creation_tokens is not None: - set_on_span( + span.set_attribute( SPANDATA.GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS, cache_creation_tokens ) if reasoning is not None: - set_on_span(SPANDATA.GEN_AI_USAGE_REASONING_OUTPUT_TOKENS, reasoning) + span.set_attribute(SPANDATA.GEN_AI_USAGE_REASONING_OUTPUT_TOKENS, reasoning) def _get_request_data( @@ -1061,7 +993,7 @@ def _simplify_langchain_tools(tools: "Any") -> "Optional[List[Any]]": return simplified_tools if simplified_tools else None -def _set_tools_on_span(span: "Union[Span, StreamedSpan]", tools: "Any") -> None: +def _set_tools_on_span(span: "Span", tools: "Any") -> None: """Set available tools data on a span if tools are provided.""" if tools is None: return @@ -1139,10 +1071,7 @@ def new_configure( isinstance(cb, SentryLangchainCallback) for cb in itertools.chain(callbacks_list, inheritable_callbacks_list) ): - sentry_handler = SentryLangchainCallback( - integration.max_spans, - integration.include_prompts, - ) + sentry_handler = SentryLangchainCallback() if isinstance(local_callbacks, BaseCallbackManager): local_callbacks = local_callbacks.copy() local_callbacks.handlers = [ @@ -1180,94 +1109,40 @@ def new_invoke(self: "Any", *args: "Any", **kwargs: "Any") -> "Any": if has_data_collection_enabled(client.options): record_inputs = client.options["data_collection"]["gen_ai"]["inputs"] record_outputs = client.options["data_collection"]["gen_ai"]["outputs"] - elif should_send_default_pii() and integration.include_prompts: + elif should_send_default_pii(): # TODO: Remove this branch once `send_default_pii` is deprecated record_inputs = True record_outputs = True - if has_span_streaming_enabled(client.options): - with sentry_sdk.traces.start_span( - name=f"invoke_agent {run_name}" if run_name else "invoke_agent", - attributes={ - "sentry.op": OP.GEN_AI_INVOKE_AGENT, - "sentry.origin": LangchainIntegration.origin, - SPANDATA.GEN_AI_OPERATION_NAME: "invoke_agent", - SPANDATA.GEN_AI_RESPONSE_STREAMING: False, - }, - ) as span: - if run_name: - span.set_attribute(SPANDATA.GEN_AI_FUNCTION_ID, run_name) - - _set_tools_on_span(span, tools) - - # Run the agent - result = f(self, *args, **kwargs) - - input = result.get("input") - if input is not None and record_inputs: - normalized_messages = normalize_message_roles([input]) - - scope = sentry_sdk.get_current_scope() - messages_data = ( - truncate_and_annotate_messages(normalized_messages, span, scope) - if should_truncate_gen_ai_input(client.options) - else normalized_messages - ) - if messages_data is not None: - set_data_normalized( - span, - SPANDATA.GEN_AI_REQUEST_MESSAGES, - messages_data, - unpack=False, - ) - - output = result.get("output") - if output is not None and record_outputs: - set_data_normalized(span, SPANDATA.GEN_AI_RESPONSE_TEXT, output) - - return result - else: - start_span_function = get_start_span_function() - - with start_span_function( - op=OP.GEN_AI_INVOKE_AGENT, - name=f"invoke_agent {run_name}" if run_name else "invoke_agent", - origin=LangchainIntegration.origin, - ) as span: - if run_name: - span.set_data(SPANDATA.GEN_AI_FUNCTION_ID, run_name) - - span.set_data(SPANDATA.GEN_AI_OPERATION_NAME, "invoke_agent") - span.set_data(SPANDATA.GEN_AI_RESPONSE_STREAMING, False) - - _set_tools_on_span(span, tools) - - # Run the agent - result = f(self, *args, **kwargs) + with sentry_sdk.start_span( + name=f"invoke_agent {run_name}" if run_name else "invoke_agent", + attributes={ + "sentry.op": OP.GEN_AI_INVOKE_AGENT, + "sentry.origin": LangchainIntegration.origin, + SPANDATA.GEN_AI_OPERATION_NAME: "invoke_agent", + }, + ) as span: + if run_name: + span.set_attribute(SPANDATA.GEN_AI_FUNCTION_ID, run_name) - input = result.get("input") - if input is not None and record_inputs: - normalized_messages = normalize_message_roles([input]) + # Run the agent + result = f(self, *args, **kwargs) - scope = sentry_sdk.get_current_scope() - messages_data = ( - truncate_and_annotate_messages(normalized_messages, span, scope) - if should_truncate_gen_ai_input(client.options) - else normalized_messages - ) - if messages_data is not None: - set_data_normalized( - span, - SPANDATA.GEN_AI_REQUEST_MESSAGES, - messages_data, - unpack=False, - ) + input = result.get("input") + if input is not None and record_inputs: + normalized_messages = normalize_message_roles([input]) + set_data_normalized( + span, + SPANDATA.GEN_AI_REQUEST_MESSAGES, + normalized_messages, + unpack=False, + ) - output = result.get("output") - if output is not None and record_outputs: - set_data_normalized(span, SPANDATA.GEN_AI_RESPONSE_TEXT, output) + output = result.get("output") + if output is not None and record_outputs: + set_data_normalized(span, SPANDATA.GEN_AI_RESPONSE_TEXT, output) - return result + return result return new_invoke @@ -1287,59 +1162,32 @@ def new_stream(self: "Any", *args: "Any", **kwargs: "Any") -> "Any": if has_data_collection_enabled(client.options): record_inputs = client.options["data_collection"]["gen_ai"]["inputs"] record_outputs = client.options["data_collection"]["gen_ai"]["outputs"] - elif should_send_default_pii() and integration.include_prompts: + elif should_send_default_pii(): # TODO: Remove this branch once `send_default_pii` is deprecated record_inputs = True record_outputs = True - if has_span_streaming_enabled(client.options): - span = sentry_sdk.traces.start_span( - name=f"invoke_agent {run_name}" if run_name else "invoke_agent", - attributes={ - "sentry.op": OP.GEN_AI_INVOKE_AGENT, - "sentry.origin": LangchainIntegration.origin, - SPANDATA.GEN_AI_OPERATION_NAME: "invoke_agent", - SPANDATA.GEN_AI_RESPONSE_STREAMING: True, - }, - ) - - if run_name: - span.set_attribute(SPANDATA.GEN_AI_FUNCTION_ID, run_name) - else: - start_span_function = get_start_span_function() - - span = start_span_function( - op=OP.GEN_AI_INVOKE_AGENT, - name=f"invoke_agent {run_name}" if run_name else "invoke_agent", - origin=LangchainIntegration.origin, - ) - span.__enter__() - - span.set_data(SPANDATA.GEN_AI_OPERATION_NAME, "invoke_agent") - span.set_data(SPANDATA.GEN_AI_RESPONSE_STREAMING, True) - - if run_name: - span.set_data(SPANDATA.GEN_AI_FUNCTION_ID, run_name) + span = sentry_sdk.start_span( + name=f"invoke_agent {run_name}" if run_name else "invoke_agent", + attributes={ + "sentry.op": OP.GEN_AI_INVOKE_AGENT, + "sentry.origin": LangchainIntegration.origin, + SPANDATA.GEN_AI_OPERATION_NAME: "invoke_agent", + }, + ) - _set_tools_on_span(span, tools) + if run_name: + span.set_attribute(SPANDATA.GEN_AI_FUNCTION_ID, run_name) input = args[0].get("input") if len(args) >= 1 else None if input is not None and record_inputs: normalized_messages = normalize_message_roles([input]) - - scope = sentry_sdk.get_current_scope() - messages_data = ( - truncate_and_annotate_messages(normalized_messages, span, scope) - if should_truncate_gen_ai_input(client.options) - else normalized_messages + set_data_normalized( + span, + SPANDATA.GEN_AI_REQUEST_MESSAGES, + normalized_messages, + unpack=False, ) - if messages_data is not None: - set_data_normalized( - span, - SPANDATA.GEN_AI_REQUEST_MESSAGES, - messages_data, - unpack=False, - ) # Run the agent result = f(self, *args, **kwargs) @@ -1396,156 +1244,3 @@ async def new_iterator_async() -> "AsyncIterator[Any]": return result return new_stream - - -def _patch_embeddings_provider(provider_class: "Any") -> None: - """Patch an embeddings provider class with monitoring wrappers.""" - if provider_class is None: - return - - if hasattr(provider_class, "embed_documents"): - provider_class.embed_documents = _wrap_embedding_method( - provider_class.embed_documents - ) - if hasattr(provider_class, "embed_query"): - provider_class.embed_query = _wrap_embedding_method(provider_class.embed_query) - if hasattr(provider_class, "aembed_documents"): - provider_class.aembed_documents = _wrap_async_embedding_method( - provider_class.aembed_documents - ) - if hasattr(provider_class, "aembed_query"): - provider_class.aembed_query = _wrap_async_embedding_method( - provider_class.aembed_query - ) - - -def _wrap_embedding_method(f: "Callable[..., Any]") -> "Callable[..., Any]": - """Wrap sync embedding methods (embed_documents and embed_query).""" - - @wraps(f) - def new_embedding_method(self: "Any", *args: "Any", **kwargs: "Any") -> "Any": - client = sentry_sdk.get_client() - integration = client.get_integration(LangchainIntegration) - if integration is None: - return f(self, *args, **kwargs) - - model_name = getattr(self, "model", None) or getattr(self, "model_name", None) - - record_inputs = False - if has_data_collection_enabled(client.options): - record_inputs = client.options["data_collection"]["gen_ai"]["inputs"] - elif should_send_default_pii() and integration.include_prompts: - # TODO: Remove this branch once `send_default_pii` is deprecated - record_inputs = True - - if has_span_streaming_enabled(client.options): - with sentry_sdk.traces.start_span( - name=f"embeddings {model_name}" if model_name else "embeddings", - attributes={ - "sentry.op": OP.GEN_AI_EMBEDDINGS, - "sentry.origin": LangchainIntegration.origin, - SPANDATA.GEN_AI_OPERATION_NAME: "embeddings", - }, - ) as span: - if model_name: - span.set_attribute(SPANDATA.GEN_AI_REQUEST_MODEL, model_name) - - if record_inputs and len(args) > 0: - input_data = args[0] - # Normalize to list format - texts = input_data if isinstance(input_data, list) else [input_data] - set_data_normalized( - span, SPANDATA.GEN_AI_EMBEDDINGS_INPUT, texts, unpack=False - ) - - result = f(self, *args, **kwargs) - return result - else: - with sentry_sdk.start_span( - op=OP.GEN_AI_EMBEDDINGS, - name=f"embeddings {model_name}" if model_name else "embeddings", - origin=LangchainIntegration.origin, - ) as span: - span.set_data(SPANDATA.GEN_AI_OPERATION_NAME, "embeddings") - if model_name: - span.set_data(SPANDATA.GEN_AI_REQUEST_MODEL, model_name) - - if record_inputs and len(args) > 0: - input_data = args[0] - # Normalize to list format - texts = input_data if isinstance(input_data, list) else [input_data] - set_data_normalized( - span, SPANDATA.GEN_AI_EMBEDDINGS_INPUT, texts, unpack=False - ) - - result = f(self, *args, **kwargs) - return result - - return new_embedding_method - - -def _wrap_async_embedding_method(f: "Callable[..., Any]") -> "Callable[..., Any]": - """Wrap async embedding methods (aembed_documents and aembed_query).""" - - @wraps(f) - async def new_async_embedding_method( - self: "Any", *args: "Any", **kwargs: "Any" - ) -> "Any": - client = sentry_sdk.get_client() - integration = client.get_integration(LangchainIntegration) - if integration is None: - return await f(self, *args, **kwargs) - - model_name = getattr(self, "model", None) or getattr(self, "model_name", None) - - record_inputs = False - if has_data_collection_enabled(client.options): - record_inputs = client.options["data_collection"]["gen_ai"]["inputs"] - elif should_send_default_pii() and integration.include_prompts: - # TODO: Remove this branch once `send_default_pii` is deprecated - record_inputs = True - - if has_span_streaming_enabled(client.options): - with sentry_sdk.traces.start_span( - name=f"embeddings {model_name}" if model_name else "embeddings", - attributes={ - "sentry.op": OP.GEN_AI_EMBEDDINGS, - "sentry.origin": LangchainIntegration.origin, - SPANDATA.GEN_AI_OPERATION_NAME: "embeddings", - }, - ) as span: - if model_name: - span.set_attribute(SPANDATA.GEN_AI_REQUEST_MODEL, model_name) - - if record_inputs and len(args) > 0: - input_data = args[0] - # Normalize to list format - texts = input_data if isinstance(input_data, list) else [input_data] - set_data_normalized( - span, SPANDATA.GEN_AI_EMBEDDINGS_INPUT, texts, unpack=False - ) - - result = await f(self, *args, **kwargs) - return result - else: - with sentry_sdk.start_span( - op=OP.GEN_AI_EMBEDDINGS, - name=f"embeddings {model_name}" if model_name else "embeddings", - origin=LangchainIntegration.origin, - ) as span: - span.set_data(SPANDATA.GEN_AI_OPERATION_NAME, "embeddings") - if model_name: - span.set_data(SPANDATA.GEN_AI_REQUEST_MODEL, model_name) - - if record_inputs and len(args) > 0: - input_data = args[0] - # Normalize to list format - texts = input_data if isinstance(input_data, list) else [input_data] - set_data_normalized( - span, SPANDATA.GEN_AI_EMBEDDINGS_INPUT, texts, unpack=False - ) - - result = await f(self, *args, **kwargs) - return result - - return new_async_embedding_method diff --git a/sentry_sdk/integrations/langgraph.py b/sentry_sdk/integrations/langgraph.py index af287b0fd4..07708dd007 100644 --- a/sentry_sdk/integrations/langgraph.py +++ b/sentry_sdk/integrations/langgraph.py @@ -1,43 +1,42 @@ from functools import wraps -from typing import Any, Callable, List, Optional +from typing import TYPE_CHECKING, Any, Callable, List, Optional import sentry_sdk from sentry_sdk.ai.utils import ( - get_start_span_function, normalize_message_roles, set_data_normalized, - truncate_and_annotate_messages, ) from sentry_sdk.consts import OP, SPANDATA -from sentry_sdk.integrations import DidNotEnable, Integration +from sentry_sdk.integrations import DidNotEnable, Integration, _check_minimum_version # This is fine because langgraph depends on langchain-base, and LangchainIntegration only imports from langchain-base. from sentry_sdk.integrations.langchain import LangchainIntegration from sentry_sdk.scope import should_send_default_pii -from sentry_sdk.traces import StreamedSpan -from sentry_sdk.tracing_utils import ( - has_span_streaming_enabled, - should_truncate_gen_ai_input, +from sentry_sdk.utils import ( + has_data_collection_enabled, + package_version, + safe_serialize, ) -from sentry_sdk.utils import has_data_collection_enabled, safe_serialize + +if TYPE_CHECKING: + pass try: from langgraph.errors import GraphBubbleUp - from langgraph.graph import StateGraph from langgraph.pregel import Pregel except ImportError: - raise DidNotEnable("langgraph not installed") + raise DidNotEnable("langgraph not installed or incompatible") class LanggraphIntegration(Integration): identifier = "langgraph" origin = f"auto.ai.{identifier}" - def __init__(self: "LanggraphIntegration", include_prompts: bool = True) -> None: - self.include_prompts = include_prompts - @staticmethod def setup_once() -> None: + version = package_version("langgraph") + _check_minimum_version(LanggraphIntegration, version) + LangchainIntegration._ignored_exceptions.add(GraphBubbleUp) # LangGraph lets users create agents using a StateGraph or the Functional API. # StateGraphs are then compiled to a CompiledStateGraph. Both CompiledStateGraph and @@ -46,7 +45,6 @@ def setup_once() -> None: # The streaming methods are not patched, because due to some internal reasons, LangGraph # will automatically patch the streaming methods to run through invoke, and by doing this # we prevent duplicate spans for invocations. - StateGraph.compile = _wrap_state_graph_compile(StateGraph.compile) if hasattr(Pregel, "invoke"): Pregel.invoke = _wrap_pregel_invoke(Pregel.invoke) if hasattr(Pregel, "ainvoke"): @@ -59,7 +57,7 @@ def _should_record_inputs(integration: "LanggraphIntegration") -> bool: return bool(client.options["data_collection"]["gen_ai"]["inputs"]) # To remove once data collection has been fully rolled out - return should_send_default_pii() and integration.include_prompts + return should_send_default_pii() def _should_record_outputs(integration: "LanggraphIntegration") -> bool: @@ -68,7 +66,7 @@ def _should_record_outputs(integration: "LanggraphIntegration") -> bool: return bool(client.options["data_collection"]["gen_ai"]["outputs"]) # To remove once data collection has been fully rolled out - return should_send_default_pii() and integration.include_prompts + return should_send_default_pii() def _get_graph_name(graph_obj: "Any") -> "Optional[str]": @@ -132,156 +130,46 @@ def _parse_langgraph_messages(state: "Any") -> "Optional[List[Any]]": return normalized_messages if normalized_messages else None -def _wrap_state_graph_compile(f: "Callable[..., Any]") -> "Callable[..., Any]": +def _wrap_pregel_invoke(f: "Callable[..., Any]") -> "Callable[..., Any]": @wraps(f) - def new_compile(self: "Any", *args: "Any", **kwargs: "Any") -> "Any": + def new_invoke(self: "Any", *args: "Any", **kwargs: "Any") -> "Any": client = sentry_sdk.get_client() integration = client.get_integration(LanggraphIntegration) - if integration is None or has_span_streaming_enabled(client.options): + if integration is None: return f(self, *args, **kwargs) + graph_name = _get_graph_name(self) + with sentry_sdk.start_span( - op=OP.GEN_AI_CREATE_AGENT, - origin=LanggraphIntegration.origin, + name=f"invoke_agent {graph_name}".strip() if graph_name else "invoke_agent", + attributes={ + "sentry.op": OP.GEN_AI_INVOKE_AGENT, + "sentry.origin": LanggraphIntegration.origin, + SPANDATA.GEN_AI_OPERATION_NAME: "invoke_agent", + }, ) as span: - compiled_graph = f(self, *args, **kwargs) - - compiled_graph_name = getattr(compiled_graph, "name", None) - span.set_data(SPANDATA.GEN_AI_OPERATION_NAME, "create_agent") - span.set_data(SPANDATA.GEN_AI_AGENT_NAME, compiled_graph_name) - - if compiled_graph_name: - span.description = f"create_agent {compiled_graph_name}" - else: - span.description = "create_agent" - - if kwargs.get("model", None) is not None: - span.set_data(SPANDATA.GEN_AI_REQUEST_MODEL, kwargs.get("model")) - - tools = None - get_graph = getattr(compiled_graph, "get_graph", None) - if get_graph and callable(get_graph): - graph_obj = compiled_graph.get_graph() - nodes = getattr(graph_obj, "nodes", None) - if nodes and isinstance(nodes, dict): - tools_node = nodes.get("tools") - if tools_node: - data = getattr(tools_node, "data", None) - if data and hasattr(data, "tools_by_name"): - tools = list(data.tools_by_name.keys()) - - if tools is not None: - # Available tools aren't gated on the legacy PII settings, so they're - # only gated when data collection has been configured. - if has_data_collection_enabled(client.options): - if client.options["data_collection"]["gen_ai"]["inputs"]: - span.set_data(SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS, tools) - else: - span.set_data(SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS, tools) - - return compiled_graph - - return new_compile + if graph_name: + span.set_attribute(SPANDATA.GEN_AI_PIPELINE_NAME, graph_name) + span.set_attribute(SPANDATA.GEN_AI_AGENT_NAME, graph_name) + # Store input messages to later compare with output + input_messages = None + if len(args) > 0: + input_messages = _parse_langgraph_messages(args[0]) + if input_messages and _should_record_inputs(integration): + normalized_input_messages = normalize_message_roles(input_messages) + set_data_normalized( + span, + SPANDATA.GEN_AI_REQUEST_MESSAGES, + normalized_input_messages, + unpack=False, + ) -def _wrap_pregel_invoke(f: "Callable[..., Any]") -> "Callable[..., Any]": - @wraps(f) - def new_invoke(self: "Any", *args: "Any", **kwargs: "Any") -> "Any": - client = sentry_sdk.get_client() - integration = client.get_integration(LanggraphIntegration) - if integration is None: - return f(self, *args, **kwargs) + result = f(self, *args, **kwargs) - graph_name = _get_graph_name(self) - span_name = ( - f"invoke_agent {graph_name}".strip() if graph_name else "invoke_agent" - ) - - if has_span_streaming_enabled(client.options): - with sentry_sdk.traces.start_span( - name=span_name, - attributes={ - "sentry.op": OP.GEN_AI_INVOKE_AGENT, - "sentry.origin": LanggraphIntegration.origin, - SPANDATA.GEN_AI_OPERATION_NAME: "invoke_agent", - }, - ) as span: - if graph_name: - span.set_attribute(SPANDATA.GEN_AI_PIPELINE_NAME, graph_name) - span.set_attribute(SPANDATA.GEN_AI_AGENT_NAME, graph_name) - - # Store input messages to later compare with output - input_messages = None - if len(args) > 0: - input_messages = _parse_langgraph_messages(args[0]) - if input_messages and _should_record_inputs(integration): - normalized_input_messages = normalize_message_roles( - input_messages - ) - - scope = sentry_sdk.get_current_scope() - messages_data = ( - truncate_and_annotate_messages( - normalized_input_messages, span, scope - ) - if should_truncate_gen_ai_input(client.options) - else normalized_input_messages - ) - if messages_data is not None: - set_data_normalized( - span, - SPANDATA.GEN_AI_REQUEST_MESSAGES, - messages_data, - unpack=False, - ) - - result = f(self, *args, **kwargs) - - _set_response_attributes(span, input_messages, result, integration) - - return result - else: - with get_start_span_function()( - op=OP.GEN_AI_INVOKE_AGENT, - name=span_name, - origin=LanggraphIntegration.origin, - ) as span: - if graph_name: - span.set_data(SPANDATA.GEN_AI_PIPELINE_NAME, graph_name) - span.set_data(SPANDATA.GEN_AI_AGENT_NAME, graph_name) - - span.set_data(SPANDATA.GEN_AI_OPERATION_NAME, "invoke_agent") - - # Store input messages to later compare with output - input_messages = None - if len(args) > 0: - input_messages = _parse_langgraph_messages(args[0]) - if input_messages and _should_record_inputs(integration): - normalized_input_messages = normalize_message_roles( - input_messages - ) - - scope = sentry_sdk.get_current_scope() - messages_data = ( - truncate_and_annotate_messages( - normalized_input_messages, span, scope - ) - if should_truncate_gen_ai_input(client.options) - else normalized_input_messages - ) - if messages_data is not None: - set_data_normalized( - span, - SPANDATA.GEN_AI_REQUEST_MESSAGES, - messages_data, - unpack=False, - ) - - result = f(self, *args, **kwargs) - - _set_response_attributes(span, input_messages, result, integration) - - return result + _set_response_attributes(span, input_messages, result, integration) + + return result return new_invoke @@ -295,85 +183,30 @@ async def new_ainvoke(self: "Any", *args: "Any", **kwargs: "Any") -> "Any": return await f(self, *args, **kwargs) graph_name = _get_graph_name(self) - span_name = ( - f"invoke_agent {graph_name}".strip() if graph_name else "invoke_agent" - ) - - if has_span_streaming_enabled(client.options): - with sentry_sdk.traces.start_span( - name=span_name, - attributes={ - "sentry.op": OP.GEN_AI_INVOKE_AGENT, - "sentry.origin": LanggraphIntegration.origin, - SPANDATA.GEN_AI_OPERATION_NAME: "invoke_agent", - }, - ) as span: - if graph_name: - span.set_attribute(SPANDATA.GEN_AI_PIPELINE_NAME, graph_name) - span.set_attribute(SPANDATA.GEN_AI_AGENT_NAME, graph_name) - - input_messages = None - if len(args) > 0: - input_messages = _parse_langgraph_messages(args[0]) - if input_messages and _should_record_inputs(integration): - normalized_input_messages = normalize_message_roles( - input_messages - ) - - scope = sentry_sdk.get_current_scope() - messages_data = ( - truncate_and_annotate_messages( - normalized_input_messages, span, scope - ) - if should_truncate_gen_ai_input(client.options) - else normalized_input_messages - ) - if messages_data is not None: - set_data_normalized( - span, - SPANDATA.GEN_AI_REQUEST_MESSAGES, - messages_data, - unpack=False, - ) - - result = await f(self, *args, **kwargs) - - _set_response_attributes(span, input_messages, result, integration) - - return result - - with get_start_span_function()( - op=OP.GEN_AI_INVOKE_AGENT, - name=span_name, - origin=LanggraphIntegration.origin, + + with sentry_sdk.start_span( + name=f"invoke_agent {graph_name}".strip() if graph_name else "invoke_agent", + attributes={ + "sentry.op": OP.GEN_AI_INVOKE_AGENT, + "sentry.origin": LanggraphIntegration.origin, + SPANDATA.GEN_AI_OPERATION_NAME: "invoke_agent", + }, ) as span: if graph_name: - span.set_data(SPANDATA.GEN_AI_PIPELINE_NAME, graph_name) - span.set_data(SPANDATA.GEN_AI_AGENT_NAME, graph_name) - - span.set_data(SPANDATA.GEN_AI_OPERATION_NAME, "invoke_agent") + span.set_attribute(SPANDATA.GEN_AI_PIPELINE_NAME, graph_name) + span.set_attribute(SPANDATA.GEN_AI_AGENT_NAME, graph_name) input_messages = None if len(args) > 0: input_messages = _parse_langgraph_messages(args[0]) if input_messages and _should_record_inputs(integration): normalized_input_messages = normalize_message_roles(input_messages) - - scope = sentry_sdk.get_current_scope() - messages_data = ( - truncate_and_annotate_messages( - normalized_input_messages, span, scope - ) - if should_truncate_gen_ai_input(client.options) - else normalized_input_messages + set_data_normalized( + span, + SPANDATA.GEN_AI_REQUEST_MESSAGES, + normalized_input_messages, + unpack=False, ) - if messages_data is not None: - set_data_normalized( - span, - SPANDATA.GEN_AI_REQUEST_MESSAGES, - messages_data, - unpack=False, - ) result = await f(self, *args, **kwargs) @@ -432,57 +265,6 @@ def _extract_tool_calls(messages: "Optional[List[Any]]") -> "Optional[List[Any]] return tool_calls if tool_calls else None -def _set_usage_data(span: "sentry_sdk.tracing.Span", messages: "Any") -> None: - input_tokens = 0 - output_tokens = 0 - total_tokens = 0 - - for message in messages: - response_metadata = message.get("response_metadata") - if response_metadata is None: - continue - - token_usage = response_metadata.get("token_usage") - if not token_usage: - continue - - input_tokens += int(token_usage.get("prompt_tokens", 0)) - output_tokens += int(token_usage.get("completion_tokens", 0)) - total_tokens += int(token_usage.get("total_tokens", 0)) - - set_on_span = ( - span.set_attribute if isinstance(span, StreamedSpan) else span.set_data - ) - - if input_tokens > 0: - set_on_span(SPANDATA.GEN_AI_USAGE_INPUT_TOKENS, input_tokens) - - if output_tokens > 0: - set_on_span(SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS, output_tokens) - - if total_tokens > 0: - set_on_span( - SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS, - total_tokens, - ) - - -def _set_response_model_name(span: "sentry_sdk.tracing.Span", messages: "Any") -> None: - if len(messages) == 0: - return - - last_message = messages[-1] - response_metadata = last_message.get("response_metadata") - if response_metadata is None: - return - - model_name = response_metadata.get("model_name") - if model_name is None: - return - - set_data_normalized(span, SPANDATA.GEN_AI_RESPONSE_MODEL, model_name) - - def _set_response_attributes( span: "Any", input_messages: "Optional[List[Any]]", @@ -495,9 +277,6 @@ def _set_response_attributes( if new_messages is None: return - _set_usage_data(span, new_messages) - _set_response_model_name(span, new_messages) - if _should_record_outputs(integration): llm_response_text = _extract_llm_response_text(new_messages) if llm_response_text: diff --git a/sentry_sdk/integrations/launchdarkly.py b/sentry_sdk/integrations/launchdarkly.py index 3c2c76450c..59ca9e3ed8 100644 --- a/sentry_sdk/integrations/launchdarkly.py +++ b/sentry_sdk/integrations/launchdarkly.py @@ -1,32 +1,33 @@ from typing import TYPE_CHECKING from sentry_sdk.feature_flags import add_feature_flag -from sentry_sdk.integrations import DidNotEnable, Integration +from sentry_sdk.integrations import DidNotEnable, Integration, _check_minimum_version +from sentry_sdk.utils import parse_version try: import ldclient + from ldclient import __version__ as LDCLIENT_VERSION from ldclient.hook import Hook, Metadata if TYPE_CHECKING: from typing import Any - from ldclient import LDClient from ldclient.evaluation import EvaluationDetail from ldclient.hook import EvaluationSeriesContext except ImportError: - raise DidNotEnable("LaunchDarkly is not installed") + raise DidNotEnable("LaunchDarkly is not installed or incompatible") class LaunchDarklyIntegration(Integration): identifier = "launchdarkly" - def __init__(self, ld_client: "LDClient | None" = None) -> None: - """ - :param client: An initialized LDClient instance. If a client is not provided, this - integration will attempt to use the shared global instance. - """ + @staticmethod + def setup_once() -> None: + version = parse_version(LDCLIENT_VERSION) + _check_minimum_version(LaunchDarklyIntegration, version) + try: - client = ld_client or ldclient.get() + client = ldclient.get() except Exception as exc: raise DidNotEnable("Error getting LaunchDarkly client. " + repr(exc)) @@ -36,10 +37,6 @@ def __init__(self, ld_client: "LDClient | None" = None) -> None: # Register the flag collection hook with the LD client. client.add_hook(LaunchDarklyHook()) - @staticmethod - def setup_once() -> None: - pass - class LaunchDarklyHook(Hook): @property diff --git a/sentry_sdk/integrations/litellm.py b/sentry_sdk/integrations/litellm.py index 74adddb7ec..467f7c07ad 100644 --- a/sentry_sdk/integrations/litellm.py +++ b/sentry_sdk/integrations/litellm.py @@ -5,20 +5,17 @@ from sentry_sdk import consts from sentry_sdk.ai.monitoring import record_token_usage from sentry_sdk.ai.utils import ( - get_start_span_function, set_data_normalized, transform_openai_content_part, - truncate_and_annotate_embedding_inputs, - truncate_and_annotate_messages, ) from sentry_sdk.consts import SPANDATA -from sentry_sdk.integrations import DidNotEnable, Integration +from sentry_sdk.integrations import DidNotEnable, Integration, _check_minimum_version from sentry_sdk.scope import should_send_default_pii -from sentry_sdk.tracing_utils import ( - has_span_streaming_enabled, - should_truncate_gen_ai_input, +from sentry_sdk.utils import ( + event_from_exception, + has_data_collection_enabled, + package_version, ) -from sentry_sdk.utils import event_from_exception, has_data_collection_enabled if TYPE_CHECKING: from datetime import datetime @@ -28,7 +25,7 @@ import litellm # type: ignore[import-not-found] from litellm import failure_callback, input_callback, success_callback except ImportError: - raise DidNotEnable("LiteLLM not installed") + raise DidNotEnable("LiteLLM not installed or incompatible") # Stash the span on a top-level key of the per-request kwargs dict litellm passes @@ -98,41 +95,29 @@ def _input_callback(kwargs: "Dict[str, Any]") -> None: operation = "chat" # Start a new span/transaction - if has_span_streaming_enabled(client.options): - span = sentry_sdk.traces.start_span( - name=f"{operation} {model}", - attributes={ - "sentry.op": ( - consts.OP.GEN_AI_CHAT - if operation == "chat" - else consts.OP.GEN_AI_EMBEDDINGS - ), - "sentry.origin": LiteLLMIntegration.origin, - }, - ) - else: - span = get_start_span_function()( - op=( + span = sentry_sdk.start_span( + name=f"{operation} {model}", + attributes={ + "sentry.op": ( consts.OP.GEN_AI_CHAT if operation == "chat" else consts.OP.GEN_AI_EMBEDDINGS ), - name=f"{operation} {model}", - origin=LiteLLMIntegration.origin, - ) - span.__enter__() + "sentry.origin": LiteLLMIntegration.origin, + }, + ) _store_span(kwargs, span) # Set basic data - set_data_normalized(span, SPANDATA.GEN_AI_SYSTEM, provider) + set_data_normalized(span, SPANDATA.GEN_AI_PROVIDER_NAME, provider) set_data_normalized(span, SPANDATA.GEN_AI_OPERATION_NAME, operation) # Record input/messages if allowed record_inputs = False if has_data_collection_enabled(client.options): record_inputs = client.options["data_collection"]["gen_ai"]["inputs"] - elif should_send_default_pii() and integration.include_prompts: + elif should_send_default_pii(): record_inputs = True if record_inputs: @@ -140,43 +125,30 @@ def _input_callback(kwargs: "Dict[str, Any]") -> None: # For embeddings, look for the 'input' parameter embedding_input = kwargs.get("input") if embedding_input: - scope = sentry_sdk.get_current_scope() # Normalize to list format input_list = ( embedding_input if isinstance(embedding_input, list) else [embedding_input] ) - messages_data = ( - truncate_and_annotate_embedding_inputs(input_list, span, scope) - if should_truncate_gen_ai_input(client.options) - else input_list - ) - if messages_data is not None: + if input_list is not None: set_data_normalized( span, SPANDATA.GEN_AI_EMBEDDINGS_INPUT, - messages_data, + input_list, unpack=False, ) else: # For chat, look for the 'messages' parameter messages = kwargs.get("messages", []) if messages: - scope = sentry_sdk.get_current_scope() messages = _convert_message_parts(messages) - messages_data = ( - truncate_and_annotate_messages(messages, span, scope) - if should_truncate_gen_ai_input(client.options) - else messages + set_data_normalized( + span, + SPANDATA.GEN_AI_REQUEST_MESSAGES, + messages, + unpack=False, ) - if messages_data is not None: - set_data_normalized( - span, - SPANDATA.GEN_AI_REQUEST_MESSAGES, - messages_data, - unpack=False, - ) # Record other parameters params = { @@ -226,7 +198,7 @@ def _success_callback( record_outputs = False if has_data_collection_enabled(client.options): record_outputs = client.options["data_collection"]["gen_ai"]["outputs"] - elif should_send_default_pii() and integration.include_prompts: + elif should_send_default_pii(): record_outputs = True if record_outputs: @@ -364,12 +336,12 @@ class LiteLLMIntegration(Integration): identifier = "litellm" origin = f"auto.ai.{identifier}" - def __init__(self: "LiteLLMIntegration", include_prompts: bool = True) -> None: - self.include_prompts = include_prompts - @staticmethod def setup_once() -> None: """Set up LiteLLM callbacks for monitoring.""" + version = package_version("litellm") + _check_minimum_version(LiteLLMIntegration, version) + litellm.input_callback = input_callback or [] if _input_callback not in litellm.input_callback: litellm.input_callback.append(_input_callback) diff --git a/sentry_sdk/integrations/litestar.py b/sentry_sdk/integrations/litestar.py index 593ac158aa..99e99c1188 100644 --- a/sentry_sdk/integrations/litestar.py +++ b/sentry_sdk/integrations/litestar.py @@ -8,16 +8,17 @@ _DEFAULT_FAILED_REQUEST_STATUS_CODES, DidNotEnable, Integration, + _check_minimum_version, ) from sentry_sdk.integrations.asgi import SentryAsgiMiddleware -from sentry_sdk.integrations.logging import ignore_logger +from sentry_sdk.integrations.logging import ignore_logger_for_events from sentry_sdk.scope import should_send_default_pii -from sentry_sdk.tracing import SOURCE_FOR_STYLE, TransactionSource -from sentry_sdk.tracing_utils import has_span_streaming_enabled +from sentry_sdk.traces import SOURCE_FOR_STYLE, SegmentNameSource from sentry_sdk.utils import ( ensure_integration_enabled, event_from_exception, has_data_collection_enabled, + package_version, transaction_from_function, ) @@ -29,7 +30,7 @@ from litestar.middleware import DefineMiddleware # type: ignore from litestar.routes.http import HTTPRoute # type: ignore except ImportError: - raise DidNotEnable("Litestar is not installed") + raise DidNotEnable("Litestar is not installed or incompatible") from typing import TYPE_CHECKING @@ -68,6 +69,9 @@ def __init__( @staticmethod def setup_once() -> None: + version = package_version("litestar") + _check_minimum_version(LitestarIntegration, version) + patch_app_init() patch_middlewares() patch_http_route_handle() @@ -80,7 +84,7 @@ def setup_once() -> None: # The `LitestarIntegration`` provides an after_exception hook (see `patch_app_init` below) to create a Sentry event # from an exception, which ends up being called during step 2 above. However, the Sentry `LoggingIntegration` will # by default create a Sentry event from error logs made in step 1 if we do not prevent it from doing so. - ignore_logger("litestar") + ignore_logger_for_events("litestar") class SentryLitestarASGIMiddleware(SentryAsgiMiddleware): @@ -89,7 +93,6 @@ def __init__( ) -> None: super().__init__( app=app, - unsafe_context_data=False, transaction_style="endpoint", mechanism_type="asgi", span_origin=span_origin, @@ -165,104 +168,60 @@ async def _create_span_call( return await old_call(self, scope, receive, send) middleware_name = self.__class__.__name__ - if has_span_streaming_enabled(client.options): - if sentry_sdk.traces.get_current_span() is None: - return await old_call(self, scope, receive, send) - with sentry_sdk.traces.start_span( - name=middleware_name, - attributes={ - "sentry.op": OP.MIDDLEWARE_LITESTAR, - "sentry.origin": LitestarIntegration.origin, - }, - ) as middleware_span: - middleware_span.set_attribute(SPANDATA.MIDDLEWARE_NAME, middleware_name) - - # Creating spans for the "receive" callback - async def _sentry_receive( - *args: "Any", **kwargs: "Any" - ) -> "Union[HTTPReceiveMessage, WebSocketReceiveMessage]": - if client.get_integration(LitestarIntegration) is None: - return await receive(*args, **kwargs) - if sentry_sdk.traces.get_current_span() is None: - return await receive(*args, **kwargs) - with sentry_sdk.traces.start_span( - name=getattr(receive, "__qualname__", str(receive)), - attributes={ - "sentry.op": OP.MIDDLEWARE_LITESTAR_RECEIVE, - "sentry.origin": LitestarIntegration.origin, - }, - ) as span: - span.set_attribute(SPANDATA.MIDDLEWARE_NAME, middleware_name) - return await receive(*args, **kwargs) - - receive_name = getattr(receive, "__name__", str(receive)) - receive_patched = receive_name == "_sentry_receive" - new_receive = _sentry_receive if not receive_patched else receive - - # Creating spans for the "send" callback - async def _sentry_send(message: "Message") -> None: - if client.get_integration(LitestarIntegration) is None: - return await send(message) - if sentry_sdk.traces.get_current_span() is None: - return await send(message) - with sentry_sdk.traces.start_span( - name=getattr(send, "__qualname__", str(send)), - attributes={ - "sentry.op": OP.MIDDLEWARE_LITESTAR_SEND, - "sentry.origin": LitestarIntegration.origin, - }, - ) as span: - span.set_attribute(SPANDATA.MIDDLEWARE_NAME, middleware_name) - return await send(message) - - send_name = getattr(send, "__name__", str(send)) - send_patched = send_name == "_sentry_send" - new_send = _sentry_send if not send_patched else send - - return await old_call(self, scope, new_receive, new_send) - else: - with sentry_sdk.start_span( - op=OP.MIDDLEWARE_LITESTAR, - name=middleware_name, - origin=LitestarIntegration.origin, - ) as middleware_span: - middleware_span.set_tag("litestar.middleware_name", middleware_name) - - # Creating spans for the "receive" callback - async def _sentry_receive( - *args: "Any", **kwargs: "Any" - ) -> "Union[HTTPReceiveMessage, WebSocketReceiveMessage]": - if client.get_integration(LitestarIntegration) is None: - return await receive(*args, **kwargs) - with sentry_sdk.start_span( - op=OP.MIDDLEWARE_LITESTAR_RECEIVE, - name=getattr(receive, "__qualname__", str(receive)), - origin=LitestarIntegration.origin, - ) as span: - span.set_tag("litestar.middleware_name", middleware_name) - return await receive(*args, **kwargs) - - receive_name = getattr(receive, "__name__", str(receive)) - receive_patched = receive_name == "_sentry_receive" - new_receive = _sentry_receive if not receive_patched else receive - - # Creating spans for the "send" callback - async def _sentry_send(message: "Message") -> None: - if client.get_integration(LitestarIntegration) is None: - return await send(message) - with sentry_sdk.start_span( - op=OP.MIDDLEWARE_LITESTAR_SEND, - name=getattr(send, "__qualname__", str(send)), - origin=LitestarIntegration.origin, - ) as span: - span.set_tag("litestar.middleware_name", middleware_name) - return await send(message) - - send_name = getattr(send, "__name__", str(send)) - send_patched = send_name == "_sentry_send" - new_send = _sentry_send if not send_patched else send - - return await old_call(self, scope, new_receive, new_send) + if sentry_sdk.get_current_span() is None: + return await old_call(self, scope, receive, send) + with sentry_sdk.start_span( + name=middleware_name, + attributes={ + "sentry.op": OP.MIDDLEWARE_LITESTAR, + "sentry.origin": LitestarIntegration.origin, + }, + ) as middleware_span: + middleware_span.set_attribute(SPANDATA.MIDDLEWARE_NAME, middleware_name) + + # Creating spans for the "receive" callback + async def _sentry_receive( + *args: "Any", **kwargs: "Any" + ) -> "Union[HTTPReceiveMessage, WebSocketReceiveMessage]": + if client.get_integration(LitestarIntegration) is None: + return await receive(*args, **kwargs) + if sentry_sdk.get_current_span() is None: + return await receive(*args, **kwargs) + with sentry_sdk.start_span( + name=getattr(receive, "__qualname__", str(receive)), + attributes={ + "sentry.op": OP.MIDDLEWARE_LITESTAR_RECEIVE, + "sentry.origin": LitestarIntegration.origin, + }, + ) as span: + span.set_attribute(SPANDATA.MIDDLEWARE_NAME, middleware_name) + return await receive(*args, **kwargs) + + receive_name = getattr(receive, "__name__", str(receive)) + receive_patched = receive_name == "_sentry_receive" + new_receive = _sentry_receive if not receive_patched else receive + + # Creating spans for the "send" callback + async def _sentry_send(message: "Message") -> None: + if client.get_integration(LitestarIntegration) is None: + return await send(message) + if sentry_sdk.get_current_span() is None: + return await send(message) + with sentry_sdk.start_span( + name=getattr(send, "__qualname__", str(send)), + attributes={ + "sentry.op": OP.MIDDLEWARE_LITESTAR_SEND, + "sentry.origin": LitestarIntegration.origin, + }, + ) as span: + span.set_attribute(SPANDATA.MIDDLEWARE_NAME, middleware_name) + return await send(message) + + send_name = getattr(send, "__name__", str(send)) + send_patched = send_name == "_sentry_send" + new_send = _sentry_send if not send_patched else send + + return await old_call(self, scope, new_receive, new_send) not_yet_patched = old_call.__name__ not in ["_create_span_call"] @@ -313,7 +272,7 @@ async def handle_wrapper( if not name: name = _DEFAULT_TRANSACTION_NAME - source = TransactionSource.ROUTE + source = SegmentNameSource.ROUTE sentry_sdk.set_transaction_name(name, source) sentry_scope.set_transaction_name(name, source) diff --git a/sentry_sdk/integrations/logging.py b/sentry_sdk/integrations/logging.py index cb0896bbcc..e272787888 100644 --- a/sentry_sdk/integrations/logging.py +++ b/sentry_sdk/integrations/logging.py @@ -19,12 +19,14 @@ if TYPE_CHECKING: from collections.abc import MutableMapping from logging import LogRecord - from typing import Any, Dict, Optional, Union + from typing import Any, Dict, Optional -_SENTINEL = object() +# Logs of this severity and above will be captured as Sentry logs DEFAULT_LEVEL = logging.INFO -DEFAULT_EVENT_LEVEL = logging.ERROR +# Logs of this severity and above will be captured as breadcrumbs +DEFAULT_LEVEL_FOR_BREADCRUMBS = logging.INFO + LOGGING_TO_EVENT_LEVEL = { logging.NOTSET: "notset", logging.DEBUG: "debug", @@ -56,7 +58,7 @@ # Events/breadcrumbs and Sentry Logs have separate ignore lists so that # framework loggers silenced for events (e.g. django.server) can still be # captured as Sentry Logs. -_IGNORED_LOGGERS = set( +_IGNORED_LOGGERS_EVENTS = set( ["sentry_sdk.errors", "urllib3.connectionpool", "urllib3.connection"] ) @@ -65,7 +67,7 @@ ) -def ignore_logger( +def ignore_logger_for_events( name: str, ) -> None: """This disables recording (both in breadcrumbs and as events) calls to @@ -74,14 +76,14 @@ def ignore_logger( to users as a way to quiet spammy loggers. This does **not** affect Sentry Logs — use - :py:func:`ignore_logger_for_sentry_logs` for that. + :py:func:`ignore_logger` for that. :param name: The name of the logger to ignore (same string you would pass to ``logging.getLogger``). """ - _IGNORED_LOGGERS.add(name) + _IGNORED_LOGGERS_EVENTS.add(name) -def ignore_logger_for_sentry_logs( +def ignore_logger( name: str, ) -> None: """This disables recording as Sentry Logs calls to a logger of a @@ -92,21 +94,21 @@ def ignore_logger_for_sentry_logs( _IGNORED_LOGGERS_SENTRY_LOGS.add(name) -def unignore_logger( +def unignore_logger_for_events( name: str, ) -> None: - """Reverts a previous :py:func:`ignore_logger` call, re-enabling + """Reverts a previous :py:func:`ignore_logger_for_events` call, re-enabling recording of breadcrumbs and events for the named logger. :param name: The name of the logger to unignore. """ - _IGNORED_LOGGERS.discard(name) + _IGNORED_LOGGERS_EVENTS.discard(name) -def unignore_logger_for_sentry_logs( +def unignore_logger( name: str, ) -> None: - """Reverts a previous :py:func:`ignore_logger_for_sentry_logs` call, + """Reverts a previous :py:func:`ignore_logger` call, re-enabling recording of Sentry Logs for the named logger. :param name: The name of the logger to unignore. @@ -116,46 +118,56 @@ def unignore_logger_for_sentry_logs( class LoggingIntegration(Integration): identifier = "logging" - capture_sentry_logs: "Optional[Union[bool, object]]" = _SENTINEL def __init__( self, level: "Optional[int]" = DEFAULT_LEVEL, - event_level: "Optional[int]" = DEFAULT_EVENT_LEVEL, - sentry_logs_level: "Optional[int]" = DEFAULT_LEVEL, - capture_sentry_logs: "Optional[Union[bool, object]]" = _SENTINEL, + event_level: "Optional[int]" = None, + breadcrumb_level: "Optional[int]" = DEFAULT_LEVEL_FOR_BREADCRUMBS, ) -> None: - LoggingIntegration.capture_sentry_logs = capture_sentry_logs - - self._handler = None + """ + Initialize the standard library logging integration. + + - `level`: Logs with severity of this level and above will be captured + as Sentry logs. + - `event_level`: Logs with severity of this level and above will be + captured as Sentry events. + - `breadcrumb_level`: Logs with this severity and above will be captured + as breadcrumbs. + """ + self._logs_handler = None + self._event_handler = None self._breadcrumb_handler = None - self._sentry_logs_handler = None if level is not None: - self._breadcrumb_handler = BreadcrumbHandler(level=level) - - if sentry_logs_level is not None: - self._sentry_logs_handler = SentryLogsHandler(level=sentry_logs_level) + self._logs_handler = LogsHandler(level=level) if event_level is not None: - self._handler = EventHandler(level=event_level) + self._event_handler = EventHandler(level=event_level) - def _handle_record(self, record: "LogRecord") -> None: - if self._handler is not None and record.levelno >= self._handler.level: - self._handler.handle(record) + if breadcrumb_level is not None: + self._breadcrumb_handler = BreadcrumbHandler(level=breadcrumb_level) + def _handle_logs_record(self, record: "LogRecord") -> None: if ( - self._breadcrumb_handler is not None - and record.levelno >= self._breadcrumb_handler.level + self._logs_handler is not None + and record.levelno >= self._logs_handler.level ): - self._breadcrumb_handler.handle(record) + self._logs_handler.handle(record) - def _handle_sentry_logs_record(self, record: "LogRecord") -> None: + def _handle_event_record(self, record: "LogRecord") -> None: if ( - self._sentry_logs_handler is not None - and record.levelno >= self._sentry_logs_handler.level + self._event_handler is not None + and record.levelno >= self._event_handler.level ): - self._sentry_logs_handler.handle(record) + self._event_handler.handle(record) + + def _handle_breadcrumb_record(self, record: "LogRecord") -> None: + if ( + self._breadcrumb_handler is not None + and record.levelno >= self._breadcrumb_handler.level + ): + self._breadcrumb_handler.handle(record) @staticmethod def setup_once() -> None: @@ -164,7 +176,7 @@ def setup_once() -> None: def sentry_patched_callhandlers(self: "Any", record: "LogRecord") -> "Any": # keeping a local reference because the # global might be discarded on shutdown - ignored_loggers = _IGNORED_LOGGERS + ignored_loggers_events = _IGNORED_LOGGERS_EVENTS ignored_loggers_sentry_logs = _IGNORED_LOGGERS_SENTRY_LOGS try: @@ -177,7 +189,8 @@ def sentry_patched_callhandlers(self: "Any", record: "LogRecord") -> "Any": name = record.name.strip() handle_events = ( - ignored_loggers is not None and name not in ignored_loggers + ignored_loggers_events is not None + and name not in ignored_loggers_events ) handle_sentry_logs = ( ignored_loggers_sentry_logs is not None @@ -189,10 +202,11 @@ def sentry_patched_callhandlers(self: "Any", record: "LogRecord") -> "Any": LoggingIntegration ) if integration is not None: - if handle_events: - integration._handle_record(record) if handle_sentry_logs: - integration._handle_sentry_logs_record(record) + integration._handle_logs_record(record) + if handle_events: + integration._handle_event_record(record) + integration._handle_breadcrumb_record(record) logging.Logger.callHandlers = sentry_patched_callhandlers # type: ignore @@ -244,14 +258,12 @@ def _extra_from_record(self, record: "LogRecord") -> "MutableMapping[str, object class EventHandler(_BaseHandler): """ - A logging handler that emits Sentry events for each log record - - Note that you do not have to use this class if the logging integration is enabled, which it is by default. + A logging handler that emits Sentry events for each log record. """ def _can_record(self, record: "LogRecord") -> bool: """Prevents ignored loggers from recording""" - for logger in _IGNORED_LOGGERS: + for logger in _IGNORED_LOGGERS_EVENTS: if fnmatch(record.name.strip(), logger): return False return True @@ -337,20 +349,14 @@ def _emit(self, record: "LogRecord") -> None: sentry_sdk.capture_event(event, hint=hint) -# Legacy name -SentryHandler = EventHandler - - class BreadcrumbHandler(_BaseHandler): """ A logging handler that records breadcrumbs for each log record. - - Note that you do not have to use this class if the logging integration is enabled, which it is by default. """ def _can_record(self, record: "LogRecord") -> bool: """Prevents ignored loggers from recording""" - for logger in _IGNORED_LOGGERS: + for logger in _IGNORED_LOGGERS_EVENTS: if fnmatch(record.name.strip(), logger): return False return True @@ -379,11 +385,9 @@ def _breadcrumb_from_record(self, record: "LogRecord") -> "Dict[str, Any]": } -class SentryLogsHandler(_BaseHandler): +class LogsHandler(_BaseHandler): """ A logging handler that records Sentry logs for each Python log record. - - Note that you do not have to use this class if the LoggingIntegration's capture_sentry_logs option is enabled. """ def _can_record(self, record: "LogRecord") -> bool: @@ -402,23 +406,6 @@ def emit(self, record: "LogRecord") -> "Any": if not client.is_active(): return - # TODO: remove this compat hack in the next major. Capture should - # only depend on capture_sentry_logs being True. - compat_logs_enabled = client.options.get( - "enable_logs", False - ) or client.options["_experiments"].get("enable_logs", False) - should_capture_logs = False - if LoggingIntegration.capture_sentry_logs is True: - should_capture_logs = True - elif ( - LoggingIntegration.capture_sentry_logs is _SENTINEL - and compat_logs_enabled - ): - should_capture_logs = True - - if not should_capture_logs: - return - self.format(record) self._capture_log_from_record(client, record) diff --git a/sentry_sdk/integrations/loguru.py b/sentry_sdk/integrations/loguru.py index f6719ac1e5..5b5645b31a 100644 --- a/sentry_sdk/integrations/loguru.py +++ b/sentry_sdk/integrations/loguru.py @@ -2,31 +2,29 @@ from typing import TYPE_CHECKING import sentry_sdk -from sentry_sdk.integrations import DidNotEnable, Integration +from sentry_sdk.integrations import DidNotEnable, Integration, _check_minimum_version from sentry_sdk.integrations.logging import ( BreadcrumbHandler, EventHandler, _BaseHandler, ) from sentry_sdk.logger import _log_level_to_otel -from sentry_sdk.utils import safe_repr +from sentry_sdk.utils import parse_version, safe_repr if TYPE_CHECKING: from logging import LogRecord - from typing import Any, Optional, Union + from typing import Any, Optional try: import loguru + from loguru import __version__ as LOGURU_VERSION # type: ignore from loguru import logger from loguru._defaults import LOGURU_FORMAT as DEFAULT_FORMAT if TYPE_CHECKING: from loguru import Message except ImportError: - raise DidNotEnable("LOGURU is not installed") - - -_SENTINEL = object() + raise DidNotEnable("LOGURU is not installed or incompatible") class LoggingLevels(enum.IntEnum): @@ -69,35 +67,34 @@ class LoguruIntegration(Integration): identifier = "loguru" level: "Optional[int]" = DEFAULT_LEVEL - event_level: "Optional[int]" = DEFAULT_EVENT_LEVEL - breadcrumb_format = DEFAULT_FORMAT event_format = DEFAULT_FORMAT - sentry_logs_level: "Optional[int]" = DEFAULT_LEVEL - capture_sentry_logs: "Optional[Union[bool, object]]" = _SENTINEL + event_level: "Optional[int]" = None + breadcrumb_level: "Optional[int]" = DEFAULT_LEVEL + breadcrumb_format = DEFAULT_FORMAT def __init__( self, level: "Optional[int]" = DEFAULT_LEVEL, - event_level: "Optional[int]" = DEFAULT_EVENT_LEVEL, - breadcrumb_format: "str | loguru.FormatFunction" = DEFAULT_FORMAT, + event_level: "Optional[int]" = None, event_format: "str | loguru.FormatFunction" = DEFAULT_FORMAT, - sentry_logs_level: "Optional[int]" = DEFAULT_LEVEL, - capture_sentry_logs: "Optional[Union[bool, object]]" = _SENTINEL, + breadcrumb_format: "str | loguru.FormatFunction" = DEFAULT_FORMAT, + breadcrumb_level: "Optional[int]" = DEFAULT_LEVEL, ) -> None: LoguruIntegration.level = level LoguruIntegration.event_level = event_level - LoguruIntegration.breadcrumb_format = breadcrumb_format LoguruIntegration.event_format = event_format - LoguruIntegration.sentry_logs_level = sentry_logs_level - LoguruIntegration.capture_sentry_logs = capture_sentry_logs + LoguruIntegration.breadcrumb_level = breadcrumb_level + LoguruIntegration.breadcrumb_format = breadcrumb_format @staticmethod def setup_once() -> None: + version = parse_version(LOGURU_VERSION) + _check_minimum_version(LoguruIntegration, version) + if LoguruIntegration.level is not None: logger.add( - LoguruBreadcrumbHandler(level=LoguruIntegration.level), + loguru_handler, level=LoguruIntegration.level, - format=LoguruIntegration.breadcrumb_format, ) if LoguruIntegration.event_level is not None: @@ -107,10 +104,11 @@ def setup_once() -> None: format=LoguruIntegration.event_format, ) - if LoguruIntegration.sentry_logs_level is not None: + if LoguruIntegration.breadcrumb_level is not None: logger.add( - loguru_sentry_logs_handler, - level=LoguruIntegration.sentry_logs_level, + LoguruBreadcrumbHandler(level=LoguruIntegration.breadcrumb_level), + level=LoguruIntegration.breadcrumb_level, + format=LoguruIntegration.breadcrumb_format, ) @@ -144,33 +142,16 @@ class LoguruBreadcrumbHandler(_LoguruBaseHandler, BreadcrumbHandler): pass -def loguru_sentry_logs_handler(message: "Message") -> None: +def loguru_handler(message: "Message") -> None: # This is intentionally a callable sink instead of a standard logging handler # since otherwise we wouldn't get direct access to message.record client = sentry_sdk.get_client() if not client.is_active(): return - # TODO: remove this compat hack in the next major. Capture should - # only depend on capture_sentry_logs being True. - compat_logs_enabled = client.options.get("enable_logs", False) or client.options[ - "_experiments" - ].get("enable_logs", False) - should_capture_logs = False - if LoguruIntegration.capture_sentry_logs is True: - should_capture_logs = True - elif LoguruIntegration.capture_sentry_logs is _SENTINEL and compat_logs_enabled: - should_capture_logs = True - - if not should_capture_logs: - return - record = message.record - if ( - LoguruIntegration.sentry_logs_level is None - or record["level"].no < LoguruIntegration.sentry_logs_level - ): + if LoguruIntegration.level is None or record["level"].no < LoguruIntegration.level: return otel_severity_number, otel_severity_text = _log_level_to_otel( diff --git a/sentry_sdk/integrations/mcp.py b/sentry_sdk/integrations/mcp.py index 5fc186f505..66a1df722a 100644 --- a/sentry_sdk/integrations/mcp.py +++ b/sentry_sdk/integrations/mcp.py @@ -7,24 +7,19 @@ Supports the low-level `mcp.server.lowlevel.Server` API. """ -import inspect from collections.abc import Iterator -from contextlib import contextmanager +from contextlib import contextmanager, nullcontext from functools import wraps from typing import TYPE_CHECKING import sentry_sdk -from sentry_sdk.ai.utils import _set_span_data_attribute, get_start_span_function from sentry_sdk.consts import OP, SPANDATA -from sentry_sdk.integrations import DidNotEnable, Integration +from sentry_sdk.integrations import DidNotEnable, Integration, _check_minimum_version from sentry_sdk.scope import should_send_default_pii -from sentry_sdk.traces import StreamedSpan -from sentry_sdk.tracing_utils import has_span_streaming_enabled from sentry_sdk.utils import ( capture_internal_exceptions, event_from_exception, has_data_collection_enabled, - nullcontext, package_version, safe_serialize, ) @@ -37,70 +32,37 @@ MCP_PACKAGE_VERSION = package_version("mcp") - if MCP_PACKAGE_VERSION and MCP_PACKAGE_VERSION < (2, 0, 0): - from mcp.server.lowlevel.server import ( # type: ignore[attr-defined] - request_ctx, - ) -except ImportError: - raise DidNotEnable("MCP SDK not installed") - -try: - from fastmcp import FastMCP # type: ignore[import-not-found] except ImportError: - FastMCP = None - -if MCP_PACKAGE_VERSION and MCP_PACKAGE_VERSION >= (2, 0, 0): - try: - from mcp.server.context import ( - ServerRequestContext, - ) - except ImportError: - ServerRequestContext = None # type: ignore[assignment,misc] -else: - ServerRequestContext = None # type: ignore[assignment,misc] + raise DidNotEnable("MCP SDK not installed or incompatible") if TYPE_CHECKING: - from typing import Any, Awaitable, Callable, Optional, Union - - from mcp.server.context import CallNext, HandlerResult - from mcp_types import ( - CallToolResult, - GetPromptResult, - InputRequiredResult, - ReadResourceResult, + from typing import Any, Optional + + from mcp.server.context import ( + CallNext, + HandlerResult, + ServerRequestContext, ) from starlette.types import Receive, Scope, Send - from sentry_sdk.traces import StreamedSpan - from sentry_sdk.tracing import Span + from sentry_sdk.traces import Span class MCPIntegration(Integration): identifier = "mcp" origin = "auto.ai.mcp" - def __init__(self, include_prompts: bool = True) -> None: - """ - Initialize the MCP integration. - - Args: - include_prompts: Whether to include prompts (tool results and prompt content) - in span data. Requires send_default_pii=True. Default is True. - """ - self.include_prompts = include_prompts - @staticmethod def setup_once() -> None: """ Patches MCP server classes to instrument handler execution. """ + _check_minimum_version(MCPIntegration, MCP_PACKAGE_VERSION) + _patch_lowlevel_server() _patch_handle_request() - if FastMCP is not None: - _patch_fastmcp() - def _capture_exception(exc: "Any") -> None: event, hint = event_from_exception( @@ -182,7 +144,7 @@ def _get_request_context_data( def _set_span_input_data( - span: "Union[StreamedSpan, Span]", + span: "Span", handler_name: str, span_data_key: str, mcp_method_name: str, @@ -194,28 +156,27 @@ def _set_span_input_data( """Set input span data for MCP handlers.""" # Set handler identifier - _set_span_data_attribute(span, span_data_key, handler_name) - _set_span_data_attribute(span, SPANDATA.MCP_METHOD_NAME, mcp_method_name) + span.set_attribute(span_data_key, handler_name) + span.set_attribute(SPANDATA.MCP_METHOD_NAME, mcp_method_name) # Set transport/MCP transport type - _set_span_data_attribute( - span, + span.set_attribute( SPANDATA.NETWORK_TRANSPORT, "pipe" if mcp_transport == "stdio" else "tcp", ) - _set_span_data_attribute(span, SPANDATA.MCP_TRANSPORT, mcp_transport) + span.set_attribute(SPANDATA.MCP_TRANSPORT, mcp_transport) # Set request_id if provided if request_id: - _set_span_data_attribute(span, SPANDATA.MCP_REQUEST_ID, request_id) + span.set_attribute(SPANDATA.MCP_REQUEST_ID, request_id) # Set session_id if provided if session_id: - _set_span_data_attribute(span, SPANDATA.MCP_SESSION_ID, session_id) + span.set_attribute(SPANDATA.MCP_SESSION_ID, session_id) # Set request arguments (excluding common request context objects) for k, v in arguments.items(): - _set_span_data_attribute(span, f"mcp.request.argument.{k}", safe_serialize(v)) + span.set_attribute(f"mcp.request.argument.{k}", safe_serialize(v)) def _extract_tool_result_content(result: "Any") -> "Any": @@ -270,131 +231,7 @@ def _extract_text_from_content_blocks(content_blocks: "Any") -> "Any": return " ".join(texts) if texts else content_blocks -async def _tool_handler_wrapper( - func: "Callable[..., Awaitable[Union[CallToolResult, InputRequiredResult]]]", - original_args: "tuple[Any, ...]", - original_kwargs: "Optional[dict[str, Any]]" = None, - self: "Optional[Any]" = None, - force_await: bool = True, -) -> "Union[CallToolResult, InputRequiredResult]": - """ - Wrapper for MCP tool handlers. - Creates and manages the MCP span and attaches all attributes on the span. - - Args: - func: The handler function to wrap - original_args: Original arguments passed to the handler - original_kwargs: Original keyword arguments passed to the handler - self: Optional instance for bound methods - """ - client = sentry_sdk.get_client() - - original_kwargs = original_kwargs or {} - - if original_args: - handler_name = original_args[0] - elif original_kwargs.get("name"): - handler_name = original_kwargs["name"] - - arguments = {} - if len(original_args) > 1 and original_args[1] is not None: - arguments = original_args[1] - elif original_kwargs.get("arguments"): - arguments = original_kwargs["arguments"] - - if has_data_collection_enabled(client.options): - if not client.options["data_collection"]["gen_ai"]["inputs"]: - # Arguments can contain sensitive data and shouldn't be added to the span - # if the user has opted out via this config. - arguments = {} - - ctx = None - try: - ctx = request_ctx.get() - except LookupError: - pass - - # Get request ID, session ID, and transport from context - request_id, session_id, mcp_transport = _get_request_context_data(ctx=ctx) - - span_streaming = has_span_streaming_enabled(sentry_sdk.get_client().options) - - # Start span and execute - with _active_http_scopes(ctx=ctx): - span_mgr: "Union[Span, StreamedSpan]" - if span_streaming: - span_mgr = sentry_sdk.traces.start_span( - name=f"tools/call {handler_name}", - attributes={ - "sentry.op": OP.MCP_SERVER, - "sentry.origin": MCPIntegration.origin, - }, - ) - else: - span_mgr = get_start_span_function()( - op=OP.MCP_SERVER, - name=f"tools/call {handler_name}", - origin=MCPIntegration.origin, - ) - - with span_mgr as span: - # Set input span data - _set_span_input_data( - span, - handler_name, - SPANDATA.MCP_TOOL_NAME, - "tools/call", - arguments, - request_id, - session_id, - mcp_transport, - ) - - try: - # Execute the async handler - if self is not None: - original_args = (self, *original_args) - - result = func(*original_args, **original_kwargs) - if force_await or inspect.isawaitable(result): - result = await result - - except Exception as e: - with capture_internal_exceptions(): - _capture_exception(e) - raise - - if result is None: - return result - - # Get integration to check PII settings - integration = client.get_integration(MCPIntegration) - if integration is None: - return result - - # Check if we should include sensitive data - should_include_data = False - if has_data_collection_enabled(client.options): - if client.options["data_collection"]["gen_ai"]["outputs"]: - should_include_data = True - elif should_send_default_pii() and integration.include_prompts: - should_include_data = True - - extracted = _extract_tool_result_content(result) - if extracted is not None and should_include_data: - _set_span_data_attribute( - span, SPANDATA.MCP_TOOL_RESULT_CONTENT, safe_serialize(extracted) - ) - # Set content count if result is a dict - if isinstance(extracted, dict): - _set_span_data_attribute( - span, SPANDATA.MCP_TOOL_RESULT_CONTENT_COUNT, len(extracted) - ) - - return result - - -async def _instrument_v2_tool_call( +async def _instrument_tool_call( ctx: "ServerRequestContext[Any, Any]", call_next: "CallNext", ) -> "HandlerResult": @@ -420,263 +257,71 @@ async def _instrument_v2_tool_call( # Get request ID, session ID, and transport from context request_id, session_id, mcp_transport = _get_request_context_data(ctx=ctx) - span_streaming = has_span_streaming_enabled(client.options) - # Start span and execute - with _active_http_scopes(ctx=ctx): - span_mgr: "Union[Span, StreamedSpan]" - if span_streaming: - span_mgr = sentry_sdk.traces.start_span( - name=f"tools/call {handler_name}", - attributes={ - "sentry.op": OP.MCP_SERVER, - "sentry.origin": MCPIntegration.origin, - }, - ) - else: - span_mgr = get_start_span_function()( - op=OP.MCP_SERVER, - name=f"tools/call {handler_name}", - origin=MCPIntegration.origin, - ) - - with span_mgr as span: - # Set input span data - _set_span_input_data( - span, - handler_name, - SPANDATA.MCP_TOOL_NAME, - "tools/call", - arguments, - request_id, - session_id, - mcp_transport, - ) - - try: - result = await call_next(ctx) - - except Exception as e: - with capture_internal_exceptions(): - _capture_exception(e) - raise - - if not isinstance(result, dict): - return result - - # Get integration to check PII settings - integration = client.get_integration(MCPIntegration) - if integration is None: - return result + with _active_http_scopes(ctx=ctx), sentry_sdk.start_span( + name=f"tools/call {handler_name}", + attributes={ + "sentry.op": OP.MCP_SERVER, + "sentry.origin": MCPIntegration.origin, + }, + ) as span: + # Set input span data + _set_span_input_data( + span, + handler_name, + SPANDATA.MCP_TOOL_NAME, + "tools/call", + arguments, + request_id, + session_id, + mcp_transport, + ) - # Check if we should include sensitive data - should_include_result_data = False - if has_data_collection_enabled(client.options): - if client.options["data_collection"]["gen_ai"]["outputs"]: - should_include_result_data = True - elif should_send_default_pii() and integration.include_prompts: + try: + result = await call_next(ctx) + except Exception as e: + with capture_internal_exceptions(): + _capture_exception(e) + raise + + if not isinstance(result, dict): + return result + + # Get integration to check PII settings + integration = client.get_integration(MCPIntegration) + if integration is None: + return result + + # Check if we should include sensitive data + should_include_result_data = False + if has_data_collection_enabled(client.options): + if client.options["data_collection"]["gen_ai"]["outputs"]: should_include_result_data = True - - result_content = result - if "structuredContent" in result: - result_content = result["structuredContent"] - elif isinstance(result.get("content"), list): - result_content = _extract_text_from_content_blocks(result["content"]) - - if result_content is not None and should_include_result_data: - _set_span_data_attribute( - span, - SPANDATA.MCP_TOOL_RESULT_CONTENT, - safe_serialize(result_content), - ) - # Set content count if result is a dict - if isinstance(result_content, dict): - _set_span_data_attribute( - span, - SPANDATA.MCP_TOOL_RESULT_CONTENT_COUNT, - len(result_content), - ) - - return result - - -async def _prompt_handler_wrapper( - func: "Callable[..., Awaitable[Union[GetPromptResult, InputRequiredResult]]]", - original_args: "tuple[Any, ...]", - original_kwargs: "Optional[dict[str, Any]]" = None, - self: "Optional[Any]" = None, - force_await: bool = True, -) -> "Union[GetPromptResult, InputRequiredResult]": - """ - Wrapper for MCP prompt handlers. - Creates and manages the MCP span and attaches all attributes on the span. - - Args: - func: The handler function to wrap - original_args: Original arguments passed to the handler - original_kwargs: Original keyword arguments passed to the handler - self: Optional instance for bound methods - """ - client = sentry_sdk.get_client() - - original_kwargs = original_kwargs or {} - - if original_args: - handler_name = original_args[0] - elif original_kwargs.get("name"): - handler_name = original_kwargs["name"] - - arguments = {} - if len(original_args) > 1 and original_args[1] is not None: - arguments = original_args[1] - elif original_kwargs.get("arguments"): - arguments = original_kwargs["arguments"] - - if has_data_collection_enabled(client.options): - if not client.options["data_collection"]["gen_ai"]["inputs"]: - # Arguments can contain sensitive data and shouldn't be added to the span - # if the user has opted out via this config. - arguments = {} - - ctx = None - try: - ctx = request_ctx.get() - except LookupError: - pass - - # Get request ID, session ID, and transport from context - request_id, session_id, mcp_transport = _get_request_context_data(ctx=ctx) - - span_streaming = has_span_streaming_enabled(client.options) - - # Start span and execute - with _active_http_scopes(ctx=ctx): - span_mgr: "Union[Span, StreamedSpan]" - if span_streaming: - span_mgr = sentry_sdk.traces.start_span( - name=f"prompts/get {handler_name}", - attributes={ - "sentry.op": OP.MCP_SERVER, - "sentry.origin": MCPIntegration.origin, - }, - ) - else: - span_mgr = get_start_span_function()( - op=OP.MCP_SERVER, - name=f"prompts/get {handler_name}", - origin=MCPIntegration.origin, - ) - - with span_mgr as span: - # Set input span data - _set_span_input_data( - span, - handler_name, - SPANDATA.MCP_PROMPT_NAME, - "prompts/get", - arguments, - request_id, - session_id, - mcp_transport, + elif should_send_default_pii(): + should_include_result_data = True + + result_content = result + if "structuredContent" in result: + result_content = result["structuredContent"] + elif isinstance(result.get("content"), list): + result_content = _extract_text_from_content_blocks(result["content"]) + + if result_content is not None and should_include_result_data: + span.set_attribute( + SPANDATA.MCP_TOOL_RESULT_CONTENT, + safe_serialize(result_content), ) - - try: - # Execute the async handler - if self is not None: - original_args = (self, *original_args) - - result = func(*original_args, **original_kwargs) - if force_await or inspect.isawaitable(result): - result = await result - - except Exception as e: - with capture_internal_exceptions(): - _capture_exception(e) - raise - - if result is None: - return result - - # Get integration to check PII settings - integration = client.get_integration(MCPIntegration) - if integration is None: - return result - - # Check if we should include sensitive data - should_include_result_data = False - if has_data_collection_enabled(client.options): - if client.options["data_collection"]["gen_ai"]["inputs"]: - should_include_result_data = True - elif should_send_default_pii() and integration.include_prompts: - should_include_result_data = True - - # For prompts, count messages and set role/content only for single-message prompts - try: - messages: "Optional[list[str]]" = None - message_count = 0 - - # Check if result has messages attribute (GetPromptResult) - if hasattr(result, "messages") and result.messages: - messages = result.messages # type: ignore[assignment] - message_count = len(messages) # type: ignore[arg-type] - # Also check if result is a dict with messages - elif isinstance(result, dict) and result.get("messages"): - messages = result["messages"] - message_count = len(messages) - - # Always set message count if we found messages - if message_count > 0: - _set_span_data_attribute( - span, SPANDATA.MCP_PROMPT_RESULT_MESSAGE_COUNT, message_count - ) - - # Only set role and content for single-message prompts if PII is allowed - if message_count == 1 and should_include_result_data and messages: - first_message = messages[0] - # Extract role - role = None - if hasattr(first_message, "role"): - role = first_message.role - elif isinstance(first_message, dict) and "role" in first_message: - role = first_message["role"] - - if role: - _set_span_data_attribute( - span, SPANDATA.MCP_PROMPT_RESULT_MESSAGE_ROLE, role - ) - - # Extract content text - content_text = None - if hasattr(first_message, "content"): - msg_content = first_message.content - # Content can be a TextContent object or similar - if hasattr(msg_content, "text"): - content_text = msg_content.text - elif isinstance(msg_content, dict) and "text" in msg_content: - content_text = msg_content["text"] - elif isinstance(msg_content, str): - content_text = msg_content - elif isinstance(first_message, dict) and "content" in first_message: - msg_content = first_message["content"] - if isinstance(msg_content, dict) and "text" in msg_content: - content_text = msg_content["text"] - elif isinstance(msg_content, str): - content_text = msg_content - - if content_text: - _set_span_data_attribute( - span, - SPANDATA.MCP_PROMPT_RESULT_MESSAGE_CONTENT, - content_text, - ) - except Exception: - # Silently ignore if we can't extract message info - pass + # Set content count if result is a dict + if isinstance(result_content, dict): + span.set_attribute( + SPANDATA.MCP_TOOL_RESULT_CONTENT_COUNT, + len(result_content), + ) return result -async def _instrument_v2_prompt_get( +async def _instrument_prompt_get( ctx: "ServerRequestContext[Any, Any]", call_next: "CallNext", ) -> "HandlerResult": @@ -704,209 +349,94 @@ async def _instrument_v2_prompt_get( # Get request ID, session ID, and transport from context request_id, session_id, mcp_transport = _get_request_context_data(ctx=ctx) - span_streaming = has_span_streaming_enabled(client.options) - # Start span and execute - with _active_http_scopes(ctx=ctx): - span_mgr: "Union[Span, StreamedSpan]" - if span_streaming: - span_mgr = sentry_sdk.traces.start_span( - name=f"prompts/get {handler_name}", - attributes={ - "sentry.op": OP.MCP_SERVER, - "sentry.origin": MCPIntegration.origin, - }, - ) - else: - span_mgr = get_start_span_function()( - op=OP.MCP_SERVER, - name=f"prompts/get {handler_name}", - origin=MCPIntegration.origin, - ) - - with span_mgr as span: - # Set input span data - _set_span_input_data( - span, - handler_name, - SPANDATA.MCP_PROMPT_NAME, - "prompts/get", - arguments, - request_id, - session_id, - mcp_transport, - ) + with _active_http_scopes(ctx=ctx), sentry_sdk.start_span( + name=f"prompts/get {handler_name}", + attributes={ + "sentry.op": OP.MCP_SERVER, + "sentry.origin": MCPIntegration.origin, + }, + ) as span: + # Set input span data + _set_span_input_data( + span, + handler_name, + SPANDATA.MCP_PROMPT_NAME, + "prompts/get", + arguments, + request_id, + session_id, + mcp_transport, + ) - try: - result = await call_next(ctx) - except Exception as e: - with capture_internal_exceptions(): - _capture_exception(e) - raise - - if not isinstance(result, dict): - return result - - # Get integration to check PII settings - integration = client.get_integration(MCPIntegration) - if integration is None: - return result - - # Check if we should include sensitive data - should_include_result_data = False - if has_data_collection_enabled(client.options): - if client.options["data_collection"]["gen_ai"]["inputs"]: - should_include_result_data = True - elif should_send_default_pii() and integration.include_prompts: + try: + result = await call_next(ctx) + except Exception as e: + with capture_internal_exceptions(): + _capture_exception(e) + raise + + if not isinstance(result, dict): + return result + + # Get integration to check PII settings + integration = client.get_integration(MCPIntegration) + if integration is None: + return result + + # Check if we should include sensitive data + should_include_result_data = False + if has_data_collection_enabled(client.options): + if client.options["data_collection"]["gen_ai"]["inputs"]: should_include_result_data = True + elif should_send_default_pii(): + should_include_result_data = True + + # For prompts, count messages and set role/content only for single-message prompts + try: + messages: "Optional[list[dict[str, Any]]]" = None + message_count = 0 + + if result.get("messages"): + messages = result["messages"] + message_count = len(messages) + + # Always set message count if we found messages + if message_count > 0: + span.set_attribute( + SPANDATA.MCP_PROMPT_RESULT_MESSAGE_COUNT, message_count + ) - # For prompts, count messages and set role/content only for single-message prompts - try: - messages: "Optional[list[dict[str, Any]]]" = None - message_count = 0 - - if result.get("messages"): - messages = result["messages"] - message_count = len(messages) - - # Always set message count if we found messages - if message_count > 0: - _set_span_data_attribute( - span, SPANDATA.MCP_PROMPT_RESULT_MESSAGE_COUNT, message_count + # Only set role and content for single-message prompts if PII is allowed + if message_count == 1 and should_include_result_data and messages: + first_message = messages[0] + # Extract role + role = None + if "role" in first_message: + role = first_message["role"] + + if role: + span.set_attribute(SPANDATA.MCP_PROMPT_RESULT_MESSAGE_ROLE, role) + + content_text = None + if "content" in first_message: + msg_content = first_message["content"] + if "text" in msg_content: + content_text = msg_content["text"] + + if content_text: + span.set_attribute( + SPANDATA.MCP_PROMPT_RESULT_MESSAGE_CONTENT, + content_text, ) - - # Only set role and content for single-message prompts if PII is allowed - if message_count == 1 and should_include_result_data and messages: - first_message = messages[0] - # Extract role - role = None - if "role" in first_message: - role = first_message["role"] - - if role: - _set_span_data_attribute( - span, SPANDATA.MCP_PROMPT_RESULT_MESSAGE_ROLE, role - ) - - content_text = None - if "content" in first_message: - msg_content = first_message["content"] - if "text" in msg_content: - content_text = msg_content["text"] - - if content_text: - _set_span_data_attribute( - span, - SPANDATA.MCP_PROMPT_RESULT_MESSAGE_CONTENT, - content_text, - ) - except Exception: - # Silently ignore if we can't extract message info - pass - - return result - - -async def _resource_handler_wrapper( - func: "Callable[..., Awaitable[Union[ReadResourceResult, InputRequiredResult]]]", - original_args: "tuple[Any, ...]", - original_kwargs: "Optional[dict[str, Any]]" = None, - self: "Optional[Any]" = None, - force_await: bool = True, -) -> "Union[ReadResourceResult, InputRequiredResult]": - """ - Wrapper for MCP resource handlers. - Creates and manages the MCP span and attaches all attributes on the span. - - Args: - func: The handler function to wrap - original_args: Original arguments passed to the handler - original_kwargs: Original keyword arguments passed to the handler - self: Optional instance for bound methods - """ - original_kwargs = original_kwargs or {} - - handler_name = "unknown" - if original_args: - handler_name = str(original_args[0]) - elif original_kwargs.get("uri"): - handler_name = str(original_kwargs["uri"]) - - arguments: "dict[str, Any]" = {} - - ctx = None - try: - ctx = request_ctx.get() - except LookupError: - pass - - # Get request ID, session ID, and transport from context - request_id, session_id, mcp_transport = _get_request_context_data(ctx=ctx) - - span_streaming = has_span_streaming_enabled(sentry_sdk.get_client().options) - - # Start span and execute - with _active_http_scopes(ctx=ctx): - span_mgr: "Union[Span, StreamedSpan]" - if span_streaming: - span_mgr = sentry_sdk.traces.start_span( - name=f"resources/read {handler_name}", - attributes={ - "sentry.op": OP.MCP_SERVER, - "sentry.origin": MCPIntegration.origin, - }, - ) - else: - span_mgr = get_start_span_function()( - op=OP.MCP_SERVER, - name=f"resources/read {handler_name}", - origin=MCPIntegration.origin, - ) - - with span_mgr as span: - # Set input span data - _set_span_input_data( - span, - handler_name, - SPANDATA.MCP_RESOURCE_URI, - "resources/read", - arguments, - request_id, - session_id, - mcp_transport, - ) - - if original_args: - uri = original_args[0] - else: - uri = original_kwargs.get("uri") - - protocol = None - if uri is not None and hasattr(uri, "scheme"): - protocol = uri.scheme - elif handler_name and "://" in handler_name: - protocol = handler_name.split("://")[0] - if protocol: - _set_span_data_attribute(span, SPANDATA.MCP_RESOURCE_PROTOCOL, protocol) - - try: - # Execute the async handler - if self is not None: - original_args = (self, *original_args) - - result = func(*original_args, **original_kwargs) - if force_await or inspect.isawaitable(result): - result = await result - - except Exception as e: - with capture_internal_exceptions(): - _capture_exception(e) - raise + except Exception: + # Silently ignore if we can't extract message info + pass return result -async def _instrument_v2_resource_read( +async def _instrument_resource_read( ctx: "ServerRequestContext[Any, Any]", call_next: "CallNext", ) -> "HandlerResult": @@ -922,145 +452,59 @@ async def _instrument_v2_resource_read( # Get request ID, session ID, and transport from context request_id, session_id, mcp_transport = _get_request_context_data(ctx=ctx) - span_streaming = has_span_streaming_enabled(sentry_sdk.get_client().options) - # Start span and execute - with _active_http_scopes(ctx=ctx): - span_mgr: "Union[Span, StreamedSpan]" - if span_streaming: - span_mgr = sentry_sdk.traces.start_span( - name=f"resources/read {handler_name}", - attributes={ - "sentry.op": OP.MCP_SERVER, - "sentry.origin": MCPIntegration.origin, - }, - ) - else: - span_mgr = get_start_span_function()( - op=OP.MCP_SERVER, - name=f"resources/read {handler_name}", - origin=MCPIntegration.origin, - ) - - with span_mgr as span: - # Set input span data - _set_span_input_data( - span, - handler_name, - SPANDATA.MCP_RESOURCE_URI, - "resources/read", - {}, - request_id, - session_id, - mcp_transport, - ) + with _active_http_scopes(ctx=ctx), sentry_sdk.start_span( + name=f"resources/read {handler_name}", + attributes={ + "sentry.op": OP.MCP_SERVER, + "sentry.origin": MCPIntegration.origin, + }, + ) as span: + # Set input span data + _set_span_input_data( + span, + handler_name, + SPANDATA.MCP_RESOURCE_URI, + "resources/read", + {}, + request_id, + session_id, + mcp_transport, + ) - protocol = None - if handler_name and "://" in handler_name: - protocol = handler_name.split("://")[0] - if protocol: - _set_span_data_attribute(span, SPANDATA.MCP_RESOURCE_PROTOCOL, protocol) + protocol = None + if handler_name and "://" in handler_name: + protocol = handler_name.split("://")[0] + if protocol: + span.set_attribute(SPANDATA.MCP_RESOURCE_PROTOCOL, protocol) - try: - result = await call_next(ctx) + try: + result = await call_next(ctx) - except Exception as e: - with capture_internal_exceptions(): - _capture_exception(e) - raise + except Exception as e: + with capture_internal_exceptions(): + _capture_exception(e) + raise return result -def _patch_lowlevel_server() -> None: - """ - Patches the mcp.server.lowlevel.Server class to instrument handler execution. - """ - if MCP_PACKAGE_VERSION and MCP_PACKAGE_VERSION >= (2, 0, 0): - _patch_lowlevel_server_v2() - else: - _patch_lowlevel_server_v1() - - -def _patch_lowlevel_server_v1() -> None: - """Patches v1 Server decorator methods (call_tool, get_prompt, read_resource).""" - # Patch call_tool decorator - original_call_tool = Server.call_tool # type: ignore[attr-defined] - - def patched_call_tool( - self: "Server", **kwargs: "Any" - ) -> "Callable[[Callable[..., Any]], Callable[..., Any]]": - """Patched version of Server.call_tool that adds Sentry instrumentation.""" - - def instrumented_decorator(func: "Callable[..., Any]") -> "Callable[..., Any]": - @wraps(func) - async def wrapper(*args: "Any") -> "Any": - return await _tool_handler_wrapper(func, args, force_await=False) - - # Then register it with the original MCP decorator - return original_call_tool(self, **kwargs)(wrapper) - - return instrumented_decorator - - Server.call_tool = patched_call_tool # type: ignore[attr-defined] - - # Patch get_prompt decorator - original_get_prompt = Server.get_prompt # type: ignore[attr-defined] - - def patched_get_prompt( - self: "Server", - ) -> "Callable[[Callable[..., Any]], Callable[..., Any]]": - """Patched version of Server.get_prompt that adds Sentry instrumentation.""" - - def instrumented_decorator(func: "Callable[..., Any]") -> "Callable[..., Any]": - @wraps(func) - async def wrapper(*args: "Any") -> "Any": - return await _prompt_handler_wrapper(func, args, force_await=False) - - # Then register it with the original MCP decorator - return original_get_prompt(self)(wrapper) - - return instrumented_decorator - - Server.get_prompt = patched_get_prompt # type: ignore[attr-defined] - - # Patch read_resource decorator - original_read_resource = Server.read_resource # type: ignore[attr-defined] - - def patched_read_resource( - self: "Server", - ) -> "Callable[[Callable[..., Any]], Callable[..., Any]]": - """Patched version of Server.read_resource that adds Sentry instrumentation.""" - - def instrumented_decorator(func: "Callable[..., Any]") -> "Callable[..., Any]": - @wraps(func) - async def wrapper(*args: "Any") -> "Any": - return await _resource_handler_wrapper(func, args, force_await=False) - - # Then register it with the original MCP decorator - return original_read_resource(self)(wrapper) - - return instrumented_decorator - - Server.read_resource = patched_read_resource # type: ignore[attr-defined] - - async def _sentry_middleware( ctx: "ServerRequestContext[Any, Any]", call_next: "CallNext" ) -> "HandlerResult": if ctx.method == "tools/call": - return await _instrument_v2_tool_call(ctx, call_next) + return await _instrument_tool_call(ctx, call_next) if ctx.method == "prompts/get": - return await _instrument_v2_prompt_get(ctx, call_next) + return await _instrument_prompt_get(ctx, call_next) if ctx.method == "resources/read": - return await _instrument_v2_resource_read(ctx, call_next) + return await _instrument_resource_read(ctx, call_next) return await call_next(ctx) -def _patch_lowlevel_server_v2() -> None: +def _patch_lowlevel_server() -> None: """Patches the v2 Server to wrap tool/prompt/resource handlers. Handlers can be registered either via the Server(...) constructor kwargs @@ -1095,45 +539,3 @@ async def patched_handle_request( await original_handle_request(self, scope, receive, send) StreamableHTTPServerTransport.handle_request = patched_handle_request # type: ignore[method-assign] - - -def _patch_fastmcp() -> None: - """ - Patches the standalone fastmcp package's FastMCP class. - - The standalone fastmcp package (v2.14.0+) registers its own handlers for - prompts and resources directly, bypassing the Server decorators we patch. - This function patches the _get_prompt_mcp and _read_resource_mcp methods - to add instrumentation for those handlers. - """ - if FastMCP is not None and hasattr(FastMCP, "_get_prompt_mcp"): - original_get_prompt_mcp = FastMCP._get_prompt_mcp - - @wraps(original_get_prompt_mcp) - async def patched_get_prompt_mcp( - self: "Any", *args: "Any", **kwargs: "Any" - ) -> "Any": - return await _prompt_handler_wrapper( - original_get_prompt_mcp, - args, - kwargs, - self, - ) - - FastMCP._get_prompt_mcp = patched_get_prompt_mcp - - if FastMCP is not None and hasattr(FastMCP, "_read_resource_mcp"): - original_read_resource_mcp = FastMCP._read_resource_mcp - - @wraps(original_read_resource_mcp) - async def patched_read_resource_mcp( - self: "Any", *args: "Any", **kwargs: "Any" - ) -> "Any": - return await _resource_handler_wrapper( - original_read_resource_mcp, - args, - kwargs, - self, - ) - - FastMCP._read_resource_mcp = patched_read_resource_mcp diff --git a/sentry_sdk/integrations/mistral.py b/sentry_sdk/integrations/mistral.py index 1ef4d42259..a7e6c5a2a2 100644 --- a/sentry_sdk/integrations/mistral.py +++ b/sentry_sdk/integrations/mistral.py @@ -4,15 +4,9 @@ from typing import TYPE_CHECKING, cast import sentry_sdk -from sentry_sdk.ai.utils import ( - get_start_span_function, -) from sentry_sdk.consts import OP, SPANDATA from sentry_sdk.integrations import DidNotEnable, Integration from sentry_sdk.scope import should_send_default_pii -from sentry_sdk.tracing_utils import ( - has_span_streaming_enabled, -) from sentry_sdk.utils import has_data_collection_enabled if TYPE_CHECKING: @@ -236,34 +230,19 @@ def wrap_complete(self: "Chat", *args: "Any", **kwargs: "Any") -> "Any": model = kwargs.get("model") - if has_span_streaming_enabled(client.options): - span = sentry_sdk.traces.start_span( - name=f"chat {model}" if model is not None else "chat", - attributes={ - "sentry.op": OP.GEN_AI_CHAT, - "sentry.origin": MistralIntegration.origin, - SPANDATA.GEN_AI_PROVIDER_NAME: "mistral", - SPANDATA.GEN_AI_OPERATION_NAME: "chat", - }, - ) - - set_on_span = span.set_attribute - else: - span = get_start_span_function()( - op=OP.GEN_AI_CHAT, - name=f"chat {model}" if model is not None else "chat", - origin=MistralIntegration.origin, - ) - span.set_data(SPANDATA.GEN_AI_PROVIDER_NAME, "mistral") - span.set_data(SPANDATA.GEN_AI_OPERATION_NAME, "chat") - - set_on_span = span.set_data - - with span: + with sentry_sdk.start_span( + name=f"chat {model}" if model is not None else "chat", + attributes={ + "sentry.op": OP.GEN_AI_CHAT, + "sentry.origin": MistralIntegration.origin, + SPANDATA.GEN_AI_PROVIDER_NAME: "mistral", + SPANDATA.GEN_AI_OPERATION_NAME: "chat", + }, + ) as span: if model is not None: - set_on_span(SPANDATA.GEN_AI_REQUEST_MODEL, model) + span.set_attribute(SPANDATA.GEN_AI_REQUEST_MODEL, model) - set_on_span(SPANDATA.GEN_AI_RESPONSE_STREAMING, False) + span.set_attribute(SPANDATA.GEN_AI_RESPONSE_STREAMING, False) messages = kwargs.get("messages") if isinstance(messages, Sequence) and ( @@ -280,41 +259,45 @@ def wrap_complete(self: "Chat", *args: "Any", **kwargs: "Any") -> "Any": message for message in messages if _is_system_instruction(message) ] if len(system_instructions) > 0: - set_on_span( + span.set_attribute( SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS, json.dumps(_transform_system_instructions(system_instructions)), ) - set_on_span( + span.set_attribute( SPANDATA.GEN_AI_INPUT_MESSAGES, json.dumps(_transform_input_messages(messages)), ) max_tokens = kwargs.get("max_tokens") if max_tokens is not None: - set_on_span(SPANDATA.GEN_AI_REQUEST_MAX_TOKENS, max_tokens) + span.set_attribute(SPANDATA.GEN_AI_REQUEST_MAX_TOKENS, max_tokens) frequency_penalty = kwargs.get("frequency_penalty") if frequency_penalty is not None: - set_on_span( + span.set_attribute( SPANDATA.GEN_AI_REQUEST_FREQUENCY_PENALTY, frequency_penalty ) presence_penalty = kwargs.get("presence_penalty") if presence_penalty is not None: - set_on_span(SPANDATA.GEN_AI_REQUEST_PRESENCE_PENALTY, presence_penalty) + span.set_attribute( + SPANDATA.GEN_AI_REQUEST_PRESENCE_PENALTY, presence_penalty + ) temperature = kwargs.get("temperature") if temperature is not None: - set_on_span(SPANDATA.GEN_AI_REQUEST_TEMPERATURE, temperature) + span.set_attribute(SPANDATA.GEN_AI_REQUEST_TEMPERATURE, temperature) top_p = kwargs.get("top_p") if top_p is not None: - set_on_span(SPANDATA.GEN_AI_REQUEST_TOP_P, top_p) + span.set_attribute(SPANDATA.GEN_AI_REQUEST_TOP_P, top_p) reasoning_effort = kwargs.get("reasoning_effort") if reasoning_effort is not None: - set_on_span(SPANDATA.GEN_AI_REQUEST_REASONING_LEVEL, reasoning_effort) + span.set_attribute( + SPANDATA.GEN_AI_REQUEST_REASONING_LEVEL, reasoning_effort + ) response = f(self, *args, **kwargs) @@ -322,18 +305,18 @@ def wrap_complete(self: "Chat", *args: "Any", **kwargs: "Any") -> "Any": return response if response.usage.prompt_tokens is not None: - set_on_span( + span.set_attribute( SPANDATA.GEN_AI_USAGE_INPUT_TOKENS, response.usage.prompt_tokens ) if response.usage.completion_tokens is not None: - set_on_span( + span.set_attribute( SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS, response.usage.completion_tokens, ) if response.usage.total_tokens is not None: - set_on_span( + span.set_attribute( SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS, response.usage.total_tokens ) @@ -355,7 +338,7 @@ def wrap_complete(self: "Chat", *args: "Any", **kwargs: "Any") -> "Any": output_messages.append(transformed_message) - set_on_span( + span.set_attribute( SPANDATA.GEN_AI_OUTPUT_MESSAGES, json.dumps(output_messages), ) @@ -375,34 +358,19 @@ async def wrap_complete_async(self: "Chat", *args: "Any", **kwargs: "Any") -> "A model = kwargs.get("model") - if has_span_streaming_enabled(client.options): - span = sentry_sdk.traces.start_span( - name=f"chat {model}" if model is not None else "chat", - attributes={ - "sentry.op": OP.GEN_AI_CHAT, - "sentry.origin": MistralIntegration.origin, - SPANDATA.GEN_AI_PROVIDER_NAME: "mistral", - SPANDATA.GEN_AI_OPERATION_NAME: "chat", - }, - ) - - set_on_span = span.set_attribute - else: - span = get_start_span_function()( - op=OP.GEN_AI_CHAT, - name=f"chat {model}" if model is not None else "chat", - origin=MistralIntegration.origin, - ) - span.set_data(SPANDATA.GEN_AI_PROVIDER_NAME, "mistral") - span.set_data(SPANDATA.GEN_AI_OPERATION_NAME, "chat") - - set_on_span = span.set_data - - with span: + with sentry_sdk.start_span( + name=f"chat {model}" if model is not None else "chat", + attributes={ + "sentry.op": OP.GEN_AI_CHAT, + "sentry.origin": MistralIntegration.origin, + SPANDATA.GEN_AI_PROVIDER_NAME: "mistral", + SPANDATA.GEN_AI_OPERATION_NAME: "chat", + }, + ) as span: if model is not None: - set_on_span(SPANDATA.GEN_AI_REQUEST_MODEL, model) + span.set_attribute(SPANDATA.GEN_AI_REQUEST_MODEL, model) - set_on_span(SPANDATA.GEN_AI_RESPONSE_STREAMING, False) + span.set_attribute(SPANDATA.GEN_AI_RESPONSE_STREAMING, False) messages: "Optional[Union[Iterable[ChatCompletionRequestMessage], Iterable[ChatCompletionRequestMessageTypedDict]]]" = kwargs.get( "messages" @@ -421,41 +389,45 @@ async def wrap_complete_async(self: "Chat", *args: "Any", **kwargs: "Any") -> "A message for message in messages if _is_system_instruction(message) ] if len(system_instructions) > 0: - set_on_span( + span.set_attribute( SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS, json.dumps(_transform_system_instructions(system_instructions)), ) - set_on_span( + span.set_attribute( SPANDATA.GEN_AI_INPUT_MESSAGES, json.dumps(_transform_input_messages(messages)), ) max_tokens = kwargs.get("max_tokens") if max_tokens is not None: - set_on_span(SPANDATA.GEN_AI_REQUEST_MAX_TOKENS, max_tokens) + span.set_attribute(SPANDATA.GEN_AI_REQUEST_MAX_TOKENS, max_tokens) frequency_penalty = kwargs.get("frequency_penalty") if frequency_penalty is not None: - set_on_span( + span.set_attribute( SPANDATA.GEN_AI_REQUEST_FREQUENCY_PENALTY, frequency_penalty ) presence_penalty = kwargs.get("presence_penalty") if presence_penalty is not None: - set_on_span(SPANDATA.GEN_AI_REQUEST_PRESENCE_PENALTY, presence_penalty) + span.set_attribute( + SPANDATA.GEN_AI_REQUEST_PRESENCE_PENALTY, presence_penalty + ) temperature = kwargs.get("temperature") if temperature is not None: - set_on_span(SPANDATA.GEN_AI_REQUEST_TEMPERATURE, temperature) + span.set_attribute(SPANDATA.GEN_AI_REQUEST_TEMPERATURE, temperature) top_p = kwargs.get("top_p") if top_p is not None: - set_on_span(SPANDATA.GEN_AI_REQUEST_TOP_P, top_p) + span.set_attribute(SPANDATA.GEN_AI_REQUEST_TOP_P, top_p) reasoning_effort = kwargs.get("reasoning_effort") if reasoning_effort is not None: - set_on_span(SPANDATA.GEN_AI_REQUEST_REASONING_LEVEL, reasoning_effort) + span.set_attribute( + SPANDATA.GEN_AI_REQUEST_REASONING_LEVEL, reasoning_effort + ) response = await f(self, *args, **kwargs) @@ -463,18 +435,18 @@ async def wrap_complete_async(self: "Chat", *args: "Any", **kwargs: "Any") -> "A return response if response.usage.prompt_tokens is not None: - set_on_span( + span.set_attribute( SPANDATA.GEN_AI_USAGE_INPUT_TOKENS, response.usage.prompt_tokens ) if response.usage.completion_tokens is not None: - set_on_span( + span.set_attribute( SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS, response.usage.completion_tokens, ) if response.usage.total_tokens is not None: - set_on_span( + span.set_attribute( SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS, response.usage.total_tokens ) @@ -496,7 +468,7 @@ async def wrap_complete_async(self: "Chat", *args: "Any", **kwargs: "Any") -> "A output_messages.append(transformed_message) - set_on_span( + span.set_attribute( SPANDATA.GEN_AI_OUTPUT_MESSAGES, json.dumps(output_messages), ) diff --git a/sentry_sdk/integrations/openai.py b/sentry_sdk/integrations/openai.py index 742b693245..f7453cfcae 100644 --- a/sentry_sdk/integrations/openai.py +++ b/sentry_sdk/integrations/openai.py @@ -36,24 +36,18 @@ ) from sentry_sdk.ai.monitoring import record_token_usage from sentry_sdk.ai.utils import ( - get_start_span_function, normalize_message_roles, set_data_normalized, - truncate_and_annotate_embedding_inputs, - truncate_and_annotate_messages, ) from sentry_sdk.consts import SPANDATA -from sentry_sdk.integrations import DidNotEnable, Integration +from sentry_sdk.integrations import DidNotEnable, Integration, _check_minimum_version from sentry_sdk.scope import should_send_default_pii -from sentry_sdk.traces import StreamedSpan -from sentry_sdk.tracing_utils import ( - has_span_streaming_enabled, - should_truncate_gen_ai_input, -) +from sentry_sdk.traces import Span from sentry_sdk.utils import ( capture_internal_exceptions, event_from_exception, has_data_collection_enabled, + parse_version, reraise, ) @@ -80,7 +74,6 @@ from openai.types.responses.response_usage import ResponseUsage from sentry_sdk._types import TextPart - from sentry_sdk.tracing import Span try: try: @@ -94,6 +87,7 @@ Omit = None # type: ignore[misc,assignment] from openai import AsyncStream, Stream + from openai import __version__ as OPENAI_VERSION from openai.resources import AsyncEmbeddings, Embeddings from openai.resources.chat.completions import AsyncCompletions, Completions from openai.types import CreateEmbeddingResponse @@ -105,7 +99,7 @@ ChatCompletionMessageParam, ) except ImportError: - raise DidNotEnable("OpenAI not installed") + raise DidNotEnable("OpenAI not installed or incompatible") RESPONSES_API_ENABLED = True try: @@ -123,10 +117,8 @@ class OpenAIIntegration(Integration): def __init__( self: "OpenAIIntegration", - include_prompts: bool = True, tiktoken_encoding_name: "Optional[str]" = None, ) -> None: - self.include_prompts = include_prompts self.tiktoken_encoding = None if tiktoken_encoding_name is not None: @@ -136,6 +128,9 @@ def __init__( @staticmethod def setup_once() -> None: + version = parse_version(OPENAI_VERSION) + _check_minimum_version(OpenAIIntegration, version) + Completions.create = _wrap_chat_completion_create(Completions.create) # type: ignore[assignment,method-assign] AsyncCompletions.create = _wrap_async_chat_completion_create( # type: ignore[assignment,method-assign] AsyncCompletions.create @@ -177,7 +172,7 @@ def _has_attr_and_is_int( def _calculate_completions_token_usage( messages: "Optional[Union[Iterable[ChatCompletionMessageParam], list[str]]]", response: "Any", - span: "Union[Span, StreamedSpan]", + span: "Span", streaming_message_responses: "Optional[List[str]]", streaming_message_total_token_usage: "Optional[CompletionUsage]", count_tokens: "Callable[..., Any]", @@ -259,7 +254,7 @@ def _calculate_completions_token_usage( def _calculate_responses_token_usage( input: "Any", response: "Any", - span: "Union[Span, StreamedSpan]", + span: "Span", streaming_message_responses: "Optional[List[str]]", count_tokens: "Callable[..., Any]", ) -> None: @@ -335,31 +330,27 @@ def _calculate_responses_token_usage( def _set_responses_api_input_data( - span: "Union[Span, StreamedSpan]", + span: "Span", kwargs: "dict[str, Any]", integration: "OpenAIIntegration", ) -> None: - set_on_span = ( - span.set_attribute if isinstance(span, StreamedSpan) else span.set_data - ) - set_data_normalized(span, SPANDATA.GEN_AI_OPERATION_NAME, "responses") model = kwargs.get("model") if model is not None: - set_on_span(SPANDATA.GEN_AI_REQUEST_MODEL, model) + span.set_attribute(SPANDATA.GEN_AI_REQUEST_MODEL, model) max_tokens = kwargs.get("max_output_tokens") if max_tokens is not None and _is_given(max_tokens): - set_on_span(SPANDATA.GEN_AI_REQUEST_MAX_TOKENS, max_tokens) + span.set_attribute(SPANDATA.GEN_AI_REQUEST_MAX_TOKENS, max_tokens) temperature = kwargs.get("temperature") if temperature is not None and _is_given(temperature): - set_on_span(SPANDATA.GEN_AI_REQUEST_TEMPERATURE, temperature) + span.set_attribute(SPANDATA.GEN_AI_REQUEST_TEMPERATURE, temperature) top_p = kwargs.get("top_p") if top_p is not None and _is_given(top_p): - set_on_span(SPANDATA.GEN_AI_REQUEST_TOP_P, top_p) + span.set_attribute(SPANDATA.GEN_AI_REQUEST_TOP_P, top_p) conversation = kwargs.get("conversation") if conversation is not None and _is_given(conversation): @@ -369,11 +360,11 @@ def _set_responses_api_input_data( elif isinstance(conversation, dict): conversation_id = conversation.get("id") if conversation_id is not None: - set_on_span(SPANDATA.GEN_AI_CONVERSATION_ID, conversation_id) + span.set_attribute(SPANDATA.GEN_AI_CONVERSATION_ID, conversation_id) reasoning = kwargs.get("reasoning") if isinstance(reasoning, dict) and "effort" in reasoning: - set_on_span( + span.set_attribute( SPANDATA.GEN_AI_REQUEST_REASONING_LEVEL, reasoning["effort"], ) @@ -383,18 +374,18 @@ def _set_responses_api_input_data( if client_options["data_collection"]["gen_ai"]["inputs"]: tools = kwargs.get("tools") if tools is not None and _is_given(tools): - set_on_span( + span.set_attribute( SPANDATA.GEN_AI_TOOL_DEFINITIONS, json.dumps(_transform_tool_definitions_responses(tools)), ) else: # Pre-data collection this was always set, so this needs to be left here for now until # we deprecate `send_default_pii`. Once we do, this 'else' branch should be removed, - # and the above branch placed below the "if not should_send_default_pii() or not integration.include_prompts" + # and the above branch placed below the "if not should_send_default_pii()" # line below tools = kwargs.get("tools") if tools is not None and _is_given(tools): - set_on_span( + span.set_attribute( SPANDATA.GEN_AI_TOOL_DEFINITIONS, json.dumps(_transform_tool_definitions_responses(tools)), ) @@ -402,7 +393,7 @@ def _set_responses_api_input_data( if has_data_collection_enabled(client_options): if not client_options["data_collection"]["gen_ai"]["inputs"]: return - elif not should_send_default_pii() or not integration.include_prompts: + elif not should_send_default_pii(): return explicit_instructions: "Union[Optional[str], Omit]" = kwargs.get("instructions") @@ -414,7 +405,7 @@ def _set_responses_api_input_data( if messages is None: if has_explicit_instructions: - set_on_span( + span.set_attribute( SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS, json.dumps( [ @@ -441,7 +432,7 @@ def _set_responses_api_input_data( system_instructions ) if len(instructions_text_parts) > 0: - set_on_span( + span.set_attribute( SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS, json.dumps(instructions_text_parts), ) @@ -449,17 +440,12 @@ def _set_responses_api_input_data( # Input was provided as a single string if isinstance(messages, str): normalized_messages = normalize_message_roles([messages]) # type: ignore - client = sentry_sdk.get_client() - scope = sentry_sdk.get_current_scope() - messages_data = ( - truncate_and_annotate_messages(normalized_messages, span, scope) - if should_truncate_gen_ai_input(client.options) - else normalized_messages + set_data_normalized( + span, + SPANDATA.GEN_AI_REQUEST_MESSAGES, + normalized_messages, + unpack=False, ) - if messages_data is not None: - set_data_normalized( - span, SPANDATA.GEN_AI_REQUEST_MESSAGES, messages_data, unpack=False - ) return # Input was provided as a list (potentially a multi-turn conversation) @@ -468,75 +454,66 @@ def _set_responses_api_input_data( ] if len(non_system_messages) > 0: normalized_messages = normalize_message_roles(non_system_messages) # type: ignore - client = sentry_sdk.get_client() - scope = sentry_sdk.get_current_scope() - messages_data = ( - truncate_and_annotate_messages(normalized_messages, span, scope) - if should_truncate_gen_ai_input(client.options) - else normalized_messages + set_data_normalized( + span, + SPANDATA.GEN_AI_REQUEST_MESSAGES, + normalized_messages, + unpack=False, ) - if messages_data is not None: - set_data_normalized( - span, SPANDATA.GEN_AI_REQUEST_MESSAGES, messages_data, unpack=False - ) def _set_completions_api_input_data( - span: "Union[Span, StreamedSpan]", + span: "Span", kwargs: "dict[str, Any]", integration: "OpenAIIntegration", ) -> None: - set_on_span = ( - span.set_attribute if isinstance(span, StreamedSpan) else span.set_data - ) - set_data_normalized(span, SPANDATA.GEN_AI_OPERATION_NAME, "chat") model = kwargs.get("model") if model is not None: - set_on_span(SPANDATA.GEN_AI_REQUEST_MODEL, model) + span.set_attribute(SPANDATA.GEN_AI_REQUEST_MODEL, model) max_tokens = kwargs.get("max_tokens") if max_tokens is not None and _is_given(max_tokens): - set_on_span(SPANDATA.GEN_AI_REQUEST_MAX_TOKENS, max_tokens) + span.set_attribute(SPANDATA.GEN_AI_REQUEST_MAX_TOKENS, max_tokens) presence_penalty = kwargs.get("presence_penalty") if presence_penalty is not None and _is_given(presence_penalty): - set_on_span(SPANDATA.GEN_AI_REQUEST_PRESENCE_PENALTY, presence_penalty) + span.set_attribute(SPANDATA.GEN_AI_REQUEST_PRESENCE_PENALTY, presence_penalty) frequency_penalty = kwargs.get("frequency_penalty") if frequency_penalty is not None and _is_given(frequency_penalty): - set_on_span(SPANDATA.GEN_AI_REQUEST_FREQUENCY_PENALTY, frequency_penalty) + span.set_attribute(SPANDATA.GEN_AI_REQUEST_FREQUENCY_PENALTY, frequency_penalty) temperature = kwargs.get("temperature") if temperature is not None and _is_given(temperature): - set_on_span(SPANDATA.GEN_AI_REQUEST_TEMPERATURE, temperature) + span.set_attribute(SPANDATA.GEN_AI_REQUEST_TEMPERATURE, temperature) top_p = kwargs.get("top_p") if top_p is not None and _is_given(top_p): - set_on_span(SPANDATA.GEN_AI_REQUEST_TOP_P, top_p) + span.set_attribute(SPANDATA.GEN_AI_REQUEST_TOP_P, top_p) reasoning_level = kwargs.get("reasoning_effort") if reasoning_level is not None and _is_given(reasoning_level): - set_on_span(SPANDATA.GEN_AI_REQUEST_REASONING_LEVEL, reasoning_level) + span.set_attribute(SPANDATA.GEN_AI_REQUEST_REASONING_LEVEL, reasoning_level) client = sentry_sdk.get_client() if has_data_collection_enabled(client.options): if client.options["data_collection"]["gen_ai"]["inputs"]: tools = kwargs.get("tools") if tools is not None and _is_given(tools): - set_on_span( + span.set_attribute( SPANDATA.GEN_AI_TOOL_DEFINITIONS, json.dumps(_transform_tool_definitions_completions(tools)), ) else: # Pre-data collection this was always set, so this needs to be left here for now until # we deprecate `send_default_pii`. Once we do, this 'else' branch should be removed, - # and the above branch placed below the "if not should_send_default_pii() or not integration.include_prompts" + # and the above branch placed below the "if not should_send_default_pii()" # line below tools = kwargs.get("tools") if tools is not None and _is_given(tools): - set_on_span( + span.set_attribute( SPANDATA.GEN_AI_TOOL_DEFINITIONS, json.dumps(_transform_tool_definitions_completions(tools)), ) @@ -548,7 +525,7 @@ def _set_completions_api_input_data( if has_data_collection_enabled(client.options): if not client.options["data_collection"]["gen_ai"]["inputs"]: return - elif not should_send_default_pii() or not integration.include_prompts: + elif not should_send_default_pii(): return if messages is None: @@ -556,16 +533,12 @@ def _set_completions_api_input_data( if isinstance(messages, str): normalized_messages = normalize_message_roles([messages]) # type: ignore - scope = sentry_sdk.get_current_scope() - messages_data = ( - truncate_and_annotate_messages(normalized_messages, span, scope) - if should_truncate_gen_ai_input(client.options) - else normalized_messages + set_data_normalized( + span, + SPANDATA.GEN_AI_REQUEST_MESSAGES, + normalized_messages, + unpack=False, ) - if messages_data is not None: - set_data_normalized( - span, SPANDATA.GEN_AI_REQUEST_MESSAGES, messages_data, unpack=False - ) return # dict special case following https://github.com/openai/openai-python/blob/3e0c05b84a2056870abf3bd6a5e7849020209cc3/src/openai/_utils/_transform.py#L194-L197 @@ -577,7 +550,7 @@ def _set_completions_api_input_data( system_instructions = _get_system_instructions_completions(messages) if len(system_instructions) > 0: - set_on_span( + span.set_attribute( SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS, json.dumps(_transform_system_instructions_completions(system_instructions)), ) @@ -590,33 +563,25 @@ def _set_completions_api_input_data( if len(non_system_messages) > 0: normalized_messages = normalize_message_roles(non_system_messages) # type: ignore client = sentry_sdk.get_client() - scope = sentry_sdk.get_current_scope() - messages_data = ( - truncate_and_annotate_messages(normalized_messages, span, scope) - if should_truncate_gen_ai_input(client.options) - else normalized_messages + set_data_normalized( + span, + SPANDATA.GEN_AI_REQUEST_MESSAGES, + normalized_messages, + unpack=False, ) - if messages_data is not None: - set_data_normalized( - span, SPANDATA.GEN_AI_REQUEST_MESSAGES, messages_data, unpack=False - ) def _set_embeddings_input_data( - span: "Union[Span, StreamedSpan]", + span: "Span", kwargs: "dict[str, Any]", integration: "OpenAIIntegration", ) -> None: set_data_normalized(span, SPANDATA.GEN_AI_OPERATION_NAME, "embeddings") - set_on_span = ( - span.set_attribute if isinstance(span, StreamedSpan) else span.set_data - ) - model = kwargs.get("model") if model is not None: - set_on_span(SPANDATA.GEN_AI_REQUEST_MODEL, model) + span.set_attribute(SPANDATA.GEN_AI_REQUEST_MODEL, model) messages: "Optional[Union[str, SequenceNotStr[str], Iterable[int], Iterable[Iterable[int]]]]" = kwargs.get( "input" @@ -626,7 +591,7 @@ def _set_embeddings_input_data( if has_data_collection_enabled(client.options): if not client.options["data_collection"]["gen_ai"]["inputs"]: return - elif not should_send_default_pii() or not integration.include_prompts: + elif not should_send_default_pii(): return if messages is None: @@ -634,15 +599,12 @@ def _set_embeddings_input_data( if isinstance(messages, str): normalized_messages = normalize_message_roles([messages]) # type: ignore - scope = sentry_sdk.get_current_scope() - messages_data = ( - truncate_and_annotate_embedding_inputs(normalized_messages, span, scope) - if should_truncate_gen_ai_input(client.options) - else normalized_messages - ) - if messages_data is not None: + if normalized_messages is not None: set_data_normalized( - span, SPANDATA.GEN_AI_EMBEDDINGS_INPUT, messages_data, unpack=False + span, + SPANDATA.GEN_AI_EMBEDDINGS_INPUT, + normalized_messages, + unpack=False, ) return @@ -656,20 +618,17 @@ def _set_embeddings_input_data( if len(messages_copy) > 0: normalized_messages = normalize_message_roles(messages_copy) # type: ignore - scope = sentry_sdk.get_current_scope() - messages_data = ( - truncate_and_annotate_embedding_inputs(normalized_messages, span, scope) - if should_truncate_gen_ai_input(client.options) - else normalized_messages - ) - if messages_data is not None: + if normalized_messages is not None: set_data_normalized( - span, SPANDATA.GEN_AI_EMBEDDINGS_INPUT, messages_data, unpack=False + span, + SPANDATA.GEN_AI_EMBEDDINGS_INPUT, + normalized_messages, + unpack=False, ) def _set_common_output_data( - span: "Union[Span, StreamedSpan]", + span: "Span", response: "Union[ChatCompletion, Stream[ChatCompletionChunk], AsyncStream[ChatCompletionChunk], Response, Stream[ResponseStreamEvent], AsyncStream[ResponseStreamEvent], CreateEmbeddingResponse]", input: "Any", integration: "OpenAIIntegration", @@ -692,7 +651,7 @@ def _set_common_output_data( set_data_normalized( span, SPANDATA.GEN_AI_RESPONSE_TEXT, response_text ) - elif should_send_default_pii() and integration.include_prompts: + elif should_send_default_pii(): response_text = [ choice.message.model_dump() for choice in response.choices @@ -754,11 +713,7 @@ def _set_common_output_data( span, SPANDATA.GEN_AI_RESPONSE_TEXT, output_messages["response"] ) - elif ( - should_send_default_pii() - and integration.include_prompts - and isinstance(response.output, list) - ): + elif should_send_default_pii() and isinstance(response.output, list): for output in response.output: if output.type == "function_call": output_messages["tool"].append(output.dict()) @@ -817,6 +772,9 @@ def _new_sync_chat_completion( if integration is None: return f(*args, **kwargs) + if sentry_sdk.get_current_scope()._agent_framework_chat_generation_entered: + return f(*args, **kwargs) + if "messages" not in kwargs: # invalid call (in all versions of openai), let it return error return f(*args, **kwargs) @@ -832,27 +790,15 @@ def _new_sync_chat_completion( # Same bool handling as in https://github.com/openai/openai-python/blob/acd0c54d8a68efeedde0e5b4e6c310eef1ce7867/src/openai/resources/completions.py#L585 is_streaming_response = kwargs.get("stream", False) or False - if has_span_streaming_enabled(client.options): - span = sentry_sdk.traces.start_span( - name=f"chat {model}", - attributes={ - "sentry.op": consts.OP.GEN_AI_CHAT, - "sentry.origin": OpenAIIntegration.origin, - SPANDATA.GEN_AI_SYSTEM: "openai", - SPANDATA.GEN_AI_RESPONSE_STREAMING: is_streaming_response, - }, - ) - - else: - span = get_start_span_function()( - op=consts.OP.GEN_AI_CHAT, - name=f"chat {model}", - origin=OpenAIIntegration.origin, - ) - span.__enter__() - - span.set_data(SPANDATA.GEN_AI_SYSTEM, "openai") - span.set_data(SPANDATA.GEN_AI_RESPONSE_STREAMING, is_streaming_response) + span = sentry_sdk.start_span( + name=f"chat {model}", + attributes={ + "sentry.op": consts.OP.GEN_AI_CHAT, + "sentry.origin": OpenAIIntegration.origin, + SPANDATA.GEN_AI_PROVIDER_NAME: "openai", + SPANDATA.GEN_AI_RESPONSE_STREAMING: is_streaming_response, + }, + ) _set_completions_api_input_data(span, kwargs, integration) @@ -904,6 +850,9 @@ async def _new_async_chat_completion( if integration is None: return await f(*args, **kwargs) + if sentry_sdk.get_current_scope()._agent_framework_chat_generation_entered: + return await f(*args, **kwargs) + if "messages" not in kwargs: # invalid call (in all versions of openai), let it return error return await f(*args, **kwargs) @@ -919,26 +868,15 @@ async def _new_async_chat_completion( # Same bool handling as in https://github.com/openai/openai-python/blob/acd0c54d8a68efeedde0e5b4e6c310eef1ce7867/src/openai/resources/completions.py#L585 is_streaming_response = kwargs.get("stream", False) or False - if has_span_streaming_enabled(client.options): - span = sentry_sdk.traces.start_span( - name=f"chat {model}", - attributes={ - "sentry.op": consts.OP.GEN_AI_CHAT, - "sentry.origin": OpenAIIntegration.origin, - SPANDATA.GEN_AI_SYSTEM: "openai", - SPANDATA.GEN_AI_RESPONSE_STREAMING: is_streaming_response, - }, - ) - else: - span = get_start_span_function()( - op=consts.OP.GEN_AI_CHAT, - name=f"chat {model}", - origin=OpenAIIntegration.origin, - ) - span.__enter__() - - span.set_data(SPANDATA.GEN_AI_SYSTEM, "openai") - span.set_data(SPANDATA.GEN_AI_RESPONSE_STREAMING, is_streaming_response) + span = sentry_sdk.start_span( + name=f"chat {model}", + attributes={ + "sentry.op": consts.OP.GEN_AI_CHAT, + "sentry.origin": OpenAIIntegration.origin, + SPANDATA.GEN_AI_PROVIDER_NAME: "openai", + SPANDATA.GEN_AI_RESPONSE_STREAMING: is_streaming_response, + }, + ) _set_completions_api_input_data(span, kwargs, integration) @@ -978,7 +916,7 @@ async def _new_async_chat_completion( def _set_completions_api_output_data( - span: "Union[Span, StreamedSpan]", + span: "Span", response: "Union[ChatCompletion, Stream[ChatCompletionChunk], AsyncStream[ChatCompletionChunk]]", kwargs: "dict[str, Any]", integration: "OpenAIIntegration", @@ -999,7 +937,7 @@ def _set_completions_api_output_data( def _wrap_synchronous_completions_chunk_iterator( - span: "Union[Span, StreamedSpan]", + span: "Span", integration: "OpenAIIntegration", start_time: "Optional[float]", messages: "Optional[Union[Iterable[ChatCompletionMessageParam], list[str]]]", @@ -1018,10 +956,7 @@ def _wrap_synchronous_completions_chunk_iterator( client = sentry_sdk.get_client() for x in old_iterator: - if isinstance(span, StreamedSpan): - span.set_attribute(SPANDATA.GEN_AI_RESPONSE_MODEL, x.model) - else: - span.set_data(SPANDATA.GEN_AI_RESPONSE_MODEL, x.model) + span.set_attribute(SPANDATA.GEN_AI_RESPONSE_MODEL, x.model) with capture_internal_exceptions(): if hasattr(x, "choices") and x.choices is not None: @@ -1043,7 +978,7 @@ def _wrap_synchronous_completions_chunk_iterator( with capture_internal_exceptions(): if ttft is not None: set_data_normalized( - span, SPANDATA.GEN_AI_RESPONSE_TIME_TO_FIRST_TOKEN, ttft + span, SPANDATA.GEN_AI_RESPONSE_TIME_TO_FIRST_CHUNK, ttft ) all_responses = None if len(data_buf) > 0: @@ -1053,7 +988,7 @@ def _wrap_synchronous_completions_chunk_iterator( set_data_normalized( span, SPANDATA.GEN_AI_RESPONSE_TEXT, all_responses ) - elif should_send_default_pii() and integration.include_prompts: + elif should_send_default_pii(): set_data_normalized(span, SPANDATA.GEN_AI_RESPONSE_TEXT, all_responses) _calculate_completions_token_usage( @@ -1070,7 +1005,7 @@ def _wrap_synchronous_completions_chunk_iterator( async def _wrap_asynchronous_completions_chunk_iterator( - span: "Union[Span, StreamedSpan]", + span: "Span", integration: "OpenAIIntegration", start_time: "Optional[float]", messages: "Optional[Union[Iterable[ChatCompletionMessageParam], list[str]]]", @@ -1089,10 +1024,7 @@ async def _wrap_asynchronous_completions_chunk_iterator( client = sentry_sdk.get_client() async for x in old_iterator: - if isinstance(span, StreamedSpan): - span.set_attribute(SPANDATA.GEN_AI_RESPONSE_MODEL, x.model) - else: - span.set_data(SPANDATA.GEN_AI_RESPONSE_MODEL, x.model) + span.set_attribute(SPANDATA.GEN_AI_RESPONSE_MODEL, x.model) with capture_internal_exceptions(): if hasattr(x, "choices") and x.choices is not None: @@ -1114,7 +1046,7 @@ async def _wrap_asynchronous_completions_chunk_iterator( with capture_internal_exceptions(): if ttft is not None: set_data_normalized( - span, SPANDATA.GEN_AI_RESPONSE_TIME_TO_FIRST_TOKEN, ttft + span, SPANDATA.GEN_AI_RESPONSE_TIME_TO_FIRST_CHUNK, ttft ) all_responses = None if len(data_buf) > 0: @@ -1124,7 +1056,7 @@ async def _wrap_asynchronous_completions_chunk_iterator( set_data_normalized( span, SPANDATA.GEN_AI_RESPONSE_TEXT, all_responses ) - elif should_send_default_pii() and integration.include_prompts: + elif should_send_default_pii(): set_data_normalized(span, SPANDATA.GEN_AI_RESPONSE_TEXT, all_responses) _calculate_completions_token_usage( @@ -1141,7 +1073,7 @@ async def _wrap_asynchronous_completions_chunk_iterator( def _wrap_synchronous_responses_event_iterator( - span: "Union[Span, StreamedSpan]", + span: "Span", integration: "OpenAIIntegration", start_time: "Optional[float]", input: "Optional[Union[str, list[str], ResponseInputParam]]", @@ -1169,10 +1101,7 @@ def _wrap_synchronous_responses_event_iterator( data_buf[0].append(x.delta or "") elif isinstance(x, ResponseCompletedEvent): - if isinstance(span, StreamedSpan): - span.set_attribute(SPANDATA.GEN_AI_RESPONSE_MODEL, x.response.model) - else: - span.set_data(SPANDATA.GEN_AI_RESPONSE_MODEL, x.response.model) + span.set_attribute(SPANDATA.GEN_AI_RESPONSE_MODEL, x.response.model) _calculate_responses_token_usage( input=input, @@ -1188,7 +1117,7 @@ def _wrap_synchronous_responses_event_iterator( with capture_internal_exceptions(): if ttft is not None: set_data_normalized( - span, SPANDATA.GEN_AI_RESPONSE_TIME_TO_FIRST_TOKEN, ttft + span, SPANDATA.GEN_AI_RESPONSE_TIME_TO_FIRST_CHUNK, ttft ) if len(data_buf) > 0: all_responses = ["".join(chunk) for chunk in data_buf] @@ -1197,7 +1126,7 @@ def _wrap_synchronous_responses_event_iterator( set_data_normalized( span, SPANDATA.GEN_AI_RESPONSE_TEXT, all_responses ) - elif should_send_default_pii() and integration.include_prompts: + elif should_send_default_pii(): set_data_normalized(span, SPANDATA.GEN_AI_RESPONSE_TEXT, all_responses) if count_tokens_manually: @@ -1214,7 +1143,7 @@ def _wrap_synchronous_responses_event_iterator( async def _wrap_asynchronous_responses_event_iterator( - span: "Union[Span, StreamedSpan]", + span: "Span", integration: "OpenAIIntegration", start_time: "Optional[float]", input: "Optional[Union[str, list[str], ResponseInputParam]]", @@ -1242,10 +1171,7 @@ async def _wrap_asynchronous_responses_event_iterator( data_buf[0].append(x.delta or "") elif isinstance(x, ResponseCompletedEvent): - if isinstance(span, StreamedSpan): - span.set_attribute(SPANDATA.GEN_AI_RESPONSE_MODEL, x.response.model) - else: - span.set_data(SPANDATA.GEN_AI_RESPONSE_MODEL, x.response.model) + span.set_attribute(SPANDATA.GEN_AI_RESPONSE_MODEL, x.response.model) _calculate_responses_token_usage( input=input, @@ -1261,7 +1187,7 @@ async def _wrap_asynchronous_responses_event_iterator( with capture_internal_exceptions(): if ttft is not None: set_data_normalized( - span, SPANDATA.GEN_AI_RESPONSE_TIME_TO_FIRST_TOKEN, ttft + span, SPANDATA.GEN_AI_RESPONSE_TIME_TO_FIRST_CHUNK, ttft ) if len(data_buf) > 0: all_responses = ["".join(chunk) for chunk in data_buf] @@ -1271,7 +1197,7 @@ async def _wrap_asynchronous_responses_event_iterator( set_data_normalized( span, SPANDATA.GEN_AI_RESPONSE_TEXT, all_responses ) - elif should_send_default_pii() and integration.include_prompts: + elif should_send_default_pii(): set_data_normalized(span, SPANDATA.GEN_AI_RESPONSE_TEXT, all_responses) if count_tokens_manually: @@ -1287,7 +1213,7 @@ async def _wrap_asynchronous_responses_event_iterator( def _set_responses_api_output_data( - span: "Union[Span, StreamedSpan]", + span: "Span", response: "Union[Response, Stream[ResponseStreamEvent], AsyncStream[ResponseStreamEvent]]", kwargs: "dict[str, Any]", integration: "OpenAIIntegration", @@ -1308,7 +1234,7 @@ def _set_responses_api_output_data( def _set_embeddings_output_data( - span: "Union[Span, StreamedSpan]", + span: "Span", response: "CreateEmbeddingResponse", kwargs: "dict[str, Any]", integration: "OpenAIIntegration", @@ -1368,52 +1294,29 @@ def _new_sync_embeddings_create(f: "Any", *args: "Any", **kwargs: "Any") -> "Any model = kwargs.get("model") - if has_span_streaming_enabled(client.options): - with sentry_sdk.traces.start_span( - name=f"embeddings {model}", - attributes={ - "sentry.op": consts.OP.GEN_AI_EMBEDDINGS, - "sentry.origin": OpenAIIntegration.origin, - SPANDATA.GEN_AI_SYSTEM: "openai", - }, - ) as span: - _set_embeddings_input_data(span, kwargs, integration) - - try: - response = f(*args, **kwargs) - except Exception as exc: - exc_info = sys.exc_info() - with capture_internal_exceptions(): - _capture_exception(exc) - reraise(*exc_info) - - _set_embeddings_output_data( - span, response, kwargs, integration, finish_span=False - ) + with sentry_sdk.start_span( + name=f"embeddings {model}", + attributes={ + "sentry.op": consts.OP.GEN_AI_EMBEDDINGS, + "sentry.origin": OpenAIIntegration.origin, + SPANDATA.GEN_AI_PROVIDER_NAME: "openai", + }, + ) as span: + _set_embeddings_input_data(span, kwargs, integration) - return response - else: - with get_start_span_function()( - op=consts.OP.GEN_AI_EMBEDDINGS, - name=f"embeddings {model}", - origin=OpenAIIntegration.origin, - ) as span: - span.set_data(SPANDATA.GEN_AI_SYSTEM, "openai") - _set_embeddings_input_data(span, kwargs, integration) - - try: - response = f(*args, **kwargs) - except Exception as exc: - exc_info = sys.exc_info() - with capture_internal_exceptions(): - _capture_exception(exc) - reraise(*exc_info) - - _set_embeddings_output_data( - span, response, kwargs, integration, finish_span=False - ) + try: + response = f(*args, **kwargs) + except Exception as exc: + exc_info = sys.exc_info() + with capture_internal_exceptions(): + _capture_exception(exc) + reraise(*exc_info) + + _set_embeddings_output_data( + span, response, kwargs, integration, finish_span=False + ) - return response + return response async def _new_async_embeddings_create( @@ -1428,52 +1331,29 @@ async def _new_async_embeddings_create( model = kwargs.get("model") - if has_span_streaming_enabled(client.options): - with sentry_sdk.traces.start_span( - name=f"embeddings {model}", - attributes={ - "sentry.op": consts.OP.GEN_AI_EMBEDDINGS, - "sentry.origin": OpenAIIntegration.origin, - SPANDATA.GEN_AI_SYSTEM: "openai", - }, - ) as span: - _set_embeddings_input_data(span, kwargs, integration) - - try: - response = await f(*args, **kwargs) - except Exception as exc: - exc_info = sys.exc_info() - with capture_internal_exceptions(): - _capture_exception(exc) - reraise(*exc_info) - - _set_embeddings_output_data( - span, response, kwargs, integration, finish_span=False - ) + with sentry_sdk.start_span( + name=f"embeddings {model}", + attributes={ + "sentry.op": consts.OP.GEN_AI_EMBEDDINGS, + "sentry.origin": OpenAIIntegration.origin, + SPANDATA.GEN_AI_PROVIDER_NAME: "openai", + }, + ) as span: + _set_embeddings_input_data(span, kwargs, integration) - return response - else: - with get_start_span_function()( - op=consts.OP.GEN_AI_EMBEDDINGS, - name=f"embeddings {model}", - origin=OpenAIIntegration.origin, - ) as span: - span.set_data(SPANDATA.GEN_AI_SYSTEM, "openai") - _set_embeddings_input_data(span, kwargs, integration) - - try: - response = await f(*args, **kwargs) - except Exception as exc: - exc_info = sys.exc_info() - with capture_internal_exceptions(): - _capture_exception(exc) - reraise(*exc_info) - - _set_embeddings_output_data( - span, response, kwargs, integration, finish_span=False - ) + try: + response = await f(*args, **kwargs) + except Exception as exc: + exc_info = sys.exc_info() + with capture_internal_exceptions(): + _capture_exception(exc) + reraise(*exc_info) + + _set_embeddings_output_data( + span, response, kwargs, integration, finish_span=False + ) - return response + return response def _wrap_embeddings_create(f: "Any") -> "Any": @@ -1510,31 +1390,23 @@ def _new_sync_responses_create( if integration is None: return f(*args, **kwargs) + if sentry_sdk.get_current_scope()._agent_framework_chat_generation_entered: + return f(*args, **kwargs) + model = kwargs.get("model") # Same bool handling as in https://github.com/openai/openai-python/blob/acd0c54d8a68efeedde0e5b4e6c310eef1ce7867/src/openai/resources/responses/responses.py#L940 is_streaming_response = kwargs.get("stream", False) or False - if has_span_streaming_enabled(client.options): - span = sentry_sdk.traces.start_span( - name=f"responses {model}", - attributes={ - "sentry.op": consts.OP.GEN_AI_RESPONSES, - "sentry.origin": OpenAIIntegration.origin, - SPANDATA.GEN_AI_SYSTEM: "openai", - SPANDATA.GEN_AI_RESPONSE_STREAMING: is_streaming_response, - }, - ) - else: - span = get_start_span_function()( - op=consts.OP.GEN_AI_RESPONSES, - name=f"responses {model}", - origin=OpenAIIntegration.origin, - ) - span.__enter__() - - span.set_data(SPANDATA.GEN_AI_SYSTEM, "openai") - span.set_data(SPANDATA.GEN_AI_RESPONSE_STREAMING, is_streaming_response) + span = sentry_sdk.start_span( + name=f"responses {model}", + attributes={ + "sentry.op": consts.OP.GEN_AI_RESPONSES, + "sentry.origin": OpenAIIntegration.origin, + SPANDATA.GEN_AI_PROVIDER_NAME: "openai", + SPANDATA.GEN_AI_RESPONSE_STREAMING: is_streaming_response, + }, + ) _set_responses_api_input_data(span, kwargs, integration) @@ -1586,31 +1458,23 @@ async def _new_async_responses_create( if integration is None: return await f(*args, **kwargs) + if sentry_sdk.get_current_scope()._agent_framework_chat_generation_entered: + return await f(*args, **kwargs) + model = kwargs.get("model") # Same bool handling as in https://github.com/openai/openai-python/blob/acd0c54d8a68efeedde0e5b4e6c310eef1ce7867/src/openai/resources/responses/responses.py#L940 is_streaming_response = kwargs.get("stream", False) or False - if has_span_streaming_enabled(client.options): - span = sentry_sdk.traces.start_span( - name=f"responses {model}", - attributes={ - "sentry.op": consts.OP.GEN_AI_RESPONSES, - "sentry.origin": OpenAIIntegration.origin, - SPANDATA.GEN_AI_SYSTEM: "openai", - SPANDATA.GEN_AI_RESPONSE_STREAMING: is_streaming_response, - }, - ) - else: - span = get_start_span_function()( - op=consts.OP.GEN_AI_RESPONSES, - name=f"responses {model}", - origin=OpenAIIntegration.origin, - ) - span.__enter__() - - span.set_data(SPANDATA.GEN_AI_SYSTEM, "openai") - span.set_data(SPANDATA.GEN_AI_RESPONSE_STREAMING, is_streaming_response) + span = sentry_sdk.start_span( + name=f"responses {model}", + attributes={ + "sentry.op": consts.OP.GEN_AI_RESPONSES, + "sentry.origin": OpenAIIntegration.origin, + SPANDATA.GEN_AI_PROVIDER_NAME: "openai", + SPANDATA.GEN_AI_RESPONSE_STREAMING: is_streaming_response, + }, + ) _set_responses_api_input_data(span, kwargs, integration) diff --git a/sentry_sdk/integrations/openai_agents/__init__.py b/sentry_sdk/integrations/openai_agents/__init__.py index a4488d169b..2fc693ee06 100644 --- a/sentry_sdk/integrations/openai_agents/__init__.py +++ b/sentry_sdk/integrations/openai_agents/__init__.py @@ -1,6 +1,6 @@ from functools import wraps -from sentry_sdk.integrations import DidNotEnable, Integration +from sentry_sdk.integrations import DidNotEnable, Integration, _check_minimum_version from sentry_sdk.utils import parse_version from .patches import ( @@ -8,7 +8,6 @@ _create_run_wrapper, _execute_final_output, _execute_handoffs, - _get_all_tools, _get_model, _patch_error_tracing, _run_single_turn, @@ -22,7 +21,6 @@ # not installed. That's why we're adding the second, more specific import # after it, even if we don't use it. import agents - from agents.run import AgentRunner from agents.version import __version__ as OPENAI_AGENTS_VERSION except ImportError: @@ -46,209 +44,110 @@ from agents.run_internal.run_steps import SingleStepResult -def _patch_runner(use_run_hooks: "bool") -> None: +def _patch_runner() -> None: # Create the root span for one full agent run (including eventual handoffs) # Note agents.run.DEFAULT_AGENT_RUNNER.run_sync is a wrapper around # agents.run.DEFAULT_AGENT_RUNNER.run. It does not need to be wrapped separately. agents.run.DEFAULT_AGENT_RUNNER.run = _create_run_wrapper( # type: ignore[method-assign] agents.run.DEFAULT_AGENT_RUNNER.run, - use_run_hooks=use_run_hooks, ) # Patch streaming runner agents.run.DEFAULT_AGENT_RUNNER.run_streamed = _create_run_streamed_wrapper( # type: ignore[method-assign] agents.run.DEFAULT_AGENT_RUNNER.run_streamed, - use_run_hooks=use_run_hooks, ) class OpenAIAgentsIntegration(Integration): """ - NOTE: With version 0.8.0, the class methods below have been refactored to functions. - - `AgentRunner._get_model()` -> `agents.run_internal.turn_preparation.get_model()` - - `AgentRunner._get_all_tools()` -> `agents.run_internal.turn_preparation.get_all_tools()` - - `AgentRunner._run_single_turn()` -> `agents.run_internal.run_loop.run_single_turn()` - - `RunImpl.execute_handoffs()` -> `agents.run_internal.turn_resolution.execute_handoffs()` - - `RunImpl.execute_final_output()` -> `agents.run_internal.turn_resolution.execute_final_output()` - Typical interaction with the library: 1. The user creates an Agent instance with configuration, including system instructions sent to every Responses API call. 2. The user passes the agent instance to a Runner with `run()` and `run_streamed()` methods. The latter can be used to incrementally receive progress. - `Runner.run()` and `Runner.run_streamed()` are thin wrappers for `DEFAULT_AGENT_RUNNER.run()` and `DEFAULT_AGENT_RUNNER.run_streamed()`. - `DEFAULT_AGENT_RUNNER.run()` and `DEFAULT_AGENT_RUNNER.run_streamed()` are patched in `_patch_runner()` with `_create_run_wrapper()` and `_create_run_streamed_wrapper()`, respectively. 3. In a loop, the agent repeatedly calls the Responses API, maintaining a conversation history that includes previous messages and tool results, which is passed to each call. - - A Model instance is created at the start of the loop by calling the `Runner._get_model()`. We patch the Model instance using `patches._get_model()`. - - Available tools are also deteremined at the start of the loop, with `Runner._get_all_tools()`. We patch Tool instances by iterating through the returned tools in `patches._get_all_tools()`. - - In each loop iteration, `run_single_turn()` or `run_single_turn_streamed()` is responsible for calling the Responses API, patched with `patches._run_single_turn()` and `patches._run_single_turn_streamed()`. - 4. On loop termination, `RunImpl.execute_final_output()` is called. The function is patched with `patches._execute_final_output()`. + - A Model instance is created at the start of the loop by calling the `run_internal.turn_preparation.get_model()`. We patch the Model instance using `patches._get_model()`. + - In each loop iteration, `run_single_turn()` or `run_single_turn_streamed()` is responsible for calling the Responses API, patched with `run_internal.run_loop.run_single_turn()` and `patches._run_single_turn_streamed()`. + 4. On loop termination, `run_internal.turn_resolution.execute_final_output()` is called. The function is patched with `patches._execute_final_output()`. Local tools are run based on the return value from the Responses API as a post-API call step in the above loop. Hosted MCP Tools are run as part of the Responses API call, and involve OpenAI reaching out to an external MCP server. An agent can handoff to another agent, also directed by the return value of the Responses API and run post-API call in the loop. Handoffs are a way to switch agent-wide configuration. - - Handoffs are executed by calling `RunImpl.execute_handoffs()`. The method is patched with `patches._execute_handoffs()` + - Handoffs are executed by calling `run_internal.turn_resolution.execute_handoffs()`. The method is patched with `patches._execute_handoffs()` """ identifier = "openai_agents" @staticmethod def setup_once() -> None: - _patch_error_tracing() - library_version = parse_version(OPENAI_AGENTS_VERSION) - # ToolContext.tool_arguments added in https://github.com/openai/openai-agents-python/commit/5e1db14da542c77f8fdd5e2e26017977ae415813 - use_run_hooks = library_version is not None and library_version >= (0, 3, 2) - - _patch_runner(use_run_hooks=use_run_hooks) - - if library_version is not None and library_version >= ( - 0, - 8, - ): - if run_loop is not None: - - @wraps(run_loop.run_single_turn) - async def new_wrapped_run_single_turn( - *args: "Any", **kwargs: "Any" - ) -> "SingleStepResult": - return await _run_single_turn( - run_loop.run_single_turn, *args, **kwargs - ) - - agents.run.run_single_turn = new_wrapped_run_single_turn - - original_run_single_turn_streamed = run_loop.run_single_turn_streamed - - @wraps(original_run_single_turn_streamed) - async def new_wrapped_run_single_turn_streamed( - *args: "Any", **kwargs: "Any" - ) -> "SingleStepResult": - return await _run_single_turn_streamed( - original_run_single_turn_streamed, - *args, - **kwargs, - ) - - agents.run_internal.run_loop.run_single_turn_streamed = ( - new_wrapped_run_single_turn_streamed - ) - - if turn_preparation is not None: - - @wraps(turn_preparation.get_model) - def new_wrapped_get_model( - agent: "agents.Agent", run_config: "agents.RunConfig" - ) -> "agents.Model": - return _get_model(turn_preparation.get_model, agent, run_config) - - agents.run_internal.run_loop.get_model = new_wrapped_get_model - - if turn_resolution is not None: - original_execute_handoffs = turn_resolution.execute_handoffs - - @wraps(original_execute_handoffs) - async def new_wrapped_execute_handoffs( - *args: "Any", **kwargs: "Any" - ) -> "SingleStepResult": - return await _execute_handoffs( - original_execute_handoffs, *args, **kwargs - ) - - agents.run_internal.turn_resolution.execute_handoffs = ( - new_wrapped_execute_handoffs - ) + _check_minimum_version(OpenAIAgentsIntegration, library_version) - original_execute_final_output = turn_resolution.execute_final_output + _patch_error_tracing() + _patch_runner() - @wraps(turn_resolution.execute_final_output) - async def new_wrapped_final_output( - *args: "Any", **kwargs: "Any" - ) -> "SingleStepResult": - return await _execute_final_output( - original_execute_final_output, *args, **kwargs - ) + if run_loop is not None: - agents.run_internal.turn_resolution.execute_final_output = ( - new_wrapped_final_output - ) + @wraps(run_loop.run_single_turn) + async def new_wrapped_run_single_turn( + *args: "Any", **kwargs: "Any" + ) -> "SingleStepResult": + return await _run_single_turn(run_loop.run_single_turn, *args, **kwargs) - return + agents.run.run_single_turn = new_wrapped_run_single_turn - if not use_run_hooks: - original_get_all_tools = AgentRunner._get_all_tools # type: ignore[attr-defined] + original_run_single_turn_streamed = run_loop.run_single_turn_streamed - @wraps(AgentRunner._get_all_tools.__func__) # type: ignore[attr-defined] - async def old_wrapped_get_all_tools( - cls: "agents.Runner", - agent: "agents.Agent", - context_wrapper: "agents.RunContextWrapper", - ) -> "list[agents.Tool]": - return await _get_all_tools( - original_get_all_tools, agent, context_wrapper + @wraps(original_run_single_turn_streamed) + async def new_wrapped_run_single_turn_streamed( + *args: "Any", **kwargs: "Any" + ) -> "SingleStepResult": + return await _run_single_turn_streamed( + original_run_single_turn_streamed, + *args, + **kwargs, ) - agents.run.AgentRunner._get_all_tools = classmethod( # type: ignore[attr-defined] - old_wrapped_get_all_tools # type: ignore[arg-type] + agents.run_internal.run_loop.run_single_turn_streamed = ( + new_wrapped_run_single_turn_streamed ) - original_get_model = AgentRunner._get_model # type: ignore[attr-defined] - - @wraps(AgentRunner._get_model.__func__) # type: ignore[attr-defined] - def old_wrapped_get_model( - cls: "agents.Runner", agent: "agents.Agent", run_config: "agents.RunConfig" - ) -> "agents.Model": - return _get_model(original_get_model, agent, run_config) + if turn_preparation is not None: - agents.run.AgentRunner._get_model = classmethod(old_wrapped_get_model) # type: ignore[arg-type,attr-defined] + @wraps(turn_preparation.get_model) + def new_wrapped_get_model( + agent: "agents.Agent", run_config: "agents.RunConfig" + ) -> "agents.Model": + return _get_model(turn_preparation.get_model, agent, run_config) - original_run_single_turn = AgentRunner._run_single_turn # type: ignore[attr-defined] + agents.run_internal.run_loop.get_model = new_wrapped_get_model - @wraps(AgentRunner._run_single_turn.__func__) # type: ignore[attr-defined] - async def old_wrapped_run_single_turn( - cls: "agents.Runner", *args: "Any", **kwargs: "Any" - ) -> "SingleStepResult": - return await _run_single_turn(original_run_single_turn, *args, **kwargs) + if turn_resolution is not None: + original_execute_handoffs = turn_resolution.execute_handoffs - agents.run.AgentRunner._run_single_turn = classmethod( # type: ignore[attr-defined] - old_wrapped_run_single_turn # type: ignore[arg-type] - ) - - original_run_single_turn_streamed = AgentRunner._run_single_turn_streamed # type: ignore[attr-defined] + @wraps(original_execute_handoffs) + async def new_wrapped_execute_handoffs( + *args: "Any", **kwargs: "Any" + ) -> "SingleStepResult": + return await _execute_handoffs( + original_execute_handoffs, *args, **kwargs + ) - @wraps(AgentRunner._run_single_turn_streamed.__func__) # type: ignore[attr-defined] - async def old_wrapped_run_single_turn_streamed( - cls: "agents.Runner", *args: "Any", **kwargs: "Any" - ) -> "SingleStepResult": - return await _run_single_turn_streamed( - original_run_single_turn_streamed, *args, **kwargs + agents.run_internal.turn_resolution.execute_handoffs = ( + new_wrapped_execute_handoffs ) - agents.run.AgentRunner._run_single_turn_streamed = classmethod( # type: ignore[attr-defined] - old_wrapped_run_single_turn_streamed # type: ignore[arg-type] - ) + original_execute_final_output = turn_resolution.execute_final_output - original_execute_handoffs = agents._run_impl.RunImpl.execute_handoffs - - @wraps(agents._run_impl.RunImpl.execute_handoffs.__func__) - async def old_wrapped_execute_handoffs( - cls: "agents.Runner", *args: "Any", **kwargs: "Any" - ) -> "SingleStepResult": - return await _execute_handoffs(original_execute_handoffs, *args, **kwargs) - - agents._run_impl.RunImpl.execute_handoffs = classmethod( - old_wrapped_execute_handoffs # type: ignore[arg-type] - ) - - original_execute_final_output = agents._run_impl.RunImpl.execute_final_output + @wraps(turn_resolution.execute_final_output) + async def new_wrapped_final_output( + *args: "Any", **kwargs: "Any" + ) -> "SingleStepResult": + return await _execute_final_output( + original_execute_final_output, *args, **kwargs + ) - @wraps(agents._run_impl.RunImpl.execute_final_output.__func__) - async def old_wrapped_final_output( - cls: "agents.Runner", *args: "Any", **kwargs: "Any" - ) -> "SingleStepResult": - return await _execute_final_output( - original_execute_final_output, *args, **kwargs + agents.run_internal.turn_resolution.execute_final_output = ( + new_wrapped_final_output ) - - agents._run_impl.RunImpl.execute_final_output = classmethod( - old_wrapped_final_output # type: ignore[arg-type] - ) diff --git a/sentry_sdk/integrations/openai_agents/patches/__init__.py b/sentry_sdk/integrations/openai_agents/patches/__init__.py index 85d48f2d41..11d6a13978 100644 --- a/sentry_sdk/integrations/openai_agents/patches/__init__.py +++ b/sentry_sdk/integrations/openai_agents/patches/__init__.py @@ -7,4 +7,3 @@ from .error_tracing import _patch_error_tracing # noqa: F401 from .models import _get_model # noqa: F401 from .runner import _create_run_streamed_wrapper, _create_run_wrapper # noqa: F401 -from .tools import _get_all_tools # noqa: F401 diff --git a/sentry_sdk/integrations/openai_agents/patches/agent_run.py b/sentry_sdk/integrations/openai_agents/patches/agent_run.py index 76611283d6..dd31703e1c 100644 --- a/sentry_sdk/integrations/openai_agents/patches/agent_run.py +++ b/sentry_sdk/integrations/openai_agents/patches/agent_run.py @@ -3,21 +3,19 @@ from sentry_sdk.consts import SPANDATA from sentry_sdk.integrations import DidNotEnable -from sentry_sdk.traces import StreamedSpan +from sentry_sdk.traces import Span from sentry_sdk.utils import capture_internal_exceptions, reraise from ..spans import ( - handoff_span, invoke_agent_span, update_invoke_agent_span, ) if TYPE_CHECKING: - from typing import Any, Awaitable, Callable, Coroutine, Optional, Union + from typing import Any, Awaitable, Callable, Coroutine, Optional from agents.run_internal.run_steps import SingleStepResult - from sentry_sdk.tracing import Span try: import agents @@ -37,21 +35,13 @@ def _get_current_agent( return getattr(context_wrapper, "_sentry_current_agent", None) -def _close_streaming_workflow_span(agent: "Optional[agents.Agent]") -> None: - """Close the workflow span for streaming executions if it exists.""" - if agent and hasattr(agent, "_sentry_workflow_span"): - workflow_span = agent._sentry_workflow_span - workflow_span.__exit__(*sys.exc_info()) - delattr(agent, "_sentry_workflow_span") - - def _maybe_start_agent_span( context_wrapper: "Optional[agents.RunContextWrapper]", agent: "Optional[agents.Agent]", should_run_agent_start_hooks: bool, span_kwargs: "dict[str, Any]", is_streaming: bool = False, -) -> "Optional[Union[Span, StreamedSpan]]": +) -> "Optional[Span]": """ Start an agent invocation span if conditions are met. Handles ending any existing span for a different agent. @@ -67,9 +57,7 @@ def _maybe_start_agent_span( if current_agent and current_agent != agent: span = getattr(context_wrapper, "_sentry_agent_span", None) if span: - update_invoke_agent_span( - span=span, context=context_wrapper, agent=agent - ) + update_invoke_agent_span(span=span, agent=agent) span.__exit__(None, None, None) delattr(context_wrapper, "_sentry_agent_span") @@ -82,10 +70,7 @@ def _maybe_start_agent_span( if not is_streaming: return span - if isinstance(span, StreamedSpan): - span.set_attribute(SPANDATA.GEN_AI_RESPONSE_STREAMING, True) - else: - span.set_data(SPANDATA.GEN_AI_RESPONSE_STREAMING, True) + span.set_attribute(SPANDATA.GEN_AI_RESPONSE_STREAMING, True) return span @@ -116,11 +101,7 @@ async def _run_single_turn( context_wrapper, agent, should_run_agent_start_hooks, kwargs ) - if ( - span is None - or (isinstance(span, StreamedSpan) and span.end_timestamp is not None) - or (not isinstance(span, StreamedSpan) and span.timestamp is not None) - ): + if span is None or span.end_timestamp is not None: return await original_run_single_turn(*args, **kwargs) try: @@ -130,9 +111,7 @@ async def _run_single_turn( with capture_internal_exceptions(): span = getattr(context_wrapper, "_sentry_agent_span", None) if span: - update_invoke_agent_span( - span=span, context=context_wrapper, agent=agent - ) + update_invoke_agent_span(span=span, agent=agent) span.__exit__(*exc_info) delattr(context_wrapper, "_sentry_agent_span") reraise(*exc_info) @@ -200,11 +179,7 @@ async def _run_single_turn_streamed( is_streaming=True, ) - if ( - span is None - or (isinstance(span, StreamedSpan) and span.end_timestamp is not None) - or (not isinstance(span, StreamedSpan) and span.timestamp is not None) - ): + if span is None or span.end_timestamp is not None: return await original_run_single_turn_streamed(*args, **kwargs) try: @@ -214,12 +189,9 @@ async def _run_single_turn_streamed( with capture_internal_exceptions(): span = getattr(context_wrapper, "_sentry_agent_span", None) if span: - update_invoke_agent_span( - span=span, context=context_wrapper, agent=agent - ) + update_invoke_agent_span(span=span, agent=agent) span.__exit__(*exc_info) delattr(context_wrapper, "_sentry_agent_span") - _close_streaming_workflow_span(agent) reraise(*exc_info) return result @@ -234,51 +206,30 @@ async def _execute_handoffs( Patched execute_handoffs that - creates and manages handoff spans. - ends the agent invocation span. - - ends the workflow span if the response is streamed and an exception is raised in `execute_handoffs()`. """ context_wrapper: "Optional[agents.RunContextWrapper]" = kwargs.get( "context_wrapper" ) - run_handoffs = kwargs.get("run_handoffs") # openai-agents >= 0.14 renamed `agent` to `public_agent`. agent: "Optional[agents.Agent]" = kwargs.get("public_agent", kwargs.get("agent")) - # Create Sentry handoff span for the first handoff (agents library only processes the first one) - if run_handoffs: - first_handoff = run_handoffs[0] - handoff_agent_name = first_handoff.handoff.agent_name - handoff_span(context_wrapper, agent, handoff_agent_name) - - if not agent or not context_wrapper or not _has_active_agent_span(context_wrapper): - # Call original method with all parameters - try: - return await original_execute_handoffs(*args, **kwargs) - except Exception: - exc_info = sys.exc_info() - with capture_internal_exceptions(): - _close_streaming_workflow_span(agent) - reraise(*exc_info) - # Call original method with all parameters try: result = await original_execute_handoffs(*args, **kwargs) except Exception: exc_info = sys.exc_info() with capture_internal_exceptions(): - _close_streaming_workflow_span(agent) span = getattr(context_wrapper, "_sentry_agent_span", None) if span: - update_invoke_agent_span( - span=span, context=context_wrapper, agent=agent - ) + update_invoke_agent_span(span=span, agent=agent) span.__exit__(*exc_info) delattr(context_wrapper, "_sentry_agent_span") reraise(*exc_info) span = getattr(context_wrapper, "_sentry_agent_span", None) if span: - update_invoke_agent_span(span=span, context=context_wrapper, agent=agent) + update_invoke_agent_span(span=span, agent=agent) span.__exit__(None, None, None) delattr(context_wrapper, "_sentry_agent_span") @@ -291,9 +242,7 @@ async def _execute_final_output( **kwargs: "Any", ) -> "SingleStepResult": """ - Patched execute_final_output that - - ends the agent invocation span. - - ends the workflow span if the response is streamed. + Patched execute_final_output that ends the agent invocation span. """ # openai-agents >= 0.14 renamed `agent` to `public_agent`. @@ -302,34 +251,23 @@ async def _execute_final_output( final_output = kwargs.get("final_output") if not agent or not context_wrapper or not _has_active_agent_span(context_wrapper): - try: - return await original_execute_final_output(*args, **kwargs) - finally: - with capture_internal_exceptions(): - # For streaming, close the workflow span (non-streaming uses context manager in _create_run_wrapper) - _close_streaming_workflow_span(agent) + return await original_execute_final_output(*args, **kwargs) try: result = await original_execute_final_output(*args, **kwargs) except Exception: exc_info = sys.exc_info() with capture_internal_exceptions(): - # For streaming, close the workflow span (non-streaming uses context manager in _create_run_wrapper) - _close_streaming_workflow_span(agent) span = getattr(context_wrapper, "_sentry_agent_span", None) if span: - update_invoke_agent_span( - span=span, context=context_wrapper, agent=agent, output=final_output - ) + update_invoke_agent_span(span=span, agent=agent, output=final_output) span.__exit__(*exc_info) delattr(context_wrapper, "_sentry_agent_span") reraise(*exc_info) span = getattr(context_wrapper, "_sentry_agent_span", None) if span: - update_invoke_agent_span( - span=span, context=context_wrapper, agent=agent, output=final_output - ) + update_invoke_agent_span(span=span, agent=agent, output=final_output) span.__exit__(None, None, None) delattr(context_wrapper, "_sentry_agent_span") diff --git a/sentry_sdk/integrations/openai_agents/patches/error_tracing.py b/sentry_sdk/integrations/openai_agents/patches/error_tracing.py index 2135ecd753..f1a561a33d 100644 --- a/sentry_sdk/integrations/openai_agents/patches/error_tracing.py +++ b/sentry_sdk/integrations/openai_agents/patches/error_tracing.py @@ -2,9 +2,7 @@ from typing import TYPE_CHECKING import sentry_sdk -from sentry_sdk.consts import SPANSTATUS from sentry_sdk.traces import SpanStatus -from sentry_sdk.tracing_utils import has_span_streaming_enabled if TYPE_CHECKING: from typing import Any @@ -56,15 +54,9 @@ def sentry_attach_error_to_current_span( the agents library swallows exceptions. """ # Set the current Sentry span to errored - span_streaming = has_span_streaming_enabled(sentry_sdk.get_client().options) - if span_streaming: - current_span = sentry_sdk.get_current_scope().streamed_span - if current_span is not None: - current_span.status = SpanStatus.ERROR - else: - current_span = sentry_sdk.get_current_span() - if current_span is not None: - current_span.set_status(SPANSTATUS.INTERNAL_ERROR) + current_span = sentry_sdk.get_current_scope().span + if current_span is not None: + current_span.status = SpanStatus.ERROR # Call the original function return original_attach_error(error, *args, **kwargs) diff --git a/sentry_sdk/integrations/openai_agents/patches/models.py b/sentry_sdk/integrations/openai_agents/patches/models.py index c2b030c42a..9514854105 100644 --- a/sentry_sdk/integrations/openai_agents/patches/models.py +++ b/sentry_sdk/integrations/openai_agents/patches/models.py @@ -6,20 +6,18 @@ import sentry_sdk from sentry_sdk.consts import SPANDATA from sentry_sdk.integrations import DidNotEnable -from sentry_sdk.traces import StreamedSpan -from sentry_sdk.tracing import BAGGAGE_HEADER_NAME +from sentry_sdk.traces import BAGGAGE_HEADER_NAME, Span from sentry_sdk.tracing_utils import ( add_sentry_baggage_to_headers, should_propagate_trace, ) from sentry_sdk.utils import logger -from ..spans import ai_client_span, update_ai_client_span +from ..spans import ai_client_context, update_ai_client_span if TYPE_CHECKING: - from typing import Any, Callable, Union + from typing import Any, Callable - from sentry_sdk.tracing import Span try: import agents @@ -29,7 +27,7 @@ def _inject_trace_propagation_headers( - hosted_tool: "HostedMCPTool", span: "Union[Span, StreamedSpan]" + hosted_tool: "HostedMCPTool", span: "Span" ) -> None: headers = hosted_tool.tool_config.get("headers") if headers is None: @@ -99,9 +97,9 @@ async def wrapped_get_response(*args: "Any", **kwargs: "Any") -> "Any": tool for tool in mcp_tools if isinstance(tool, HostedMCPTool) ] - with ai_client_span(agent, kwargs) as span: + with ai_client_context(agent, kwargs) as context: for hosted_tool in hosted_tools: - _inject_trace_propagation_headers(hosted_tool, span=span) + _inject_trace_propagation_headers(hosted_tool, span=context.span) result = await original_get_response(*args, **kwargs) @@ -110,7 +108,7 @@ async def wrapped_get_response(*args: "Any", **kwargs: "Any") -> "Any": if response_model: delattr(agent, "_sentry_response_model") - update_ai_client_span(span, result, response_model, agent) + update_ai_client_span(context.span, result, response_model, agent) return result @@ -137,16 +135,11 @@ async def wrapped_stream_response(*args: "Any", **kwargs: "Any") -> "Any": tool for tool in mcp_tools if isinstance(tool, HostedMCPTool) ] - with ai_client_span(agent, span_kwargs) as span: + with ai_client_context(agent, span_kwargs) as context: for hosted_tool in hosted_tools: - _inject_trace_propagation_headers(hosted_tool, span=span) + _inject_trace_propagation_headers(hosted_tool, span=context.span) - set_on_span = ( - span.set_attribute - if isinstance(span, StreamedSpan) - else span.set_data - ) - set_on_span(SPANDATA.GEN_AI_RESPONSE_STREAMING, True) + context.span.set_attribute(SPANDATA.GEN_AI_RESPONSE_STREAMING, True) streaming_response = None ttft_recorded = False @@ -157,7 +150,9 @@ async def wrapped_stream_response(*args: "Any", **kwargs: "Any") -> "Any": # Detect first content token (text delta event) if not ttft_recorded and hasattr(event, "delta"): ttft = time.perf_counter() - start_time - set_on_span(SPANDATA.GEN_AI_RESPONSE_TIME_TO_FIRST_TOKEN, ttft) + context.span.set_attribute( + SPANDATA.GEN_AI_RESPONSE_TIME_TO_FIRST_CHUNK, ttft + ) ttft_recorded = True # Capture the full response from ResponseCompletedEvent @@ -174,7 +169,7 @@ async def wrapped_stream_response(*args: "Any", **kwargs: "Any") -> "Any": else None ) update_ai_client_span( - span, streaming_response, response_model, agent + context.span, streaming_response, response_model, agent ) model.stream_response = wrapped_stream_response # type: ignore[method-assign] diff --git a/sentry_sdk/integrations/openai_agents/patches/runner.py b/sentry_sdk/integrations/openai_agents/patches/runner.py index 48857bf382..66c3482695 100644 --- a/sentry_sdk/integrations/openai_agents/patches/runner.py +++ b/sentry_sdk/integrations/openai_agents/patches/runner.py @@ -5,7 +5,6 @@ from sentry_sdk.consts import SPANDATA from sentry_sdk.integrations import DidNotEnable from sentry_sdk.scope import should_send_default_pii -from sentry_sdk.traces import StreamedSpan from sentry_sdk.utils import ( capture_internal_exceptions, has_data_collection_enabled, @@ -13,7 +12,6 @@ ) from ..spans import ( - agent_workflow_span, execute_tool_span, update_execute_tool_span, update_invoke_agent_span, @@ -29,7 +27,7 @@ from typing import TYPE_CHECKING, TypeVar if TYPE_CHECKING: - from typing import Any, AsyncIterator, Callable + from typing import Any, Callable from agents import Agent, Tool, ToolContext @@ -64,10 +62,7 @@ async def on_tool_start( elif not should_send_default_pii(): return - if isinstance(span, StreamedSpan): - span.set_attribute(SPANDATA.GEN_AI_TOOL_INPUT, context.tool_arguments) - else: - span.set_data(SPANDATA.GEN_AI_TOOL_INPUT, context.tool_arguments) + span.set_attribute(SPANDATA.GEN_AI_TOOL_INPUT, context.tool_arguments) async def on_tool_end( self, @@ -126,11 +121,10 @@ async def on_tool_end( def _create_run_wrapper( - original_func: "Callable[..., Any]", use_run_hooks: "bool" + original_func: "Callable[..., Any]", ) -> "Callable[..., Any]": """ Wraps the agents.Runner.run methods to - - create and manage a root span for the agent workflow runs. - end the agent invocation span if an `AgentsException` is raised in `run()`. Note agents.Runner.run_sync() is a wrapper around agents.Runner.run(), @@ -139,12 +133,11 @@ def _create_run_wrapper( @wraps(original_func) async def wrapper(*args: "Any", **kwargs: "Any") -> "Any": - if use_run_hooks: - hooks = kwargs.get("hooks") - if hooks is not None: - _patch_run_hooks(hooks=hooks) - else: - kwargs["hooks"] = _SentryRunHooks() + hooks = kwargs.get("hooks") + if hooks is not None: + _patch_run_hooks(hooks=hooks) + else: + kwargs["hooks"] = _SentryRunHooks() # Isolate each workflow so that when agents are run in asyncio tasks they # don't touch each other's scopes @@ -155,101 +148,73 @@ async def wrapper(*args: "Any", **kwargs: "Any") -> "Any": else: agent = args[0].clone() - with agent_workflow_span(agent) as workflow_span: - # Set conversation ID on workflow span early so it's captured even on errors - conversation_id = kwargs.get("conversation_id") - if conversation_id: - agent._sentry_conversation_id = conversation_id + # Set conversation ID on workflow span early so it's captured even on errors + conversation_id = kwargs.get("conversation_id") + if conversation_id: + agent._sentry_conversation_id = conversation_id - if isinstance(workflow_span, StreamedSpan): - workflow_span.set_attribute( - SPANDATA.GEN_AI_CONVERSATION_ID, conversation_id - ) - else: - workflow_span.set_data( - SPANDATA.GEN_AI_CONVERSATION_ID, conversation_id + if "starting_agent" in kwargs: + kwargs["starting_agent"] = agent + else: + args = (agent, *args[1:]) + + try: + run_result = await original_func(*args, **kwargs) + except AgentsException as exc: + exc_info = sys.exc_info() + with capture_internal_exceptions(): + _capture_exception(exc) + + context_wrapper = getattr(exc.run_data, "context_wrapper", None) + if context_wrapper is not None: + invoke_agent_span = getattr( + context_wrapper, "_sentry_agent_span", None ) - if "starting_agent" in kwargs: - kwargs["starting_agent"] = agent - else: - args = (agent, *args[1:]) - - try: - run_result = await original_func(*args, **kwargs) - except AgentsException as exc: - exc_info = sys.exc_info() - with capture_internal_exceptions(): - _capture_exception(exc) - - context_wrapper = getattr(exc.run_data, "context_wrapper", None) - if context_wrapper is not None: - invoke_agent_span = getattr( - context_wrapper, "_sentry_agent_span", None + if ( + invoke_agent_span is not None + and invoke_agent_span.end_timestamp is None + ): + update_invoke_agent_span( + span=invoke_agent_span, + agent=agent, ) - if invoke_agent_span is not None and ( - ( - isinstance(invoke_agent_span, StreamedSpan) - and invoke_agent_span.end_timestamp is None - ) - or ( - not isinstance(invoke_agent_span, StreamedSpan) - and invoke_agent_span.timestamp is None - ) - ): - update_invoke_agent_span( - span=invoke_agent_span, - context=context_wrapper, - agent=agent, - ) - - invoke_agent_span.__exit__(*exc_info) - delattr(context_wrapper, "_sentry_agent_span") - reraise(*exc_info) - except Exception as exc: - exc_info = sys.exc_info() - with capture_internal_exceptions(): - # Invoke agent span is not finished in this case. - # This is much less likely to occur than other cases because - # AgentRunner.run() is "just" a while loop around _run_single_turn. - _capture_exception(exc) - reraise(*exc_info) - - invoke_agent_span = getattr( - run_result.context_wrapper, "_sentry_agent_span", None - ) - if not invoke_agent_span: - return run_result - - update_invoke_agent_span( - span=invoke_agent_span, - context=run_result.context_wrapper, - agent=agent, - ) - - invoke_agent_span.__exit__(None, None, None) - delattr(run_result.context_wrapper, "_sentry_agent_span") + invoke_agent_span.__exit__(*exc_info) + delattr(context_wrapper, "_sentry_agent_span") + reraise(*exc_info) + except Exception as exc: + exc_info = sys.exc_info() + with capture_internal_exceptions(): + # Invoke agent span is not finished in this case. + # This is much less likely to occur than other cases because + # AgentRunner.run() is "just" a while loop around _run_single_turn. + _capture_exception(exc) + reraise(*exc_info) + + invoke_agent_span = getattr( + run_result.context_wrapper, "_sentry_agent_span", None + ) + if not invoke_agent_span: return run_result + update_invoke_agent_span( + span=invoke_agent_span, + agent=agent, + ) + + invoke_agent_span.__exit__(None, None, None) + delattr(run_result.context_wrapper, "_sentry_agent_span") + return run_result + return wrapper def _create_run_streamed_wrapper( - original_func: "Callable[..., Any]", use_run_hooks: "bool" + original_func: "Callable[..., Any]", ) -> "Callable[..., Any]": """ - Wraps the agents.Runner.run_streamed method to - - create a root span for streaming agent workflow runs. - - end the workflow span if and only if the response stream is consumed or cancelled. - - Unlike run(), run_streamed() returns immediately with a RunResultStreaming object - while execution continues in a background task. The workflow span must stay open - throughout the streaming operation and close when streaming completes or is abandoned. - - Note: We don't use isolation_scope() here because it uses context variables that - cannot span async boundaries (the __enter__ and __exit__ would be called from - different async contexts, causing ValueError). + Wraps the agents.Runner.run_streamed method to inject run hooks. """ @wraps(original_func) @@ -265,78 +230,25 @@ def wrapper(*args: "Any", **kwargs: "Any") -> "Any": if conversation_id: agent._sentry_conversation_id = conversation_id - # Start workflow span immediately (before run_streamed returns) - workflow_span = agent_workflow_span(agent) - workflow_span.__enter__() - - # Set conversation ID on workflow span early so it's captured even on errors - if conversation_id: - if isinstance(workflow_span, StreamedSpan): - workflow_span.set_attribute( - SPANDATA.GEN_AI_CONVERSATION_ID, conversation_id - ) - else: - workflow_span.set_data(SPANDATA.GEN_AI_CONVERSATION_ID, conversation_id) - - # Store span on agent for cleanup - agent._sentry_workflow_span = workflow_span - if "starting_agent" in kwargs: kwargs["starting_agent"] = agent else: args = (agent, *args[1:]) - if use_run_hooks: - sentry_hooks = _SentryRunHooks() # type: ignore[var-annotated] - hooks = kwargs.get("hooks") - if hooks is not None: - _patch_run_hooks(hooks=hooks) - else: - kwargs["hooks"] = sentry_hooks + sentry_hooks = _SentryRunHooks() # type: ignore[var-annotated] + hooks = kwargs.get("hooks") + if hooks is not None: + _patch_run_hooks(hooks=hooks) + else: + kwargs["hooks"] = sentry_hooks try: # Call original function to get RunResultStreaming run_result = original_func(*args, **kwargs) except Exception as exc: - # If run_streamed itself fails (not the background task), clean up immediately - workflow_span.__exit__(*sys.exc_info()) _capture_exception(exc) raise - def _close_workflow_span() -> None: - if hasattr(agent, "_sentry_workflow_span"): - workflow_span.__exit__(*sys.exc_info()) - delattr(agent, "_sentry_workflow_span") - - if hasattr(run_result, "stream_events"): - original_stream_events = run_result.stream_events - - @wraps(original_stream_events) - async def wrapped_stream_events( - *stream_args: "Any", **stream_kwargs: "Any" - ) -> "AsyncIterator[Any]": - try: - async for event in original_stream_events( - *stream_args, **stream_kwargs - ): - yield event - finally: - _close_workflow_span() - - run_result.stream_events = wrapped_stream_events - - if hasattr(run_result, "cancel"): - original_cancel = run_result.cancel - - @wraps(original_cancel) - def wrapped_cancel(*cancel_args: "Any", **cancel_kwargs: "Any") -> "Any": - try: - return original_cancel(*cancel_args, **cancel_kwargs) - finally: - _close_workflow_span() - - run_result.cancel = wrapped_cancel - return run_result return wrapper diff --git a/sentry_sdk/integrations/openai_agents/patches/tools.py b/sentry_sdk/integrations/openai_agents/patches/tools.py deleted file mode 100644 index 66d02e7a00..0000000000 --- a/sentry_sdk/integrations/openai_agents/patches/tools.py +++ /dev/null @@ -1,81 +0,0 @@ -from functools import wraps -from typing import TYPE_CHECKING - -import sentry_sdk -from sentry_sdk.consts import SPANDATA -from sentry_sdk.integrations import DidNotEnable -from sentry_sdk.scope import should_send_default_pii -from sentry_sdk.traces import StreamedSpan -from sentry_sdk.utils import has_data_collection_enabled - -from ..spans import execute_tool_span, update_execute_tool_span - -if TYPE_CHECKING: - from typing import Any, Awaitable, Callable - -try: - import agents - from agents import FunctionTool -except ImportError: - raise DidNotEnable("OpenAI Agents not installed") - - -async def _get_all_tools( - original_get_all_tools: "Callable[..., Awaitable[list[agents.Tool]]]", - agent: "agents.Agent", - context_wrapper: "agents.RunContextWrapper", -) -> "list[agents.Tool]": - """ - Responsible for creating and managing `gen_ai.execute_tool` spans. - """ - # Get the original tools - tools = await original_get_all_tools(agent, context_wrapper) - - wrapped_tools: "list[agents.Tool]" = [] - for tool in tools: - # Wrap only the function tools (for now) - if not isinstance(tool, FunctionTool): - wrapped_tools.append(tool) - continue - - # Create a new FunctionTool with our wrapped invoke method - original_on_invoke = tool.on_invoke_tool - - def create_wrapped_invoke( - current_tool: "FunctionTool", current_on_invoke: "Callable[..., Any]" - ) -> "Callable[..., Any]": - @wraps(current_on_invoke) - async def sentry_wrapped_on_invoke_tool( - *args: "Any", **kwargs: "Any" - ) -> "Any": - with execute_tool_span(current_tool, *args, **kwargs) as span: - # We can not capture exceptions in tool execution here because - # `_on_invoke_tool` is swallowing the exception here: - # https://github.com/openai/openai-agents-python/blob/main/src/agents/tool.py#L409-L422 - # And because function_tool is a decorator with `default_tool_error_function` set as a default parameter - # I was unable to monkey patch it because those are evaluated at module import time - # and the SDK is too late to patch it. I was also unable to patch `_on_invoke_tool_impl` - # because it is nested inside this import time code. As if they made it hard to patch on purpose... - result = await current_on_invoke(*args, **kwargs) - update_execute_tool_span(span, agent, current_tool, result) - - client = sentry_sdk.get_client() - if has_data_collection_enabled(client.options): - if not client.options["data_collection"]["gen_ai"]["inputs"]: - return result - elif not should_send_default_pii(): - return result - - if isinstance(span, StreamedSpan): - span.set_attribute(SPANDATA.GEN_AI_TOOL_INPUT, args[1]) - else: - span.set_data(SPANDATA.GEN_AI_TOOL_INPUT, args[1]) - - return result - - return sentry_wrapped_on_invoke_tool - - tool.on_invoke_tool = create_wrapped_invoke(tool, original_on_invoke) - wrapped_tools.append(tool) - - return wrapped_tools diff --git a/sentry_sdk/integrations/openai_agents/spans/__init__.py b/sentry_sdk/integrations/openai_agents/spans/__init__.py index 08802a87a4..0b6ae0edd5 100644 --- a/sentry_sdk/integrations/openai_agents/spans/__init__.py +++ b/sentry_sdk/integrations/openai_agents/spans/__init__.py @@ -1,7 +1,5 @@ -from .agent_workflow import agent_workflow_span # noqa: F401 -from .ai_client import ai_client_span, update_ai_client_span # noqa: F401 +from .ai_client import ai_client_context, update_ai_client_span # noqa: F401 from .execute_tool import execute_tool_span, update_execute_tool_span # noqa: F401 -from .handoff import handoff_span # noqa: F401 from .invoke_agent import ( invoke_agent_span, # noqa: F401 update_invoke_agent_span, # noqa: F401 diff --git a/sentry_sdk/integrations/openai_agents/spans/agent_workflow.py b/sentry_sdk/integrations/openai_agents/spans/agent_workflow.py deleted file mode 100644 index 758f06db8d..0000000000 --- a/sentry_sdk/integrations/openai_agents/spans/agent_workflow.py +++ /dev/null @@ -1,32 +0,0 @@ -from typing import TYPE_CHECKING - -import sentry_sdk -from sentry_sdk.ai.utils import get_start_span_function -from sentry_sdk.tracing_utils import has_span_streaming_enabled - -from ..consts import SPAN_ORIGIN - -if TYPE_CHECKING: - from typing import Union - - import agents - - -def agent_workflow_span( - agent: "agents.Agent", -) -> "Union[sentry_sdk.tracing.Span, sentry_sdk.traces.StreamedSpan]": - # Create a transaction or a span if an transaction is already active - span_streaming = has_span_streaming_enabled(sentry_sdk.get_client().options) - if span_streaming: - span = sentry_sdk.traces.start_span( - name=f"{agent.name} workflow", attributes={"sentry.origin": SPAN_ORIGIN} - ) - - return span - - span = get_start_span_function()( - name=f"{agent.name} workflow", - origin=SPAN_ORIGIN, - ) - - return span diff --git a/sentry_sdk/integrations/openai_agents/spans/ai_client.py b/sentry_sdk/integrations/openai_agents/spans/ai_client.py index 697f0d6cf7..203e4efd74 100644 --- a/sentry_sdk/integrations/openai_agents/spans/ai_client.py +++ b/sentry_sdk/integrations/openai_agents/spans/ai_client.py @@ -4,8 +4,7 @@ import sentry_sdk from sentry_sdk.consts import OP, SPANDATA from sentry_sdk.integrations import DidNotEnable -from sentry_sdk.traces import StreamedSpan -from sentry_sdk.tracing_utils import has_span_streaming_enabled +from sentry_sdk.traces import Span, _AgentFrameworkChatGenerationContext from sentry_sdk.utils import has_data_collection_enabled try: @@ -53,7 +52,7 @@ ) if TYPE_CHECKING: - from typing import Any, Optional, Union + from typing import Any, Optional from agents import Agent, Tool @@ -197,9 +196,9 @@ def _transform_tool_definitions(tools: "list[Tool]") -> "list[ToolDefinition]": return tool_definitions -def ai_client_span( +def ai_client_context( agent: "Agent", get_response_kwargs: "dict[str, Any]" -) -> "Union[sentry_sdk.tracing.Span, StreamedSpan]": +) -> "_AgentFrameworkChatGenerationContext": # TODO-anton: implement other types of operations. Now "chat" is hardcoded. model_name = None if agent.model: @@ -209,52 +208,38 @@ def ai_client_span( client_options = sentry_sdk.get_client().options - span_streaming = has_span_streaming_enabled(client_options) - if span_streaming: - span = sentry_sdk.traces.start_span( - name=f"chat {model_name}", - attributes={ - "sentry.op": OP.GEN_AI_CHAT, - "sentry.origin": SPAN_ORIGIN, - SPANDATA.GEN_AI_OPERATION_NAME: "chat", - }, - ) - - set_on_span = span.set_attribute - else: - span = sentry_sdk.start_span( - op=OP.GEN_AI_CHAT, - name=f"chat {model_name}", - origin=SPAN_ORIGIN, - ) - # TODO-anton: remove hardcoded stuff and replace something that also works for embedding and so on - span.set_data(SPANDATA.GEN_AI_OPERATION_NAME, "chat") - - set_on_span = span.set_data + context = _AgentFrameworkChatGenerationContext( + name=f"chat {model_name}", + attributes={ + "sentry.op": OP.GEN_AI_CHAT, + "sentry.origin": SPAN_ORIGIN, + SPANDATA.GEN_AI_OPERATION_NAME: "chat", + }, + ) - _set_agent_data(span, agent) + _set_agent_data(context.span, agent) if has_data_collection_enabled(client_options): if client_options["data_collection"]["gen_ai"]["inputs"]: - set_on_span( + context.span.set_attribute( SPANDATA.GEN_AI_TOOL_DEFINITIONS, json.dumps(_transform_tool_definitions(agent.tools)), ) else: # This is set unconditionally prior to data collection being introduced. # Remove this block once data collection is fully rolled out - set_on_span( + context.span.set_attribute( SPANDATA.GEN_AI_TOOL_DEFINITIONS, json.dumps(_transform_tool_definitions(agent.tools)), ) - _set_input_data(span, get_response_kwargs) + _set_input_data(context.span, get_response_kwargs) - return span + return context def update_ai_client_span( - span: "Union[sentry_sdk.tracing.Span, StreamedSpan]", + span: "Span", response: "Any", response_model: "Optional[str]" = None, agent: "Optional[Agent]" = None, @@ -266,17 +251,13 @@ def update_ai_client_span( if hasattr(response, "output") and response.output: _set_output_data(span, response) - set_on_span = ( - span.set_attribute if isinstance(span, StreamedSpan) else span.set_data - ) - if response_model is not None: - set_on_span(SPANDATA.GEN_AI_RESPONSE_MODEL, response_model) + span.set_attribute(SPANDATA.GEN_AI_RESPONSE_MODEL, response_model) elif hasattr(response, "model") and response.model: - set_on_span(SPANDATA.GEN_AI_RESPONSE_MODEL, str(response.model)) + span.set_attribute(SPANDATA.GEN_AI_RESPONSE_MODEL, str(response.model)) # Set conversation ID from agent if available if agent: conv_id = getattr(agent, "_sentry_conversation_id", None) if conv_id: - set_on_span(SPANDATA.GEN_AI_CONVERSATION_ID, conv_id) + span.set_attribute(SPANDATA.GEN_AI_CONVERSATION_ID, conv_id) diff --git a/sentry_sdk/integrations/openai_agents/spans/execute_tool.py b/sentry_sdk/integrations/openai_agents/spans/execute_tool.py index 49d75d6d83..9cadea6fdb 100644 --- a/sentry_sdk/integrations/openai_agents/spans/execute_tool.py +++ b/sentry_sdk/integrations/openai_agents/spans/execute_tool.py @@ -1,54 +1,37 @@ from typing import TYPE_CHECKING import sentry_sdk -from sentry_sdk.consts import OP, SPANDATA, SPANSTATUS +from sentry_sdk.consts import OP, SPANDATA from sentry_sdk.scope import should_send_default_pii -from sentry_sdk.traces import SpanStatus, StreamedSpan -from sentry_sdk.tracing_utils import has_span_streaming_enabled +from sentry_sdk.traces import Span, SpanStatus from sentry_sdk.utils import has_data_collection_enabled from ..consts import SPAN_ORIGIN from ..utils import _set_agent_data if TYPE_CHECKING: - from typing import Any, Union + from typing import Any import agents def execute_tool_span( tool: "agents.FunctionTool", *args: "Any", **kwargs: "Any" -) -> "Union[sentry_sdk.tracing.Span, StreamedSpan]": - span_streaming = has_span_streaming_enabled(sentry_sdk.get_client().options) - - if span_streaming: - span = sentry_sdk.traces.start_span( - name=f"execute_tool {tool.name}", - attributes={ - "sentry.op": OP.GEN_AI_EXECUTE_TOOL, - "sentry.origin": SPAN_ORIGIN, - SPANDATA.GEN_AI_OPERATION_NAME: "execute_tool", - SPANDATA.GEN_AI_TOOL_NAME: tool.name, - SPANDATA.GEN_AI_TOOL_DESCRIPTION: tool.description, - }, - ) - else: - span = sentry_sdk.start_span( - op=OP.GEN_AI_EXECUTE_TOOL, - name=f"execute_tool {tool.name}", - origin=SPAN_ORIGIN, - ) - - span.set_data(SPANDATA.GEN_AI_OPERATION_NAME, "execute_tool") - - span.set_data(SPANDATA.GEN_AI_TOOL_NAME, tool.name) - span.set_data(SPANDATA.GEN_AI_TOOL_DESCRIPTION, tool.description) - - return span +) -> "Span": + return sentry_sdk.start_span( + name=f"execute_tool {tool.name}", + attributes={ + "sentry.op": OP.GEN_AI_EXECUTE_TOOL, + "sentry.origin": SPAN_ORIGIN, + SPANDATA.GEN_AI_OPERATION_NAME: "execute_tool", + SPANDATA.GEN_AI_TOOL_NAME: tool.name, + SPANDATA.GEN_AI_TOOL_DESCRIPTION: tool.description, + }, + ) def update_execute_tool_span( - span: "Union[sentry_sdk.tracing.Span, StreamedSpan]", + span: "Span", agent: "agents.Agent", tool: "agents.Tool", result: "Any", @@ -60,22 +43,15 @@ def update_execute_tool_span( if isinstance(result, str) and result.startswith( "An error occurred while running the tool" ): - if isinstance(span, StreamedSpan): - span.status = SpanStatus.ERROR - else: - span.set_status(SPANSTATUS.INTERNAL_ERROR) - - set_on_span = ( - span.set_attribute if isinstance(span, StreamedSpan) else span.set_data - ) + span.status = SpanStatus.ERROR if has_data_collection_enabled(client.options): if client.options["data_collection"]["gen_ai"]["outputs"]: - set_on_span(SPANDATA.GEN_AI_TOOL_OUTPUT, result) + span.set_attribute(SPANDATA.GEN_AI_TOOL_OUTPUT, result) elif should_send_default_pii(): - set_on_span(SPANDATA.GEN_AI_TOOL_OUTPUT, result) + span.set_attribute(SPANDATA.GEN_AI_TOOL_OUTPUT, result) # Add conversation ID from agent conv_id = getattr(agent, "_sentry_conversation_id", None) if conv_id: - set_on_span(SPANDATA.GEN_AI_CONVERSATION_ID, conv_id) + span.set_attribute(SPANDATA.GEN_AI_CONVERSATION_ID, conv_id) diff --git a/sentry_sdk/integrations/openai_agents/spans/handoff.py b/sentry_sdk/integrations/openai_agents/spans/handoff.py deleted file mode 100644 index 8c54ecfabb..0000000000 --- a/sentry_sdk/integrations/openai_agents/spans/handoff.py +++ /dev/null @@ -1,45 +0,0 @@ -from typing import TYPE_CHECKING - -import sentry_sdk -from sentry_sdk.consts import OP, SPANDATA -from sentry_sdk.tracing_utils import has_span_streaming_enabled - -from ..consts import SPAN_ORIGIN - -if TYPE_CHECKING: - from typing import Optional - - import agents - - -def handoff_span( - context: "Optional[agents.RunContextWrapper]", - from_agent: "Optional[agents.Agent]", - to_agent_name: str, -) -> None: - span_streaming = has_span_streaming_enabled(sentry_sdk.get_client().options) - if span_streaming: - with sentry_sdk.traces.start_span( - name=f"handoff from {from_agent.name} to {to_agent_name}", # type: ignore[union-attr] - attributes={ - "sentry.op": OP.GEN_AI_HANDOFF, - "sentry.origin": SPAN_ORIGIN, - SPANDATA.GEN_AI_OPERATION_NAME: "handoff", - }, - ) as span: - # Add conversation ID from agent - conv_id = getattr(from_agent, "_sentry_conversation_id", None) - if conv_id: - span.set_attribute(SPANDATA.GEN_AI_CONVERSATION_ID, conv_id) - else: - with sentry_sdk.start_span( - op=OP.GEN_AI_HANDOFF, - name=f"handoff from {from_agent.name} to {to_agent_name}", # type: ignore[union-attr] - origin=SPAN_ORIGIN, - ) as span: - span.set_data(SPANDATA.GEN_AI_OPERATION_NAME, "handoff") - - # Add conversation ID from agent - conv_id = getattr(from_agent, "_sentry_conversation_id", None) - if conv_id: - span.set_data(SPANDATA.GEN_AI_CONVERSATION_ID, conv_id) diff --git a/sentry_sdk/integrations/openai_agents/spans/invoke_agent.py b/sentry_sdk/integrations/openai_agents/spans/invoke_agent.py index eef59bdf0a..ff306e4138 100644 --- a/sentry_sdk/integrations/openai_agents/spans/invoke_agent.py +++ b/sentry_sdk/integrations/openai_agents/spans/invoke_agent.py @@ -2,53 +2,36 @@ import sentry_sdk from sentry_sdk.ai.utils import ( - get_start_span_function, normalize_message_roles, set_data_normalized, - truncate_and_annotate_messages, ) from sentry_sdk.consts import OP, SPANDATA from sentry_sdk.scope import should_send_default_pii -from sentry_sdk.traces import StreamedSpan -from sentry_sdk.tracing_utils import ( - has_span_streaming_enabled, - should_truncate_gen_ai_input, -) +from sentry_sdk.traces import Span from sentry_sdk.utils import has_data_collection_enabled, safe_serialize from ..consts import SPAN_ORIGIN -from ..utils import _set_agent_data, _set_usage_data +from ..utils import _set_agent_data if TYPE_CHECKING: - from typing import Any, Optional, Union + from typing import Any, Optional import agents def invoke_agent_span( context: "agents.RunContextWrapper", agent: "agents.Agent", kwargs: "dict[str, Any]" -) -> "Union[sentry_sdk.tracing.Span, StreamedSpan]": +) -> "Span": client_options = sentry_sdk.get_client().options - span_streaming = has_span_streaming_enabled(client_options) - if span_streaming: - span = sentry_sdk.traces.start_span( - name=f"invoke_agent {agent.name}", - attributes={ - "sentry.op": OP.GEN_AI_INVOKE_AGENT, - "sentry.origin": SPAN_ORIGIN, - SPANDATA.GEN_AI_OPERATION_NAME: "invoke_agent", - }, - ) - else: - start_span_function = get_start_span_function() - span = start_span_function( - op=OP.GEN_AI_INVOKE_AGENT, - name=f"invoke_agent {agent.name}", - origin=SPAN_ORIGIN, - ) - span.__enter__() - - span.set_data(SPANDATA.GEN_AI_OPERATION_NAME, "invoke_agent") + + span = sentry_sdk.start_span( + name=f"invoke_agent {agent.name}", + attributes={ + "sentry.op": OP.GEN_AI_INVOKE_AGENT, + "sentry.origin": SPAN_ORIGIN, + SPANDATA.GEN_AI_OPERATION_NAME: "invoke_agent", + }, + ) record_inputs = False if has_data_collection_enabled(client_options): @@ -88,20 +71,12 @@ def invoke_agent_span( if len(messages) > 0: normalized_messages = normalize_message_roles(messages) - client = sentry_sdk.get_client() - scope = sentry_sdk.get_current_scope() - messages_data = ( - truncate_and_annotate_messages(normalized_messages, span, scope) - if should_truncate_gen_ai_input(client.options) - else normalized_messages + set_data_normalized( + span, + SPANDATA.GEN_AI_REQUEST_MESSAGES, + normalized_messages, + unpack=False, ) - if messages_data is not None: - set_data_normalized( - span, - SPANDATA.GEN_AI_REQUEST_MESSAGES, - messages_data, - unpack=False, - ) _set_agent_data(span, agent) @@ -109,15 +84,10 @@ def invoke_agent_span( def update_invoke_agent_span( - span: "Union[sentry_sdk.tracing.Span, StreamedSpan]", - context: "Optional[agents.RunContextWrapper]", + span: "Span", agent: "Optional[agents.Agent]", output: "Any" = None, ) -> None: - # Add aggregated usage data from context_wrapper - if context and hasattr(context, "usage"): - _set_usage_data(span, context.usage) - client = sentry_sdk.get_client() if has_data_collection_enabled(client.options): if client.options["data_collection"]["gen_ai"]["outputs"]: @@ -130,7 +100,4 @@ def update_invoke_agent_span( # Add conversation ID from agent conv_id = getattr(agent, "_sentry_conversation_id", None) if conv_id: - if isinstance(span, StreamedSpan): - span.set_attribute(SPANDATA.GEN_AI_CONVERSATION_ID, conv_id) - else: - span.set_data(SPANDATA.GEN_AI_CONVERSATION_ID, conv_id) + span.set_attribute(SPANDATA.GEN_AI_CONVERSATION_ID, conv_id) diff --git a/sentry_sdk/integrations/openai_agents/utils.py b/sentry_sdk/integrations/openai_agents/utils.py index 01303e0e58..b104b2c042 100644 --- a/sentry_sdk/integrations/openai_agents/utils.py +++ b/sentry_sdk/integrations/openai_agents/utils.py @@ -12,13 +12,11 @@ normalize_message_role, normalize_message_roles, set_data_normalized, - truncate_and_annotate_messages, ) from sentry_sdk.consts import SPANDATA from sentry_sdk.integrations import DidNotEnable from sentry_sdk.scope import should_send_default_pii -from sentry_sdk.traces import StreamedSpan -from sentry_sdk.tracing_utils import should_truncate_gen_ai_input +from sentry_sdk.traces import Span from sentry_sdk.utils import ( event_from_exception, has_data_collection_enabled, @@ -26,7 +24,7 @@ ) if TYPE_CHECKING: - from typing import Any, Optional, Union + from typing import Any, Optional from agents import TResponseInputItem, Usage @@ -48,21 +46,17 @@ def _capture_exception(exc: "Any") -> None: sentry_sdk.capture_event(event, hint=hint) -def _set_agent_data( - span: "Union[sentry_sdk.tracing.Span, StreamedSpan]", agent: "agents.Agent" -) -> None: - set_on_span = ( - span.set_attribute if isinstance(span, StreamedSpan) else span.set_data - ) - - set_on_span( - SPANDATA.GEN_AI_SYSTEM, "openai" +def _set_agent_data(span: "Span", agent: "agents.Agent") -> None: + span.set_attribute( + SPANDATA.GEN_AI_PROVIDER_NAME, "openai" ) # See footnote for https://opentelemetry.io/docs/specs/semconv/registry/attributes/gen-ai/#gen-ai-system for explanation why. - set_on_span(SPANDATA.GEN_AI_AGENT_NAME, agent.name) + span.set_attribute(SPANDATA.GEN_AI_AGENT_NAME, agent.name) if agent.model_settings.max_tokens: - set_on_span(SPANDATA.GEN_AI_REQUEST_MAX_TOKENS, agent.model_settings.max_tokens) + span.set_attribute( + SPANDATA.GEN_AI_REQUEST_MAX_TOKENS, agent.model_settings.max_tokens + ) model_name: "Optional[str]" = None if isinstance(agent.model, Model) and hasattr(agent.model, "model"): @@ -73,50 +67,45 @@ def _set_agent_data( model_name = agent._sentry_request_model if model_name: - set_on_span(SPANDATA.GEN_AI_REQUEST_MODEL, model_name) + span.set_attribute(SPANDATA.GEN_AI_REQUEST_MODEL, model_name) if agent.model_settings.presence_penalty: - set_on_span( + span.set_attribute( SPANDATA.GEN_AI_REQUEST_PRESENCE_PENALTY, agent.model_settings.presence_penalty, ) if agent.model_settings.temperature: - set_on_span( + span.set_attribute( SPANDATA.GEN_AI_REQUEST_TEMPERATURE, agent.model_settings.temperature ) if agent.model_settings.top_p: - set_on_span(SPANDATA.GEN_AI_REQUEST_TOP_P, agent.model_settings.top_p) + span.set_attribute(SPANDATA.GEN_AI_REQUEST_TOP_P, agent.model_settings.top_p) if agent.model_settings.frequency_penalty: - set_on_span( + span.set_attribute( SPANDATA.GEN_AI_REQUEST_FREQUENCY_PENALTY, agent.model_settings.frequency_penalty, ) -def _set_usage_data( - span: "Union[sentry_sdk.tracing.Span, StreamedSpan]", usage: "Usage" -) -> None: - set_on_span = ( - span.set_attribute if isinstance(span, StreamedSpan) else span.set_data - ) - set_on_span(SPANDATA.GEN_AI_USAGE_INPUT_TOKENS, usage.input_tokens) - set_on_span( - SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHED, +def _set_usage_data(span: "Span", usage: "Usage") -> None: + span.set_attribute(SPANDATA.GEN_AI_USAGE_INPUT_TOKENS, usage.input_tokens) + span.set_attribute( + SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS, usage.input_tokens_details.cached_tokens, ) - set_on_span(SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS, usage.output_tokens) - set_on_span( - SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS_REASONING, + span.set_attribute(SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS, usage.output_tokens) + span.set_attribute( + SPANDATA.GEN_AI_USAGE_REASONING_OUTPUT_TOKENS, usage.output_tokens_details.reasoning_tokens, ) - set_on_span(SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS, usage.total_tokens) + span.set_attribute(SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS, usage.total_tokens) def _set_input_data( - span: "Union[sentry_sdk.tracing.Span, StreamedSpan]", + span: "Span", get_response_kwargs: "dict[str, Any]", ) -> None: client = sentry_sdk.get_client() @@ -144,16 +133,10 @@ def _set_input_data( instructions_text_parts += _transform_system_instructions(system_instructions) if len(instructions_text_parts) > 0: - if isinstance(span, StreamedSpan): - span.set_attribute( - SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS, - json.dumps(instructions_text_parts), - ) - else: - span.set_data( - SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS, - json.dumps(instructions_text_parts), - ) + span.set_attribute( + SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS, + json.dumps(instructions_text_parts), + ) non_system_messages = [ message @@ -191,24 +174,15 @@ def _set_input_data( ) normalized_messages = normalize_message_roles(request_messages) - scope = sentry_sdk.get_current_scope() - messages_data = ( - truncate_and_annotate_messages(normalized_messages, span, scope) - if should_truncate_gen_ai_input(client.options) - else normalized_messages + set_data_normalized( + span, + SPANDATA.GEN_AI_REQUEST_MESSAGES, + normalized_messages, + unpack=False, ) - if messages_data is not None: - set_data_normalized( - span, - SPANDATA.GEN_AI_REQUEST_MESSAGES, - messages_data, - unpack=False, - ) -def _set_output_data( - span: "Union[sentry_sdk.tracing.Span, StreamedSpan]", result: "Any" -) -> None: +def _set_output_data(span: "Span", result: "Any") -> None: client = sentry_sdk.get_client() record_outputs = False if has_data_collection_enabled(client.options): @@ -236,16 +210,10 @@ def _set_output_data( output_messages["response"].append(output_message.dict()) if record_outputs and len(output_messages["tool"]) > 0: - if isinstance(span, StreamedSpan): - span.set_attribute( - SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS, - safe_serialize(output_messages["tool"]), - ) - else: - span.set_data( - SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS, - safe_serialize(output_messages["tool"]), - ) + span.set_attribute( + SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS, + safe_serialize(output_messages["tool"]), + ) if record_outputs and len(output_messages["response"]) > 0: set_data_normalized( diff --git a/sentry_sdk/integrations/openfeature.py b/sentry_sdk/integrations/openfeature.py index 281604fe38..6cf3c4e721 100644 --- a/sentry_sdk/integrations/openfeature.py +++ b/sentry_sdk/integrations/openfeature.py @@ -1,7 +1,8 @@ from typing import TYPE_CHECKING, Any from sentry_sdk.feature_flags import add_feature_flag -from sentry_sdk.integrations import DidNotEnable, Integration +from sentry_sdk.integrations import DidNotEnable, Integration, _check_minimum_version +from sentry_sdk.utils import package_version try: from openfeature import api @@ -10,7 +11,7 @@ if TYPE_CHECKING: from openfeature.hook import HookContext, HookHints except ImportError: - raise DidNotEnable("OpenFeature is not installed") + raise DidNotEnable("OpenFeature is not installed or incompatible") class OpenFeatureIntegration(Integration): @@ -18,6 +19,9 @@ class OpenFeatureIntegration(Integration): @staticmethod def setup_once() -> None: + version = package_version("openfeature-sdk") + _check_minimum_version(OpenFeatureIntegration, version) + # Register the hook within the global openfeature hooks list. api.add_hooks(hooks=[OpenFeatureHook()]) diff --git a/sentry_sdk/integrations/opentelemetry/__init__.py b/sentry_sdk/integrations/opentelemetry/__init__.py deleted file mode 100644 index d76b8058ee..0000000000 --- a/sentry_sdk/integrations/opentelemetry/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -from sentry_sdk.integrations.opentelemetry.propagator import SentryPropagator -from sentry_sdk.integrations.opentelemetry.span_processor import SentrySpanProcessor - -__all__ = [ - "SentryPropagator", - "SentrySpanProcessor", -] diff --git a/sentry_sdk/integrations/opentelemetry/consts.py b/sentry_sdk/integrations/opentelemetry/consts.py deleted file mode 100644 index d6733036ea..0000000000 --- a/sentry_sdk/integrations/opentelemetry/consts.py +++ /dev/null @@ -1,9 +0,0 @@ -from sentry_sdk.integrations import DidNotEnable - -try: - from opentelemetry.context import create_key -except ImportError: - raise DidNotEnable("opentelemetry not installed") - -SENTRY_TRACE_KEY = create_key("sentry-trace") -SENTRY_BAGGAGE_KEY = create_key("sentry-baggage") diff --git a/sentry_sdk/integrations/opentelemetry/integration.py b/sentry_sdk/integrations/opentelemetry/integration.py deleted file mode 100644 index 472e8181f9..0000000000 --- a/sentry_sdk/integrations/opentelemetry/integration.py +++ /dev/null @@ -1,81 +0,0 @@ -""" -IMPORTANT: The contents of this file are part of a proof of concept and as such -are experimental and not suitable for production use. They may be changed or -removed at any time without prior notice. -""" - -import warnings -from typing import TYPE_CHECKING - -from sentry_sdk.integrations import DidNotEnable, Integration -from sentry_sdk.integrations.opentelemetry.propagator import SentryPropagator -from sentry_sdk.integrations.opentelemetry.span_processor import SentrySpanProcessor -from sentry_sdk.tracing_utils import has_span_streaming_enabled -from sentry_sdk.utils import logger - -if TYPE_CHECKING: - from typing import Any, Dict, Optional - -try: - from opentelemetry import trace - from opentelemetry.propagate import set_global_textmap - from opentelemetry.sdk.trace import TracerProvider -except ImportError: - raise DidNotEnable("opentelemetry not installed") - -try: - from opentelemetry.instrumentation.django import ( # type: ignore[import-not-found] - DjangoInstrumentor, - ) -except ImportError: - DjangoInstrumentor = None - - -CONFIGURABLE_INSTRUMENTATIONS = { - DjangoInstrumentor: {"is_sql_commentor_enabled": True}, -} - - -class OpenTelemetryIntegration(Integration): - identifier = "opentelemetry" - - @staticmethod - def setup_once() -> None: - pass - - def setup_once_with_options( - self, options: "Optional[Dict[str, Any]]" = None - ) -> None: - if has_span_streaming_enabled(options): - logger.warning( - "[OTel] OpenTelemetryIntegration is not compatible with span streaming " - "(trace_lifecycle='stream') and will be disabled." - ) - return - - warnings.warn( - "OpenTelemetryIntegration is deprecated. " - "Please use OTLPIntegration instead: " - "https://docs.sentry.io/platforms/python/integrations/otlp/", - DeprecationWarning, - stacklevel=2, - ) - - _setup_sentry_tracing() - # _setup_instrumentors() - - logger.debug("[OTel] Finished setting up OpenTelemetry integration") - - -def _setup_sentry_tracing() -> None: - provider = TracerProvider() - provider.add_span_processor(SentrySpanProcessor()) - trace.set_tracer_provider(provider) - set_global_textmap(SentryPropagator()) - - -def _setup_instrumentors() -> None: - for instrumentor, kwargs in CONFIGURABLE_INSTRUMENTATIONS.items(): - if instrumentor is None: - continue - instrumentor().instrument(**kwargs) diff --git a/sentry_sdk/integrations/opentelemetry/propagator.py b/sentry_sdk/integrations/opentelemetry/propagator.py deleted file mode 100644 index 5b5f13861d..0000000000 --- a/sentry_sdk/integrations/opentelemetry/propagator.py +++ /dev/null @@ -1,128 +0,0 @@ -from sentry_sdk.integrations import DidNotEnable -from sentry_sdk.integrations.opentelemetry.consts import ( - SENTRY_BAGGAGE_KEY, - SENTRY_TRACE_KEY, -) -from sentry_sdk.integrations.opentelemetry.span_processor import ( - SentrySpanProcessor, -) -from sentry_sdk.tracing import ( - BAGGAGE_HEADER_NAME, - SENTRY_TRACE_HEADER_NAME, -) -from sentry_sdk.tracing_utils import Baggage, extract_sentrytrace_data - -try: - from opentelemetry import trace - from opentelemetry.context import ( - Context, - get_current, - set_value, - ) - from opentelemetry.propagators.textmap import ( - CarrierT, - Getter, - Setter, - TextMapPropagator, - default_getter, - default_setter, - ) - from opentelemetry.trace import ( - NonRecordingSpan, - SpanContext, - TraceFlags, - ) -except ImportError: - raise DidNotEnable("opentelemetry not installed") - -from typing import TYPE_CHECKING - -if TYPE_CHECKING: - from typing import Optional, Set - - -class SentryPropagator(TextMapPropagator): - """ - Propagates tracing headers for Sentry's tracing system in a way OTel understands. - """ - - def extract( - self, - carrier: "CarrierT", - context: "Optional[Context]" = None, - getter: "Getter[CarrierT]" = default_getter, - ) -> "Context": - if context is None: - context = get_current() - - sentry_trace = getter.get(carrier, SENTRY_TRACE_HEADER_NAME) - if not sentry_trace: - return context - - sentrytrace = extract_sentrytrace_data(sentry_trace[0]) - if not sentrytrace: - return context - - context = set_value(SENTRY_TRACE_KEY, sentrytrace, context) - - trace_id, span_id = sentrytrace["trace_id"], sentrytrace["parent_span_id"] - - span_context = SpanContext( - trace_id=int(trace_id, 16), # type: ignore - span_id=int(span_id, 16), # type: ignore - # we simulate a sampled trace on the otel side and leave the sampling to sentry - trace_flags=TraceFlags(TraceFlags.SAMPLED), - is_remote=True, - ) - - baggage_header = getter.get(carrier, BAGGAGE_HEADER_NAME) - - if baggage_header: - baggage = Baggage.from_incoming_header(baggage_header[0]) - else: - # If there's an incoming sentry-trace but no incoming baggage header, - # for instance in traces coming from older SDKs, - # baggage will be empty and frozen and won't be populated as head SDK. - baggage = Baggage(sentry_items={}) - - baggage.freeze() - context = set_value(SENTRY_BAGGAGE_KEY, baggage, context) - - span = NonRecordingSpan(span_context) - modified_context = trace.set_span_in_context(span, context) - return modified_context - - def inject( - self, - carrier: "CarrierT", - context: "Optional[Context]" = None, - setter: "Setter[CarrierT]" = default_setter, - ) -> None: - if context is None: - context = get_current() - - current_span = trace.get_current_span(context) - current_span_context = current_span.get_span_context() - - if not current_span_context.is_valid: - return - - span_id = trace.format_span_id(current_span_context.span_id) - - span_map = SentrySpanProcessor.otel_span_map - sentry_span = span_map.get(span_id, None) - if not sentry_span: - return - - setter.set(carrier, SENTRY_TRACE_HEADER_NAME, sentry_span.to_traceparent()) - - if sentry_span.containing_transaction: - baggage = sentry_span.containing_transaction.get_baggage() - if baggage: - baggage_data = baggage.serialize() - if baggage_data: - setter.set(carrier, BAGGAGE_HEADER_NAME, baggage_data) - - @property - def fields(self) -> "Set[str]": - return {SENTRY_TRACE_HEADER_NAME, BAGGAGE_HEADER_NAME} diff --git a/sentry_sdk/integrations/opentelemetry/span_processor.py b/sentry_sdk/integrations/opentelemetry/span_processor.py deleted file mode 100644 index 1efd2ac455..0000000000 --- a/sentry_sdk/integrations/opentelemetry/span_processor.py +++ /dev/null @@ -1,407 +0,0 @@ -from datetime import datetime, timezone -from time import time -from typing import TYPE_CHECKING, cast - -from urllib3.util import parse_url as urlparse - -from sentry_sdk import get_client, start_transaction -from sentry_sdk.consts import INSTRUMENTER, SPANSTATUS -from sentry_sdk.integrations import DidNotEnable -from sentry_sdk.integrations.opentelemetry.consts import ( - SENTRY_BAGGAGE_KEY, - SENTRY_TRACE_KEY, -) -from sentry_sdk.scope import add_global_event_processor -from sentry_sdk.tracing import Span as SentrySpan -from sentry_sdk.tracing import Transaction - -try: - from opentelemetry.context import get_value - from opentelemetry.sdk.trace import ReadableSpan as OTelSpan - from opentelemetry.sdk.trace import SpanProcessor - from opentelemetry.semconv.trace import SpanAttributes - from opentelemetry.trace import ( - SpanKind, - format_span_id, - format_trace_id, - get_current_span, - ) - from opentelemetry.trace.span import ( - INVALID_SPAN_ID, - INVALID_TRACE_ID, - ) -except ImportError: - raise DidNotEnable("opentelemetry not installed") - -if TYPE_CHECKING: - from typing import Any, Optional, Union - - from opentelemetry import context as context_api - from opentelemetry.trace import SpanContext - - from sentry_sdk._types import Event, Hint - -OPEN_TELEMETRY_CONTEXT = "otel" -SPAN_MAX_TIME_OPEN_MINUTES = 10 -SPAN_ORIGIN = "auto.otel" - - -def link_trace_context_to_error_event( - event: "Event", otel_span_map: "dict[str, Union[Transaction, SentrySpan]]" -) -> "Event": - client = get_client() - - if client.options["instrumenter"] != INSTRUMENTER.OTEL: - return event - - if hasattr(event, "type") and event["type"] == "transaction": - return event - - otel_span = get_current_span() - if not otel_span: - return event - - ctx = otel_span.get_span_context() - - if ctx.trace_id == INVALID_TRACE_ID or ctx.span_id == INVALID_SPAN_ID: - return event - - sentry_span = otel_span_map.get(format_span_id(ctx.span_id), None) - if not sentry_span: - return event - - contexts = event.setdefault("contexts", {}) - contexts.setdefault("trace", {}).update(sentry_span.get_trace_context()) - - return event - - -class SentrySpanProcessor(SpanProcessor): - """ - Converts OTel spans into Sentry spans so they can be sent to the Sentry backend. - """ - - # The mapping from otel span ids to sentry spans - otel_span_map: "dict[str, Union[Transaction, SentrySpan]]" = {} - - # The currently open spans. Elements will be discarded after SPAN_MAX_TIME_OPEN_MINUTES - open_spans: "dict[int, set[str]]" = {} - - initialized: "bool" = False - - def __new__(cls) -> "SentrySpanProcessor": - if not hasattr(cls, "instance"): - cls.instance = super().__new__(cls) - - # "instance" class attribute is guaranteed to be set above (mypy believes instance is an instance-only attribute). - return cls.instance # type: ignore[misc] - - def __init__(self) -> None: - if self.initialized: - return - - @add_global_event_processor - def global_event_processor(event: "Event", hint: "Hint") -> "Event": - return link_trace_context_to_error_event(event, self.otel_span_map) - - self.initialized = True - - def _prune_old_spans(self: "SentrySpanProcessor") -> None: - """ - Prune spans that have been open for too long. - """ - current_time_minutes = int(time() / 60) - for span_start_minutes in list( - self.open_spans.keys() - ): # making a list because we change the dict - # prune empty open spans buckets - if self.open_spans[span_start_minutes] == set(): - self.open_spans.pop(span_start_minutes) - - # prune old buckets - elif current_time_minutes - span_start_minutes > SPAN_MAX_TIME_OPEN_MINUTES: - for span_id in self.open_spans.pop(span_start_minutes): - self.otel_span_map.pop(span_id, None) - - def on_start( - self, - otel_span: "OTelSpan", - parent_context: "Optional[context_api.Context]" = None, - ) -> None: - client = get_client() - - if not client.parsed_dsn: - return - - if client.options["instrumenter"] != INSTRUMENTER.OTEL: - return - - span_context = otel_span.get_span_context() - if span_context is None or not span_context.is_valid: - return - - if self._is_sentry_span(otel_span): - return - - trace_data = self._get_trace_data( - span_context, otel_span.parent, parent_context - ) - - parent_span_id = trace_data["parent_span_id"] - sentry_parent_span = ( - self.otel_span_map.get(parent_span_id) if parent_span_id else None - ) - - start_timestamp = None - if otel_span.start_time is not None: - start_timestamp = datetime.fromtimestamp( - otel_span.start_time / 1e9, timezone.utc - ) # OTel spans have nanosecond precision - - sentry_span = None - if sentry_parent_span: - sentry_span = sentry_parent_span.start_child( - span_id=trace_data["span_id"], - name=otel_span.name, - start_timestamp=start_timestamp, - instrumenter=INSTRUMENTER.OTEL, - origin=SPAN_ORIGIN, - ) - else: - sentry_span = start_transaction( - name=otel_span.name, - span_id=trace_data["span_id"], - parent_span_id=parent_span_id, - trace_id=trace_data["trace_id"], - baggage=trace_data["baggage"], - start_timestamp=start_timestamp, - instrumenter=INSTRUMENTER.OTEL, - origin=SPAN_ORIGIN, - ) - - self.otel_span_map[trace_data["span_id"]] = sentry_span - - if otel_span.start_time is not None: - span_start_in_minutes = int( - otel_span.start_time / 1e9 / 60 - ) # OTel spans have nanosecond precision - self.open_spans.setdefault(span_start_in_minutes, set()).add( - trace_data["span_id"] - ) - - self._prune_old_spans() - - def on_end(self, otel_span: "OTelSpan") -> None: - client = get_client() - - if client.options["instrumenter"] != INSTRUMENTER.OTEL: - return - - span_context = otel_span.get_span_context() - if span_context is None or not span_context.is_valid: - return - - span_id = format_span_id(span_context.span_id) - sentry_span = self.otel_span_map.pop(span_id, None) - if not sentry_span: - return - - sentry_span.op = otel_span.name - - self._update_span_with_otel_status(sentry_span, otel_span) - - if isinstance(sentry_span, Transaction): - sentry_span.name = otel_span.name - sentry_span.set_context( - OPEN_TELEMETRY_CONTEXT, self._get_otel_context(otel_span) - ) - self._update_transaction_with_otel_data(sentry_span, otel_span) - - else: - self._update_span_with_otel_data(sentry_span, otel_span) - - end_timestamp = None - if otel_span.end_time is not None: - end_timestamp = datetime.fromtimestamp( - otel_span.end_time / 1e9, timezone.utc - ) # OTel spans have nanosecond precision - - sentry_span.finish(end_timestamp=end_timestamp) - - if otel_span.start_time is not None: - span_start_in_minutes = int( - otel_span.start_time / 1e9 / 60 - ) # OTel spans have nanosecond precision - self.open_spans.setdefault(span_start_in_minutes, set()).discard(span_id) - - self._prune_old_spans() - - def _is_sentry_span(self, otel_span: "OTelSpan") -> bool: - """ - Break infinite loop: - HTTP requests to Sentry are caught by OTel and send again to Sentry. - """ - otel_span_url = None - if otel_span.attributes is not None: - otel_span_url = otel_span.attributes.get(SpanAttributes.HTTP_URL) - otel_span_url = cast("Optional[str]", otel_span_url) - - parsed_dsn = get_client().parsed_dsn - dsn_url = parsed_dsn.netloc if parsed_dsn else None - - if otel_span_url and dsn_url and dsn_url in otel_span_url: - return True - - return False - - def _get_otel_context(self, otel_span: "OTelSpan") -> "dict[str, Any]": - """ - Returns the OTel context for Sentry. - See: https://develop.sentry.dev/sdk/performance/opentelemetry/#step-5-add-opentelemetry-context - """ - ctx = {} - - if otel_span.attributes: - ctx["attributes"] = dict(otel_span.attributes) - - if otel_span.resource.attributes: - ctx["resource"] = dict(otel_span.resource.attributes) - - return ctx - - def _get_trace_data( - self, - span_context: "SpanContext", - parent_span_context: "Optional[SpanContext]", - parent_context: "Optional[context_api.Context]", - ) -> "dict[str, Any]": - """ - Extracts tracing information from one OTel span's context and its parent OTel context. - """ - trace_data: "dict[str, Any]" = {} - - span_id = format_span_id(span_context.span_id) - trace_data["span_id"] = span_id - - trace_id = format_trace_id(span_context.trace_id) - trace_data["trace_id"] = trace_id - - parent_span_id = ( - format_span_id(parent_span_context.span_id) if parent_span_context else None - ) - trace_data["parent_span_id"] = parent_span_id - - sentry_trace_data = get_value(SENTRY_TRACE_KEY, parent_context) - sentry_trace_data = cast("dict[str, Union[str, bool, None]]", sentry_trace_data) - trace_data["parent_sampled"] = ( - sentry_trace_data["parent_sampled"] if sentry_trace_data else None - ) - - baggage = get_value(SENTRY_BAGGAGE_KEY, parent_context) - trace_data["baggage"] = baggage - - return trace_data - - def _update_span_with_otel_status( - self, sentry_span: "SentrySpan", otel_span: "OTelSpan" - ) -> None: - """ - Set the Sentry span status from the OTel span - """ - if otel_span.status.is_unset: - return - - if otel_span.status.is_ok: - sentry_span.set_status(SPANSTATUS.OK) - return - - sentry_span.set_status(SPANSTATUS.INTERNAL_ERROR) - - def _update_span_with_otel_data( - self, sentry_span: "SentrySpan", otel_span: "OTelSpan" - ) -> None: - """ - Convert OTel span data and update the Sentry span with it. - This should eventually happen on the server when ingesting the spans. - """ - sentry_span.set_data("otel.kind", otel_span.kind) - - op = otel_span.name - description = otel_span.name - - if otel_span.attributes is not None: - for key, val in otel_span.attributes.items(): - sentry_span.set_data(key, val) - - http_method = otel_span.attributes.get(SpanAttributes.HTTP_METHOD) - http_method = cast("Optional[str]", http_method) - - db_query = otel_span.attributes.get(SpanAttributes.DB_SYSTEM) - - if http_method: - op = "http" - - if otel_span.kind == SpanKind.SERVER: - op += ".server" - elif otel_span.kind == SpanKind.CLIENT: - op += ".client" - - description = http_method - - peer_name = otel_span.attributes.get(SpanAttributes.NET_PEER_NAME, None) - if peer_name: - description += " {}".format(peer_name) - - target = otel_span.attributes.get(SpanAttributes.HTTP_TARGET, None) - if target: - description += " {}".format(target) - - if not peer_name and not target: - url = otel_span.attributes.get(SpanAttributes.HTTP_URL, None) - url = cast("Optional[str]", url) - if url: - parsed_url = urlparse(url) - url = "{}://{}{}".format( - parsed_url.scheme, parsed_url.netloc, parsed_url.path - ) - description += " {}".format(url) - - status_code = otel_span.attributes.get( - SpanAttributes.HTTP_STATUS_CODE, None - ) - status_code = cast("Optional[int]", status_code) - if status_code: - sentry_span.set_http_status(status_code) - - elif db_query: - op = "db" - statement = otel_span.attributes.get(SpanAttributes.DB_STATEMENT, None) - statement = cast("Optional[str]", statement) - if statement: - description = statement - - sentry_span.op = op - sentry_span.description = description - - def _update_transaction_with_otel_data( - self, sentry_span: "SentrySpan", otel_span: "OTelSpan" - ) -> None: - if otel_span.attributes is None: - return - - http_method = otel_span.attributes.get(SpanAttributes.HTTP_METHOD) - - if http_method: - status_code = otel_span.attributes.get(SpanAttributes.HTTP_STATUS_CODE) - status_code = cast("Optional[int]", status_code) - if status_code: - sentry_span.set_http_status(status_code) - - op = "http" - - if otel_span.kind == SpanKind.SERVER: - op += ".server" - elif otel_span.kind == SpanKind.CLIENT: - op += ".client" - - sentry_span.op = op diff --git a/sentry_sdk/integrations/otlp.py b/sentry_sdk/integrations/otlp.py index b91f2cfd21..ed1658d156 100644 --- a/sentry_sdk/integrations/otlp.py +++ b/sentry_sdk/integrations/otlp.py @@ -2,11 +2,11 @@ from sentry_sdk.consts import VERSION, EndpointType from sentry_sdk.integrations import DidNotEnable, Integration from sentry_sdk.scope import register_external_propagation_context -from sentry_sdk.tracing import ( +from sentry_sdk.traces import ( BAGGAGE_HEADER_NAME, SENTRY_TRACE_HEADER_NAME, ) -from sentry_sdk.tracing_utils import Baggage +from sentry_sdk.tracing_utils import Baggage, extract_sentrytrace_data from sentry_sdk.utils import ( Dsn, capture_internal_exceptions, @@ -15,16 +15,22 @@ ) try: + from opentelemetry import trace from opentelemetry.context import ( Context, + create_key, get_current, get_value, + set_value, ) from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter from opentelemetry.propagate import set_global_textmap from opentelemetry.propagators.textmap import ( CarrierT, + Getter, Setter, + TextMapPropagator, + default_getter, default_setter, ) from opentelemetry.sdk.trace import Span, TracerProvider @@ -32,23 +38,27 @@ from opentelemetry.trace import ( INVALID_SPAN_ID, INVALID_TRACE_ID, + NonRecordingSpan, SpanContext, + TraceFlags, format_span_id, format_trace_id, get_current_span, get_tracer_provider, set_tracer_provider, ) - - from sentry_sdk.integrations.opentelemetry.consts import SENTRY_BAGGAGE_KEY - from sentry_sdk.integrations.opentelemetry.propagator import SentryPropagator except ImportError: - raise DidNotEnable("opentelemetry-distro[otlp] is not installed") + raise DidNotEnable("opentelemetry-distro[otlp] is not installed or incompatible") + from typing import TYPE_CHECKING if TYPE_CHECKING: - from typing import Any, Dict, Optional, Tuple + from typing import Any, Dict, Optional, Set, Tuple + + +SENTRY_BAGGAGE_KEY = create_key("sentry-baggage") +SENTRY_TRACE_KEY = create_key("sentry-trace") def otel_propagation_context() -> "Optional[Tuple[str, str]]": @@ -121,11 +131,8 @@ def _sentry_patched_record_exception( _sentry_patched_exception = True -class SentryOTLPPropagator(SentryPropagator): +class SentryOTLPPropagator(TextMapPropagator): """ - We need to override the inject of the older propagator since that - is SpanProcessor based. - !!! Note regarding baggage: We cannot meaningfully populate a new baggage as a head SDK when we are using OTLP since we don't have any sort of transaction semantic to @@ -134,6 +141,52 @@ class SentryOTLPPropagator(SentryPropagator): For incoming baggage, we just pass it on as is so that case is correctly handled. """ + def extract( + self, + carrier: "CarrierT", + context: "Optional[Context]" = None, + getter: "Getter[CarrierT]" = default_getter, + ) -> "Context": + if context is None: + context = get_current() + + sentry_trace = getter.get(carrier, SENTRY_TRACE_HEADER_NAME) + if not sentry_trace: + return context + + sentrytrace = extract_sentrytrace_data(sentry_trace[0]) + if not sentrytrace: + return context + + context = set_value(SENTRY_TRACE_KEY, sentrytrace, context) + + trace_id, span_id = sentrytrace["trace_id"], sentrytrace["parent_span_id"] + + span_context = SpanContext( + trace_id=int(trace_id, 16), # type: ignore + span_id=int(span_id, 16), # type: ignore + # we simulate a sampled trace on the otel side and leave the sampling to sentry + trace_flags=TraceFlags(TraceFlags.SAMPLED), + is_remote=True, + ) + + baggage_header = getter.get(carrier, BAGGAGE_HEADER_NAME) + + if baggage_header: + baggage = Baggage.from_incoming_header(baggage_header[0]) + else: + # If there's an incoming sentry-trace but no incoming baggage header, + # for instance in traces coming from older SDKs, + # baggage will be empty and frozen and won't be populated as head SDK. + baggage = Baggage(sentry_items={}) + + baggage.freeze() + context = set_value(SENTRY_BAGGAGE_KEY, baggage, context) + + span = NonRecordingSpan(span_context) + modified_context = trace.set_span_in_context(span, context) + return modified_context + def inject( self, carrier: "CarrierT", @@ -162,6 +215,10 @@ def inject( if baggage_data: setter.set(carrier, BAGGAGE_HEADER_NAME, baggage_data) + @property + def fields(self) -> "Set[str]": + return {SENTRY_TRACE_HEADER_NAME, BAGGAGE_HEADER_NAME} + def _to_traceparent(span_context: "SpanContext") -> str: """ diff --git a/sentry_sdk/integrations/pure_eval.py b/sentry_sdk/integrations/pure_eval.py index 569e3e1fa5..d990cac4aa 100644 --- a/sentry_sdk/integrations/pure_eval.py +++ b/sentry_sdk/integrations/pure_eval.py @@ -16,18 +16,18 @@ try: from executing import Source except ImportError: - raise DidNotEnable("executing is not installed") + raise DidNotEnable("executing is not installed or incompatible") try: from pure_eval import Evaluator except ImportError: - raise DidNotEnable("pure_eval is not installed") + raise DidNotEnable("pure_eval is not installed or incompatible") try: # Used implicitly, just testing it's available import asttokens # noqa except ImportError: - raise DidNotEnable("asttokens is not installed") + raise DidNotEnable("asttokens is not installed or incompatible") class PureEvalIntegration(Integration): diff --git a/sentry_sdk/integrations/pydantic_ai/__init__.py b/sentry_sdk/integrations/pydantic_ai/__init__.py index a3215aa284..5b9dcc0717 100644 --- a/sentry_sdk/integrations/pydantic_ai/__init__.py +++ b/sentry_sdk/integrations/pydantic_ai/__init__.py @@ -1,11 +1,17 @@ import functools +import sys -from sentry_sdk.integrations import DidNotEnable, Integration -from sentry_sdk.utils import parse_version +import sentry_sdk +from sentry_sdk.integrations import DidNotEnable, Integration, _check_minimum_version +from sentry_sdk.utils import capture_internal_exceptions, parse_version, reraise + +from .spans import execute_tool_span, update_execute_tool_span +from .utils import _capture_exception try: import pydantic_ai # noqa: F401 from pydantic_ai import Agent + from pydantic_ai.exceptions import ToolRetryError except ImportError: raise DidNotEnable("pydantic-ai not installed") @@ -13,18 +19,29 @@ from importlib.metadata import PackageNotFoundError, version from typing import TYPE_CHECKING -from .patches import ( - _patch_agent_run, - _patch_graph_nodes, - _patch_tool_execution, -) -from .spans.ai_client import ai_client_span, update_ai_client_span +from .spans.ai_client import ai_client_context, update_ai_client_span +from .spans.invoke_agent import invoke_agent_span, update_invoke_agent_span if TYPE_CHECKING: from typing import Any - from pydantic_ai import ModelRequestContext, RunContext - from pydantic_ai.capabilities import Hooks, WrapModelRequestHandler + from pydantic import ValidationError + from pydantic_ai import ( + ModelRequestContext, + ModelRetry, + RunContext, + ToolCallPart, + ToolDefinition, + ) + from pydantic_ai.agent import AgentRunResult + from pydantic_ai.capabilities import ( + Hooks, + RawToolArgs, + ValidatedToolArgs, + WrapModelRequestHandler, + WrapRunHandler, + WrapToolExecuteHandler, + ) from pydantic_ai.messages import ModelResponse @@ -40,17 +57,89 @@ async def on_model_request( request_context: "ModelRequestContext", handler: "WrapModelRequestHandler", ) -> "ModelResponse": - with ai_client_span( + with ai_client_context( messages=request_context.messages, - agent=None, + agent=ctx.agent, model=request_context.model, model_settings=request_context.model_settings, - ) as span: + ) as context: response = await handler(request_context) - update_ai_client_span(span, response) + update_ai_client_span(context.span, response) return response + @hooks.on.tool_validate_error + async def sentry_on_tool_validate_error( + ctx: "RunContext[Any]", + *, + call: "ToolCallPart", + tool_def: "ToolDefinition", + args: "RawToolArgs", + error: "ValidationError | ModelRetry", + ) -> "ValidatedToolArgs": + with capture_internal_exceptions(): + integration = sentry_sdk.get_client().get_integration( + PydanticAIIntegration, + ) + if integration is not None and integration.handled_tool_call_exceptions: + _capture_exception(error, handled=True) + + raise error + + @hooks.on.tool_execute + async def sentry_wrap_tool_execute( + ctx: "RunContext[Any]", + *, + call: "ToolCallPart", + tool_def: "ToolDefinition", + args: "ValidatedToolArgs", + handler: "WrapToolExecuteHandler", + ) -> "Any": + with execute_tool_span( + tool_name=call.tool_name, + tool_args=args, + agent=ctx.agent, + tool_definition=tool_def, + ) as span: + try: + result = await handler(args) + update_execute_tool_span(span, result) + return result + except ToolRetryError as exc: + exc_info = sys.exc_info() + with capture_internal_exceptions(): + integration = sentry_sdk.get_client().get_integration( + PydanticAIIntegration, + ) + if ( + integration is not None + and integration.handled_tool_call_exceptions + ): + _capture_exception(exc, handled=True) + reraise(*exc_info) + + @hooks.on.run + async def sentry_wrap_run( + ctx: "RunContext[Any]", + *, + handler: "WrapRunHandler", + ) -> "AgentRunResult[Any]": + with sentry_sdk.isolation_scope(), invoke_agent_span( + user_prompt=ctx.prompt, + agent=ctx.agent, + model=ctx.model, + model_settings=ctx.model_settings, + ) as span: + try: + result = await handler() + update_invoke_agent_span(span, result) + return result + except Exception as exc: + exc_info = sys.exc_info() + with capture_internal_exceptions(): + _capture_exception(exc, handled=False) + reraise(*exc_info) + original_init = Agent.__init__ @functools.wraps(original_init) @@ -83,19 +172,14 @@ class PydanticAIIntegration(Integration): identifier = "pydantic_ai" origin = f"auto.ai.{identifier}" - def __init__( - self, include_prompts: bool = True, handled_tool_call_exceptions: bool = True - ) -> None: + def __init__(self, handled_tool_call_exceptions: bool = True) -> None: """ Initialize the Pydantic AI integration. Args: - include_prompts: Whether to include prompts and messages in span data. - Requires send_default_pii=True. Defaults to True. handled_tool_exceptions: Capture tool call exceptions that Pydantic AI internally prevents from bubbling up. """ - self.include_prompts = include_prompts self.handled_tool_call_exceptions = handled_tool_call_exceptions @staticmethod @@ -108,26 +192,16 @@ def setup_once() -> None: - Model requests (AI client calls) - Tool executions """ - _patch_agent_run() - _patch_tool_execution() - try: PYDANTIC_AI_VERSION = version("pydantic-ai-slim") except PackageNotFoundError: return PYDANTIC_AI_VERSION = parse_version(PYDANTIC_AI_VERSION) + _check_minimum_version(PydanticAIIntegration, PYDANTIC_AI_VERSION) if PYDANTIC_AI_VERSION is None: return - # ModelRequestContext.model added in https://github.com/pydantic/pydantic-ai/commit/f1260dfe09907f17688eee1646daf898fc428d4c - if PYDANTIC_AI_VERSION < ( - 1, - 73, - ): - _patch_graph_nodes() - return - try: from pydantic_ai.capabilities import Hooks except ImportError: diff --git a/sentry_sdk/integrations/pydantic_ai/patches/__init__.py b/sentry_sdk/integrations/pydantic_ai/patches/__init__.py deleted file mode 100644 index d0ea6242b4..0000000000 --- a/sentry_sdk/integrations/pydantic_ai/patches/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .agent_run import _patch_agent_run # noqa: F401 -from .graph_nodes import _patch_graph_nodes # noqa: F401 -from .tools import _patch_tool_execution # noqa: F401 diff --git a/sentry_sdk/integrations/pydantic_ai/patches/agent_run.py b/sentry_sdk/integrations/pydantic_ai/patches/agent_run.py deleted file mode 100644 index b15b27f802..0000000000 --- a/sentry_sdk/integrations/pydantic_ai/patches/agent_run.py +++ /dev/null @@ -1,182 +0,0 @@ -import sys -from functools import wraps -from typing import TYPE_CHECKING - -import sentry_sdk -from sentry_sdk.integrations import DidNotEnable -from sentry_sdk.utils import capture_internal_exceptions, reraise - -from ..spans import invoke_agent_span, update_invoke_agent_span -from ..utils import _capture_exception, pop_agent, push_agent - -try: - from pydantic_ai.agent import Agent -except ImportError: - raise DidNotEnable("pydantic-ai not installed") - -if TYPE_CHECKING: - from typing import Any, Callable, Optional, Union - - -class _StreamingContextManagerWrapper: - """Wrapper for streaming methods that return async context managers.""" - - def __init__( - self, - agent: "Any", - original_ctx_manager: "Any", - user_prompt: "Any", - model: "Any", - model_settings: "Any", - is_streaming: bool = True, - ) -> None: - self.agent = agent - self.original_ctx_manager = original_ctx_manager - self.user_prompt = user_prompt - self.model = model - self.model_settings = model_settings - self.is_streaming = is_streaming - self._isolation_scope: "Any" = None - self._span: "Optional[Union[sentry_sdk.tracing.Span, sentry_sdk.traces.StreamedSpan]]" = None - self._result: "Any" = None - - async def __aenter__(self) -> "Any": - # Set up isolation scope and invoke_agent span - self._isolation_scope = sentry_sdk.isolation_scope() - self._isolation_scope.__enter__() - - # Create invoke_agent span (will be closed in __aexit__) - self._span = invoke_agent_span( - self.user_prompt, - self.agent, - self.model, - self.model_settings, - self.is_streaming, - ) - self._span.__enter__() - - # Push agent to contextvar stack after span is successfully created and entered - # This ensures proper pairing with pop_agent() in __aexit__ even if exceptions occur - push_agent(self.agent, self.is_streaming) - - # Enter the original context manager - result = await self.original_ctx_manager.__aenter__() - self._result = result - return result - - async def __aexit__(self, exc_type: "Any", exc_val: "Any", exc_tb: "Any") -> None: - try: - # Exit the original context manager first - await self.original_ctx_manager.__aexit__(exc_type, exc_val, exc_tb) - - # Update span with result if successful - if exc_type is None and self._result and self._span is not None: - update_invoke_agent_span(self._span, self._result) - finally: - # Pop agent from contextvar stack - pop_agent() - - # Clean up invoke span - if self._span: - self._span.__exit__(exc_type, exc_val, exc_tb) - - # Clean up isolation scope - if self._isolation_scope: - self._isolation_scope.__exit__(exc_type, exc_val, exc_tb) - - -def _create_run_wrapper( - original_func: "Callable[..., Any]", is_streaming: bool = False -) -> "Callable[..., Any]": - """ - Wraps the Agent.run method to create an invoke_agent span. - - Args: - original_func: The original run method - is_streaming: Whether this is a streaming method (for future use) - """ - - @wraps(original_func) - async def wrapper(self: "Any", *args: "Any", **kwargs: "Any") -> "Any": - # Isolate each workflow so that when agents are run in asyncio tasks they - # don't touch each other's scopes - with sentry_sdk.isolation_scope(): - # Extract parameters for the span - user_prompt = kwargs.get("user_prompt") or (args[0] if args else None) - model = kwargs.get("model") - model_settings = kwargs.get("model_settings") - - # Create invoke_agent span - with invoke_agent_span( - user_prompt, self, model, model_settings, is_streaming - ) as span: - # Push agent to contextvar stack after span is successfully created and entered - # This ensures proper pairing with pop_agent() in finally even if exceptions occur - push_agent(self, is_streaming) - - try: - result = await original_func(self, *args, **kwargs) - - # Update span with result - update_invoke_agent_span(span, result) - - return result - except Exception as exc: - exc_info = sys.exc_info() - with capture_internal_exceptions(): - _capture_exception(exc) - reraise(*exc_info) - finally: - # Pop agent from contextvar stack - pop_agent() - - return wrapper - - -def _create_streaming_wrapper( - original_func: "Callable[..., Any]", -) -> "Callable[..., Any]": - """ - Wraps run_stream method that returns an async context manager. - """ - - @wraps(original_func) - def wrapper(self: "Any", *args: "Any", **kwargs: "Any") -> "Any": - # Extract parameters for the span - user_prompt = kwargs.get("user_prompt") or (args[0] if args else None) - model = kwargs.get("model") - model_settings = kwargs.get("model_settings") - - # Call original function to get the context manager - original_ctx_manager = original_func(self, *args, **kwargs) - - # Wrap it with our instrumentation - return _StreamingContextManagerWrapper( - agent=self, - original_ctx_manager=original_ctx_manager, - user_prompt=user_prompt, - model=model, - model_settings=model_settings, - is_streaming=True, - ) - - return wrapper - - -def _patch_agent_run() -> None: - """ - Patches the Agent run methods to create spans for agent execution. - - This patches both non-streaming (run, run_sync) and streaming - (run_stream, run_stream_events) methods. - """ - - # Store original methods - original_run = Agent.run - original_run_stream = Agent.run_stream - - # Wrap and apply patches for non-streaming methods - Agent.run = _create_run_wrapper(original_run, is_streaming=False) # type: ignore[method-assign] - - # Wrap and apply patches for streaming methods - Agent.run_stream = _create_streaming_wrapper(original_run_stream) # type: ignore[method-assign] diff --git a/sentry_sdk/integrations/pydantic_ai/patches/graph_nodes.py b/sentry_sdk/integrations/pydantic_ai/patches/graph_nodes.py deleted file mode 100644 index a177628773..0000000000 --- a/sentry_sdk/integrations/pydantic_ai/patches/graph_nodes.py +++ /dev/null @@ -1,124 +0,0 @@ -from contextlib import asynccontextmanager -from functools import wraps - -from sentry_sdk.integrations import DidNotEnable - -from ..spans import ( - ai_client_span, - update_ai_client_span, -) - -try: - from pydantic_ai._agent_graph import ModelRequestNode -except ImportError: - raise DidNotEnable("pydantic-ai not installed") - -from typing import TYPE_CHECKING - -if TYPE_CHECKING: - from typing import Any, Callable, Optional - - from pydantic_ai.messages import ModelResponse - - -def _extract_span_data(node: "Any", ctx: "Any") -> "tuple[list[Any], Any, Any]": - """Extract common data needed for creating chat spans. - - Returns: - Tuple of (messages, model, model_settings) - """ - # Extract model and settings from context - model = None - model_settings = None - if hasattr(ctx, "deps"): - model = getattr(ctx.deps, "model", None) - model_settings = getattr(ctx.deps, "model_settings", None) - - # Build full message list: history + current request - messages = [] - if hasattr(ctx, "state") and hasattr(ctx.state, "message_history"): - messages.extend(ctx.state.message_history) - - current_request = getattr(node, "request", None) - if current_request: - messages.append(current_request) - - return messages, model, model_settings - - -def _patch_graph_nodes() -> None: - """ - Patches the graph node execution to create appropriate spans. - - ModelRequestNode -> Creates ai_client span for model requests - CallToolsNode -> Handles tool calls (spans created in tool patching) - """ - - # Patch ModelRequestNode to create ai_client spans - original_model_request_run = ModelRequestNode.run - - @wraps(original_model_request_run) - async def wrapped_model_request_run(self: "Any", ctx: "Any") -> "Any": - # Avoid creating a duplicate span if run() is invoked after stream(). - # This fails here: https://github.com/pydantic/pydantic-ai/blob/916fc83e8929470679db5ac1b3065bda5d5f4253/pydantic_ai_slim/pydantic_ai/_agent_graph.py#L1119 - did_stream = getattr(self, "_did_stream", False) - # Do not create a duplicate span when a cached result is served. - cached_result = getattr(self, "_result", None) - if did_stream or cached_result is not None: - return await original_model_request_run(self, ctx) - - messages, model, model_settings = _extract_span_data(self, ctx) - - with ai_client_span(messages, None, model, model_settings) as span: - result = await original_model_request_run(self, ctx) - - # Extract response from result if available - model_response: "Optional[ModelResponse]" = None - if hasattr(result, "model_response"): - model_response = result.model_response - - update_ai_client_span(span, model_response) - return result - - ModelRequestNode.run = wrapped_model_request_run # type: ignore[method-assign] - - # Patch ModelRequestNode.stream for streaming requests - original_model_request_stream = ModelRequestNode.stream - - def create_wrapped_stream( - original_stream_method: "Callable[..., Any]", - ) -> "Callable[..., Any]": - """Create a wrapper for ModelRequestNode.stream that creates chat spans.""" - - @asynccontextmanager - @wraps(original_stream_method) - async def wrapped_model_request_stream(self: "Any", ctx: "Any") -> "Any": - # Avoid creating a duplicate span if the function is invoked twice. - # This fails here: https://github.com/pydantic/pydantic-ai/blob/916fc83e8929470679db5ac1b3065bda5d5f4253/pydantic_ai_slim/pydantic_ai/_agent_graph.py#L1128 - did_stream = getattr(self, "_did_stream", False) - if did_stream: - async with original_stream_method(self, ctx) as stream: - yield stream - return - - messages, model, model_settings = _extract_span_data(self, ctx) - - # Create chat span for streaming request - with ai_client_span(messages, None, model, model_settings) as span: - # Call the original stream method - async with original_stream_method(self, ctx) as stream: - yield stream - - # After streaming completes, update span with response data - # The ModelRequestNode stores the final response in _result - model_response: "Optional[ModelResponse]" = None - if hasattr(self, "_result") and self._result is not None: - # _result is a NextNode containing the model_response - if hasattr(self._result, "model_response"): - model_response = self._result.model_response - - update_ai_client_span(span, model_response) - - return wrapped_model_request_stream - - ModelRequestNode.stream = create_wrapped_stream(original_model_request_stream) # type: ignore[method-assign] diff --git a/sentry_sdk/integrations/pydantic_ai/patches/tools.py b/sentry_sdk/integrations/pydantic_ai/patches/tools.py deleted file mode 100644 index a88e1d5712..0000000000 --- a/sentry_sdk/integrations/pydantic_ai/patches/tools.py +++ /dev/null @@ -1,183 +0,0 @@ -import sys -from contextlib import nullcontext -from functools import wraps -from typing import TYPE_CHECKING - -import sentry_sdk -from sentry_sdk.integrations import DidNotEnable -from sentry_sdk.utils import capture_internal_exceptions, reraise - -from ..spans import execute_tool_span, update_execute_tool_span -from ..utils import _capture_exception, get_current_agent - -if TYPE_CHECKING: - from typing import Any - -try: - try: - from pydantic_ai.tool_manager import ToolManager - except ImportError: - from pydantic_ai._tool_manager import ToolManager # type: ignore - - from pydantic_ai.exceptions import ToolRetryError -except ImportError: - raise DidNotEnable("pydantic-ai not installed") - - -def _patch_tool_execution() -> None: - if hasattr(ToolManager, "execute_tool_call"): - _patch_execute_tool_call() - - elif hasattr(ToolManager, "_call_tool"): - # older versions - _patch_call_tool() - - -def _patch_execute_tool_call() -> None: - original_execute_tool_call = ToolManager.execute_tool_call - - @wraps(original_execute_tool_call) - async def wrapped_execute_tool_call( - self: "Any", validated: "Any", *args: "Any", **kwargs: "Any" - ) -> "Any": - if not validated or not hasattr(validated, "call"): - return await original_execute_tool_call(self, validated, *args, **kwargs) - - # Extract tool info before calling original - call = validated.call - name = call.tool_name - tool = self.tools.get(name) if self.tools else None - selected_tool_definition = getattr(tool, "tool_def", None) - - # Get agent from contextvar - agent = get_current_agent() - - if agent and tool: - try: - args_dict = call.args_as_dict() - except Exception: - args_dict = call.args if isinstance(call.args, dict) else {} - - # Create execute_tool span - # Nesting is handled by isolation_scope() to ensure proper parent-child relationships - with sentry_sdk.isolation_scope(): - with ( - execute_tool_span( - name, - args_dict, - agent, - tool_definition=selected_tool_definition, - ) - if validated.args_valid - else nullcontext() - ) as span: - try: - result = await original_execute_tool_call( - self, - validated, - *args, - **kwargs, - ) - if span is not None: - update_execute_tool_span(span, result) - return result - except ToolRetryError as exc: - exc_info = sys.exc_info() - with capture_internal_exceptions(): - # Avoid circular import due to multi-file integration structure - from sentry_sdk.integrations.pydantic_ai import ( - PydanticAIIntegration, - ) - - integration = sentry_sdk.get_client().get_integration( - PydanticAIIntegration - ) - if ( - integration is not None - and integration.handled_tool_call_exceptions - ): - _capture_exception(exc, handled=True) - reraise(*exc_info) - - return await original_execute_tool_call(self, validated, *args, **kwargs) - - ToolManager.execute_tool_call = wrapped_execute_tool_call # type: ignore[method-assign] - - -def _patch_call_tool() -> None: - """ - Patch ToolManager._call_tool to create execute_tool spans. - - This is the single point where ALL tool calls flow through in pydantic_ai, - regardless of toolset type (function, MCP, combined, wrapper, etc.). - - By patching here, we avoid: - - Patching multiple toolset classes - - Dealing with signature mismatches from instrumented MCP servers - - Complex nested toolset handling - """ - original_call_tool = ToolManager._call_tool # type: ignore[attr-defined] - - @wraps(original_call_tool) - async def wrapped_call_tool( - self: "Any", call: "Any", *args: "Any", **kwargs: "Any" - ) -> "Any": - # Extract tool info before calling original - name = call.tool_name - tool = self.tools.get(name) if self.tools else None - selected_tool_definition = getattr(tool, "tool_def", None) - - # Get agent from contextvar - agent = get_current_agent() - - if agent and tool: - try: - args_dict = call.args_as_dict() - except Exception: - args_dict = call.args if isinstance(call.args, dict) else {} - - # Create execute_tool span - # Nesting is handled by isolation_scope() to ensure proper parent-child relationships - with sentry_sdk.isolation_scope(): - with execute_tool_span( - name, - args_dict, - agent, - tool_definition=selected_tool_definition, - ) as span: - try: - result = await original_call_tool( - self, - call, - *args, - **kwargs, - ) - update_execute_tool_span(span, result) - return result - except ToolRetryError as exc: - exc_info = sys.exc_info() - with capture_internal_exceptions(): - # Avoid circular import due to multi-file integration structure - from sentry_sdk.integrations.pydantic_ai import ( - PydanticAIIntegration, - ) - - integration = sentry_sdk.get_client().get_integration( - PydanticAIIntegration - ) - if ( - integration is not None - and integration.handled_tool_call_exceptions - ): - _capture_exception(exc, handled=True) - reraise(*exc_info) - - # No span context - just call original - return await original_call_tool( - self, - call, - *args, - **kwargs, - ) - - ToolManager._call_tool = wrapped_call_tool # type: ignore[attr-defined] diff --git a/sentry_sdk/integrations/pydantic_ai/spans/__init__.py b/sentry_sdk/integrations/pydantic_ai/spans/__init__.py index 574046d645..fa8ac6a87f 100644 --- a/sentry_sdk/integrations/pydantic_ai/spans/__init__.py +++ b/sentry_sdk/integrations/pydantic_ai/spans/__init__.py @@ -1,3 +1,3 @@ -from .ai_client import ai_client_span, update_ai_client_span # noqa: F401 +from .ai_client import ai_client_context, update_ai_client_span # noqa: F401 from .execute_tool import execute_tool_span, update_execute_tool_span # noqa: F401 from .invoke_agent import invoke_agent_span, update_invoke_agent_span # noqa: F401 diff --git a/sentry_sdk/integrations/pydantic_ai/spans/ai_client.py b/sentry_sdk/integrations/pydantic_ai/spans/ai_client.py index 4ff5f87577..1a0fdb6dde 100644 --- a/sentry_sdk/integrations/pydantic_ai/spans/ai_client.py +++ b/sentry_sdk/integrations/pydantic_ai/spans/ai_client.py @@ -1,18 +1,12 @@ import json from typing import TYPE_CHECKING -import sentry_sdk from sentry_sdk.ai.utils import ( normalize_message_roles, set_data_normalized, - truncate_and_annotate_messages, ) from sentry_sdk.consts import OP, SPANDATA -from sentry_sdk.traces import StreamedSpan -from sentry_sdk.tracing_utils import ( - has_span_streaming_enabled, - should_truncate_gen_ai_input, -) +from sentry_sdk.traces import Span, _AgentFrameworkChatGenerationContext from sentry_sdk.utils import safe_serialize from ..consts import SPAN_ORIGIN @@ -23,8 +17,6 @@ _set_model_data, _should_send_inputs, _should_send_outputs, - get_current_agent, - get_is_streaming, ) from .utils import ( _serialize_binary_content_item, @@ -35,7 +27,10 @@ if TYPE_CHECKING: from typing import Any, Dict, List, Optional, Union + from pydantic_ai import Agent from pydantic_ai.messages import ModelMessage, ModelResponse, SystemPromptPart + from pydantic_ai.models import Model + from pydantic_ai.settings import ModelSettings from sentry_sdk import _types @@ -104,9 +99,7 @@ def _get_system_instructions( return permanent_instructions, current_instructions -def _set_input_messages( - span: "Union[sentry_sdk.tracing.Span, StreamedSpan]", messages: "Any" -) -> None: +def _set_input_messages(span: "Span", messages: "list[ModelMessage]") -> None: """Set input messages data on a span.""" if not _should_send_inputs(): return @@ -116,24 +109,14 @@ def _set_input_messages( permanent_instructions, current_instructions = _get_system_instructions(messages) if len(permanent_instructions) > 0 or len(current_instructions) > 0: - if isinstance(span, StreamedSpan): - span.set_attribute( - SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS, - json.dumps( - _transform_system_instructions( - permanent_instructions, current_instructions - ) - ), - ) - else: - span.set_data( - SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS, - json.dumps( - _transform_system_instructions( - permanent_instructions, current_instructions - ) - ), - ) + span.set_attribute( + SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS, + json.dumps( + _transform_system_instructions( + permanent_instructions, current_instructions + ) + ), + ) try: formatted_messages = [] @@ -217,15 +200,11 @@ def _set_input_messages( if formatted_messages: normalized_messages = normalize_message_roles(formatted_messages) - client = sentry_sdk.get_client() - scope = sentry_sdk.get_current_scope() - messages_data = ( - truncate_and_annotate_messages(normalized_messages, span, scope) - if should_truncate_gen_ai_input(client.options) - else normalized_messages - ) set_data_normalized( - span, SPANDATA.GEN_AI_REQUEST_MESSAGES, messages_data, unpack=False + span, + SPANDATA.GEN_AI_REQUEST_MESSAGES, + normalized_messages, + unpack=False, ) except Exception: # If we fail to format messages, just skip it @@ -233,7 +212,7 @@ def _set_input_messages( def _set_output_data( - span: "Union[sentry_sdk.tracing.Span, StreamedSpan]", + span: "Span", response: "Optional[ModelResponse]", ) -> None: """Set output data on a span.""" @@ -242,10 +221,7 @@ def _set_output_data( if not response: return - set_on_span = ( - span.set_attribute if isinstance(span, StreamedSpan) else span.set_data - ) - set_on_span(SPANDATA.GEN_AI_RESPONSE_MODEL, response.model_name) # type: ignore[arg-type] + span.set_attribute(SPANDATA.GEN_AI_RESPONSE_MODEL, response.model_name) # type: ignore[arg-type] if not record_outputs: return @@ -281,7 +257,7 @@ def _set_output_data( parts.append(tool_part) if parts: - set_on_span( + span.set_attribute( SPANDATA.GEN_AI_OUTPUT_MESSAGES, json.dumps([{"role": "assistant", "parts": parts}]), ) @@ -291,9 +267,12 @@ def _set_output_data( pass -def ai_client_span( - messages: "Any", agent: "Any", model: "Any", model_settings: "Any" -) -> "Union[sentry_sdk.tracing.Span, StreamedSpan]": +def ai_client_context( + messages: "list[ModelMessage]", + agent: "Optional[Agent[Any, Any]]", + model: "Model", + model_settings: "Optional[ModelSettings]", +) -> "_AgentFrameworkChatGenerationContext": """Create a span for an AI client call (model request). Args: @@ -302,51 +281,30 @@ def ai_client_span( model: Model object model_settings: Model settings """ - # Determine model name for span name - model_obj = model - if agent and hasattr(agent, "model"): - model_obj = agent.model - - model_name = _get_model_name(model_obj) or "unknown" - - span_streaming = has_span_streaming_enabled(sentry_sdk.get_client().options) - if span_streaming: - span = sentry_sdk.traces.start_span( - name=f"chat {model_name}", - attributes={ - "sentry.op": OP.GEN_AI_CHAT, - "sentry.origin": SPAN_ORIGIN, - SPANDATA.GEN_AI_OPERATION_NAME: "chat", - SPANDATA.GEN_AI_RESPONSE_STREAMING: get_is_streaming(), - }, - ) - else: - span = sentry_sdk.start_span( - op=OP.GEN_AI_CHAT, - name=f"chat {model_name}", - origin=SPAN_ORIGIN, - ) - - span.set_data(SPANDATA.GEN_AI_OPERATION_NAME, "chat") - # Set streaming flag from contextvar - span.set_data(SPANDATA.GEN_AI_RESPONSE_STREAMING, get_is_streaming()) - - _set_agent_data(span, agent) - _set_model_data(span, model, model_settings) + model_name = _get_model_name(model) or "unknown" + + context = _AgentFrameworkChatGenerationContext( + name=f"chat {model_name}", + attributes={ + "sentry.op": OP.GEN_AI_CHAT, + "sentry.origin": SPAN_ORIGIN, + SPANDATA.GEN_AI_OPERATION_NAME: "chat", + }, + ) - # Add available tools if agent is available - agent_obj = agent or get_current_agent() - _set_available_tools(span, agent_obj) + _set_agent_data(context.span, agent) + _set_model_data(context.span, agent, model, model_settings) + _set_available_tools(context.span, agent) # Set input messages (full conversation history) if messages: - _set_input_messages(span, messages) + _set_input_messages(context.span, messages) - return span + return context def update_ai_client_span( - span: "Union[sentry_sdk.tracing.Span, StreamedSpan]", + span: "Span", model_response: "Optional[ModelResponse]", ) -> None: """Update the AI client span with response data.""" diff --git a/sentry_sdk/integrations/pydantic_ai/spans/execute_tool.py b/sentry_sdk/integrations/pydantic_ai/spans/execute_tool.py index 03c96455f2..e40848654a 100644 --- a/sentry_sdk/integrations/pydantic_ai/spans/execute_tool.py +++ b/sentry_sdk/integrations/pydantic_ai/spans/execute_tool.py @@ -2,25 +2,25 @@ import sentry_sdk from sentry_sdk.consts import OP, SPANDATA -from sentry_sdk.traces import StreamedSpan -from sentry_sdk.tracing_utils import has_span_streaming_enabled +from sentry_sdk.traces import Span from sentry_sdk.utils import safe_serialize from ..consts import SPAN_ORIGIN from ..utils import _set_agent_data, _should_send_inputs, _should_send_outputs if TYPE_CHECKING: - from typing import Any, Optional, Union + from typing import Any, Optional + from pydantic_ai import Agent from pydantic_ai._tool_manager import ToolDefinition # type: ignore def execute_tool_span( tool_name: str, - tool_args: "Any", - agent: "Any", - tool_definition: "Optional[ToolDefinition]" = None, -) -> "Union[sentry_sdk.tracing.Span, StreamedSpan]": + tool_args: "dict[str, Any]", + agent: "Optional[Agent[Any, Any]]", + tool_definition: "ToolDefinition", +) -> "Span": """Create a span for tool execution. Args: @@ -29,33 +29,18 @@ def execute_tool_span( agent: The agent executing the tool tool_definition: The definition of the tool, if available """ - span_streaming = has_span_streaming_enabled(sentry_sdk.get_client().options) - if span_streaming: - span = sentry_sdk.traces.start_span( - name=f"execute_tool {tool_name}", - attributes={ - "sentry.op": OP.GEN_AI_EXECUTE_TOOL, - "sentry.origin": SPAN_ORIGIN, - SPANDATA.GEN_AI_OPERATION_NAME: "execute_tool", - SPANDATA.GEN_AI_TOOL_NAME: tool_name, - }, - ) - - set_on_span = span.set_attribute - else: - span = sentry_sdk.start_span( - op=OP.GEN_AI_EXECUTE_TOOL, - name=f"execute_tool {tool_name}", - origin=SPAN_ORIGIN, - ) - - span.set_data(SPANDATA.GEN_AI_OPERATION_NAME, "execute_tool") - span.set_data(SPANDATA.GEN_AI_TOOL_NAME, tool_name) - - set_on_span = span.set_data + span = sentry_sdk.start_span( + name=f"execute_tool {tool_name}", + attributes={ + "sentry.op": OP.GEN_AI_EXECUTE_TOOL, + "sentry.origin": SPAN_ORIGIN, + SPANDATA.GEN_AI_OPERATION_NAME: "execute_tool", + SPANDATA.GEN_AI_TOOL_NAME: tool_name, + }, + ) if tool_definition is not None and hasattr(tool_definition, "description"): - set_on_span( + span.set_attribute( SPANDATA.GEN_AI_TOOL_DESCRIPTION, tool_definition.description, ) @@ -63,14 +48,12 @@ def execute_tool_span( _set_agent_data(span, agent) if _should_send_inputs() and tool_args is not None: - set_on_span(SPANDATA.GEN_AI_TOOL_INPUT, safe_serialize(tool_args)) + span.set_attribute(SPANDATA.GEN_AI_TOOL_INPUT, safe_serialize(tool_args)) return span -def update_execute_tool_span( - span: "Union[sentry_sdk.tracing.Span, StreamedSpan]", result: "Any" -) -> None: +def update_execute_tool_span(span: "Span", result: "Any") -> None: """Update the execute tool span with the result.""" if not span: return @@ -78,7 +61,4 @@ def update_execute_tool_span( if not _should_send_outputs() or result is None: return - if isinstance(span, StreamedSpan): - span.set_attribute(SPANDATA.GEN_AI_TOOL_OUTPUT, safe_serialize(result)) - else: - span.set_data(SPANDATA.GEN_AI_TOOL_OUTPUT, safe_serialize(result)) + span.set_attribute(SPANDATA.GEN_AI_TOOL_OUTPUT, safe_serialize(result)) diff --git a/sentry_sdk/integrations/pydantic_ai/spans/invoke_agent.py b/sentry_sdk/integrations/pydantic_ai/spans/invoke_agent.py index a9d020edea..96c8de42fb 100644 --- a/sentry_sdk/integrations/pydantic_ai/spans/invoke_agent.py +++ b/sentry_sdk/integrations/pydantic_ai/spans/invoke_agent.py @@ -2,22 +2,15 @@ import sentry_sdk from sentry_sdk.ai.utils import ( - get_start_span_function, normalize_message_roles, set_data_normalized, - truncate_and_annotate_messages, ) from sentry_sdk.consts import OP, SPANDATA -from sentry_sdk.traces import StreamedSpan -from sentry_sdk.tracing_utils import ( - has_span_streaming_enabled, - should_truncate_gen_ai_input, -) +from sentry_sdk.traces import Span from ..consts import SPAN_ORIGIN from ..utils import ( _set_agent_data, - _set_available_tools, _set_model_data, _should_send_inputs, _should_send_outputs, @@ -28,7 +21,12 @@ ) if TYPE_CHECKING: - from typing import Any, Union + from typing import Any, Optional, Sequence, Union + + from pydantic_ai import Agent, UserContent + from pydantic_ai.models import AbstractModel + from pydantic_ai.realtime.settings import RealtimeModelSettings + from pydantic_ai.settings import ModelSettings try: from pydantic_ai.messages import BinaryContent, ImageUrl @@ -38,40 +36,28 @@ def invoke_agent_span( - user_prompt: "Any", - agent: "Any", - model: "Any", - model_settings: "Any", - is_streaming: bool = False, -) -> "Union[sentry_sdk.tracing.Span, StreamedSpan]": + user_prompt: "Optional[Union[str, Sequence[UserContent]]]", + agent: "Optional[Agent]", + model: "AbstractModel", + model_settings: "Optional[Union[ModelSettings, RealtimeModelSettings]]", +) -> "Span": """Create a span for invoking the agent.""" # Determine agent name for span name = "agent" if agent and getattr(agent, "name", None): name = agent.name - span_streaming = has_span_streaming_enabled(sentry_sdk.get_client().options) - if span_streaming: - span = sentry_sdk.traces.start_span( - name=f"invoke_agent {name}", - attributes={ - "sentry.op": OP.GEN_AI_INVOKE_AGENT, - "sentry.origin": SPAN_ORIGIN, - SPANDATA.GEN_AI_OPERATION_NAME: "invoke_agent", - }, - ) - else: - span = get_start_span_function()( - op=OP.GEN_AI_INVOKE_AGENT, - name=f"invoke_agent {name}", - origin=SPAN_ORIGIN, - ) - - span.set_data(SPANDATA.GEN_AI_OPERATION_NAME, "invoke_agent") + span = sentry_sdk.start_span( + name=f"invoke_agent {name}", + attributes={ + "sentry.op": OP.GEN_AI_INVOKE_AGENT, + "sentry.origin": SPAN_ORIGIN, + SPANDATA.GEN_AI_OPERATION_NAME: "invoke_agent", + }, + ) _set_agent_data(span, agent) - _set_model_data(span, model, model_settings) - _set_available_tools(span, agent) + _set_model_data(span, agent, model, model_settings) # Add user prompt and system prompts if available and prompts are enabled if _should_send_inputs(): @@ -138,22 +124,18 @@ def invoke_agent_span( if messages: normalized_messages = normalize_message_roles(messages) - client = sentry_sdk.get_client() - scope = sentry_sdk.get_current_scope() - messages_data = ( - truncate_and_annotate_messages(normalized_messages, span, scope) - if should_truncate_gen_ai_input(client.options) - else normalized_messages - ) set_data_normalized( - span, SPANDATA.GEN_AI_REQUEST_MESSAGES, messages_data, unpack=False + span, + SPANDATA.GEN_AI_REQUEST_MESSAGES, + normalized_messages, + unpack=False, ) return span def update_invoke_agent_span( - span: "Union[sentry_sdk.tracing.Span, StreamedSpan]", + span: "Span", result: "Any", ) -> None: """Update and close the invoke agent span.""" @@ -168,18 +150,3 @@ def update_invoke_agent_span( set_data_normalized( span, SPANDATA.GEN_AI_RESPONSE_TEXT, str(output), unpack=False ) - - # Set model name from response if available - if hasattr(result, "response"): - try: - response = result.response - if hasattr(response, "model_name") and response.model_name: - if isinstance(span, StreamedSpan): - span.set_attribute( - SPANDATA.GEN_AI_RESPONSE_MODEL, response.model_name - ) - else: - span.set_data(SPANDATA.GEN_AI_RESPONSE_MODEL, response.model_name) - except Exception: - # If response access fails, continue without setting model name - pass diff --git a/sentry_sdk/integrations/pydantic_ai/spans/utils.py b/sentry_sdk/integrations/pydantic_ai/spans/utils.py index cbce0c0c77..b48fc788fa 100644 --- a/sentry_sdk/integrations/pydantic_ai/spans/utils.py +++ b/sentry_sdk/integrations/pydantic_ai/spans/utils.py @@ -2,18 +2,18 @@ from typing import TYPE_CHECKING -import sentry_sdk from sentry_sdk._types import BLOB_DATA_SUBSTITUTE from sentry_sdk.ai.consts import DATA_URL_BASE64_REGEX from sentry_sdk.ai.utils import get_modality_from_mime_type from sentry_sdk.consts import SPANDATA -from sentry_sdk.traces import StreamedSpan if TYPE_CHECKING: from typing import Any, Dict, Union from pydantic_ai.usage import RequestUsage, RunUsage + from sentry_sdk.traces import Span + def _serialize_image_url_item(item: "Any") -> "Dict[str, Any]": """Serialize an ImageUrl content item for span data. @@ -47,7 +47,7 @@ def _serialize_binary_content_item(item: "Any") -> "Dict[str, Any]": def _set_usage_data( - span: "Union[sentry_sdk.tracing.Span, StreamedSpan]", + span: "Span", usage: "Union[RequestUsage, RunUsage]", ) -> None: """Set token usage data on a span. @@ -62,26 +62,24 @@ def _set_usage_data( if usage is None: return - set_on_span = ( - span.set_attribute if isinstance(span, StreamedSpan) else span.set_data - ) - if hasattr(usage, "input_tokens") and usage.input_tokens is not None: - set_on_span(SPANDATA.GEN_AI_USAGE_INPUT_TOKENS, usage.input_tokens) + span.set_attribute(SPANDATA.GEN_AI_USAGE_INPUT_TOKENS, usage.input_tokens) # Pydantic AI uses cache_read_tokens (not input_tokens_cached) if hasattr(usage, "cache_read_tokens") and usage.cache_read_tokens is not None: - set_on_span(SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHED, usage.cache_read_tokens) + span.set_attribute( + SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS, usage.cache_read_tokens + ) # Pydantic AI uses cache_write_tokens (not input_tokens_cache_write) if hasattr(usage, "cache_write_tokens") and usage.cache_write_tokens is not None: - set_on_span( - SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHE_WRITE, + span.set_attribute( + SPANDATA.GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS, usage.cache_write_tokens, ) if hasattr(usage, "output_tokens") and usage.output_tokens is not None: - set_on_span(SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS, usage.output_tokens) + span.set_attribute(SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS, usage.output_tokens) if hasattr(usage, "total_tokens") and usage.total_tokens is not None: - set_on_span(SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS, usage.total_tokens) + span.set_attribute(SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS, usage.total_tokens) diff --git a/sentry_sdk/integrations/pydantic_ai/utils.py b/sentry_sdk/integrations/pydantic_ai/utils.py index c847c143b5..a5b873fa51 100644 --- a/sentry_sdk/integrations/pydantic_ai/utils.py +++ b/sentry_sdk/integrations/pydantic_ai/utils.py @@ -1,10 +1,9 @@ -from contextvars import ContextVar from typing import TYPE_CHECKING import sentry_sdk from sentry_sdk.consts import SPANDATA from sentry_sdk.scope import should_send_default_pii -from sentry_sdk.traces import StreamedSpan +from sentry_sdk.traces import Span from sentry_sdk.utils import ( event_from_exception, has_data_collection_enabled, @@ -14,64 +13,10 @@ if TYPE_CHECKING: from typing import Any, Optional, Union - -# Store the current agent context in a contextvar for re-entrant safety -# Using a list as a stack to support nested agent calls -_agent_context_stack: "ContextVar[list[dict[str, Any]]]" = ContextVar( - "pydantic_ai_agent_context_stack", default=[] -) - - -def push_agent(agent: "Any", is_streaming: bool = False) -> None: - """Push an agent context onto the stack along with its streaming flag.""" - stack = _agent_context_stack.get().copy() - stack.append({"agent": agent, "is_streaming": is_streaming}) - _agent_context_stack.set(stack) - - -def pop_agent() -> None: - """Pop an agent context from the stack.""" - stack = _agent_context_stack.get().copy() - if stack: - stack.pop() - _agent_context_stack.set(stack) - - -def get_current_agent() -> "Any": - """Get the current agent from the contextvar stack.""" - stack = _agent_context_stack.get() - if stack: - return stack[-1]["agent"] - return None - - -def get_is_streaming() -> bool: - """Get the streaming flag from the contextvar stack.""" - stack = _agent_context_stack.get() - if stack: - return stack[-1].get("is_streaming", False) - return False - - -def _should_send_prompts_legacy() -> bool: - """ - Check if prompts should be sent to Sentry based on the deprecated - ``send_default_pii`` option and the ``include_prompts`` integration setting. - - TODO: Remove this once `send_default_pii` is deprecated. - """ - if not should_send_default_pii(): - return False - - from . import PydanticAIIntegration - - # Get the integration instance from the client - integration = sentry_sdk.get_client().get_integration(PydanticAIIntegration) - - if integration is None: - return False - - return getattr(integration, "include_prompts", False) + from pydantic_ai import Agent + from pydantic_ai.models import AbstractModel, Model + from pydantic_ai.realtime.settings import RealtimeModelSettings + from pydantic_ai.settings import ModelSettings def _should_send_inputs() -> bool: @@ -79,7 +24,7 @@ def _should_send_inputs() -> bool: if has_data_collection_enabled(client.options): return bool(client.options["data_collection"]["gen_ai"]["inputs"]) - return _should_send_prompts_legacy() + return should_send_default_pii() def _should_send_outputs() -> bool: @@ -87,32 +32,23 @@ def _should_send_outputs() -> bool: if has_data_collection_enabled(client.options): return bool(client.options["data_collection"]["gen_ai"]["outputs"]) - return _should_send_prompts_legacy() + return should_send_default_pii() -def _set_agent_data( - span: "Union[sentry_sdk.tracing.Span, StreamedSpan]", agent: "Any" -) -> None: +def _set_agent_data(span: "Span", agent: "Optional[Agent]") -> None: """Set agent-related data on a span. Args: span: The span to set data on - agent: Agent object (can be None, will try to get from contextvar if not provided) + agent: Agent object """ - # Extract agent name from agent object or contextvar - agent_obj = agent - if not agent_obj: - # Try to get from contextvar - agent_obj = get_current_agent() - - if agent_obj and hasattr(agent_obj, "name") and agent_obj.name: - if isinstance(span, StreamedSpan): - span.set_attribute(SPANDATA.GEN_AI_AGENT_NAME, agent_obj.name) - else: - span.set_data(SPANDATA.GEN_AI_AGENT_NAME, agent_obj.name) + if agent and hasattr(agent, "name") and agent.name: + span.set_attribute(SPANDATA.GEN_AI_AGENT_NAME, agent.name) -def _get_model_name(model_obj: "Any") -> "Optional[str]": +def _get_model_name( + model_obj: "Optional[Union[AbstractModel, Model, str]]", +) -> "Optional[str]": """Extract model name from a model object. Args: @@ -138,9 +74,10 @@ def _get_model_name(model_obj: "Any") -> "Optional[str]": def _set_model_data( - span: "Union[sentry_sdk.tracing.Span, StreamedSpan]", - model: "Any", - model_settings: "Any", + span: "Span", + agent: "Optional[Agent]", + model: "Union[Model, AbstractModel]", + model_settings: "Optional[Union[ModelSettings, RealtimeModelSettings]]", ) -> None: """Set model-related data on a span. @@ -149,32 +86,25 @@ def _set_model_data( model: Model object (can be None, will try to get from agent if not provided) model_settings: Model settings (can be None, will try to get from agent if not provided) """ - # Try to get agent from contextvar if we need it - agent_obj = get_current_agent() - # Extract model information model_obj = model - if not model_obj and agent_obj and hasattr(agent_obj, "model"): - model_obj = agent_obj.model - - set_on_span = ( - span.set_attribute if isinstance(span, StreamedSpan) else span.set_data - ) + if not model_obj and agent and hasattr(agent, "model"): + model_obj = agent.model if model_obj: # Set system from model if hasattr(model_obj, "system"): - set_on_span(SPANDATA.GEN_AI_SYSTEM, model_obj.system) + span.set_attribute(SPANDATA.GEN_AI_PROVIDER_NAME, model_obj.system) # Set model name model_name = _get_model_name(model_obj) if model_name: - set_on_span(SPANDATA.GEN_AI_REQUEST_MODEL, model_name) + span.set_attribute(SPANDATA.GEN_AI_REQUEST_MODEL, model_name) # Extract model settings settings = model_settings - if not settings and agent_obj and hasattr(agent_obj, "model_settings"): - settings = agent_obj.model_settings + if not settings and agent and hasattr(agent, "model_settings"): + settings = agent.model_settings if settings: settings_map = { @@ -190,19 +120,17 @@ def _set_model_data( for setting_name, spandata_key in settings_map.items(): value = settings.get(setting_name) if value is not None: - set_on_span(spandata_key, value) + span.set_attribute(spandata_key, value) # type: ignore[arg-type] else: # Fallback for object-style settings for setting_name, spandata_key in settings_map.items(): if hasattr(settings, setting_name): value = getattr(settings, setting_name) if value is not None: - set_on_span(spandata_key, value) + span.set_attribute(spandata_key, value) -def _set_available_tools( - span: "Union[sentry_sdk.tracing.Span, StreamedSpan]", agent: "Any" -) -> None: +def _set_available_tools(span: "Span", agent: "Optional[Agent[Any, Any]]") -> None: """Set available tools data on a span from an agent's function toolset. Args: @@ -222,7 +150,7 @@ def _set_available_tools( # Get tools from the function toolset if hasattr(agent._function_toolset, "tools"): for tool_name, tool in agent._function_toolset.tools.items(): - tool_info = {"name": tool_name} + tool_info: "dict[str, Any]" = {"name": tool_name} # Add description from function_schema if available if hasattr(tool, "function_schema"): @@ -237,14 +165,10 @@ def _set_available_tools( tools.append(tool_info) if tools: - if isinstance(span, StreamedSpan): - span.set_attribute( - SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS, safe_serialize(tools) - ) - else: - span.set_data( - SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS, safe_serialize(tools) - ) + span.set_attribute( + SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS, safe_serialize(tools) + ) + except Exception: # If we can't extract tools, just skip it pass diff --git a/sentry_sdk/integrations/pymongo.py b/sentry_sdk/integrations/pymongo.py index 22da5d18ff..2cc9d2663b 100644 --- a/sentry_sdk/integrations/pymongo.py +++ b/sentry_sdk/integrations/pymongo.py @@ -2,18 +2,21 @@ import json import sentry_sdk -from sentry_sdk.consts import OP, SPANDATA, SPANSTATUS -from sentry_sdk.integrations import DidNotEnable, Integration +from sentry_sdk.consts import OP, SPANDATA +from sentry_sdk.integrations import DidNotEnable, Integration, _check_minimum_version from sentry_sdk.scope import should_send_default_pii -from sentry_sdk.traces import SpanStatus, StreamedSpan -from sentry_sdk.tracing import Span -from sentry_sdk.tracing_utils import has_span_streaming_enabled -from sentry_sdk.utils import capture_internal_exceptions, has_data_collection_enabled +from sentry_sdk.traces import SpanStatus +from sentry_sdk.utils import ( + capture_internal_exceptions, + has_data_collection_enabled, + parse_version, +) try: + from pymongo import __version__ as PYMONGO_VERSION from pymongo import monitoring except ImportError: - raise DidNotEnable("Pymongo not installed") + raise DidNotEnable("Pymongo not installed or incompatible") from typing import TYPE_CHECKING @@ -26,6 +29,8 @@ CommandSucceededEvent, ) + from sentry_sdk.traces import Span + SAFE_COMMAND_ATTRIBUTES = [ "insert", @@ -89,9 +94,6 @@ def _strip_pii(command: "Dict[str, Any]") -> "Dict[str, Any]": def _get_db_data(event: "Any") -> "Dict[str, Any]": data = {} - client = sentry_sdk.get_client() - is_span_streaming_enabled = has_span_streaming_enabled(client.options) - data[SPANDATA.DB_DRIVER_NAME] = "pymongo" db_name = event.database_name @@ -103,23 +105,17 @@ def _get_db_data(event: "Any") -> "Dict[str, Any]": if server_port is not None: data[SPANDATA.SERVER_PORT] = server_port - if is_span_streaming_enabled: - data["db.system.name"] = "mongodb" + data["db.system.name"] = "mongodb" - if db_name is not None: - data["db.namespace"] = db_name - else: - data[SPANDATA.DB_SYSTEM] = "mongodb" - - if db_name is not None: - data[SPANDATA.DB_NAME] = db_name + if db_name is not None: + data["db.namespace"] = db_name return data class CommandTracer(monitoring.CommandListener): def __init__(self) -> None: - self._ongoing_operations: "Dict[int, Union[Span, StreamedSpan]]" = {} + self._ongoing_operations: "dict[int, Span]" = {} def _operation_key( self, @@ -143,9 +139,8 @@ def started(self, event: "CommandStartedEvent") -> None: collection_name = command.get(event.command_name) operation_name = event.command_name - db_name = event.database_name - lsid = command.pop("lsid", None) + command.pop("lsid", None) if has_data_collection_enabled(client.options): if not client.options["data_collection"]["database_query_data"]: command = _strip_pii(command) @@ -154,82 +149,29 @@ def started(self, event: "CommandStartedEvent") -> None: query = json.dumps(command, default=str) - if has_span_streaming_enabled(client.options): - span_first_data = { - "db.operation.name": operation_name, - "db.collection.name": collection_name, - SPANDATA.DB_QUERY_TEXT: query, - "sentry.op": OP.DB, - "sentry.origin": PyMongoIntegration.origin, - **db_data, - } - - with capture_internal_exceptions(): - sentry_sdk.add_breadcrumb( - message=query, - category="query", - type=OP.DB, - data=span_first_data, - ) - - if sentry_sdk.traces.get_current_span() is None: - return - - span = sentry_sdk.traces.start_span( - name=query, attributes=span_first_data + data = { + "db.operation.name": operation_name, + "db.collection.name": collection_name, + SPANDATA.DB_QUERY_TEXT: query, + "sentry.op": OP.DB, + "sentry.origin": PyMongoIntegration.origin, + **db_data, + } + + with capture_internal_exceptions(): + sentry_sdk.add_breadcrumb( + message=query, + category="query", + type=OP.DB, + data=data, ) - else: - tags = { - "db.name": db_name, - SPANDATA.DB_SYSTEM: "mongodb", - SPANDATA.DB_DRIVER_NAME: "pymongo", - SPANDATA.DB_OPERATION: operation_name, - # The below is a deprecated field, but leaving for legacy reasons. - # The v2 spans will use `db.collection.name` instead. - SPANDATA.DB_MONGODB_COLLECTION: collection_name, - } - - try: - tags["net.peer.name"] = event.connection_id[0] - tags["net.peer.port"] = str(event.connection_id[1]) - except TypeError: - pass - - data: "Dict[str, Any]" = {"operation_ids": {}} - data["operation_ids"]["operation"] = event.operation_id - data["operation_ids"]["request"] = event.request_id - - data.update(db_data) - - try: - if lsid: - lsid_id = lsid["id"] - data["operation_ids"]["session"] = str(lsid_id) - except KeyError: - pass - - span = sentry_sdk.start_span( - op=OP.DB, - name=query, - origin=PyMongoIntegration.origin, - ) + if sentry_sdk.get_current_span() is None: + return - for tag, value in tags.items(): - # set the tag for backwards-compatibility. - # TODO: remove the set_tag call in the next major release! - span.set_tag(tag, value) - span.set_data(tag, value) + span = sentry_sdk.start_span(name=query, attributes=data) - for key, value in data.items(): - span.set_data(key, value) - - with capture_internal_exceptions(): - sentry_sdk.add_breadcrumb( - message=query, category="query", type=OP.DB, data=tags - ) - - self._ongoing_operations[self._operation_key(event)] = span.__enter__() + self._ongoing_operations[self._operation_key(event)] = span def failed(self, event: "CommandFailedEvent") -> None: if sentry_sdk.get_client().get_integration(PyMongoIntegration) is None: @@ -237,12 +179,8 @@ def failed(self, event: "CommandFailedEvent") -> None: try: span = self._ongoing_operations.pop(self._operation_key(event)) - # Ignoring NoOpStreamedSpan as it will always have a status of "ok" - if type(span) is StreamedSpan: - span.status = SpanStatus.ERROR - elif type(span) is Span: - span.set_status(SPANSTATUS.INTERNAL_ERROR) - span.__exit__(None, None, None) + span.status = SpanStatus.ERROR + span.end() except KeyError: return @@ -252,9 +190,7 @@ def succeeded(self, event: "CommandSucceededEvent") -> None: try: span = self._ongoing_operations.pop(self._operation_key(event)) - if type(span) is Span: - span.set_status(SPANSTATUS.OK) - span.__exit__(None, None, None) + span.end() except KeyError: pass @@ -265,4 +201,7 @@ class PyMongoIntegration(Integration): @staticmethod def setup_once() -> None: + version = parse_version(PYMONGO_VERSION) + _check_minimum_version(PyMongoIntegration, version) + monitoring.register(CommandTracer()) diff --git a/sentry_sdk/integrations/pyramid.py b/sentry_sdk/integrations/pyramid.py index 49f734f52b..7707917c68 100644 --- a/sentry_sdk/integrations/pyramid.py +++ b/sentry_sdk/integrations/pyramid.py @@ -5,18 +5,17 @@ import sentry_sdk from sentry_sdk.consts import SPANDATA -from sentry_sdk.integrations import DidNotEnable, Integration +from sentry_sdk.integrations import DidNotEnable, Integration, _check_minimum_version from sentry_sdk.integrations._wsgi_common import RequestExtractor from sentry_sdk.integrations.wsgi import SentryWsgiMiddleware from sentry_sdk.scope import should_send_default_pii from sentry_sdk.traces import SOURCE_FOR_STYLE as SEGMENT_SOURCE_FOR_STYLE -from sentry_sdk.tracing import SOURCE_FOR_STYLE as TRANSACTION_SOURCE_FOR_STYLE -from sentry_sdk.tracing_utils import has_span_streaming_enabled from sentry_sdk.utils import ( capture_internal_exceptions, ensure_integration_enabled, event_from_exception, has_data_collection_enabled, + package_version, reraise, ) @@ -24,12 +23,12 @@ from pyramid.httpexceptions import HTTPException from pyramid.request import Request except ImportError: - raise DidNotEnable("Pyramid not installed") + raise DidNotEnable("Pyramid not installed or incompatible") from typing import TYPE_CHECKING if TYPE_CHECKING: - from typing import Any, Callable, Dict, Optional + from typing import Any, Callable, Dict from pyramid.response import Response from webob.cookies import RequestCookies @@ -40,16 +39,6 @@ from sentry_sdk.utils import ExcInfo -if getattr(Request, "authenticated_userid", None): - - def authenticated_userid(request: "Request") -> "Optional[Any]": - return request.authenticated_userid - -else: - # bw-compat for pyramid < 1.5 - from pyramid.security import authenticated_userid # type: ignore - - TRANSACTION_STYLE_VALUES = ("route_name", "route_pattern") @@ -69,6 +58,9 @@ def __init__(self, transaction_style: str = "route_name") -> None: @staticmethod def setup_once() -> None: + version = package_version("pyramid") + _check_minimum_version(PyramidIntegration, version) + from pyramid import router old_call_view = router._call_view @@ -100,16 +92,15 @@ def sentry_patched_call_view( scope = sentry_sdk.get_isolation_scope() - if has_span_streaming_enabled(client.options): - if has_data_collection_enabled(client.options): - if client.options["data_collection"]["user_info"]: - user_id = authenticated_userid(request) - if user_id: - scope.set_user({"id": user_id}) - elif should_send_default_pii(): - user_id = authenticated_userid(request) + if has_data_collection_enabled(client.options): + if client.options["data_collection"]["user_info"]: + user_id = request.authenticated_userid if user_id: scope.set_user({"id": user_id}) + elif should_send_default_pii(): + user_id = request.authenticated_userid + if user_id: + scope.set_user({"id": user_id}) scope.add_event_processor( _make_event_processor(weakref.ref(request), integration) @@ -187,17 +178,9 @@ def _set_transaction_name_and_source( "route_name": request.matched_route.name, "route_pattern": request.matched_route.pattern, } - is_span_streaming_enabled = has_span_streaming_enabled( - sentry_sdk.get_client().options - ) - source = ( - SEGMENT_SOURCE_FOR_STYLE[transaction_style] - if is_span_streaming_enabled - else TRANSACTION_SOURCE_FOR_STYLE[transaction_style] - ) scope.set_transaction_name( name_for_style[transaction_style], - source=source, + source=SEGMENT_SOURCE_FOR_STYLE[transaction_style], ) except Exception: pass @@ -254,11 +237,11 @@ def pyramid_event_processor(event: "Event", hint: "Dict[str, Any]") -> "Event": if client_options["data_collection"]["user_info"]: with capture_internal_exceptions(): user_info = event.setdefault("user", {}) - user_info.setdefault("id", authenticated_userid(request)) + user_info.setdefault("id", request.authenticated_userid) elif should_send_default_pii(): with capture_internal_exceptions(): user_info = event.setdefault("user", {}) - user_info.setdefault("id", authenticated_userid(request)) + user_info.setdefault("id", request.authenticated_userid) return event diff --git a/sentry_sdk/integrations/pyreqwest.py b/sentry_sdk/integrations/pyreqwest.py index 100d5be2fb..3d9d3c0d8a 100644 --- a/sentry_sdk/integrations/pyreqwest.py +++ b/sentry_sdk/integrations/pyreqwest.py @@ -2,25 +2,19 @@ from typing import TYPE_CHECKING, Any, Generator import sentry_sdk -from sentry_sdk import start_span from sentry_sdk.consts import OP, SPANDATA -from sentry_sdk.integrations import DidNotEnable, Integration -from sentry_sdk.traces import StreamedSpan -from sentry_sdk.tracing import BAGGAGE_HEADER_NAME +from sentry_sdk.integrations import DidNotEnable, Integration, _check_minimum_version from sentry_sdk.tracing_utils import ( add_http_breadcrumb, add_http_request_source, - add_sentry_baggage_to_headers, - get_url_attributes, - has_span_streaming_enabled, + get_url_attributes_legacy, propagate_trace_headers, - should_propagate_trace, ) from sentry_sdk.utils import ( SENSITIVE_DATA_SUBSTITUTE, capture_internal_exceptions, - logger, parse_url, + parse_version, ) if TYPE_CHECKING: @@ -30,6 +24,9 @@ from sentry_sdk.utils import ParsedUrl try: + from pyreqwest import ( # type: ignore[import-not-found] + __version__ as PYREQWEST_VERSION, + ) from pyreqwest.client import ( # type: ignore[import-not-found] ClientBuilder, SyncClientBuilder, @@ -45,7 +42,7 @@ SyncResponse, ) except ImportError: - raise DidNotEnable("pyreqwest not installed or incompatible version installed") + raise DidNotEnable("pyreqwest not installed or incompatible") class PyreqwestIntegration(Integration): @@ -54,6 +51,9 @@ class PyreqwestIntegration(Integration): @staticmethod def setup_once() -> None: + version = parse_version(PYREQWEST_VERSION) + _check_minimum_version(PyreqwestIntegration, version) + _patch_pyreqwest() @@ -98,11 +98,8 @@ def _get_breadcrumb_url_data( if parsed_url is None or not url_attributes: return {} - # Legacy spans keep the bare URL in breadcrumbs; only span streaming - # reports the full URL url = parsed_url.url - if has_span_streaming_enabled(sentry_sdk.get_client().options): - url = url_attributes.get(SPANDATA.URL_FULL, url) + url = url_attributes.get(SPANDATA.URL_FULL, url) return { "url": url, @@ -119,65 +116,29 @@ def _sentry_pyreqwest_span( with capture_internal_exceptions(): parsed_url = parse_url(str(request.url), sanitize=False) - span_streaming = has_span_streaming_enabled(sentry_sdk.get_client().options) - if span_streaming: - if sentry_sdk.traces.get_current_span() is None: - propagate_trace_headers(client=sentry_sdk.get_client(), request=request) - yield None - return - - with sentry_sdk.traces.start_span( - name=f"{request.method} {parsed_url.url if parsed_url else SENSITIVE_DATA_SUBSTITUTE}", - attributes={ - "sentry.op": OP.HTTP_CLIENT, - "sentry.origin": PyreqwestIntegration.origin, - SPANDATA.HTTP_REQUEST_METHOD: request.method, - }, - ) as span: - for key, value in url_attributes.items(): - span.set_attribute(key, value) - - propagate_trace_headers(client=sentry_sdk.get_client(), request=request) - - yield span - - if span is not None: - with capture_internal_exceptions(): - add_http_request_source(span) - - return + if sentry_sdk.get_current_span() is None: + propagate_trace_headers(client=sentry_sdk.get_client(), request=request) + yield None + return - with start_span( - op=OP.HTTP_CLIENT, + with sentry_sdk.start_span( name=f"{request.method} {parsed_url.url if parsed_url else SENSITIVE_DATA_SUBSTITUTE}", - origin=PyreqwestIntegration.origin, + attributes={ + "sentry.op": OP.HTTP_CLIENT, + "sentry.origin": PyreqwestIntegration.origin, + SPANDATA.HTTP_REQUEST_METHOD: request.method, + }, ) as span: - span.set_data(SPANDATA.HTTP_METHOD, request.method) - if parsed_url is not None: - span.set_data("url", parsed_url.url) - span.set_data(SPANDATA.HTTP_QUERY, parsed_url.query) - span.set_data(SPANDATA.HTTP_FRAGMENT, parsed_url.fragment) - - if should_propagate_trace(sentry_sdk.get_client(), str(request.url)): - for ( - key, - value, - ) in sentry_sdk.get_current_scope().iter_trace_propagation_headers(): - logger.debug( - "[Tracing] Adding `{key}` header {value} to outgoing request to {url}.".format( - key=key, value=value, url=request.url - ) - ) - - if key == BAGGAGE_HEADER_NAME: - add_sentry_baggage_to_headers(request.headers, value) - else: - request.headers[key] = value + for key, value in url_attributes.items(): + span.set_attribute(key, value) + + propagate_trace_headers(client=sentry_sdk.get_client(), request=request) yield span - with capture_internal_exceptions(): - add_http_request_source(span) + if span is not None: + with capture_internal_exceptions(): + add_http_request_source(span) async def sentry_async_middleware( @@ -194,19 +155,17 @@ async def sentry_async_middleware( # after the request has been sent parsed_url = parse_url(str(request.url), sanitize=False) - url_attributes = get_url_attributes(sentry_sdk.get_client(), parsed_url) + url_attributes = get_url_attributes_legacy(sentry_sdk.get_client(), parsed_url) response = None with _sentry_pyreqwest_span(request, url_attributes) as span: response = await next_handler.run(request) - if isinstance(span, StreamedSpan): + if span is not None: span.status = "error" if response.status >= 400 else "ok" span.set_attribute( SPANDATA.HTTP_STATUS_CODE, response.status, ) - elif span is not None: - span.set_http_status(response.status) if response is not None: breadcrumb_data = { @@ -234,19 +193,17 @@ def sentry_sync_middleware( # after the request has been sent parsed_url = parse_url(str(request.url), sanitize=False) - url_attributes = get_url_attributes(sentry_sdk.get_client(), parsed_url) + url_attributes = get_url_attributes_legacy(sentry_sdk.get_client(), parsed_url) response = None with _sentry_pyreqwest_span(request, url_attributes) as span: response = next_handler.run(request) - if isinstance(span, StreamedSpan): + if span is not None: span.status = "error" if response.status >= 400 else "ok" span.set_attribute( SPANDATA.HTTP_STATUS_CODE, response.status, ) - elif span is not None: - span.set_http_status(response.status) if response is not None: breadcrumb_data = { diff --git a/sentry_sdk/integrations/quart.py b/sentry_sdk/integrations/quart.py index 0aa6dedfa4..1343867fc3 100644 --- a/sentry_sdk/integrations/quart.py +++ b/sentry_sdk/integrations/quart.py @@ -12,9 +12,7 @@ from sentry_sdk.integrations.asgi import SentryAsgiMiddleware from sentry_sdk.scope import should_send_default_pii from sentry_sdk.traces import SOURCE_FOR_STYLE as SEGMENT_SOURCE_FOR_STYLE -from sentry_sdk.traces import StreamedSpan, get_current_span -from sentry_sdk.tracing import SOURCE_FOR_STYLE as TRANSACTION_SOURCE_FOR_STYLE -from sentry_sdk.tracing_utils import has_span_streaming_enabled +from sentry_sdk.traces import Span, get_current_span from sentry_sdk.utils import ( capture_internal_exceptions, ensure_integration_enabled, @@ -34,6 +32,7 @@ quart_auth = None try: + from flask.sansio.scaffold import Scaffold # type: ignore from quart import ( # type: ignore Quart, Request, @@ -50,13 +49,7 @@ websocket_started, ) except ImportError: - raise DidNotEnable("Quart is not installed") -else: - # Quart 0.19 is based on Flask and hence no longer has a Scaffold - try: - from quart.scaffold import Scaffold # type: ignore - except ImportError: - from flask.sansio.scaffold import Scaffold # type: ignore + raise DidNotEnable("Quart is not installed or incompatible") TRANSACTION_STYLE_VALUES = ("endpoint", "url") @@ -124,19 +117,10 @@ def decorator(old_func: "Any") -> "Any": @wraps(old_func) @ensure_integration_enabled(QuartIntegration, old_func) def _sentry_func(*args: "Any", **kwargs: "Any") -> "Any": - client = sentry_sdk.get_client() - if has_span_streaming_enabled(client.options): - span = get_current_span() - if span is not None and hasattr(span, "_segment"): - span._segment._update_active_thread() - else: - current_scope = sentry_sdk.get_current_scope() - if current_scope.transaction is not None: - current_scope.transaction.update_active_thread() - - sentry_scope = sentry_sdk.get_isolation_scope() - if sentry_scope.profile is not None: - sentry_scope.profile.update_active_thread_id() + span = get_current_span() + + if span is not None and hasattr(span, "_segment"): + span._segment._update_active_thread() return old_func(*args, **kwargs) @@ -158,11 +142,7 @@ def _set_transaction_name_and_source( "endpoint": request.url_rule.endpoint, } - source = ( - SEGMENT_SOURCE_FOR_STYLE[transaction_style] - if has_span_streaming_enabled(sentry_sdk.get_client().options) - else TRANSACTION_SOURCE_FOR_STYLE[transaction_style] - ) + source = SEGMENT_SOURCE_FOR_STYLE[transaction_style] scope.set_transaction_name( name=name_for_style[transaction_style], @@ -200,79 +180,50 @@ async def _request_websocket_started(app: "Quart", **kwargs: "Any") -> None: scope = sentry_sdk.get_isolation_scope() - if has_span_streaming_enabled(sentry_sdk.get_client().options): - current_span = get_current_span() - if type(current_span) is StreamedSpan: - segment = current_span._segment + current_span = get_current_span() + if type(current_span) is Span: + segment = current_span._segment - segment.set_attribute("http.request.method", request_websocket.method) - header_attributes: "dict[str, Any]" = {} + segment.set_attribute("http.request.method", request_websocket.method) + header_attributes: "dict[str, Any]" = {} - for header, header_value in _filter_headers( - dict(request_websocket.headers), use_annotated_value=False - ).items(): - header_attributes[f"http.request.header.{header.lower()}"] = ( - header_value - ) + for header, header_value in _filter_headers( + dict(request_websocket.headers), use_annotated_value=False + ).items(): + header_attributes[f"http.request.header.{header.lower()}"] = header_value - segment.set_attributes(header_attributes) + segment.set_attributes(header_attributes) - client_options = sentry_sdk.get_client().options - filtered_query_string = None - if has_data_collection_enabled(client_options): - query_string = request_websocket.query_string.decode( - "utf-8", errors="replace" - ) - if query_string: - filtered_query_string = ( - _apply_data_collection_filtering_to_query_string( - query_string=query_string, - behaviour=client_options["data_collection"][ - "url_query_params" - ], - ) + client_options = sentry_sdk.get_client().options + filtered_query_string = None + if has_data_collection_enabled(client_options): + query_string = request_websocket.query_string.decode( + "utf-8", errors="replace" + ) + if query_string: + filtered_query_string = ( + _apply_data_collection_filtering_to_query_string( + query_string=query_string, + behaviour=client_options["data_collection"]["url_query_params"], ) - if filtered_query_string: - segment.set_attribute( - "url.query", - filtered_query_string, - ) - - parsed_url = parse_url(request_websocket.url) - segment.set_attribute( - "url.full", - f"{parsed_url.url}?{filtered_query_string}" - if filtered_query_string - else parsed_url.url, ) + if filtered_query_string: + segment.set_attribute( + "url.query", + filtered_query_string, + ) - if client_options["data_collection"]["user_info"]: - user_properties = {} - - if len(request_websocket.access_route) >= 1: - segment.set_attribute( - "client.address", request_websocket.access_route[0] - ) - user_properties["ip_address"] = request_websocket.access_route[ - 0 - ] - - current_user_id = _get_current_user_id_from_quart() - if current_user_id: - user_properties["id"] = current_user_id - - if user_properties: - existing_user_properties = scope._user or {} - scope.set_user({**existing_user_properties, **user_properties}) - - elif should_send_default_pii(): - segment.set_attribute("url.full", request_websocket.url) - segment.set_attribute( - "url.query", - request_websocket.query_string.decode("utf-8", errors="replace"), - ) + parsed_url = parse_url(request_websocket.url) + segment.set_attribute( + "url.full", + f"{parsed_url.url}?{filtered_query_string}" + if filtered_query_string + else parsed_url.url, + ) + if client_options["data_collection"]["user_info"]: user_properties = {} + if len(request_websocket.access_route) >= 1: segment.set_attribute( "client.address", request_websocket.access_route[0] @@ -287,6 +238,28 @@ async def _request_websocket_started(app: "Quart", **kwargs: "Any") -> None: existing_user_properties = scope._user or {} scope.set_user({**existing_user_properties, **user_properties}) + elif should_send_default_pii(): + segment.set_attribute("url.full", request_websocket.url) + segment.set_attribute( + "url.query", + request_websocket.query_string.decode("utf-8", errors="replace"), + ) + + user_properties = {} + if len(request_websocket.access_route) >= 1: + segment.set_attribute( + "client.address", request_websocket.access_route[0] + ) + user_properties["ip_address"] = request_websocket.access_route[0] + + current_user_id = _get_current_user_id_from_quart() + if current_user_id: + user_properties["id"] = current_user_id + + if user_properties: + existing_user_properties = scope._user or {} + scope.set_user({**existing_user_properties, **user_properties}) + evt_processor = _make_request_event_processor(app, request_websocket, integration) scope.add_event_processor(evt_processor) diff --git a/sentry_sdk/integrations/ray.py b/sentry_sdk/integrations/ray.py index 744cc266cf..b7029685c3 100644 --- a/sentry_sdk/integrations/ray.py +++ b/sentry_sdk/integrations/ray.py @@ -3,24 +3,23 @@ import sys import sentry_sdk -from sentry_sdk.consts import OP, SPANSTATUS +from sentry_sdk.consts import OP from sentry_sdk.integrations import DidNotEnable, Integration, _check_minimum_version from sentry_sdk.traces import SegmentNameSource -from sentry_sdk.tracing import TransactionSource -from sentry_sdk.tracing_utils import has_span_streaming_enabled from sentry_sdk.utils import ( event_from_exception, logger, - package_version, + parse_version, qualname_from_function, reraise, ) try: import ray # type: ignore[import-not-found] + from ray import __version__ as RAY_VERSION from ray import remote except ImportError: - raise DidNotEnable("Ray not installed.") + raise DidNotEnable("Ray not installed or incompatible") from typing import TYPE_CHECKING @@ -90,52 +89,26 @@ def new_func( ) -> "Any": _check_sentry_initialized() - span_streaming = has_span_streaming_enabled( - sentry_sdk.get_client().options - ) - if span_streaming: - sentry_sdk.traces.continue_trace(_sentry_tracing or {}) - - function_name = qualname_from_function(user_f) - with sentry_sdk.traces.start_span( - name="unknown Ray task" - if function_name is None - else function_name, - attributes={ - "sentry.op": OP.QUEUE_TASK_RAY, - "sentry.origin": RayIntegration.origin, - "sentry.segment.name.source": SegmentNameSource.TASK, - }, - parent_span=None, - ): - try: - result = user_f(*f_args, **f_kwargs) - except Exception: - exc_info = sys.exc_info() - _capture_exception(exc_info) - reraise(*exc_info) - - return result - else: - transaction = sentry_sdk.continue_trace( - _sentry_tracing or {}, - op=OP.QUEUE_TASK_RAY, - name=qualname_from_function(user_f), - origin=RayIntegration.origin, - source=TransactionSource.TASK, - ) - - with sentry_sdk.start_transaction(transaction) as transaction: - try: - result = user_f(*f_args, **f_kwargs) - transaction.set_status(SPANSTATUS.OK) - except Exception: - transaction.set_status(SPANSTATUS.INTERNAL_ERROR) - exc_info = sys.exc_info() - _capture_exception(exc_info) - reraise(*exc_info) - - return result + sentry_sdk.continue_trace(_sentry_tracing or {}) + + function_name = qualname_from_function(user_f) + with sentry_sdk.start_span( + name="unknown Ray task" if function_name is None else function_name, + attributes={ + "sentry.op": OP.QUEUE_TASK_RAY, + "sentry.origin": RayIntegration.origin, + "sentry.segment.name.source": SegmentNameSource.TASK, + }, + parent_span=None, + ): + try: + result = user_f(*f_args, **f_kwargs) + except Exception: + exc_info = sys.exc_info() + _capture_exception(exc_info) + reraise(*exc_info) + + return result _insert_sentry_tracing_in_signature(new_func) @@ -151,73 +124,45 @@ def _remote_method_with_header_propagation( """ Ray Client """ - span_streaming = has_span_streaming_enabled( - sentry_sdk.get_client().options - ) - if span_streaming: - function_name = qualname_from_function(user_f) - - if sentry_sdk.traces.get_current_span() is None: - tracing = { - k: v - for k, v in sentry_sdk.get_current_scope().iter_trace_propagation_headers() - } - try: - result = old_remote_method( - *args, **kwargs, _sentry_tracing=tracing - ) - except Exception: - exc_info = sys.exc_info() - _capture_exception(exc_info) - reraise(*exc_info) - - return result - - with sentry_sdk.traces.start_span( - name="unknown Ray task" - if function_name is None - else function_name, - attributes={ - "sentry.op": OP.QUEUE_SUBMIT_RAY, - "sentry.origin": RayIntegration.origin, - }, - ): - tracing = { - k: v - for k, v in sentry_sdk.get_current_scope().iter_trace_propagation_headers() - } - try: - result = old_remote_method( - *args, **kwargs, _sentry_tracing=tracing - ) - except Exception: - exc_info = sys.exc_info() - _capture_exception(exc_info) - reraise(*exc_info) - - return result - else: - with sentry_sdk.start_span( - op=OP.QUEUE_SUBMIT_RAY, - name=qualname_from_function(user_f), - origin=RayIntegration.origin, - ) as span: - tracing = { - k: v - for k, v in sentry_sdk.get_current_scope().iter_trace_propagation_headers() - } - try: - result = old_remote_method( - *args, **kwargs, _sentry_tracing=tracing - ) - span.set_status(SPANSTATUS.OK) - except Exception: - span.set_status(SPANSTATUS.INTERNAL_ERROR) - exc_info = sys.exc_info() - _capture_exception(exc_info) - reraise(*exc_info) - - return result + function_name = qualname_from_function(user_f) + + if sentry_sdk.get_current_span() is None: + tracing = { + k: v + for k, v in sentry_sdk.get_current_scope().iter_trace_propagation_headers() + } + try: + result = old_remote_method( + *args, **kwargs, _sentry_tracing=tracing + ) + except Exception: + exc_info = sys.exc_info() + _capture_exception(exc_info) + reraise(*exc_info) + + return result + + with sentry_sdk.start_span( + name="unknown Ray task" if function_name is None else function_name, + attributes={ + "sentry.op": OP.QUEUE_SUBMIT_RAY, + "sentry.origin": RayIntegration.origin, + }, + ): + tracing = { + k: v + for k, v in sentry_sdk.get_current_scope().iter_trace_propagation_headers() + } + try: + result = old_remote_method( + *args, **kwargs, _sentry_tracing=tracing + ) + except Exception: + exc_info = sys.exc_info() + _capture_exception(exc_info) + reraise(*exc_info) + + return result rv.remote = _remote_method_with_header_propagation @@ -251,7 +196,7 @@ class RayIntegration(Integration): @staticmethod def setup_once() -> None: - version = package_version("ray") + version = parse_version(RAY_VERSION) _check_minimum_version(RayIntegration, version) _patch_ray_remote() diff --git a/sentry_sdk/integrations/redis/__init__.py b/sentry_sdk/integrations/redis/__init__.py index 7095721ed2..9871ca038d 100644 --- a/sentry_sdk/integrations/redis/__init__.py +++ b/sentry_sdk/integrations/redis/__init__.py @@ -1,13 +1,10 @@ -import warnings from typing import TYPE_CHECKING -from sentry_sdk.integrations import DidNotEnable, Integration -from sentry_sdk.integrations.redis.consts import _DEFAULT_MAX_DATA_SIZE +from sentry_sdk.integrations import DidNotEnable, Integration, _check_minimum_version from sentry_sdk.integrations.redis.rb import _patch_rb from sentry_sdk.integrations.redis.redis import _patch_redis from sentry_sdk.integrations.redis.redis_cluster import _patch_redis_cluster -from sentry_sdk.integrations.redis.redis_py_cluster_legacy import _patch_rediscluster -from sentry_sdk.utils import logger +from sentry_sdk.utils import parse_version if TYPE_CHECKING: from typing import Optional @@ -18,32 +15,20 @@ class RedisIntegration(Integration): def __init__( self, - max_data_size: "Optional[int]" = _DEFAULT_MAX_DATA_SIZE, cache_prefixes: "Optional[list[str]]" = None, ) -> None: - self.max_data_size = max_data_size self.cache_prefixes = cache_prefixes if cache_prefixes is not None else [] - if max_data_size is not None: - warnings.warn( - "The `max_data_size` parameter of `RedisIntegration` is " - "deprecated and will be removed in version 3.0 of sentry-sdk.", - DeprecationWarning, - stacklevel=2, - ) - @staticmethod def setup_once() -> None: try: - from redis import StrictRedis, client + from redis import __version__ as REDIS_VERSION except ImportError: raise DidNotEnable("Redis client not installed") - _patch_redis(StrictRedis, client) + version = parse_version(REDIS_VERSION) + _check_minimum_version(RedisIntegration, version) + + _patch_redis() _patch_redis_cluster() _patch_rb() - - try: - _patch_rediscluster() - except Exception: - logger.exception("Error occurred while patching `rediscluster` library") diff --git a/sentry_sdk/integrations/redis/_async_common.py b/sentry_sdk/integrations/redis/_async_common.py index 956fe91154..5a70d6a449 100644 --- a/sentry_sdk/integrations/redis/_async_common.py +++ b/sentry_sdk/integrations/redis/_async_common.py @@ -14,27 +14,24 @@ _extract_key, _get_safe_command, _set_client_data, - _set_pipeline_data, ) -from sentry_sdk.tracing import Span -from sentry_sdk.tracing_utils import has_span_streaming_enabled from sentry_sdk.utils import capture_internal_exceptions if TYPE_CHECKING: from collections.abc import Callable from typing import Any, Optional, Union - from redis.asyncio.client import Pipeline, StrictRedis + from redis.asyncio.client import Pipeline, Redis from redis.asyncio.cluster import ClusterPipeline, RedisCluster - from sentry_sdk.traces import StreamedSpan + from sentry_sdk.traces import Span def patch_redis_async_pipeline( pipeline_cls: "Union[type[Pipeline[Any]], type[ClusterPipeline[Any]]]", is_cluster: bool, get_command_args_fn: "Any", - set_db_data_fn: "Callable[[Union[Span, StreamedSpan], Any], None]", + set_db_data_fn: "Callable[[Span, Any], None]", ) -> None: old_execute = pipeline_cls.execute @@ -55,44 +52,20 @@ async def _sentry_execute(self: "Any", *args: "Any", **kwargs: "Any") -> "Any": }, ) - span_streaming = has_span_streaming_enabled(client.options) + if sentry_sdk.get_current_span() is None: + return await old_execute(self, *args, **kwargs) - span: "Union[Span, StreamedSpan]" - if span_streaming: - if sentry_sdk.traces.get_current_span() is None: - return await old_execute(self, *args, **kwargs) - span = sentry_sdk.traces.start_span( - name="redis.pipeline.execute", - attributes={ - "sentry.origin": SPAN_ORIGIN, - "sentry.op": OP.DB_REDIS, - }, - ) - else: - span = sentry_sdk.start_span( - op=OP.DB_REDIS, - name="redis.pipeline.execute", - origin=SPAN_ORIGIN, - ) + span = sentry_sdk.start_span( + name="redis.pipeline.execute", + attributes={ + "sentry.origin": SPAN_ORIGIN, + "sentry.op": OP.DB_REDIS, + }, + ) with span: with capture_internal_exceptions(): - try: - command_seq = self._execution_strategy._command_queue - except AttributeError: - if is_cluster: - command_seq = self._command_stack - else: - command_seq = self.command_stack - set_db_data_fn(span, self) - _set_pipeline_data( - span, - is_cluster, - get_command_args_fn, - False if is_cluster else self.is_transaction, - command_seq, - ) return await old_execute(self, *args, **kwargs) @@ -100,9 +73,9 @@ async def _sentry_execute(self: "Any", *args: "Any", **kwargs: "Any") -> "Any": def patch_redis_async_client( - cls: "Union[type[StrictRedis[Any]], type[RedisCluster[Any]]]", + cls: "Union[type[Redis[Any]], type[RedisCluster[Any]]]", is_cluster: bool, - set_db_data_fn: "Callable[[Union[Span, StreamedSpan], Any], None]", + set_db_data_fn: "Callable[[Span, Any], None]", ) -> None: old_execute_command = cls.execute_command @@ -134,9 +107,7 @@ async def _sentry_execute_command( data=breadcrumb_data, ) - span_streaming = has_span_streaming_enabled(client.options) - - if span_streaming and sentry_sdk.traces.get_current_span() is None: + if sentry_sdk.get_current_span() is None: return await old_execute_command(self, name, *args, **kwargs) cache_properties = _compile_cache_span_properties( @@ -152,24 +123,16 @@ async def _sentry_execute_command( _get_safe_command(name, args) ) - cache_span: "Optional[Union[Span, StreamedSpan]]" = None + cache_span: "Optional[Span]" = None if cache_properties["is_cache_key"] and cache_properties["op"] is not None: - if span_streaming: - cache_span = sentry_sdk.traces.start_span( - name=cache_properties["description"], - attributes={ - "sentry.op": cache_properties["op"], - "sentry.origin": SPAN_ORIGIN, - **additional_cache_span_attributes, - }, - ) - else: - cache_span = sentry_sdk.start_span( - op=cache_properties["op"], - name=cache_properties["description"], - origin=SPAN_ORIGIN, - ) - cache_span.__enter__() + cache_span = sentry_sdk.start_span( + name=cache_properties["description"], + attributes={ + "sentry.op": cache_properties["op"], + "sentry.origin": SPAN_ORIGIN, + **additional_cache_span_attributes, + }, + ) additional_db_span_attributes = {} with capture_internal_exceptions(): @@ -177,35 +140,29 @@ async def _sentry_execute_command( name, args ) - db_span: "Union[Span, StreamedSpan]" - if span_streaming: - db_span = sentry_sdk.traces.start_span( - name=db_properties["description"], - attributes={ - "sentry.op": db_properties["op"], - "sentry.origin": SPAN_ORIGIN, - **additional_db_span_attributes, - }, - ) - else: - db_span = sentry_sdk.start_span( - op=db_properties["op"], - name=db_properties["description"], - origin=SPAN_ORIGIN, - ) - db_span.__enter__() + db_span = sentry_sdk.start_span( + name=db_properties["description"], + attributes={ + "sentry.op": db_properties["op"], + "sentry.origin": SPAN_ORIGIN, + **additional_db_span_attributes, + }, + ) set_db_data_fn(db_span, self) _set_client_data(db_span, is_cluster, name, *args) - value = await old_execute_command(self, name, *args, **kwargs) + try: + value = await old_execute_command(self, name, *args, **kwargs) - db_span.__exit__(None, None, None) + if cache_span: + _set_cache_data(cache_span, self, cache_properties, value) - if cache_span: - _set_cache_data(cache_span, self, cache_properties, value) - cache_span.__exit__(None, None, None) + return value + finally: + db_span.end() - return value + if cache_span: + cache_span.end() cls.execute_command = _sentry_execute_command # type: ignore diff --git a/sentry_sdk/integrations/redis/_sync_common.py b/sentry_sdk/integrations/redis/_sync_common.py index fcb1822094..2503098661 100644 --- a/sentry_sdk/integrations/redis/_sync_common.py +++ b/sentry_sdk/integrations/redis/_sync_common.py @@ -14,24 +14,21 @@ _extract_key, _get_safe_command, _set_client_data, - _set_pipeline_data, ) -from sentry_sdk.tracing import Span -from sentry_sdk.tracing_utils import has_span_streaming_enabled from sentry_sdk.utils import capture_internal_exceptions if TYPE_CHECKING: from collections.abc import Callable - from typing import Any, Optional, Union + from typing import Any, Optional - from sentry_sdk.traces import StreamedSpan + from sentry_sdk.traces import Span def patch_redis_pipeline( pipeline_cls: "Any", is_cluster: bool, get_command_args_fn: "Any", - set_db_data_fn: "Callable[[Union[Span, StreamedSpan], Any], None]", + set_db_data_fn: "Callable[[Span, Any], None]", ) -> None: old_execute = pipeline_cls.execute @@ -52,41 +49,20 @@ def sentry_patched_execute(self: "Any", *args: "Any", **kwargs: "Any") -> "Any": }, ) - span_streaming = has_span_streaming_enabled(client.options) - span: "Union[Span, StreamedSpan]" - if span_streaming: - if sentry_sdk.traces.get_current_span() is None: - return old_execute(self, *args, **kwargs) - span = sentry_sdk.traces.start_span( - name="redis.pipeline.execute", - attributes={ - "sentry.origin": SPAN_ORIGIN, - "sentry.op": OP.DB_REDIS, - }, - ) - else: - span = sentry_sdk.start_span( - op=OP.DB_REDIS, - name="redis.pipeline.execute", - origin=SPAN_ORIGIN, - ) + if sentry_sdk.get_current_span() is None: + return old_execute(self, *args, **kwargs) + + span = sentry_sdk.start_span( + name="redis.pipeline.execute", + attributes={ + "sentry.origin": SPAN_ORIGIN, + "sentry.op": OP.DB_REDIS, + }, + ) with span: with capture_internal_exceptions(): - command_seq = None - try: - command_seq = self._execution_strategy.command_queue - except AttributeError: - command_seq = self.command_stack - set_db_data_fn(span, self) - _set_pipeline_data( - span, - is_cluster, - get_command_args_fn, - False if is_cluster else self.transaction, - command_seq, - ) return old_execute(self, *args, **kwargs) @@ -96,7 +72,7 @@ def sentry_patched_execute(self: "Any", *args: "Any", **kwargs: "Any") -> "Any": def patch_redis_client( cls: "Any", is_cluster: bool, - set_db_data_fn: "Callable[[Union[Span, StreamedSpan], Any], None]", + set_db_data_fn: "Callable[[Span, Any], None]", ) -> None: """ This function can be used to instrument custom redis client classes or @@ -132,9 +108,7 @@ def sentry_patched_execute_command( data=breadcrumb_data, ) - span_streaming = has_span_streaming_enabled(client.options) - - if span_streaming and sentry_sdk.traces.get_current_span() is None: + if sentry_sdk.get_current_span() is None: return old_execute_command(self, name, *args, **kwargs) cache_properties = _compile_cache_span_properties( @@ -150,24 +124,16 @@ def sentry_patched_execute_command( _get_safe_command(name, args) ) - cache_span: "Optional[Union[Span, StreamedSpan]]" = None + cache_span: "Optional[Span]" = None if cache_properties["is_cache_key"] and cache_properties["op"] is not None: - if span_streaming: - cache_span = sentry_sdk.traces.start_span( - name=cache_properties["description"], - attributes={ - "sentry.op": cache_properties["op"], - "sentry.origin": SPAN_ORIGIN, - **additional_cache_span_attributes, - }, - ) - else: - cache_span = sentry_sdk.start_span( - op=cache_properties["op"], - name=cache_properties["description"], - origin=SPAN_ORIGIN, - ) - cache_span.__enter__() + cache_span = sentry_sdk.start_span( + name=cache_properties["description"], + attributes={ + "sentry.op": cache_properties["op"], + "sentry.origin": SPAN_ORIGIN, + **additional_cache_span_attributes, + }, + ) additional_db_span_attributes = {} with capture_internal_exceptions(): @@ -175,34 +141,25 @@ def sentry_patched_execute_command( name, args ) - db_span: "Union[Span, StreamedSpan]" - if span_streaming: - db_span = sentry_sdk.traces.start_span( - name=db_properties["description"], - attributes={ - "sentry.op": db_properties["op"], - "sentry.origin": SPAN_ORIGIN, - **additional_db_span_attributes, - }, - ) - else: - db_span = sentry_sdk.start_span( - op=db_properties["op"], - name=db_properties["description"], - origin=SPAN_ORIGIN, - ) - db_span.__enter__() + db_span = sentry_sdk.start_span( + name=db_properties["description"], + attributes={ + "sentry.op": db_properties["op"], + "sentry.origin": SPAN_ORIGIN, + **additional_db_span_attributes, + }, + ) set_db_data_fn(db_span, self) _set_client_data(db_span, is_cluster, name, *args) value = old_execute_command(self, name, *args, **kwargs) - db_span.__exit__(None, None, None) + db_span.end() if cache_span: _set_cache_data(cache_span, self, cache_properties, value) - cache_span.__exit__(None, None, None) + cache_span.end() return value diff --git a/sentry_sdk/integrations/redis/consts.py b/sentry_sdk/integrations/redis/consts.py index 0822c2c930..60e1220650 100644 --- a/sentry_sdk/integrations/redis/consts.py +++ b/sentry_sdk/integrations/redis/consts.py @@ -15,5 +15,3 @@ "auth", ] _MAX_NUM_ARGS = 10 # Trim argument lists to this many values -_MAX_NUM_COMMANDS = 10 # Trim command lists to this many values -_DEFAULT_MAX_DATA_SIZE = None diff --git a/sentry_sdk/integrations/redis/modules/caches.py b/sentry_sdk/integrations/redis/modules/caches.py index 35f20fddd9..134c9983f9 100644 --- a/sentry_sdk/integrations/redis/modules/caches.py +++ b/sentry_sdk/integrations/redis/modules/caches.py @@ -4,7 +4,6 @@ from sentry_sdk.consts import OP, SPANDATA from sentry_sdk.integrations.redis.utils import _get_safe_key, _key_as_string -from sentry_sdk.traces import StreamedSpan from sentry_sdk.utils import capture_internal_exceptions GET_COMMANDS = ("get", "mget") @@ -13,10 +12,10 @@ from typing import TYPE_CHECKING if TYPE_CHECKING: - from typing import Any, Optional, Union + from typing import Any, Optional from sentry_sdk.integrations.redis import RedisIntegration - from sentry_sdk.tracing import Span + from sentry_sdk.traces import Span def _get_op(name: str) -> "Optional[str]": @@ -74,38 +73,29 @@ def _get_cache_span_description( integration: "RedisIntegration", ) -> str: description = _key_as_string(_get_safe_key(redis_command, args, kwargs)) - - if integration.max_data_size and len(description) > integration.max_data_size: - description = description[: integration.max_data_size - len("...")] + "..." - return description def _set_cache_data( - span: "Union[Span, StreamedSpan]", + span: "Span", redis_client: "Any", properties: "dict[str, Any]", return_value: "Optional[Any]", ) -> None: - if isinstance(span, StreamedSpan): - set_on_span = span.set_attribute - else: - set_on_span = span.set_data - with capture_internal_exceptions(): - set_on_span(SPANDATA.CACHE_KEY, properties["key"]) + span.set_attribute(SPANDATA.CACHE_KEY, properties["key"]) if properties["redis_command"] in GET_COMMANDS: if return_value is not None: - set_on_span(SPANDATA.CACHE_HIT, True) + span.set_attribute(SPANDATA.CACHE_HIT, True) size = ( len(str(return_value).encode("utf-8")) if not isinstance(return_value, bytes) else len(return_value) ) - set_on_span(SPANDATA.CACHE_ITEM_SIZE, size) + span.set_attribute(SPANDATA.CACHE_ITEM_SIZE, size) else: - set_on_span(SPANDATA.CACHE_HIT, False) + span.set_attribute(SPANDATA.CACHE_HIT, False) elif properties["redis_command"] in SET_COMMANDS: if properties["value"] is not None: @@ -114,7 +104,7 @@ def _set_cache_data( if not isinstance(properties["value"], bytes) else len(properties["value"]) ) - set_on_span(SPANDATA.CACHE_ITEM_SIZE, size) + span.set_attribute(SPANDATA.CACHE_ITEM_SIZE, size) try: connection_params = redis_client.connection_pool.connection_kwargs @@ -129,8 +119,8 @@ def _set_cache_data( host = connection_params.get("host") if host is not None: - set_on_span(SPANDATA.NETWORK_PEER_ADDRESS, host) + span.set_attribute(SPANDATA.NETWORK_PEER_ADDRESS, host) port = connection_params.get("port") if port is not None: - set_on_span(SPANDATA.NETWORK_PEER_PORT, port) + span.set_attribute(SPANDATA.NETWORK_PEER_PORT, port) diff --git a/sentry_sdk/integrations/redis/modules/queries.py b/sentry_sdk/integrations/redis/modules/queries.py index 69207bf6f6..3199df62cd 100644 --- a/sentry_sdk/integrations/redis/modules/queries.py +++ b/sentry_sdk/integrations/redis/modules/queries.py @@ -6,16 +6,15 @@ from sentry_sdk.consts import OP, SPANDATA from sentry_sdk.integrations.redis.utils import _get_safe_command -from sentry_sdk.traces import StreamedSpan from sentry_sdk.utils import capture_internal_exceptions if TYPE_CHECKING: - from typing import Any, Union + from typing import Any from redis import Redis from sentry_sdk.integrations.redis import RedisIntegration - from sentry_sdk.tracing import Span + from sentry_sdk.traces import Span def _compile_db_span_properties( @@ -39,49 +38,28 @@ def _get_db_span_description( with capture_internal_exceptions(): description = _get_safe_command(command_name, args) - if integration.max_data_size and len(description) > integration.max_data_size: - description = description[: integration.max_data_size - len("...")] + "..." - return description -def _set_db_data_on_span( - span: "Union[Span, StreamedSpan]", connection_params: "dict[str, Any]" -) -> None: +def _set_db_data_on_span(span: "Span", connection_params: "dict[str, Any]") -> None: db = connection_params.get("db") host = connection_params.get("host") port = connection_params.get("port") - if isinstance(span, StreamedSpan): - span.set_attribute(SPANDATA.DB_SYSTEM_NAME, "redis") - span.set_attribute(SPANDATA.DB_DRIVER_NAME, "redis-py") - - if db is not None: - span.set_attribute(SPANDATA.DB_NAMESPACE, str(db)) - - if host is not None: - span.set_attribute(SPANDATA.SERVER_ADDRESS, host) - - if port is not None: - span.set_attribute(SPANDATA.SERVER_PORT, port) - - else: - span.set_data(SPANDATA.DB_SYSTEM, "redis") - span.set_data(SPANDATA.DB_DRIVER_NAME, "redis-py") + span.set_attribute(SPANDATA.DB_SYSTEM_NAME, "redis") + span.set_attribute(SPANDATA.DB_DRIVER_NAME, "redis-py") - if db is not None: - span.set_data(SPANDATA.DB_NAME, str(db)) + if db is not None: + span.set_attribute(SPANDATA.DB_NAMESPACE, str(db)) - if host is not None: - span.set_data(SPANDATA.SERVER_ADDRESS, host) + if host is not None: + span.set_attribute(SPANDATA.SERVER_ADDRESS, host) - if port is not None: - span.set_data(SPANDATA.SERVER_PORT, port) + if port is not None: + span.set_attribute(SPANDATA.SERVER_PORT, port) -def _set_db_data( - span: "Union[Span, StreamedSpan]", redis_instance: "Redis[Any]" -) -> None: +def _set_db_data(span: "Span", redis_instance: "Redis[Any]") -> None: try: _set_db_data_on_span(span, redis_instance.connection_pool.connection_kwargs) except AttributeError: diff --git a/sentry_sdk/integrations/redis/redis.py b/sentry_sdk/integrations/redis/redis.py index e704c9bc6a..5ebdf30b7b 100644 --- a/sentry_sdk/integrations/redis/redis.py +++ b/sentry_sdk/integrations/redis/redis.py @@ -6,6 +6,10 @@ from typing import TYPE_CHECKING +from sentry_sdk.integrations.redis._async_common import ( + patch_redis_async_client, + patch_redis_async_pipeline, +) from sentry_sdk.integrations.redis._sync_common import ( patch_redis_client, patch_redis_pipeline, @@ -20,9 +24,12 @@ def _get_redis_command_args(command: "Any") -> "Sequence[Any]": return command[0] -def _patch_redis(StrictRedis: "Any", client: "Any") -> None: # noqa: N803 +def _patch_redis() -> None: + import redis.asyncio + from redis import Redis, client + patch_redis_client( - StrictRedis, + Redis, is_cluster=False, set_db_data_fn=_set_db_data, ) @@ -32,36 +39,15 @@ def _patch_redis(StrictRedis: "Any", client: "Any") -> None: # noqa: N803 get_command_args_fn=_get_redis_command_args, set_db_data_fn=_set_db_data, ) - try: - strict_pipeline = client.StrictPipeline - except AttributeError: - pass - else: - patch_redis_pipeline( - strict_pipeline, - is_cluster=False, - get_command_args_fn=_get_redis_command_args, - set_db_data_fn=_set_db_data, - ) - try: - import redis.asyncio - except ImportError: - pass - else: - from sentry_sdk.integrations.redis._async_common import ( - patch_redis_async_client, - patch_redis_async_pipeline, - ) - - patch_redis_async_client( - redis.asyncio.client.StrictRedis, - is_cluster=False, - set_db_data_fn=_set_db_data, - ) - patch_redis_async_pipeline( - redis.asyncio.client.Pipeline, - False, - _get_redis_command_args, - set_db_data_fn=_set_db_data, - ) + patch_redis_async_client( + redis.asyncio.client.Redis, + is_cluster=False, + set_db_data_fn=_set_db_data, + ) + patch_redis_async_pipeline( + redis.asyncio.client.Pipeline, + False, + _get_redis_command_args, + set_db_data_fn=_set_db_data, + ) diff --git a/sentry_sdk/integrations/redis/redis_cluster.py b/sentry_sdk/integrations/redis/redis_cluster.py index b6c95e6abd..bb2e8fe0ca 100644 --- a/sentry_sdk/integrations/redis/redis_cluster.py +++ b/sentry_sdk/integrations/redis/redis_cluster.py @@ -16,7 +16,7 @@ from sentry_sdk.utils import capture_internal_exceptions if TYPE_CHECKING: - from typing import Any, Union + from typing import Any from redis import RedisCluster from redis.asyncio.cluster import ( @@ -26,12 +26,11 @@ RedisCluster as AsyncRedisCluster, ) - from sentry_sdk.traces import StreamedSpan - from sentry_sdk.tracing import Span + from sentry_sdk.traces import Span def _set_async_cluster_db_data( - span: "Union[Span, StreamedSpan]", + span: "Span", async_redis_cluster_instance: "AsyncRedisCluster[Any]", ) -> None: default_node = async_redis_cluster_instance.get_default_node() @@ -40,7 +39,7 @@ def _set_async_cluster_db_data( def _set_async_cluster_pipeline_db_data( - span: "Union[Span, StreamedSpan]", + span: "Span", async_redis_cluster_pipeline_instance: "AsyncClusterPipeline[Any]", ) -> None: with capture_internal_exceptions(): @@ -61,7 +60,7 @@ def _set_async_cluster_pipeline_db_data( def _set_cluster_db_data( - span: "Union[Span, StreamedSpan]", redis_cluster_instance: "RedisCluster[Any]" + span: "Span", redis_cluster_instance: "RedisCluster[Any]" ) -> None: default_node = redis_cluster_instance.get_default_node() diff --git a/sentry_sdk/integrations/redis/redis_py_cluster_legacy.py b/sentry_sdk/integrations/redis/redis_py_cluster_legacy.py deleted file mode 100644 index 3437aa1f2f..0000000000 --- a/sentry_sdk/integrations/redis/redis_py_cluster_legacy.py +++ /dev/null @@ -1,49 +0,0 @@ -""" -Instrumentation for redis-py-cluster -The project redis-py-cluster is EOL and was integrated into redis-py starting from version 4.1.0 (Dec 26, 2021). - -https://github.com/grokzen/redis-py-cluster -""" - -from sentry_sdk.integrations.redis._sync_common import ( - patch_redis_client, - patch_redis_pipeline, -) -from sentry_sdk.integrations.redis.modules.queries import _set_db_data -from sentry_sdk.integrations.redis.utils import _parse_rediscluster_command - - -def _patch_rediscluster() -> None: - try: - import rediscluster # type: ignore - except ImportError: - return - - patch_redis_client( - rediscluster.RedisCluster, - is_cluster=True, - set_db_data_fn=_set_db_data, - ) - - # up to v1.3.6, __version__ attribute is a tuple - # from v2.0.0, __version__ is a string and VERSION a tuple - version = getattr(rediscluster, "VERSION", rediscluster.__version__) - - # StrictRedisCluster was introduced in v0.2.0 and removed in v2.0.0 - # https://github.com/Grokzen/redis-py-cluster/blob/master/docs/release-notes.rst - if (0, 2, 0) < version < (2, 0, 0): - pipeline_cls = rediscluster.pipeline.StrictClusterPipeline - patch_redis_client( - rediscluster.StrictRedisCluster, - is_cluster=True, - set_db_data_fn=_set_db_data, - ) - else: - pipeline_cls = rediscluster.pipeline.ClusterPipeline - - patch_redis_pipeline( - pipeline_cls, - is_cluster=True, - get_command_args_fn=_parse_rediscluster_command, - set_db_data_fn=_set_db_data, - ) diff --git a/sentry_sdk/integrations/redis/utils.py b/sentry_sdk/integrations/redis/utils.py index c9cf38cdbd..a8c782018d 100644 --- a/sentry_sdk/integrations/redis/utils.py +++ b/sentry_sdk/integrations/redis/utils.py @@ -5,17 +5,15 @@ from sentry_sdk.integrations.redis.consts import ( _COMMANDS_INCLUDING_SENSITIVE_DATA, _MAX_NUM_ARGS, - _MAX_NUM_COMMANDS, _MULTI_KEY_COMMANDS, _SINGLE_KEY_COMMANDS, ) from sentry_sdk.scope import should_send_default_pii -from sentry_sdk.traces import StreamedSpan -from sentry_sdk.tracing import Span +from sentry_sdk.traces import Span from sentry_sdk.utils import SENSITIVE_DATA_SUBSTITUTE, has_data_collection_enabled if TYPE_CHECKING: - from typing import Any, Optional, Sequence, Union + from typing import Any, Optional, Sequence def _get_safe_command(name: str, args: "Sequence[Any]") -> str: @@ -110,55 +108,13 @@ def _parse_rediscluster_command(command: "Any") -> "Sequence[Any]": return command.args -def _set_pipeline_data( - span: "Union[Span, StreamedSpan]", - is_cluster: bool, - get_command_args_fn: "Any", - is_transaction: bool, - commands_seq: "Sequence[Any]", -) -> None: - # TODO: Remove this whole function when removing transaction based tracing - if isinstance(span, StreamedSpan): - return - - span.set_tag("redis.is_cluster", is_cluster) - span.set_tag("redis.transaction", is_transaction) - - commands = [] - for i, arg in enumerate(commands_seq): - if i >= _MAX_NUM_COMMANDS: - break - - command = get_command_args_fn(arg) - commands.append(_get_safe_command(command[0], command[1:])) - - span.set_data( - "redis.commands", - { - "count": len(commands_seq), - "first_ten": commands, - }, - ) - - -def _set_client_data( - span: "Union[Span, StreamedSpan]", is_cluster: bool, name: str, *args: "Any" -) -> None: - if isinstance(span, StreamedSpan): - if name: - span.set_attribute(SPANDATA.DB_OPERATION_NAME, name) - else: - span.set_tag("redis.is_cluster", is_cluster) - if name: - span.set_tag("redis.command", name) - span.set_tag(SPANDATA.DB_OPERATION, name) +def _set_client_data(span: "Span", is_cluster: bool, name: str, *args: "Any") -> None: + if name: + span.set_attribute(SPANDATA.DB_OPERATION_NAME, name) key = _extract_key(name, args) if key is not None: - if isinstance(span, StreamedSpan): - span.set_attribute("db.redis.key", key) - else: - span.set_tag("redis.key", key) + span.set_attribute("db.redis.key", key) def _extract_key(name: str, args: "Any") -> "Optional[str]": diff --git a/sentry_sdk/integrations/rq.py b/sentry_sdk/integrations/rq.py index d6b51ba77d..5098026293 100644 --- a/sentry_sdk/integrations/rq.py +++ b/sentry_sdk/integrations/rq.py @@ -2,14 +2,11 @@ import weakref import sentry_sdk -from sentry_sdk.api import continue_trace from sentry_sdk.consts import OP, SPANDATA from sentry_sdk.integrations import DidNotEnable, Integration, _check_minimum_version -from sentry_sdk.integrations.logging import ignore_logger +from sentry_sdk.integrations.logging import ignore_logger_for_events from sentry_sdk.scope import Scope, should_send_default_pii from sentry_sdk.traces import SegmentNameSource -from sentry_sdk.tracing import TransactionSource -from sentry_sdk.tracing_utils import has_span_streaming_enabled from sentry_sdk.utils import ( SENSITIVE_DATA_SUBSTITUTE, capture_internal_exceptions, @@ -26,7 +23,7 @@ from rq.version import VERSION as RQ_VERSION from rq.worker import Worker except ImportError: - raise DidNotEnable("RQ not installed") + raise DidNotEnable("RQ not installed or incompatible") try: from rq.worker import BaseWorker @@ -76,51 +73,29 @@ def sentry_patched_perform_job( scope.clear_breadcrumbs() scope.add_event_processor(_make_event_processor(weakref.ref(job))) - if has_span_streaming_enabled(client.options): - sentry_sdk.traces.continue_trace( - job.meta.get("_sentry_trace_headers") or {} - ) - - Scope.set_custom_sampling_context({"rq_job": job}) - - func_name = None - with capture_internal_exceptions(): - func_name = job.func_name - - with sentry_sdk.traces.start_span( - name="unknown RQ task" if func_name is None else func_name, - attributes={ - "sentry.op": OP.QUEUE_TASK_RQ, - "sentry.origin": RqIntegration.origin, - "sentry.segment.name.source": SegmentNameSource.TASK, - SPANDATA.MESSAGING_MESSAGE_ID: job.id, - SPANDATA.MESSAGING_DESTINATION_NAME: queue.name, - }, - parent_span=None, - ) as span: - if func_name is not None: - span.set_attribute(SPANDATA.CODE_FUNCTION_NAME, func_name) - - rv = old_perform_job(self, job, queue, *args, **kwargs) - else: - transaction = continue_trace( - job.meta.get("_sentry_trace_headers") or {}, - op=OP.QUEUE_TASK_RQ, - name="unknown RQ task", - source=TransactionSource.TASK, - origin=RqIntegration.origin, - ) + sentry_sdk.continue_trace(job.meta.get("_sentry_trace_headers") or {}) + + Scope.set_custom_sampling_context({"rq_job": job}) - with capture_internal_exceptions(): - transaction.name = job.func_name + func_name = None + with capture_internal_exceptions(): + func_name = job.func_name - with sentry_sdk.start_transaction( - transaction, - custom_sampling_context={"rq_job": job}, - ) as span: - span.set_data(SPANDATA.MESSAGING_DESTINATION_NAME, queue.name) + with sentry_sdk.start_span( + name="unknown RQ task" if func_name is None else func_name, + attributes={ + "sentry.op": OP.QUEUE_TASK_RQ, + "sentry.origin": RqIntegration.origin, + "sentry.segment.name.source": SegmentNameSource.TASK, + SPANDATA.MESSAGING_MESSAGE_ID: job.id, + SPANDATA.MESSAGING_DESTINATION_NAME: queue.name, + }, + parent_span=None, + ) as span: + if func_name is not None: + span.set_attribute(SPANDATA.CODE_FUNCTION_NAME, func_name) - rv = old_perform_job(self, job, queue, *args, **kwargs) + rv = old_perform_job(self, job, queue, *args, **kwargs) if self.is_horse: # We're inside of a forked process and RQ is @@ -161,12 +136,7 @@ def sentry_patched_enqueue_job( return old_enqueue_job(self, job, **kwargs) scope = sentry_sdk.get_current_scope() - span = ( - scope.streamed_span - if has_span_streaming_enabled(client.options) - else scope.span - ) - if span is not None: + if scope.span is not None: job.meta["_sentry_trace_headers"] = dict( scope.iter_trace_propagation_headers() ) @@ -175,7 +145,7 @@ def sentry_patched_enqueue_job( Queue.enqueue_job = sentry_patched_enqueue_job - ignore_logger("rq.worker") + ignore_logger_for_events("rq.worker") def _make_event_processor(weak_job: "Callable[[], Job]") -> "EventProcessor": diff --git a/sentry_sdk/integrations/rust_tracing.py b/sentry_sdk/integrations/rust_tracing.py index d02b7fb5ab..70f8422e2c 100644 --- a/sentry_sdk/integrations/rust_tracing.py +++ b/sentry_sdk/integrations/rust_tracing.py @@ -32,16 +32,16 @@ import json from enum import Enum, auto -from typing import Any, Callable, Dict, Optional, Union +from typing import TYPE_CHECKING, Any, Callable, Dict, Optional import sentry_sdk from sentry_sdk.integrations import Integration from sentry_sdk.scope import should_send_default_pii -from sentry_sdk.traces import StreamedSpan -from sentry_sdk.tracing import Span as SentrySpan -from sentry_sdk.tracing_utils import has_span_streaming_enabled from sentry_sdk.utils import SENSITIVE_DATA_SUBSTITUTE +if TYPE_CHECKING: + from sentry_sdk.traces import Span + class RustTracingLevel(Enum): Trace = "TRACE" @@ -170,7 +170,7 @@ def _include_tracing_fields(self) -> bool: else self.include_tracing_fields ) - def on_event(self, event: str, sentry_span: "SentrySpan") -> None: + def on_event(self, event: str, sentry_span: "Span") -> None: deserialized_event = json.loads(event) metadata = deserialized_event.get("metadata", {}) @@ -184,9 +184,7 @@ def on_event(self, event: str, sentry_span: "SentrySpan") -> None: elif event_type == EventTypeMapping.Event: process_event(deserialized_event) - def on_new_span( - self, attrs: str, span_id: str - ) -> "Optional[Union[SentrySpan, StreamedSpan]]": + def on_new_span(self, attrs: str, span_id: str) -> "Optional[Span]": attrs = json.loads(attrs) metadata = attrs.get("metadata", {}) @@ -206,66 +204,41 @@ def on_new_span( else: sentry_span_name = "" - span_streaming = has_span_streaming_enabled(sentry_sdk.get_client().options) - if span_streaming: - if sentry_sdk.traces.get_current_span() is None: - return None - - sentry_span = sentry_sdk.traces.start_span( - name=sentry_span_name, - attributes={ - "sentry.op": "function", - "sentry.origin": self.origin, - }, - ) - fields = metadata.get("fields", []) - for field in fields: - if self._include_tracing_fields(): - sentry_span.set_attribute(field, attrs.get(field)) - else: - sentry_span.set_attribute(field, SENSITIVE_DATA_SUBSTITUTE) - - return sentry_span + if sentry_sdk.get_current_span() is None: + return None sentry_span = sentry_sdk.start_span( - op="function", name=sentry_span_name, - origin=self.origin, + attributes={ + "sentry.op": "function", + "sentry.origin": self.origin, + }, ) fields = metadata.get("fields", []) for field in fields: if self._include_tracing_fields(): - sentry_span.set_data(field, attrs.get(field)) + sentry_span.set_attribute(field, attrs.get(field)) else: - sentry_span.set_data(field, SENSITIVE_DATA_SUBSTITUTE) + sentry_span.set_attribute(field, SENSITIVE_DATA_SUBSTITUTE) - sentry_span.__enter__() return sentry_span - def on_close(self, span_id: str, sentry_span: "SentrySpan") -> None: + def on_close(self, span_id: str, sentry_span: "Span") -> None: if sentry_span is None: return sentry_span.__exit__(None, None, None) - def on_record( - self, span_id: str, values: str, sentry_span: "Union[SentrySpan, StreamedSpan]" - ) -> None: + def on_record(self, span_id: str, values: str, sentry_span: "Span") -> None: if sentry_span is None: return - set_on_span = ( - sentry_span.set_attribute - if isinstance(sentry_span, StreamedSpan) - else sentry_span.set_data - ) - deserialized_values = json.loads(values) for key, value in deserialized_values.items(): if self._include_tracing_fields(): - set_on_span(key, value) + sentry_span.set_attribute(key, value) else: - set_on_span(key, SENSITIVE_DATA_SUBSTITUTE) + sentry_span.set_attribute(key, SENSITIVE_DATA_SUBSTITUTE) class RustTracingIntegration(Integration): diff --git a/sentry_sdk/integrations/sanic.py b/sentry_sdk/integrations/sanic.py index 2545f8f780..be536b2a4f 100644 --- a/sentry_sdk/integrations/sanic.py +++ b/sentry_sdk/integrations/sanic.py @@ -1,26 +1,19 @@ import sys -import warnings import weakref from inspect import isawaitable from typing import TYPE_CHECKING from urllib.parse import urlsplit import sentry_sdk -from sentry_sdk import continue_trace from sentry_sdk.consts import OP, SPANDATA from sentry_sdk.data_collection import ( _apply_data_collection_filtering_to_query_string, ) from sentry_sdk.integrations import DidNotEnable, Integration, _check_minimum_version from sentry_sdk.integrations._wsgi_common import RequestExtractor, _filter_headers -from sentry_sdk.integrations.logging import ignore_logger from sentry_sdk.scope import should_send_default_pii -from sentry_sdk.traces import SegmentNameSource, StreamedSpan -from sentry_sdk.tracing import TransactionSource -from sentry_sdk.tracing_utils import has_span_streaming_enabled +from sentry_sdk.traces import SegmentNameSource from sentry_sdk.utils import ( - CONTEXTVARS_ERROR_MESSAGE, - HAS_REAL_CONTEXTVARS, capture_internal_exceptions, ensure_integration_enabled, event_from_exception, @@ -30,7 +23,6 @@ ) if TYPE_CHECKING: - from collections.abc import Container from typing import Any, Callable, Dict, Optional, Union from sanic.request import Request, RequestParameters @@ -46,7 +38,7 @@ from sanic.handlers import ErrorHandler from sanic.router import Router except ImportError: - raise DidNotEnable("Sanic not installed") + raise DidNotEnable("Sanic not installed or incompatible") old_error_handler_lookup = ErrorHandler.lookup old_handle_request = Sanic.handle_request @@ -64,46 +56,11 @@ class SanicIntegration(Integration): origin = f"auto.http.{identifier}" version: "Optional[tuple[int, ...]]" = None - def __init__( - self, unsampled_statuses: "Optional[Container[int]]" = frozenset({404}) - ) -> None: - """ - The unsampled_statuses parameter can be used to specify for which HTTP statuses the - transactions should not be sent to Sentry. By default, transactions are sent for all - HTTP statuses, except 404. Set unsampled_statuses to None to send transactions for all - HTTP statuses, including 404. - """ - self._unsampled_statuses = unsampled_statuses or set() - @staticmethod def setup_once() -> None: SanicIntegration.version = parse_version(SANIC_VERSION) _check_minimum_version(SanicIntegration, SanicIntegration.version) - if not HAS_REAL_CONTEXTVARS: - # We better have contextvars or we're going to leak state between - # requests. - raise DidNotEnable( - "The sanic integration for Sentry requires Python 3.7+ " - " or the aiocontextvars package." + CONTEXTVARS_ERROR_MESSAGE - ) - - if SANIC_VERSION.startswith("0.8."): - # Sanic 0.8 and older creates a logger named "root" and puts a - # stringified version of every exception in there (without exc_info), - # which our error deduplication can't detect. - # - # We explicitly check the version here because it is a very - # invasive step to ignore this logger and not necessary in newer - # versions at all. - # - # https://github.com/huge-success/sanic/issues/1332 - ignore_logger("root") - - if SanicIntegration.version is not None and SanicIntegration.version < (21, 9): - _setup_legacy_sanic() - return - _setup_sanic() @@ -140,12 +97,6 @@ def _setup_sanic() -> None: ErrorHandler.lookup = _sentry_error_handler_lookup -def _setup_legacy_sanic() -> None: - Sanic.handle_request = _legacy_handle_request - Router.get = _legacy_router_get - ErrorHandler.lookup = _sentry_error_handler_lookup - - async def _startup(self: "Sanic") -> None: # This happens about as early in the lifecycle as possible, just after the # Request object is created. The body has not yet been consumed. @@ -174,7 +125,6 @@ async def _context_enter(request: "Request") -> None: return client = sentry_sdk.get_client() - is_span_streaming_enabled = has_span_streaming_enabled(client.options) weak_request = weakref.ref(request) request.ctx._sentry_scope = sentry_sdk.isolation_scope() @@ -182,51 +132,28 @@ async def _context_enter(request: "Request") -> None: scope.clear_breadcrumbs() scope.add_event_processor(_make_request_processor(weak_request)) - if is_span_streaming_enabled: - integration = client.get_integration(SanicIntegration) - if ( - isinstance(integration, SanicIntegration) - and integration._unsampled_statuses - ): - warnings.warn( - "The `unsampled_statuses` option of SanicIntegration has no effect when span streaming is enabled.", - stacklevel=2, - ) - - sentry_sdk.traces.continue_trace(dict(request.headers)) - scope.set_custom_sampling_context({"sanic_request": request}) + sentry_sdk.continue_trace(dict(request.headers)) + scope.set_custom_sampling_context({"sanic_request": request}) - if request.remote_addr: - if has_data_collection_enabled(client.options): - if client.options["data_collection"]["user_info"]: - scope.set_attribute(SPANDATA.USER_IP_ADDRESS, request.remote_addr) - elif should_send_default_pii(): + if request.remote_addr: + if has_data_collection_enabled(client.options): + if client.options["data_collection"]["user_info"]: scope.set_attribute(SPANDATA.USER_IP_ADDRESS, request.remote_addr) - - span = sentry_sdk.traces.start_span( - # Unless the request results in a 404 error, the name and source - # will get overwritten in _set_transaction - name=request.path, - attributes={ - "sentry.op": OP.HTTP_SERVER, - "sentry.origin": SanicIntegration.origin, - "sentry.segment.name.source": SegmentNameSource.URL.value, - }, - parent_span=None, - ) - request.ctx._sentry_root_span = span - else: - transaction = continue_trace( - dict(request.headers), - op=OP.HTTP_SERVER, - # Unless the request results in a 404 error, the name and source will get overwritten in _set_transaction - name=request.path, - source=TransactionSource.URL, - origin=SanicIntegration.origin, - ) - request.ctx._sentry_root_span = sentry_sdk.start_transaction( - transaction - ).__enter__() + elif should_send_default_pii(): + scope.set_attribute(SPANDATA.USER_IP_ADDRESS, request.remote_addr) + + span = sentry_sdk.start_span( + # Unless the request results in a 404 error, the name and source + # will get overwritten in _set_transaction + name=request.path, + attributes={ + "sentry.op": OP.HTTP_SERVER, + "sentry.origin": SanicIntegration.origin, + "sentry.segment.name.source": SegmentNameSource.URL.value, + }, + parent_span=None, + ) + request.ctx._sentry_root_span = span async def _context_exit( @@ -236,32 +163,22 @@ async def _context_exit( if not request.ctx._sentry_do_integration: return - integration = sentry_sdk.get_client().get_integration(SanicIntegration) - response_status = None if response is None else response.status # This capture_internal_exceptions block has been intentionally nested here, so that in case an exception - # happens while trying to end the transaction, we still attempt to exit the hub. + # happens while trying to end the transaction, we still attempt to exit the scope. with capture_internal_exceptions(): span = request.ctx._sentry_root_span - if isinstance(span, StreamedSpan): - with capture_internal_exceptions(): - for attr, value in _get_request_attributes(request).items(): - span.set_attribute(attr, value) - if response_status is not None: - span.set_attribute(SPANDATA.HTTP_STATUS_CODE, response_status) - span.status = "error" if response_status >= 400 else "ok" - span.end() + with capture_internal_exceptions(): + for attr, value in _get_request_attributes(request).items(): + span.set_attribute(attr, value) - else: - span.set_http_status(response_status) - span.sampled &= ( - isinstance(integration, SanicIntegration) - and response_status not in integration._unsampled_statuses - ) + if response_status is not None: + span.set_attribute(SPANDATA.HTTP_STATUS_CODE, response_status) + span.status = "error" if response_status >= 400 else "ok" - span.__exit__(None, None, None) + span.end() request.ctx._sentry_scope.__exit__(None, None, None) @@ -271,7 +188,7 @@ async def _set_transaction(request: "Request", route: "Route", **_: "Any") -> No with capture_internal_exceptions(): scope = sentry_sdk.get_current_scope() route_name = route.name.replace(request.app.name, "").strip(".") - scope.set_transaction_name(route_name, source=TransactionSource.COMPONENT) + scope.set_transaction_name(route_name, source=SegmentNameSource.COMPONENT) def _sentry_error_handler_lookup( @@ -310,54 +227,6 @@ async def sentry_wrapped_error_handler( return sentry_wrapped_error_handler -async def _legacy_handle_request( - self: "Any", request: "Request", *args: "Any", **kwargs: "Any" -) -> "Any": - if sentry_sdk.get_client().get_integration(SanicIntegration) is None: - return await old_handle_request(self, request, *args, **kwargs) - - weak_request = weakref.ref(request) - - with sentry_sdk.isolation_scope() as scope: - scope.clear_breadcrumbs() - scope.add_event_processor(_make_request_processor(weak_request)) - - response = old_handle_request(self, request, *args, **kwargs) - if isawaitable(response): - response = await response - - return response - - -def _legacy_router_get(self: "Any", *args: "Union[Any, Request]") -> "Any": - rv = old_router_get(self, *args) - if sentry_sdk.get_client().get_integration(SanicIntegration) is not None: - with capture_internal_exceptions(): - scope = sentry_sdk.get_isolation_scope() - if SanicIntegration.version and SanicIntegration.version >= (21, 3): - # Sanic versions above and including 21.3 append the app name to the - # route name, and so we need to remove it from Route name so the - # transaction name is consistent across all versions - sanic_app_name = self.ctx.app.name - sanic_route = rv[0].name - - if sanic_route.startswith("%s." % sanic_app_name): - # We add a 1 to the len of the sanic_app_name because there is a dot - # that joins app name and the route name - # Format: app_name.route_name - sanic_route = sanic_route[len(sanic_app_name) + 1 :] - - scope.set_transaction_name( - sanic_route, source=TransactionSource.COMPONENT - ) - else: - scope.set_transaction_name( - rv[0].__name__, source=TransactionSource.COMPONENT - ) - - return rv - - @ensure_integration_enabled(SanicIntegration) def _capture_exception(exception: "Union[ExcInfo, BaseException]") -> None: with capture_internal_exceptions(): diff --git a/sentry_sdk/integrations/socket.py b/sentry_sdk/integrations/socket.py index c719f14227..76bce59d4b 100644 --- a/sentry_sdk/integrations/socket.py +++ b/sentry_sdk/integrations/socket.py @@ -4,7 +4,6 @@ from sentry_sdk._types import MYPY from sentry_sdk.consts import OP, SPANDATA from sentry_sdk.integrations import Integration -from sentry_sdk.tracing_utils import has_span_streaming_enabled if MYPY: from socket import AddressFamily, SocketKind @@ -56,37 +55,23 @@ def create_connection( if integration is None: return real_create_connection(address, timeout, source_address) - if has_span_streaming_enabled(client.options): - if sentry_sdk.traces.get_current_span() is None: - return real_create_connection(address, timeout, source_address) - - with sentry_sdk.traces.start_span( - name=_get_span_description(address[0], address[1]), - attributes={ - "sentry.op": OP.SOCKET_CONNECTION, - "sentry.origin": SocketIntegration.origin, - }, - ) as span: - if address[0] is not None: - span.set_attribute(SPANDATA.SERVER_ADDRESS, address[0]) - span.set_attribute(SPANDATA.SERVER_PORT, address[1]) - - return real_create_connection( - address=address, timeout=timeout, source_address=source_address - ) - else: - with sentry_sdk.start_span( - op=OP.SOCKET_CONNECTION, - name=_get_span_description(address[0], address[1]), - origin=SocketIntegration.origin, - ) as span: - span.set_data("address", address) - span.set_data("timeout", timeout) - span.set_data("source_address", source_address) - - return real_create_connection( - address=address, timeout=timeout, source_address=source_address - ) + if sentry_sdk.get_current_span() is None: + return real_create_connection(address, timeout, source_address) + + with sentry_sdk.start_span( + name=_get_span_description(address[0], address[1]), + attributes={ + "sentry.op": OP.SOCKET_CONNECTION, + "sentry.origin": SocketIntegration.origin, + }, + ) as span: + if address[0] is not None: + span.set_attribute(SPANDATA.SERVER_ADDRESS, address[0]) + span.set_attribute(SPANDATA.SERVER_PORT, address[1]) + + return real_create_connection( + address=address, timeout=timeout, source_address=source_address + ) socket.create_connection = create_connection # type: ignore @@ -107,42 +92,31 @@ def getaddrinfo( if integration is None: return real_getaddrinfo(host, port, family, type, proto, flags) - if has_span_streaming_enabled(client.options): - if sentry_sdk.traces.get_current_span() is None: - return real_getaddrinfo(host, port, family, type, proto, flags) - - with sentry_sdk.traces.start_span( - name=_get_span_description(host, port), - attributes={ - "sentry.op": OP.SOCKET_DNS, - "sentry.origin": SocketIntegration.origin, - }, - ) as span: - if isinstance(host, str): - span.set_attribute(SPANDATA.SERVER_ADDRESS, host) - elif isinstance(host, bytes): - span.set_attribute( - SPANDATA.SERVER_ADDRESS, host.decode(errors="replace") - ) - - if isinstance(port, int): - span.set_attribute(SPANDATA.SERVER_PORT, port) - elif port is not None: - try: - span.set_attribute(SPANDATA.SERVER_PORT, int(port)) - except (ValueError, TypeError): - pass - - return real_getaddrinfo(host, port, family, type, proto, flags) - else: - with sentry_sdk.start_span( - op=OP.SOCKET_DNS, - name=_get_span_description(host, port), - origin=SocketIntegration.origin, - ) as span: - span.set_data("host", host) - span.set_data("port", port) - - return real_getaddrinfo(host, port, family, type, proto, flags) + if sentry_sdk.get_current_span() is None: + return real_getaddrinfo(host, port, family, type, proto, flags) + + with sentry_sdk.start_span( + name=_get_span_description(host, port), + attributes={ + "sentry.op": OP.SOCKET_DNS, + "sentry.origin": SocketIntegration.origin, + }, + ) as span: + if isinstance(host, str): + span.set_attribute(SPANDATA.SERVER_ADDRESS, host) + elif isinstance(host, bytes): + span.set_attribute( + SPANDATA.SERVER_ADDRESS, host.decode(errors="replace") + ) + + if isinstance(port, int): + span.set_attribute(SPANDATA.SERVER_PORT, port) + elif port is not None: + try: + span.set_attribute(SPANDATA.SERVER_PORT, int(port)) + except (ValueError, TypeError): + pass + + return real_getaddrinfo(host, port, family, type, proto, flags) socket.getaddrinfo = getaddrinfo diff --git a/sentry_sdk/integrations/spark/spark_driver.py b/sentry_sdk/integrations/spark/spark_driver.py index a83532b6a6..d30454aa64 100644 --- a/sentry_sdk/integrations/spark/spark_driver.py +++ b/sentry_sdk/integrations/spark/spark_driver.py @@ -1,8 +1,17 @@ from typing import TYPE_CHECKING import sentry_sdk -from sentry_sdk.integrations import Integration -from sentry_sdk.utils import capture_internal_exceptions, ensure_integration_enabled +from sentry_sdk.integrations import DidNotEnable, Integration, _check_minimum_version +from sentry_sdk.utils import ( + capture_internal_exceptions, + ensure_integration_enabled, + parse_version, +) + +try: + from pyspark import __version__ as PYSPARK_VERSION +except ImportError: + raise DidNotEnable("pyspark is not installed") if TYPE_CHECKING: from typing import Any, Optional @@ -17,6 +26,9 @@ class SparkIntegration(Integration): @staticmethod def setup_once() -> None: + version = parse_version(PYSPARK_VERSION) + _check_minimum_version(SparkIntegration, version) + _setup_sentry_tracing() diff --git a/sentry_sdk/integrations/sqlalchemy.py b/sentry_sdk/integrations/sqlalchemy.py index e3cc637ab0..2e13302f99 100644 --- a/sentry_sdk/integrations/sqlalchemy.py +++ b/sentry_sdk/integrations/sqlalchemy.py @@ -1,7 +1,6 @@ -from sentry_sdk.consts import SPANDATA, SPANSTATUS +from sentry_sdk.consts import SPANDATA from sentry_sdk.integrations import DidNotEnable, Integration, _check_minimum_version -from sentry_sdk.traces import SpanStatus, StreamedSpan -from sentry_sdk.tracing import Span +from sentry_sdk.traces import Span, SpanStatus from sentry_sdk.tracing_utils import ( add_query_source, record_sql_queries, @@ -17,12 +16,12 @@ from sqlalchemy.engine import Engine # type: ignore from sqlalchemy.event import listen # type: ignore except ImportError: - raise DidNotEnable("SQLAlchemy not installed.") + raise DidNotEnable("SQLAlchemy not installed or incompatible") from typing import TYPE_CHECKING if TYPE_CHECKING: - from typing import Any, ContextManager, Optional, Union + from typing import Any, ContextManager, Optional class SqlalchemyIntegration(Integration): @@ -31,8 +30,7 @@ class SqlalchemyIntegration(Integration): @staticmethod def setup_once() -> None: - version = parse_version(SQLALCHEMY_VERSION) - _check_minimum_version(SqlalchemyIntegration, version) + _check_minimum_version(SqlalchemyIntegration, parse_version(SQLALCHEMY_VERSION)) listen(Engine, "before_cursor_execute", _before_cursor_execute) listen(Engine, "after_cursor_execute", _after_cursor_execute) @@ -80,10 +78,8 @@ def _after_cursor_execute( ) # Record query source immediately before span is finished: accurate end timestamp and before the span is flushed. - span: "Optional[Union[Span, StreamedSpan]]" = getattr( - context, "_sentry_sql_span", None - ) - if isinstance(span, StreamedSpan): + span: "Optional[Span]" = getattr(context, "_sentry_sql_span", None) + if span is not None: with capture_internal_exceptions(): add_query_source(span) @@ -91,10 +87,6 @@ def _after_cursor_execute( context._sentry_sql_span_manager = None ctx_mgr.__exit__(None, None, None) - if isinstance(span, Span): - with capture_internal_exceptions(): - add_query_source(span) - def _handle_error(context: "Any", *args: "Any") -> None: execution_context = context.execution_context @@ -104,10 +96,7 @@ def _handle_error(context: "Any", *args: "Any") -> None: span: "Optional[Span]" = getattr(execution_context, "_sentry_sql_span", None) if span is not None: - if isinstance(span, StreamedSpan): - span.status = SpanStatus.ERROR - else: - span.set_status(SPANSTATUS.INTERNAL_ERROR) + span.status = SpanStatus.ERROR # _after_cursor_execute does not get called for crashing SQL stmts. Judging # from SQLAlchemy codebase it does seem like any error coming into this @@ -155,25 +144,16 @@ def _get_db_system(name: str) -> "Optional[str]": return None -def _set_db_data(span: "Union[Span, StreamedSpan]", conn: "Any") -> None: +def _set_db_data(span: "Span", conn: "Any") -> None: db_system = _get_db_system(conn.engine.name) - if isinstance(span, StreamedSpan): - if db_system is not None: - span.set_attribute(SPANDATA.DB_SYSTEM_NAME, db_system) - else: - if db_system is not None: - span.set_data(SPANDATA.DB_SYSTEM, db_system) - - if isinstance(span, StreamedSpan): - set_on_span = span.set_attribute - else: - set_on_span = span.set_data + if db_system is not None: + span.set_attribute(SPANDATA.DB_SYSTEM_NAME, db_system) try: driver = conn.dialect.driver if driver: - set_on_span(SPANDATA.DB_DRIVER_NAME, driver) + span.set_attribute(SPANDATA.DB_DRIVER_NAME, driver) except Exception: pass @@ -181,17 +161,13 @@ def _set_db_data(span: "Union[Span, StreamedSpan]", conn: "Any") -> None: return db_name = conn.engine.url.database - if isinstance(span, StreamedSpan): - if db_name is not None: - span.set_attribute(SPANDATA.DB_NAMESPACE, db_name) - else: - if db_name is not None: - span.set_data(SPANDATA.DB_NAME, db_name) + if db_name is not None: + span.set_attribute(SPANDATA.DB_NAMESPACE, db_name) server_address = conn.engine.url.host if server_address is not None: - set_on_span(SPANDATA.SERVER_ADDRESS, server_address) + span.set_attribute(SPANDATA.SERVER_ADDRESS, server_address) server_port = conn.engine.url.port if server_port is not None: - set_on_span(SPANDATA.SERVER_PORT, server_port) + span.set_attribute(SPANDATA.SERVER_PORT, server_port) diff --git a/sentry_sdk/integrations/starlette.py b/sentry_sdk/integrations/starlette.py index a9ed8f2f73..a3ae8d5653 100644 --- a/sentry_sdk/integrations/starlette.py +++ b/sentry_sdk/integrations/starlette.py @@ -1,8 +1,8 @@ import functools import json import sys -import warnings from collections.abc import Set +from contextlib import nullcontext from copy import deepcopy from json import JSONDecodeError from typing import TYPE_CHECKING @@ -15,29 +15,23 @@ _DEFAULT_FAILED_REQUEST_STATUS_CODES, DidNotEnable, Integration, + _check_minimum_version, ) from sentry_sdk.integrations._asgi_common import _RootPathInPath from sentry_sdk.integrations._wsgi_common import ( DEFAULT_HTTP_METHODS_TO_CAPTURE, - HttpCodeRangeContainer, _is_json_content_type, request_body_within_bounds, ) from sentry_sdk.integrations.asgi import SentryAsgiMiddleware from sentry_sdk.scope import should_send_default_pii -from sentry_sdk.traces import StreamedSpan, get_current_span -from sentry_sdk.tracing import ( - SOURCE_FOR_STYLE, - TransactionSource, -) -from sentry_sdk.tracing_utils import has_span_streaming_enabled +from sentry_sdk.traces import SOURCE_FOR_STYLE, SegmentNameSource, Span from sentry_sdk.utils import ( AnnotatedValue, capture_internal_exceptions, ensure_integration_enabled, event_from_exception, has_data_collection_enabled, - nullcontext, parse_version, transaction_from_function, ) @@ -51,10 +45,9 @@ Dict, Optional, Tuple, - Union, ) - from sentry_sdk._types import Event, HttpStatusCodeRange + from sentry_sdk._types import Event try: import starlette from starlette import __version__ as STARLETTE_VERSION @@ -66,19 +59,13 @@ from starlette.middleware.authentication import ( AuthenticationMiddleware, ) + from starlette.middleware.exceptions import ExceptionMiddleware from starlette.requests import Request from starlette.routing import Match from starlette.types import ASGIApp, Receive, Send from starlette.types import Scope as StarletteScope except ImportError: - raise DidNotEnable("Starlette is not installed") - -try: - # Starlette 0.20 - from starlette.middleware.exceptions import ExceptionMiddleware -except ImportError: - # Startlette 0.19.1 - from starlette.exceptions import ExceptionMiddleware # type: ignore + raise DidNotEnable("Starlette is not installed or incompatible") try: # Optional dependency of Starlette to parse form data. @@ -113,7 +100,7 @@ class StarletteIntegration(Integration): def __init__( self, transaction_style: str = "url", - failed_request_status_codes: "Union[Set[int], list[HttpStatusCodeRange], None]" = _DEFAULT_FAILED_REQUEST_STATUS_CODES, + failed_request_status_codes: "Set[int]" = _DEFAULT_FAILED_REQUEST_STATUS_CODES, middleware_spans: bool = False, http_methods_to_capture: "tuple[str, ...]" = DEFAULT_HTTP_METHODS_TO_CAPTURE, ): @@ -126,33 +113,14 @@ def __init__( self.middleware_spans = middleware_spans self.http_methods_to_capture = tuple(map(str.upper, http_methods_to_capture)) - if isinstance(failed_request_status_codes, Set): - self.failed_request_status_codes: "Container[int]" = ( - failed_request_status_codes - ) - else: - warnings.warn( - "Passing a list or None for failed_request_status_codes is deprecated. " - "Please pass a set of int instead.", - DeprecationWarning, - stacklevel=2, - ) - - if failed_request_status_codes is None: - self.failed_request_status_codes = _DEFAULT_FAILED_REQUEST_STATUS_CODES - else: - self.failed_request_status_codes = HttpCodeRangeContainer( - failed_request_status_codes - ) + self.failed_request_status_codes: "Container[int]" = failed_request_status_codes @staticmethod def setup_once() -> None: version = parse_version(STARLETTE_VERSION) - + _check_minimum_version(StarletteIntegration, version) if version is None: - raise DidNotEnable( - "Unparsable Starlette version: {}".format(STARLETTE_VERSION) - ) + return patch_middlewares() # Starlette tolerates both starting with: @@ -190,7 +158,7 @@ async def _create_span_call( if ( server_span is not None and route_path is not None - and name_source == TransactionSource.ROUTE + and name_source == SegmentNameSource.ROUTE ): server_span.set_attribute(SPANDATA.HTTP_ROUTE, route_path) @@ -209,40 +177,27 @@ async def _create_span_call( return await old_call(app, scope, receive, send, **kwargs) middleware_name = app.__class__.__name__ - is_span_streaming_enabled = has_span_streaming_enabled(client.options) def _start_middleware_span(op: str, name: str) -> "Any": - if is_span_streaming_enabled: - if sentry_sdk.traces.get_current_span() is None: - return nullcontext() - return sentry_sdk.traces.start_span( - name=name, - attributes={ - "sentry.op": op, - "sentry.origin": StarletteIntegration.origin, - "middleware.name": middleware_name, - }, - ) + if sentry_sdk.get_current_span() is None: + return nullcontext() + return sentry_sdk.start_span( - op=op, name=name, - origin=StarletteIntegration.origin, + attributes={ + "sentry.op": op, + "sentry.origin": StarletteIntegration.origin, + "middleware.name": middleware_name, + }, ) - with _start_middleware_span( - op=OP.MIDDLEWARE_STARLETTE, name=middleware_name - ) as middleware_span: - if not is_span_streaming_enabled: - middleware_span.set_tag("starlette.middleware_name", middleware_name) - + with _start_middleware_span(op=OP.MIDDLEWARE_STARLETTE, name=middleware_name): # Creating spans for the "receive" callback async def _sentry_receive(*args: "Any", **kwargs: "Any") -> "Any": with _start_middleware_span( op=OP.MIDDLEWARE_STARLETTE_RECEIVE, name=getattr(receive, "__qualname__", str(receive)), - ) as span: - if not is_span_streaming_enabled: - span.set_tag("starlette.middleware_name", middleware_name) + ): return await receive(*args, **kwargs) receive_name = getattr(receive, "__name__", str(receive)) @@ -254,9 +209,7 @@ async def _sentry_send(*args: "Any", **kwargs: "Any") -> "Any": with _start_middleware_span( op=OP.MIDDLEWARE_STARLETTE_SEND, name=getattr(send, "__qualname__", str(send)), - ) as span: - if not is_span_streaming_enabled: - span.set_tag("starlette.middleware_name", middleware_name) + ): return await send(*args, **kwargs) send_name = getattr(send, "__name__", str(send)) @@ -559,7 +512,7 @@ async def _wrap_async_handler( if ( server_span is not None and route_path is not None - and name_source == TransactionSource.ROUTE + and name_source == SegmentNameSource.ROUTE ): server_span.set_attribute(SPANDATA.HTTP_ROUTE, route_path) @@ -574,14 +527,14 @@ async def _wrap_async_handler( sentry_scope = sentry_sdk.get_isolation_scope() extractor = StarletteRequestExtractor(request) - info = await extractor.extract_request_info() - def _make_request_event_processor( req: "Any", integration: "Any" ) -> "Callable[[Event, dict[str, Any]], Event]": def event_processor(event: "Event", hint: "Dict[str, Any]") -> "Event": # Add info from request to event request_info = event.get("request", {}) + + info = extractor.extract_request_info() if info: if "cookies" in info: request_info["cookies"] = info["cookies"] @@ -609,9 +562,9 @@ def event_processor(event: "Event", hint: "Dict[str, Any]") -> "Event": try: return await handler(*args, **kwargs) finally: - current_span = get_current_span() + current_span = sentry_sdk.get_current_span() - if type(current_span) is StreamedSpan: + if type(current_span) is Span: attach_request_data = True if has_data_collection_enabled(client.options): attach_request_data = ( @@ -654,20 +607,12 @@ def _sentry_sync_func(*args: "Any", **kwargs: "Any") -> "Any": if integration is None: return old_func(*args, **kwargs) - current_scope = sentry_sdk.get_current_scope() - - span_streaming = has_span_streaming_enabled(client.options) - if span_streaming: - current_span = current_scope.streamed_span + current_span = sentry_sdk.get_current_span() - if type(current_span) is StreamedSpan: - current_span._segment._update_active_thread() - elif current_scope.transaction is not None: - current_scope.transaction.update_active_thread() + if type(current_span) is Span: + current_span._segment._update_active_thread() sentry_scope = sentry_sdk.get_isolation_scope() - if sentry_scope.profile is not None: - sentry_scope.profile.update_active_thread_id() request = args[0] @@ -679,12 +624,12 @@ def _sentry_sync_func(*args: "Any", **kwargs: "Any") -> "Any": if ( server_span is not None and route_path is not None - and name_source == TransactionSource.ROUTE + and name_source == SegmentNameSource.ROUTE ): server_span.set_attribute(SPANDATA.HTTP_ROUTE, route_path) _set_transaction_name_and_source( - current_scope, + sentry_sdk.get_current_scope(), integration.transaction_style, endpoint=request.scope.get("endpoint"), route_path=route_path, @@ -794,7 +739,7 @@ def extract_cookies_from_request( return cookies - async def extract_request_info( + def extract_request_info( self: "StarletteRequestExtractor", ) -> "Optional[Dict[str, Any]]": client = sentry_sdk.get_client() @@ -814,7 +759,7 @@ async def extract_request_info( request_info["cookies"] = self.cookies() # If there is no body, just return the cookies - content_length = await self.content_length() + content_length = self.content_length() if not content_length: return request_info @@ -825,32 +770,30 @@ async def extract_request_info( request_info["data"] = AnnotatedValue.removed_because_over_size_limit() return request_info - # Add JSON body, if it is a JSON request - json = await self.json() - if json: - request_info["data"] = json + if hasattr(self.request, "_json"): + request_info["data"] = self.request._json return request_info - # Add form as key/value pairs, if request has form data - form = await self.form() - if form: - form_data = {} - for key, val in form.items(): - is_file = isinstance(val, UploadFile) - form_data[key] = ( - val - if not is_file - else AnnotatedValue.removed_because_raw_data() - ) + formdata_body = getattr(self.request, "_form", None) + if formdata_body is None and hasattr(self.request, "_body"): + # Raw data, do not add body just an annotation + request_info["data"] = AnnotatedValue.removed_because_raw_data() + return request_info - request_info["data"] = form_data + if formdata_body is None: return request_info - # Raw data, do not add body just an annotation - request_info["data"] = AnnotatedValue.removed_because_raw_data() + form_data = {} + for key, val in formdata_body.items(): + is_file = isinstance(val, UploadFile) + form_data[key] = ( + val if not is_file else AnnotatedValue.removed_because_raw_data() + ) + + request_info["data"] = form_data return request_info - async def content_length(self: "StarletteRequestExtractor") -> "Optional[int]": + def content_length(self: "StarletteRequestExtractor") -> "Optional[int]": if "content-length" in self.request.headers: return int(self.request.headers["content-length"]) @@ -885,22 +828,22 @@ async def json(self: "StarletteRequestExtractor") -> "Optional[Dict[str, Any]]": def _http_route_and_source_from_router( scope: "StarletteScope", -) -> "Tuple[Optional[str], TransactionSource]": +) -> "Tuple[Optional[str], SegmentNameSource]": router = scope.get("router") if not router: - return None, TransactionSource.ROUTE + return None, SegmentNameSource.ROUTE for route in router.routes: match = route.matches(scope) if match[0] == Match.FULL: try: - return route.path, TransactionSource.ROUTE + return route.path, SegmentNameSource.ROUTE except AttributeError: # Host routes have no path template, so fall back to the # concrete request path and classify it as a URL. - return scope.get("path"), TransactionSource.URL + return scope.get("path"), SegmentNameSource.URL - return None, TransactionSource.ROUTE + return None, SegmentNameSource.ROUTE def _set_transaction_name_and_source( @@ -908,7 +851,7 @@ def _set_transaction_name_and_source( transaction_style: str, endpoint: "Optional[Callable[..., Any]]", route_path: "Optional[str]", - name_source: "TransactionSource", + name_source: "SegmentNameSource", ) -> None: name = None source = SOURCE_FOR_STYLE[transaction_style] @@ -921,7 +864,7 @@ def _set_transaction_name_and_source( if name is None: name = _DEFAULT_TRANSACTION_NAME - source = TransactionSource.ROUTE + source = SegmentNameSource.ROUTE scope.set_transaction_name(name, source=source) @@ -930,14 +873,14 @@ def _get_transaction_from_middleware( app: "Any", integration: "StarletteIntegration", route_path: "Optional[str]", - name_source: "TransactionSource", + name_source: "SegmentNameSource", ) -> "Tuple[Optional[str], Optional[str]]": name = None source = None if integration.transaction_style == "endpoint": name = transaction_from_function(app.__class__) - source = TransactionSource.COMPONENT + source = SegmentNameSource.COMPONENT elif integration.transaction_style == "url": name, source = route_path, name_source diff --git a/sentry_sdk/integrations/starlite.py b/sentry_sdk/integrations/starlite.py index 398412c762..cc5fad4158 100644 --- a/sentry_sdk/integrations/starlite.py +++ b/sentry_sdk/integrations/starlite.py @@ -1,18 +1,18 @@ +from contextlib import nullcontext from copy import deepcopy import sentry_sdk from sentry_sdk.consts import OP, SPANDATA from sentry_sdk.data_collection import _apply_key_value_collection_filtering -from sentry_sdk.integrations import DidNotEnable, Integration +from sentry_sdk.integrations import DidNotEnable, Integration, _check_minimum_version from sentry_sdk.integrations.asgi import SentryAsgiMiddleware from sentry_sdk.scope import should_send_default_pii -from sentry_sdk.tracing import SOURCE_FOR_STYLE, TransactionSource -from sentry_sdk.tracing_utils import has_span_streaming_enabled +from sentry_sdk.traces import SOURCE_FOR_STYLE, SegmentNameSource from sentry_sdk.utils import ( ensure_integration_enabled, event_from_exception, has_data_collection_enabled, - nullcontext, + package_version, transaction_from_function, ) @@ -29,7 +29,7 @@ is_async_callable, ) except ImportError: - raise DidNotEnable("Starlite is not installed") + raise DidNotEnable("Starlite is not installed or incompatible") from typing import TYPE_CHECKING @@ -64,6 +64,9 @@ class StarliteIntegration(Integration): @staticmethod def setup_once() -> None: + version = package_version("starlite") + _check_minimum_version(StarliteIntegration, version) + patch_app_init() patch_middlewares() patch_http_route_handle() @@ -75,7 +78,6 @@ def __init__( ) -> None: super().__init__( app=app, - unsafe_context_data=False, transaction_style="endpoint", mechanism_type="asgi", span_origin=span_origin, @@ -150,32 +152,21 @@ async def _create_span_call( return await old_call(self, scope, receive, send) middleware_name = self.__class__.__name__ - is_span_streaming_enabled = has_span_streaming_enabled(client.options) def _start_middleware_span(op: str, name: str) -> "Any": - if is_span_streaming_enabled: - if sentry_sdk.traces.get_current_span() is None: - return nullcontext() - return sentry_sdk.traces.start_span( - name=name, - attributes={ - "sentry.op": op, - "sentry.origin": StarliteIntegration.origin, - SPANDATA.MIDDLEWARE_NAME: middleware_name, - }, - ) + if sentry_sdk.get_current_span() is None: + return nullcontext() + return sentry_sdk.start_span( - op=op, name=name, - origin=StarliteIntegration.origin, + attributes={ + "sentry.op": op, + "sentry.origin": StarliteIntegration.origin, + SPANDATA.MIDDLEWARE_NAME: middleware_name, + }, ) - with _start_middleware_span( - op=OP.MIDDLEWARE_STARLITE, name=middleware_name - ) as middleware_span: - if not is_span_streaming_enabled: - middleware_span.set_tag("starlite.middleware_name", middleware_name) - + with _start_middleware_span(op=OP.MIDDLEWARE_STARLITE, name=middleware_name): # Creating spans for the "receive" callback async def _sentry_receive( *args: "Any", **kwargs: "Any" @@ -185,9 +176,7 @@ async def _sentry_receive( with _start_middleware_span( op=OP.MIDDLEWARE_STARLITE_RECEIVE, name=getattr(receive, "__qualname__", str(receive)), - ) as span: - if not is_span_streaming_enabled: - span.set_tag("starlite.middleware_name", middleware_name) + ): return await receive(*args, **kwargs) receive_name = getattr(receive, "__name__", str(receive)) @@ -201,9 +190,7 @@ async def _sentry_send(message: "Message") -> None: with _start_middleware_span( op=OP.MIDDLEWARE_STARLITE_SEND, name=getattr(send, "__qualname__", str(send)), - ) as span: - if not is_span_streaming_enabled: - span.set_tag("starlite.middleware_name", middleware_name) + ): return await send(message) send_name = getattr(send, "__name__", str(send)) @@ -260,7 +247,7 @@ async def handle_wrapper( if not name: name = _DEFAULT_TRANSACTION_NAME - source = TransactionSource.ROUTE + source = SegmentNameSource.ROUTE sentry_sdk.set_transaction_name(name, source) sentry_scope.set_transaction_name(name, source) diff --git a/sentry_sdk/integrations/statsig.py b/sentry_sdk/integrations/statsig.py index 746e09b36f..7ec3b2cabc 100644 --- a/sentry_sdk/integrations/statsig.py +++ b/sentry_sdk/integrations/statsig.py @@ -9,7 +9,7 @@ from statsig import statsig as statsig_module from statsig.version import __version__ as STATSIG_VERSION except ImportError: - raise DidNotEnable("statsig is not installed") + raise DidNotEnable("statsig is not installed or incompatible") if TYPE_CHECKING: from statsig.statsig_user import StatsigUser diff --git a/sentry_sdk/integrations/stdlib.py b/sentry_sdk/integrations/stdlib.py index 02f8b245f7..b6ebd83ad4 100644 --- a/sentry_sdk/integrations/stdlib.py +++ b/sentry_sdk/integrations/stdlib.py @@ -9,14 +9,12 @@ from sentry_sdk.consts import _SENTRY_HEADER_NAMES, OP, SPANDATA from sentry_sdk.integrations import Integration from sentry_sdk.scope import add_global_event_processor -from sentry_sdk.traces import StreamedSpan -from sentry_sdk.tracing import SENTRY_TRACE_HEADER_NAME, Span +from sentry_sdk.traces import SENTRY_TRACE_HEADER_NAME, Span from sentry_sdk.tracing_utils import ( EnvironHeaders, add_http_breadcrumb, add_http_request_source, - get_url_attributes, - has_span_streaming_enabled, + get_url_attributes_legacy, should_propagate_trace, ) from sentry_sdk.utils import ( @@ -32,7 +30,7 @@ ) if TYPE_CHECKING: - from typing import Any, Callable, Dict, List, Optional, Set, Union + from typing import Any, Callable, Dict, List, Optional, Set from sentry_sdk._types import Event, Hint @@ -70,15 +68,10 @@ def add_python_runtime_context( return event -def _complete_span(span: "Union[Span, StreamedSpan]") -> None: - if isinstance(span, StreamedSpan): - with capture_internal_exceptions(): - add_http_request_source(span) - span.end() - else: - span.finish() - with capture_internal_exceptions(): - add_http_request_source(span) +def _complete_span(span: "Span") -> None: + with capture_internal_exceptions(): + add_http_request_source(span) + span.end() def _get_wrapped_putheader( @@ -278,66 +271,36 @@ def putrequest( with capture_internal_exceptions(): parsed_url = parse_url(real_url, sanitize=False) - span_streaming = has_span_streaming_enabled(client.options) - span: "Union[Span, StreamedSpan, None]" = None + span: "Optional[Span]" = None breadcrumb: "dict[str, Any]" = {} - if span_streaming: - url_attributes = get_url_attributes(client, parsed_url) - - breadcrumb[SPANDATA.HTTP_REQUEST_METHOD] = method - breadcrumb.update(url_attributes) - - if sentry_sdk.traces.get_current_span() is not None: - span = sentry_sdk.traces.start_span( - name="%s %s" - % ( - method, - parsed_url.url if parsed_url else SENSITIVE_DATA_SUBSTITUTE, - ), - attributes={ - "sentry.origin": "auto.http.stdlib.httplib", - "sentry.op": OP.HTTP_CLIENT, - SPANDATA.HTTP_REQUEST_METHOD: method, - }, - ) + url_attributes = get_url_attributes_legacy(client, parsed_url) - for key, value in url_attributes.items(): - span.set_attribute(key, value) + breadcrumb[SPANDATA.HTTP_REQUEST_METHOD] = method + breadcrumb.update(url_attributes) - set_on_span = span.set_attribute - - else: + if sentry_sdk.get_current_span() is not None: span = sentry_sdk.start_span( - op=OP.HTTP_CLIENT, name="%s %s" - % (method, parsed_url.url if parsed_url else SENSITIVE_DATA_SUBSTITUTE), - origin="auto.http.stdlib.httplib", + % ( + method, + parsed_url.url if parsed_url else SENSITIVE_DATA_SUBSTITUTE, + ), + attributes={ + "sentry.origin": "auto.http.stdlib.httplib", + "sentry.op": OP.HTTP_CLIENT, + SPANDATA.HTTP_REQUEST_METHOD: method, + }, ) - span.set_data(SPANDATA.HTTP_METHOD, method) - breadcrumb[SPANDATA.HTTP_METHOD] = method - - if parsed_url is not None: - span.set_data(SPANDATA.HTTP_FRAGMENT, parsed_url.fragment) - span.set_data("url", parsed_url.url) - span.set_data(SPANDATA.HTTP_QUERY, parsed_url.query) - - breadcrumb.update( - { - SPANDATA.HTTP_FRAGMENT: parsed_url.fragment, - "url": parsed_url.url, - SPANDATA.HTTP_QUERY: parsed_url.query, - } - ) - - set_on_span = span.set_data + for key, value in url_attributes.items(): + span.set_attribute(key, value) # for proxies, these point to the proxy host/port if tunnel_host: if span: - set_on_span(SPANDATA.NETWORK_PEER_ADDRESS, self.host) - set_on_span(SPANDATA.NETWORK_PEER_PORT, self.port) + span.set_attribute(SPANDATA.NETWORK_PEER_ADDRESS, self.host) + span.set_attribute(SPANDATA.NETWORK_PEER_PORT, self.port) breadcrumb.update( { @@ -401,14 +364,8 @@ def getresponse(self: "HTTPConnection", *args: "Any", **kwargs: "Any") -> "Any": add_http_breadcrumb(status_code, breadcrumb) return rv - if isinstance(span, StreamedSpan): - span.status = "error" if status_code >= 400 else "ok" - span.set_attribute(SPANDATA.HTTP_STATUS_CODE, status_code) - elif isinstance(span, Span): - span.set_http_status(status_code) - span.set_data("reason", rv.reason) - if breadcrumb: - breadcrumb["reason"] = rv.reason + span.status = "error" if status_code >= 400 else "ok" + span.set_attribute(SPANDATA.HTTP_STATUS_CODE, status_code) # getresponse doesn't include actually reading the response body. This # is done in read(). So if the metadata/headers suggest there's a body to @@ -531,27 +488,16 @@ def sentry_patched_popen_init( data={"subprocess.cwd": cwd} if cwd else {}, ) - span_streaming = has_span_streaming_enabled(sentry_sdk.get_client().options) - span: "Union[Span, StreamedSpan]" - if span_streaming: - if sentry_sdk.traces.get_current_span() is None: - return old_popen_init(self, *a, **kw) + if sentry_sdk.get_current_span() is None: + return old_popen_init(self, *a, **kw) - span = sentry_sdk.traces.start_span( - name=description, - attributes={ - "sentry.op": OP.SUBPROCESS, - "sentry.origin": "auto.subprocess.stdlib.subprocess", - }, - ) - else: - span = sentry_sdk.start_span( - op=OP.SUBPROCESS, - name=description, - origin="auto.subprocess.stdlib.subprocess", - ) - - with span: + with sentry_sdk.start_span( + name=description, + attributes={ + "sentry.op": OP.SUBPROCESS, + "sentry.origin": "auto.subprocess.stdlib.subprocess", + }, + ) as span: for k, v in sentry_sdk.get_current_scope().iter_trace_propagation_headers( span=span ): @@ -565,15 +511,9 @@ def sentry_patched_popen_init( ) env["SUBPROCESS_" + k.upper().replace("-", "_")] = v - if cwd and isinstance(span, Span): - span.set_data("subprocess.cwd", cwd) - rv = old_popen_init(self, *a, **kw) - if isinstance(span, StreamedSpan): - span.set_attribute(SPANDATA.PROCESS_PID, self.pid) - else: - span.set_tag("subprocess.pid", self.pid) + span.set_attribute(SPANDATA.PROCESS_PID, self.pid) return rv @@ -585,26 +525,17 @@ def sentry_patched_popen_init( def sentry_patched_popen_wait( self: "subprocess.Popen[Any]", *a: "Any", **kw: "Any" ) -> "Any": - span_streaming = has_span_streaming_enabled(sentry_sdk.get_client().options) - if span_streaming: - if sentry_sdk.traces.get_current_span() is None: - return old_popen_wait(self, *a, **kw) - with sentry_sdk.traces.start_span( - name=OP.SUBPROCESS_WAIT, - attributes={ - "sentry.op": OP.SUBPROCESS_WAIT, - "sentry.origin": "auto.subprocess.stdlib.subprocess", - }, - ) as span: - span.set_attribute(SPANDATA.PROCESS_PID, self.pid) - return old_popen_wait(self, *a, **kw) - else: - with sentry_sdk.start_span( - op=OP.SUBPROCESS_WAIT, - origin="auto.subprocess.stdlib.subprocess", - ) as span: - span.set_tag("subprocess.pid", self.pid) - return old_popen_wait(self, *a, **kw) + if sentry_sdk.get_current_span() is None: + return old_popen_wait(self, *a, **kw) + with sentry_sdk.start_span( + name=OP.SUBPROCESS_WAIT, + attributes={ + "sentry.op": OP.SUBPROCESS_WAIT, + "sentry.origin": "auto.subprocess.stdlib.subprocess", + }, + ) as span: + span.set_attribute(SPANDATA.PROCESS_PID, self.pid) + return old_popen_wait(self, *a, **kw) subprocess.Popen.wait = sentry_patched_popen_wait # type: ignore @@ -614,26 +545,17 @@ def sentry_patched_popen_wait( def sentry_patched_popen_communicate( self: "subprocess.Popen[Any]", *a: "Any", **kw: "Any" ) -> "Any": - span_streaming = has_span_streaming_enabled(sentry_sdk.get_client().options) - if span_streaming: - if sentry_sdk.traces.get_current_span() is None: - return old_popen_communicate(self, *a, **kw) - with sentry_sdk.traces.start_span( - name=OP.SUBPROCESS_COMMUNICATE, - attributes={ - "sentry.op": OP.SUBPROCESS_COMMUNICATE, - "sentry.origin": "auto.subprocess.stdlib.subprocess", - }, - ) as span: - span.set_attribute(SPANDATA.PROCESS_PID, self.pid) - return old_popen_communicate(self, *a, **kw) - else: - with sentry_sdk.start_span( - op=OP.SUBPROCESS_COMMUNICATE, - origin="auto.subprocess.stdlib.subprocess", - ) as span: - span.set_tag("subprocess.pid", self.pid) - return old_popen_communicate(self, *a, **kw) + if sentry_sdk.get_current_span() is None: + return old_popen_communicate(self, *a, **kw) + with sentry_sdk.start_span( + name=OP.SUBPROCESS_COMMUNICATE, + attributes={ + "sentry.op": OP.SUBPROCESS_COMMUNICATE, + "sentry.origin": "auto.subprocess.stdlib.subprocess", + }, + ) as span: + span.set_attribute(SPANDATA.PROCESS_PID, self.pid) + return old_popen_communicate(self, *a, **kw) subprocess.Popen.communicate = sentry_patched_popen_communicate # type: ignore diff --git a/sentry_sdk/integrations/strawberry.py b/sentry_sdk/integrations/strawberry.py index a3fa59b489..da3e2f0b63 100644 --- a/sentry_sdk/integrations/strawberry.py +++ b/sentry_sdk/integrations/strawberry.py @@ -1,33 +1,21 @@ import functools -import hashlib -import warnings from inspect import isawaitable import sentry_sdk from sentry_sdk.consts import OP from sentry_sdk.integrations import DidNotEnable, Integration, _check_minimum_version -from sentry_sdk.integrations.logging import ignore_logger +from sentry_sdk.integrations.logging import ignore_logger_for_events from sentry_sdk.scope import should_send_default_pii from sentry_sdk.traces import SegmentNameSource -from sentry_sdk.tracing import Span, TransactionSource -from sentry_sdk.tracing_utils import StreamedSpan, has_span_streaming_enabled from sentry_sdk.utils import ( capture_internal_exceptions, ensure_integration_enabled, event_from_exception, has_data_collection_enabled, + logger, package_version, ) -try: - from functools import cached_property -except ImportError: - # The strawberry integration requires Python 3.8+. functools.cached_property - # was added in 3.8, so this check is technically not needed, but since this - # is an auto-enabling integration, we might get to executing this import in - # lower Python versions, so we need to deal with it. - raise DidNotEnable("strawberry-graphql integration requires Python 3.8 or newer") - try: from strawberry import Schema from strawberry.extensions import SchemaExtension @@ -36,7 +24,7 @@ ) from strawberry.http import async_base_view, sync_base_view except ImportError: - raise DidNotEnable("strawberry-graphql is not installed") + raise DidNotEnable("strawberry-graphql is not installed or incompatible") try: from strawberry.extensions.tracing import ( @@ -61,7 +49,7 @@ from sentry_sdk._types import Event, EventProcessor -ignore_logger("strawberry.execution") +ignore_logger_for_events("strawberry.execution") class StrawberryIntegration(Integration): @@ -107,9 +95,8 @@ def _sentry_patched_schema_init( should_use_async_extension = _guess_if_using_async(extensions) if should_use_async_extension is None: - warnings.warn( + logger.warning( "Assuming strawberry is running sync. If not, initialize the integration as StrawberryIntegration(async_execution=True).", - stacklevel=2, ) should_use_async_extension = False @@ -142,18 +129,6 @@ def __init__( if execution_context: self.execution_context = execution_context - @cached_property - def _resource_name(self) -> str: - query_hash = self.hash_query(self.execution_context.query) # type: ignore - - if self.execution_context.operation_name: - return "{}:{}".format(self.execution_context.operation_name, query_hash) - - return query_hash - - def hash_query(self, query: str) -> str: - return hashlib.md5(query.encode("utf-8")).hexdigest() - def on_operation(self) -> "Generator[None, None, None]": operation_name = self.execution_context.operation_name @@ -187,138 +162,81 @@ def on_operation(self) -> "Generator[None, None, None]": scope.add_event_processor(event_processor) client = sentry_sdk.get_client() - is_span_streaming_enabled = has_span_streaming_enabled(client.options) - if is_span_streaming_enabled: - if sentry_sdk.traces.get_current_span() is None: - yield - return - - additional_attributes: "dict[str, Any]" = {} - if has_data_collection_enabled(client.options): - if client.options["data_collection"]["graphql"]["document"]: - additional_attributes["graphql.document"] = ( - self.execution_context.query - ) - elif should_send_default_pii(): - additional_attributes["graphql.document"] = self.execution_context.query + if sentry_sdk.get_current_span() is None: + yield + return - if operation_name: - additional_attributes["graphql.operation.name"] = operation_name - - graphql_span = sentry_sdk.traces.start_span( - name=description, - attributes={ - "sentry.origin": StrawberryIntegration.origin, - "sentry.op": op, - "graphql.operation.type": operation_type, - **additional_attributes, - }, - ) - else: - graphql_span = sentry_sdk.start_span( - op=op, - name=description, - origin=StrawberryIntegration.origin, - ) - graphql_span.__enter__() + additional_attributes: "dict[str, Any]" = {} + if has_data_collection_enabled(client.options): + if client.options["data_collection"]["graphql"]["document"]: + additional_attributes["graphql.document"] = self.execution_context.query - if type(graphql_span) is Span: - if has_data_collection_enabled(client.options): - if client.options["data_collection"]["graphql"]["document"]: - graphql_span.set_data( - "graphql.document", self.execution_context.query - ) - elif should_send_default_pii(): - graphql_span.set_data("graphql.document", self.execution_context.query) + elif should_send_default_pii(): + additional_attributes["graphql.document"] = self.execution_context.query - graphql_span.set_data("graphql.operation.type", operation_type) - graphql_span.set_data("graphql.operation.name", operation_name) - # This attribute is being removed in streamed spans - graphql_span.set_data("graphql.resource_name", self._resource_name) + if operation_name: + additional_attributes["graphql.operation.name"] = operation_name + + graphql_span = sentry_sdk.start_span( + name=description, + attributes={ + "sentry.origin": StrawberryIntegration.origin, + "sentry.op": op, + "graphql.operation.type": operation_type, + **additional_attributes, + }, + ) yield - if type(graphql_span) is StreamedSpan: - if self.execution_context.operation_name: - segment = graphql_span._segment - segment.set_attribute( - "sentry.segment.name.source", SegmentNameSource.COMPONENT - ) - segment.set_attribute("sentry.op", op) - segment.name = self.execution_context.operation_name - elif isinstance(graphql_span, Span): - transaction = graphql_span.containing_transaction - if transaction and self.execution_context.operation_name: - transaction.name = self.execution_context.operation_name - transaction.source = TransactionSource.COMPONENT - transaction.op = op + if self.execution_context.operation_name: + segment = graphql_span._segment + segment.set_attribute( + "sentry.segment.name.source", SegmentNameSource.COMPONENT + ) + segment.set_attribute("sentry.op", op) + segment.name = self.execution_context.operation_name - graphql_span.__exit__(None, None, None) + graphql_span.end() def on_validate(self) -> "Generator[None, None, None]": - client = sentry_sdk.get_client() - is_span_streaming_enabled = has_span_streaming_enabled(client.options) - - if is_span_streaming_enabled: - if sentry_sdk.traces.get_current_span() is None: - yield - return - - validation_span = sentry_sdk.traces.start_span( - name="validation", - attributes={ - "sentry.op": OP.GRAPHQL_VALIDATE, - "sentry.origin": StrawberryIntegration.origin, - }, - ) - else: - validation_span = sentry_sdk.start_span( - op=OP.GRAPHQL_VALIDATE, - name="validation", - origin=StrawberryIntegration.origin, - ) + if sentry_sdk.get_current_span() is None: + yield + return + + validation_span = sentry_sdk.start_span( + name="validation", + attributes={ + "sentry.op": OP.GRAPHQL_VALIDATE, + "sentry.origin": StrawberryIntegration.origin, + }, + ) # If an exception is raised during validation, we still need to close the span try: yield finally: - if isinstance(validation_span, StreamedSpan): - validation_span.end() - else: - validation_span.finish() + validation_span.end() def on_parse(self) -> "Generator[None, None, None]": - client = sentry_sdk.get_client() - is_span_streaming_enabled = has_span_streaming_enabled(client.options) - - if is_span_streaming_enabled: - if sentry_sdk.traces.get_current_span() is None: - yield - return - - parsing_span = sentry_sdk.traces.start_span( - name="parsing", - attributes={ - "sentry.op": OP.GRAPHQL_PARSE, - "sentry.origin": StrawberryIntegration.origin, - }, - ) - else: - parsing_span = sentry_sdk.start_span( - op=OP.GRAPHQL_PARSE, - name="parsing", - origin=StrawberryIntegration.origin, - ) + if sentry_sdk.get_current_span() is None: + yield + return + + parsing_span = sentry_sdk.start_span( + name="parsing", + attributes={ + "sentry.op": OP.GRAPHQL_PARSE, + "sentry.origin": StrawberryIntegration.origin, + }, + ) # If an exception is raised during parsing, we still need to close the span try: yield finally: - if isinstance(parsing_span, StreamedSpan): - parsing_span.end() - else: - parsing_span.finish() + parsing_span.end() def should_skip_tracing( self, @@ -355,31 +273,16 @@ async def resolve( field_path = "{}.{}".format(info.parent_type, info.field_name) - client = sentry_sdk.get_client() - is_span_streaming_enabled = has_span_streaming_enabled(client.options) - if is_span_streaming_enabled: - if sentry_sdk.traces.get_current_span() is None: - return await self._resolve(_next, root, info, *args, **kwargs) - - with sentry_sdk.traces.start_span( - name=f"resolving {field_path}", - attributes={ - "sentry.origin": StrawberryIntegration.origin, - "sentry.op": OP.GRAPHQL_RESOLVE, - }, - ): - return await self._resolve(_next, root, info, *args, **kwargs) + if sentry_sdk.get_current_span() is None: + return await self._resolve(_next, root, info, *args, **kwargs) with sentry_sdk.start_span( - op=OP.GRAPHQL_RESOLVE, - name="resolving {}".format(field_path), - origin=StrawberryIntegration.origin, - ) as span: - span.set_data("graphql.field_name", info.field_name) - span.set_data("graphql.parent_type", info.parent_type.name) - span.set_data("graphql.field_path", field_path) - span.set_data("graphql.path", ".".join(map(str, info.path.as_list()))) - + name=f"resolving {field_path}", + attributes={ + "sentry.origin": StrawberryIntegration.origin, + "sentry.op": OP.GRAPHQL_RESOLVE, + }, + ): return await self._resolve(_next, root, info, *args, **kwargs) @@ -397,31 +300,16 @@ def resolve( field_path = "{}.{}".format(info.parent_type, info.field_name) - client = sentry_sdk.get_client() - is_span_streaming_enabled = has_span_streaming_enabled(client.options) - if is_span_streaming_enabled: - if sentry_sdk.traces.get_current_span() is None: - return _next(root, info, *args, **kwargs) - - with sentry_sdk.traces.start_span( - name=f"resolving {field_path}", - attributes={ - "sentry.origin": StrawberryIntegration.origin, - "sentry.op": OP.GRAPHQL_RESOLVE, - }, - ): - return _next(root, info, *args, **kwargs) + if sentry_sdk.get_current_span() is None: + return _next(root, info, *args, **kwargs) with sentry_sdk.start_span( - op=OP.GRAPHQL_RESOLVE, - name="resolving {}".format(field_path), - origin=StrawberryIntegration.origin, - ) as span: - span.set_data("graphql.field_name", info.field_name) - span.set_data("graphql.parent_type", info.parent_type.name) - span.set_data("graphql.field_path", field_path) - span.set_data("graphql.path", ".".join(map(str, info.path.as_list()))) - + name=f"resolving {field_path}", + attributes={ + "sentry.origin": StrawberryIntegration.origin, + "sentry.op": OP.GRAPHQL_RESOLVE, + }, + ): return _next(root, info, *args, **kwargs) diff --git a/sentry_sdk/integrations/threading.py b/sentry_sdk/integrations/threading.py index f3ba046332..3c299deef0 100644 --- a/sentry_sdk/integrations/threading.py +++ b/sentry_sdk/integrations/threading.py @@ -1,5 +1,4 @@ import sys -import warnings from concurrent.futures import Future, ThreadPoolExecutor from functools import wraps from threading import Thread, current_thread @@ -27,23 +26,9 @@ class ThreadingIntegration(Integration): identifier = "threading" - def __init__( - self, propagate_hub: "Optional[bool]" = None, propagate_scope: bool = True - ) -> None: - if propagate_hub is not None: - logger.warning( - "Deprecated: propagate_hub is deprecated. This will be removed in the future." - ) - - # Note: propagate_hub did not have any effect on propagation of scope data - # scope data was always propagated no matter what the value of propagate_hub was - # This is why the default for propagate_scope is True - + def __init__(self, propagate_scope: bool = True) -> None: self.propagate_scope = propagate_scope - if propagate_hub is not None: - self.propagate_scope = propagate_hub - @staticmethod def setup_once() -> None: old_start = Thread.start @@ -77,12 +62,11 @@ def sentry_start(self: "Thread", *a: "Any", **kw: "Any") -> "Any": if integration.propagate_scope: if is_async_emulated_with_threads: - warnings.warn( + logger.warning( "There is a known issue with Django channels 2.x and 3.x when using Python 3.8 or older. " "(Async support is emulated using threads and some Sentry data may be leaked between those threads.) " "Please either upgrade to Django channels 4.0+, use Django's async features " "available in Django 3.1+ instead of Django channels, or upgrade to Python 3.9+.", - stacklevel=2, ) isolation_scope = sentry_sdk.get_isolation_scope() current_scope = sentry_sdk.get_current_scope() diff --git a/sentry_sdk/integrations/tornado.py b/sentry_sdk/integrations/tornado.py index d0be7fceb0..0dba1f8e46 100644 --- a/sentry_sdk/integrations/tornado.py +++ b/sentry_sdk/integrations/tornado.py @@ -1,9 +1,7 @@ import contextlib import weakref -from inspect import iscoroutinefunction import sentry_sdk -from sentry_sdk.api import continue_trace from sentry_sdk.consts import OP, SPANDATA from sentry_sdk.data_collection import _apply_data_collection_filtering_to_query_string from sentry_sdk.integrations import DidNotEnable, Integration, _check_minimum_version @@ -13,14 +11,10 @@ _is_json_content_type, request_body_within_bounds, ) -from sentry_sdk.integrations.logging import ignore_logger +from sentry_sdk.integrations.logging import ignore_logger_for_events from sentry_sdk.scope import should_send_default_pii -from sentry_sdk.traces import SegmentNameSource, StreamedSpan -from sentry_sdk.tracing import TransactionSource -from sentry_sdk.tracing_utils import has_span_streaming_enabled +from sentry_sdk.traces import SegmentNameSource from sentry_sdk.utils import ( - CONTEXTVARS_ERROR_MESSAGE, - HAS_REAL_CONTEXTVARS, AnnotatedValue, capture_internal_exceptions, ensure_integration_enabled, @@ -32,18 +26,16 @@ try: from tornado import version_info as TORNADO_VERSION - from tornado.gen import coroutine from tornado.web import HTTPError, RequestHandler except ImportError: - raise DidNotEnable("Tornado not installed") + raise DidNotEnable("Tornado not installed or incompatible") from typing import TYPE_CHECKING if TYPE_CHECKING: - from typing import Any, Callable, ContextManager, Dict, Generator, Optional, Union + from typing import Any, Callable, Dict, Generator, Optional, Union from sentry_sdk._types import Event, EventProcessor - from sentry_sdk.tracing import Span class TornadoIntegration(Integration): @@ -54,38 +46,15 @@ class TornadoIntegration(Integration): def setup_once() -> None: _check_minimum_version(TornadoIntegration, TORNADO_VERSION) - if not HAS_REAL_CONTEXTVARS: - # Tornado is async. We better have contextvars or we're going to leak - # state between requests. - raise DidNotEnable( - "The tornado integration for Sentry requires Python 3.7+ or the aiocontextvars package" - + CONTEXTVARS_ERROR_MESSAGE - ) - - ignore_logger("tornado.access") + ignore_logger_for_events("tornado.access") old_execute = RequestHandler._execute - awaitable = iscoroutinefunction(old_execute) - - if awaitable: - # Starting Tornado 6 RequestHandler._execute method is a standard Python coroutine (async/await) - # In that case our method should be a coroutine function too - async def sentry_execute_request_handler( - self: "RequestHandler", *args: "Any", **kwargs: "Any" - ) -> "Any": - with _handle_request_impl(self): - return await old_execute(self, *args, **kwargs) - - else: - - @coroutine # type: ignore - def sentry_execute_request_handler( - self: "RequestHandler", *args: "Any", **kwargs: "Any" - ) -> "Any": - with _handle_request_impl(self): - result = yield from old_execute(self, *args, **kwargs) - return result + async def sentry_execute_request_handler( + self: "RequestHandler", *args: "Any", **kwargs: "Any" + ) -> "Any": + with _handle_request_impl(self): + return await old_execute(self, *args, **kwargs) RequestHandler._execute = sentry_execute_request_handler @@ -118,7 +87,6 @@ def _handle_request_impl(self: "RequestHandler") -> "Generator[None, None, None] weak_handler = weakref.ref(self) client = sentry_sdk.get_client() - is_span_streaming_enabled = has_span_streaming_enabled(client.options) with sentry_sdk.isolation_scope() as scope: headers = self.request.headers @@ -127,75 +95,49 @@ def _handle_request_impl(self: "RequestHandler") -> "Generator[None, None, None] processor = _make_event_processor(weak_handler) scope.add_event_processor(processor) - span_ctx: "ContextManager[Union[Span, StreamedSpan, None]]" - - if is_span_streaming_enabled: - sentry_sdk.traces.continue_trace(dict(headers)) - scope.set_custom_sampling_context({"tornado_request": self.request}) + sentry_sdk.continue_trace(dict(headers)) + scope.set_custom_sampling_context({"tornado_request": self.request}) - if self.request.remote_ip: - if has_data_collection_enabled(client.options): - if client.options["data_collection"]["user_info"]: - scope.set_attribute( - SPANDATA.USER_IP_ADDRESS, self.request.remote_ip - ) - elif should_send_default_pii(): + if self.request.remote_ip: + if has_data_collection_enabled(client.options): + if client.options["data_collection"]["user_info"]: scope.set_attribute( SPANDATA.USER_IP_ADDRESS, self.request.remote_ip ) - - span_ctx = sentry_sdk.traces.start_span( - name=_DEFAULT_ROOT_SPAN_NAME, - attributes={ - "sentry.op": OP.HTTP_SERVER, - "sentry.origin": TornadoIntegration.origin, - "sentry.segment.name.source": SegmentNameSource.ROUTE, - }, - parent_span=None, - ) - else: - transaction = continue_trace( - headers, - op=OP.HTTP_SERVER, - # Like with all other integrations, this is our - # fallback transaction in case there is no route. - # sentry_urldispatcher_resolve is responsible for - # setting a transaction name later. - name=_DEFAULT_ROOT_SPAN_NAME, - source=TransactionSource.ROUTE, - origin=TornadoIntegration.origin, - ) - span_ctx = sentry_sdk.start_transaction( - transaction, - custom_sampling_context={"tornado_request": self.request}, - ) - - with span_ctx as span: + elif should_send_default_pii(): + scope.set_attribute(SPANDATA.USER_IP_ADDRESS, self.request.remote_ip) + + with sentry_sdk.start_span( + name=_DEFAULT_ROOT_SPAN_NAME, + attributes={ + "sentry.op": OP.HTTP_SERVER, + "sentry.origin": TornadoIntegration.origin, + "sentry.segment.name.source": SegmentNameSource.ROUTE, + }, + parent_span=None, + ) as span: try: yield finally: - if type(span) is StreamedSpan: - with capture_internal_exceptions(): - for attr, value in _get_request_attributes( - self.request - ).items(): - span.set_attribute(attr, value) - - with capture_internal_exceptions(): - method = getattr(self, self.request.method.lower(), None) - if method is not None: - span_name = transaction_from_function(method) - if span_name: - span.name = span_name - span.set_attribute( - "sentry.segment.name.source", - SegmentNameSource.COMPONENT, - ) - - with capture_internal_exceptions(): - status_int = self.get_status() - span.set_attribute(SPANDATA.HTTP_STATUS_CODE, status_int) - span.status = "error" if status_int >= 400 else "ok" + with capture_internal_exceptions(): + for attr, value in _get_request_attributes(self.request).items(): + span.set_attribute(attr, value) + + with capture_internal_exceptions(): + method = getattr(self, self.request.method.lower(), None) + if method is not None: + span_name = transaction_from_function(method) + if span_name: + span.name = span_name + span.set_attribute( + "sentry.segment.name.source", + SegmentNameSource.COMPONENT, + ) + + with capture_internal_exceptions(): + status_int = self.get_status() + span.set_attribute(SPANDATA.HTTP_STATUS_CODE, status_int) + span.status = "error" if status_int >= 400 else "ok" def _get_request_attributes(request: "Any") -> "Dict[str, Any]": @@ -303,7 +245,7 @@ def tornado_processor(event: "Event", hint: "dict[str, Any]") -> "Event": with capture_internal_exceptions(): method = getattr(handler, handler.request.method.lower()) event["transaction"] = transaction_from_function(method) or "" - event["transaction_info"] = {"source": TransactionSource.COMPONENT} + event["transaction_info"] = {"source": SegmentNameSource.COMPONENT} client_options = sentry_sdk.get_client().options with capture_internal_exceptions(): diff --git a/sentry_sdk/integrations/trytond.py b/sentry_sdk/integrations/trytond.py index 0449a8f10c..2c574d0fa0 100644 --- a/sentry_sdk/integrations/trytond.py +++ b/sentry_sdk/integrations/trytond.py @@ -1,15 +1,20 @@ import sentry_sdk -from sentry_sdk.integrations import DidNotEnable, Integration +from sentry_sdk.integrations import DidNotEnable, Integration, _check_minimum_version from sentry_sdk.integrations.wsgi import SentryWsgiMiddleware -from sentry_sdk.utils import ensure_integration_enabled, event_from_exception +from sentry_sdk.utils import ( + ensure_integration_enabled, + event_from_exception, + parse_version, +) try: + from trytond import __version__ as TRYTOND_VERSION # type: ignore from trytond.exceptions import TrytonException # type: ignore from trytond.wsgi import app # type: ignore except ImportError: - raise DidNotEnable("Trytond is not installed.") + raise DidNotEnable("Trytond is not installed or incompatible") -# TODO: trytond-worker, trytond-cron and trytond-admin intergations +# TODO: trytond-worker, trytond-cron and trytond-admin integrations class TrytondWSGIIntegration(Integration): @@ -21,6 +26,9 @@ def __init__(self) -> None: @staticmethod def setup_once() -> None: + version = parse_version(TRYTOND_VERSION) + _check_minimum_version(TrytondWSGIIntegration, version, "trytond") + app.wsgi_app = SentryWsgiMiddleware( app.wsgi_app, span_origin=TrytondWSGIIntegration.origin, @@ -39,14 +47,6 @@ def error_handler(e: Exception) -> None: ) sentry_sdk.capture_event(event, hint=hint) - # Expected error handlers signature was changed - # when the error_handler decorator was introduced - # in Tryton-5.4 - if hasattr(app, "error_handler"): - - @app.error_handler - def _(app, request, e): # type: ignore - error_handler(e) - - else: - app.error_handlers.append(error_handler) + @app.error_handler + def _(app, request, e): # type: ignore + error_handler(e) diff --git a/sentry_sdk/integrations/typer.py b/sentry_sdk/integrations/typer.py index 497f0539ec..4b714b5d76 100644 --- a/sentry_sdk/integrations/typer.py +++ b/sentry_sdk/integrations/typer.py @@ -1,10 +1,11 @@ from typing import TYPE_CHECKING import sentry_sdk -from sentry_sdk.integrations import DidNotEnable, Integration +from sentry_sdk.integrations import DidNotEnable, Integration, _check_minimum_version from sentry_sdk.utils import ( capture_internal_exceptions, event_from_exception, + parse_version, ) if TYPE_CHECKING: @@ -18,9 +19,10 @@ try: import typer + from typer import __version__ as TYPER_VERSION from typer.main import except_hook except ImportError: - raise DidNotEnable("Typer not installed") + raise DidNotEnable("Typer not installed or incompatible") class TyperIntegration(Integration): @@ -28,6 +30,9 @@ class TyperIntegration(Integration): @staticmethod def setup_once() -> None: + version = parse_version(TYPER_VERSION) + _check_minimum_version(TyperIntegration, version) + typer.main.except_hook = _make_excepthook(except_hook) # type: ignore diff --git a/sentry_sdk/integrations/unleash.py b/sentry_sdk/integrations/unleash.py index 0316f6b88a..a7e7f6608c 100644 --- a/sentry_sdk/integrations/unleash.py +++ b/sentry_sdk/integrations/unleash.py @@ -2,12 +2,13 @@ from typing import Any from sentry_sdk.feature_flags import add_feature_flag -from sentry_sdk.integrations import DidNotEnable, Integration +from sentry_sdk.integrations import DidNotEnable, Integration, _check_minimum_version +from sentry_sdk.utils import package_version try: from UnleashClient import UnleashClient except ImportError: - raise DidNotEnable("UnleashClient is not installed") + raise DidNotEnable("UnleashClient is not installed or incompatible") class UnleashIntegration(Integration): @@ -15,6 +16,9 @@ class UnleashIntegration(Integration): @staticmethod def setup_once() -> None: + version = package_version("UnleashClient") + _check_minimum_version(UnleashIntegration, version) + # Wrap and patch evaluation methods (class methods) old_is_enabled = UnleashClient.is_enabled diff --git a/sentry_sdk/integrations/wsgi.py b/sentry_sdk/integrations/wsgi.py index 3204e15e43..a4df7d1dc2 100644 --- a/sentry_sdk/integrations/wsgi.py +++ b/sentry_sdk/integrations/wsgi.py @@ -1,10 +1,11 @@ import sys +from contextlib import nullcontext +from contextvars import ContextVar from functools import partial from typing import TYPE_CHECKING import sentry_sdk from sentry_sdk._werkzeug import _get_headers, get_host -from sentry_sdk.api import continue_trace from sentry_sdk.consts import OP, SPANDATA from sentry_sdk.data_collection import _apply_data_collection_filtering_to_query_string from sentry_sdk.integrations._wsgi_common import ( @@ -13,15 +14,11 @@ ) from sentry_sdk.scope import Scope, should_send_default_pii, use_isolation_scope from sentry_sdk.sessions import track_session -from sentry_sdk.traces import SegmentNameSource, StreamedSpan -from sentry_sdk.tracing import Span, TransactionSource -from sentry_sdk.tracing_utils import has_span_streaming_enabled +from sentry_sdk.traces import SegmentNameSource from sentry_sdk.utils import ( - ContextVar, capture_internal_exceptions, event_from_exception, has_data_collection_enabled, - nullcontext, reraise, ) @@ -40,6 +37,7 @@ ) from sentry_sdk._types import Event, EventProcessor + from sentry_sdk.traces import Span from sentry_sdk.utils import ExcInfo WsgiResponseIter = TypeVar("WsgiResponseIter") @@ -56,7 +54,9 @@ def __call__( pass -_wsgi_middleware_applied = ContextVar("sentry_wsgi_middleware_applied") +_wsgi_middleware_applied: "ContextVar[bool]" = ContextVar( + "sentry_wsgi_middleware_applied" +) _DEFAULT_TRANSACTION_NAME = "generic WSGI request" @@ -111,7 +111,6 @@ def __call__( return self.app(environ, start_response) client = sentry_sdk.get_client() - span_streaming = has_span_streaming_enabled(client.options) _wsgi_middleware_applied.set(True) try: @@ -128,56 +127,36 @@ def __call__( method = environ.get("REQUEST_METHOD", "").upper() - span_ctx: "Optional[ContextManager[Union[Span, StreamedSpan, None]]]" = None + span_ctx: "ContextManager[Union[Span, None]]" = nullcontext() if method in self.http_methods_to_capture: - if span_streaming: - sentry_sdk.traces.continue_trace( - dict(_get_headers(environ)) - ) - Scope.set_custom_sampling_context({"wsgi_environ": environ}) - - if has_data_collection_enabled(client.options): - if client.options["data_collection"]["user_info"]: - client_ip = get_client_ip(environ) - if client_ip: - scope.set_attribute( - SPANDATA.USER_IP_ADDRESS, client_ip - ) - elif should_send_default_pii(): + sentry_sdk.continue_trace(dict(_get_headers(environ))) + Scope.set_custom_sampling_context({"wsgi_environ": environ}) + + if has_data_collection_enabled(client.options): + if client.options["data_collection"]["user_info"]: client_ip = get_client_ip(environ) if client_ip: scope.set_attribute( SPANDATA.USER_IP_ADDRESS, client_ip ) - - span_ctx = sentry_sdk.traces.start_span( - name=_DEFAULT_TRANSACTION_NAME, - attributes={ - "sentry.segment.name.source": SegmentNameSource.ROUTE, - "sentry.origin": self.span_origin, - "sentry.op": OP.HTTP_SERVER, - }, - parent_span=None, - ) - scope.get_current_scope()._server_segment_span = span_ctx - else: - transaction = continue_trace( - environ, - op=OP.HTTP_SERVER, - name=_DEFAULT_TRANSACTION_NAME, - source=TransactionSource.ROUTE, - origin=self.span_origin, - ) - - span_ctx = sentry_sdk.start_transaction( - transaction, - custom_sampling_context={"wsgi_environ": environ}, - ) - - span_ctx = span_ctx or nullcontext() + elif should_send_default_pii(): + client_ip = get_client_ip(environ) + if client_ip: + scope.set_attribute(SPANDATA.USER_IP_ADDRESS, client_ip) + + span_ctx = sentry_sdk.start_span( + name=_DEFAULT_TRANSACTION_NAME, + attributes={ + "sentry.segment.name.source": SegmentNameSource.ROUTE, + "sentry.origin": self.span_origin, + "sentry.op": OP.HTTP_SERVER, + }, + parent_span=None, + ) + scope.get_current_scope()._server_segment_span = span_ctx with span_ctx as span: - if isinstance(span, StreamedSpan): + if span is not None: with capture_internal_exceptions(): for attr, value in _get_request_attributes( environ, self.use_x_forwarded_for @@ -222,7 +201,7 @@ def __call__( def _sentry_start_response( old_start_response: "StartResponse", - span: "Optional[Union[Span, StreamedSpan]]", + span: "Optional[Union[Span]]", status: str, response_headers: "WsgiResponseHeaders", exc_info: "Optional[WsgiExcInfo]" = None, @@ -230,11 +209,8 @@ def _sentry_start_response( with capture_internal_exceptions(): status_int = int(status.split(" ", 1)[0]) if span is not None: - if isinstance(span, StreamedSpan): - span.status = "error" if status_int >= 400 else "ok" - span.set_attribute("http.response.status_code", status_int) - else: - span.set_http_status(status_int) + span.status = "error" if status_int >= 400 else "ok" + span.set_attribute("http.response.status_code", status_int) if exc_info is None: # The Django Rest Framework WSGI test client, and likely other diff --git a/sentry_sdk/profiler/__init__.py b/sentry_sdk/profiler/__init__.py index d562405295..af45f84164 100644 --- a/sentry_sdk/profiler/__init__.py +++ b/sentry_sdk/profiler/__init__.py @@ -1,20 +1,7 @@ from sentry_sdk.profiler.continuous_profiler import ( - start_profile_session, start_profiler, - stop_profile_session, stop_profiler, ) -from sentry_sdk.profiler.transaction_profiler import ( - MAX_PROFILE_DURATION_NS, - PROFILE_MINIMUM_SAMPLES, - GeventScheduler, - Profile, - Scheduler, - ThreadScheduler, - has_profiling_enabled, - setup_profiler, - teardown_profiler, -) from sentry_sdk.profiler.utils import ( DEFAULT_SAMPLING_FREQUENCY, MAX_STACK_DEPTH, @@ -25,21 +12,8 @@ ) __all__ = [ - "start_profile_session", # TODO: Deprecate this in favor of `start_profiler` "start_profiler", - "stop_profile_session", # TODO: Deprecate this in favor of `stop_profiler` "stop_profiler", - # DEPRECATED: The following was re-exported for backwards compatibility. It - # will be removed from sentry_sdk.profiler in a future release. - "MAX_PROFILE_DURATION_NS", - "PROFILE_MINIMUM_SAMPLES", - "Profile", - "Scheduler", - "ThreadScheduler", - "GeventScheduler", - "has_profiling_enabled", - "setup_profiler", - "teardown_profiler", "DEFAULT_SAMPLING_FREQUENCY", "MAX_STACK_DEPTH", "get_frame_name", diff --git a/sentry_sdk/profiler/continuous_profiler.py b/sentry_sdk/profiler/continuous_profiler.py index ed525f52bd..2e82289e72 100644 --- a/sentry_sdk/profiler/continuous_profiler.py +++ b/sentry_sdk/profiler/continuous_profiler.py @@ -5,7 +5,6 @@ import threading import time import uuid -import warnings from collections import deque from datetime import datetime, timezone from typing import TYPE_CHECKING @@ -82,19 +81,12 @@ def setup_continuous_profiler( # them to spawn a native thread for sampling. # Instead we default to the GeventContinuousScheduler which is capable of # spawning native threads within gevent. - default_profiler_mode = GeventContinuousScheduler.mode + profiler_mode = GeventContinuousScheduler.mode else: - default_profiler_mode = ThreadContinuousScheduler.mode + profiler_mode = ThreadContinuousScheduler.mode if options.get("profiler_mode") is not None: profiler_mode = options["profiler_mode"] - else: - # TODO: deprecate this and just use the existing `profiler_mode` - experiments = options.get("_experiments", {}) - - profiler_mode = ( - experiments.get("continuous_profiling_mode") or default_profiler_mode - ) frequency = DEFAULT_SAMPLING_FREQUENCY @@ -153,15 +145,6 @@ def start_profiler() -> None: _scheduler.manual_start() -def start_profile_session() -> None: - warnings.warn( - "The `start_profile_session` function is deprecated. Please use `start_profile` instead.", - DeprecationWarning, - stacklevel=2, - ) - start_profiler() - - def stop_profiler() -> None: if _scheduler is None: return @@ -169,15 +152,6 @@ def stop_profiler() -> None: _scheduler.manual_stop() -def stop_profile_session() -> None: - warnings.warn( - "The `stop_profile_session` function is deprecated. Please use `stop_profile` instead.", - DeprecationWarning, - stacklevel=2, - ) - stop_profiler() - - def teardown_continuous_profiler() -> None: stop_profiler() diff --git a/sentry_sdk/profiler/transaction_profiler.py b/sentry_sdk/profiler/transaction_profiler.py deleted file mode 100644 index fe65774c0b..0000000000 --- a/sentry_sdk/profiler/transaction_profiler.py +++ /dev/null @@ -1,802 +0,0 @@ -""" -This file is originally based on code from https://github.com/nylas/nylas-perftools, -which is published under the following license: - -The MIT License (MIT) - -Copyright (c) 2014 Nylas - -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. -""" - -import atexit -import os -import platform -import random -import sys -import threading -import time -import uuid -import warnings -from abc import ABC, abstractmethod -from collections import deque -from typing import TYPE_CHECKING - -import sentry_sdk -from sentry_sdk._lru_cache import LRUCache -from sentry_sdk.profiler.utils import ( - DEFAULT_SAMPLING_FREQUENCY, - extract_stack, -) -from sentry_sdk.utils import ( - capture_internal_exception, - capture_internal_exceptions, - get_current_thread_meta, - is_gevent, - is_valid_sample_rate, - logger, - nanosecond_time, - set_in_app_in_frames, -) - -if TYPE_CHECKING: - from typing import Any, Callable, Deque, Dict, List, Optional, Set, Type - - from typing_extensions import TypedDict - - from sentry_sdk._types import Event, ProfilerMode, SamplingContext - from sentry_sdk.profiler.utils import ( - ExtractedSample, - FrameId, - ProcessedFrame, - ProcessedStack, - ProcessedThreadMetadata, - StackId, - ThreadId, - ) - - ProcessedSample = TypedDict( - "ProcessedSample", - { - "elapsed_since_start_ns": str, - "thread_id": ThreadId, - "stack_id": int, - }, - ) - - ProcessedProfile = TypedDict( - "ProcessedProfile", - { - "frames": List[ProcessedFrame], - "stacks": List[ProcessedStack], - "samples": List[ProcessedSample], - "thread_metadata": Dict[ThreadId, ProcessedThreadMetadata], - }, - ) - - -try: - from gevent.monkey import get_original - from gevent.threadpool import ThreadPool as _ThreadPool - - ThreadPool: "Optional[Type[_ThreadPool]]" = _ThreadPool - thread_sleep = get_original("time", "sleep") -except ImportError: - thread_sleep = time.sleep - - ThreadPool = None - - -_scheduler: "Optional[Scheduler]" = None - - -# The minimum number of unique samples that must exist in a profile to be -# considered valid. -PROFILE_MINIMUM_SAMPLES = 2 - - -def has_profiling_enabled(options: "Dict[str, Any]") -> bool: - profiles_sampler = options["profiles_sampler"] - if profiles_sampler is not None: - return True - - profiles_sample_rate = options["profiles_sample_rate"] - if profiles_sample_rate is not None and profiles_sample_rate > 0: - return True - - profiles_sample_rate = options["_experiments"].get("profiles_sample_rate") - if profiles_sample_rate is not None: - logger.warning( - "_experiments['profiles_sample_rate'] is deprecated. " - "Please use the non-experimental profiles_sample_rate option " - "directly." - ) - if profiles_sample_rate > 0: - return True - - return False - - -def setup_profiler(options: "Dict[str, Any]") -> bool: - global _scheduler - - if _scheduler is not None: - logger.debug("[Profiling] Profiler is already setup") - return False - - frequency = DEFAULT_SAMPLING_FREQUENCY - - if is_gevent(): - # If gevent has patched the threading modules then we cannot rely on - # them to spawn a native thread for sampling. - # Instead we default to the GeventScheduler which is capable of - # spawning native threads within gevent. - default_profiler_mode = GeventScheduler.mode - else: - default_profiler_mode = ThreadScheduler.mode - - if options.get("profiler_mode") is not None: - profiler_mode = options["profiler_mode"] - else: - profiler_mode = options.get("_experiments", {}).get("profiler_mode") - if profiler_mode is not None: - logger.warning( - "_experiments['profiler_mode'] is deprecated. Please use the " - "non-experimental profiler_mode option directly." - ) - profiler_mode = profiler_mode or default_profiler_mode - - if ( - profiler_mode == ThreadScheduler.mode - # for legacy reasons, we'll keep supporting sleep mode for this scheduler - or profiler_mode == "sleep" - ): - _scheduler = ThreadScheduler(frequency=frequency) - elif profiler_mode == GeventScheduler.mode: - _scheduler = GeventScheduler(frequency=frequency) - else: - raise ValueError("Unknown profiler mode: {}".format(profiler_mode)) - - logger.debug( - "[Profiling] Setting up profiler in {mode} mode".format(mode=_scheduler.mode) - ) - _scheduler.setup() - - atexit.register(teardown_profiler) - - return True - - -def teardown_profiler() -> None: - global _scheduler - - if _scheduler is not None: - _scheduler.teardown() - - _scheduler = None - - -MAX_PROFILE_DURATION_NS = int(3e10) # 30 seconds - - -class Profile: - def __init__( - self, - sampled: "Optional[bool]", - start_ns: int, - hub: "Optional[sentry_sdk.Hub]" = None, - scheduler: "Optional[Scheduler]" = None, - ) -> None: - self.scheduler = _scheduler if scheduler is None else scheduler - - self.event_id: str = uuid.uuid4().hex - - self.sampled: "Optional[bool]" = sampled - - # Various framework integrations are capable of overwriting the active thread id. - # If it is set to `None` at the end of the profile, we fall back to the default. - self._default_active_thread_id: int = get_current_thread_meta()[0] or 0 - self.active_thread_id: "Optional[int]" = None - - try: - self.start_ns: int = start_ns - except AttributeError: - self.start_ns = 0 - - self.stop_ns: int = 0 - self.active: bool = False - - self.indexed_frames: "Dict[FrameId, int]" = {} - self.indexed_stacks: "Dict[StackId, int]" = {} - self.frames: "List[ProcessedFrame]" = [] - self.stacks: "List[ProcessedStack]" = [] - self.samples: "List[ProcessedSample]" = [] - - self.unique_samples = 0 - - # Backwards compatibility with the old hub property - self._hub: "Optional[sentry_sdk.Hub]" = None - if hub is not None: - self._hub = hub - warnings.warn( - "The `hub` parameter is deprecated. Please do not use it.", - DeprecationWarning, - stacklevel=2, - ) - - def update_active_thread_id(self) -> None: - self.active_thread_id = get_current_thread_meta()[0] - logger.debug( - "[Profiling] updating active thread id to {tid}".format( - tid=self.active_thread_id - ) - ) - - def _set_initial_sampling_decision( - self, sampling_context: "SamplingContext" - ) -> None: - """ - Sets the profile's sampling decision according to the following - precedence rules: - - 1. If the transaction to be profiled is not sampled, that decision - will be used, regardless of anything else. - - 2. Use `profiles_sample_rate` to decide. - """ - - # The corresponding transaction was not sampled, - # so don't generate a profile for it. - if not self.sampled: - logger.debug( - "[Profiling] Discarding profile because transaction is discarded." - ) - self.sampled = False - return - - # The profiler hasn't been properly initialized. - if self.scheduler is None: - logger.debug( - "[Profiling] Discarding profile because profiler was not started." - ) - self.sampled = False - return - - client = sentry_sdk.get_client() - if not client.is_active(): - self.sampled = False - return - - options = client.options - - if callable(options.get("profiles_sampler")): - sample_rate = options["profiles_sampler"](sampling_context) - elif options["profiles_sample_rate"] is not None: - sample_rate = options["profiles_sample_rate"] - else: - sample_rate = options["_experiments"].get("profiles_sample_rate") - - # The profiles_sample_rate option was not set, so profiling - # was never enabled. - if sample_rate is None: - logger.debug( - "[Profiling] Discarding profile because profiling was not enabled." - ) - self.sampled = False - return - - if not is_valid_sample_rate(sample_rate, source="Profiling"): - logger.warning( - "[Profiling] Discarding profile because of invalid sample rate." - ) - self.sampled = False - return - - # Now we roll the dice. random.random is inclusive of 0, but not of 1, - # so strict < is safe here. In case sample_rate is a boolean, cast it - # to a float (True becomes 1.0 and False becomes 0.0) - self.sampled = random.random() < float(sample_rate) - - if self.sampled: - logger.debug("[Profiling] Initializing profile") - else: - logger.debug( - "[Profiling] Discarding profile because it's not included in the random sample (sample rate = {sample_rate})".format( - sample_rate=float(sample_rate) - ) - ) - - def start(self) -> None: - if not self.sampled or self.active: - return - - assert self.scheduler, "No scheduler specified" - logger.debug("[Profiling] Starting profile") - self.active = True - if not self.start_ns: - self.start_ns = nanosecond_time() - self.scheduler.start_profiling(self) - - def stop(self) -> None: - if not self.sampled or not self.active: - return - - assert self.scheduler, "No scheduler specified" - logger.debug("[Profiling] Stopping profile") - self.active = False - self.stop_ns = nanosecond_time() - - def __enter__(self) -> "Profile": - scope = sentry_sdk.get_isolation_scope() - old_profile = scope.profile - scope.profile = self - - self._context_manager_state = (scope, old_profile) - - self.start() - - return self - - def __exit__( - self, ty: "Optional[Any]", value: "Optional[Any]", tb: "Optional[Any]" - ) -> None: - with capture_internal_exceptions(): - self.stop() - - scope, old_profile = self._context_manager_state - del self._context_manager_state - - scope.profile = old_profile - - def write(self, ts: int, sample: "ExtractedSample") -> None: - if not self.active: - return - - if ts < self.start_ns: - return - - offset = ts - self.start_ns - if offset > MAX_PROFILE_DURATION_NS: - self.stop() - return - - self.unique_samples += 1 - - elapsed_since_start_ns = str(offset) - - for tid, (stack_id, frame_ids, frames) in sample: - try: - # Check if the stack is indexed first, this lets us skip - # indexing frames if it's not necessary - if stack_id not in self.indexed_stacks: - for i, frame_id in enumerate(frame_ids): - if frame_id not in self.indexed_frames: - self.indexed_frames[frame_id] = len(self.indexed_frames) - self.frames.append(frames[i]) - - self.indexed_stacks[stack_id] = len(self.indexed_stacks) - self.stacks.append( - [self.indexed_frames[frame_id] for frame_id in frame_ids] - ) - - self.samples.append( - { - "elapsed_since_start_ns": elapsed_since_start_ns, - "thread_id": tid, - "stack_id": self.indexed_stacks[stack_id], - } - ) - except AttributeError: - # For some reason, the frame we get doesn't have certain attributes. - # When this happens, we abandon the current sample as it's bad. - capture_internal_exception(sys.exc_info()) - - def process(self) -> "ProcessedProfile": - # This collects the thread metadata at the end of a profile. Doing it - # this way means that any threads that terminate before the profile ends - # will not have any metadata associated with it. - thread_metadata: "Dict[str, ProcessedThreadMetadata]" = { - str(thread.ident): { - "name": str(thread.name), - } - for thread in threading.enumerate() - } - - return { - "frames": self.frames, - "stacks": self.stacks, - "samples": self.samples, - "thread_metadata": thread_metadata, - } - - def to_json( - self, event_opt: "Event", options: "Dict[str, Any]" - ) -> "Dict[str, Any]": - profile = self.process() - - set_in_app_in_frames( - profile["frames"], - options["in_app_exclude"], - options["in_app_include"], - options["project_root"], - ) - - return { - "environment": event_opt.get("environment"), - "event_id": self.event_id, - "platform": "python", - "profile": profile, - "release": event_opt.get("release", ""), - "timestamp": event_opt["start_timestamp"], - "version": "1", - "device": { - "architecture": platform.machine(), - }, - "os": { - "name": platform.system(), - "version": platform.release(), - }, - "runtime": { - "name": platform.python_implementation(), - "version": platform.python_version(), - }, - "transactions": [ - { - "id": event_opt["event_id"], - "name": event_opt["transaction"], - # we start the transaction before the profile and this is - # the transaction start time relative to the profile, so we - # hardcode it to 0 until we can start the profile before - "relative_start_ns": "0", - # use the duration of the profile instead of the transaction - # because we end the transaction after the profile - "relative_end_ns": str(self.stop_ns - self.start_ns), - "trace_id": event_opt["contexts"]["trace"]["trace_id"], - "active_thread_id": str( - self._default_active_thread_id - if self.active_thread_id is None - else self.active_thread_id - ), - } - ], - } - - def valid(self) -> bool: - client = sentry_sdk.get_client() - if not client.is_active(): - return False - - if not has_profiling_enabled(client.options): - return False - - if self.sampled is None or not self.sampled: - if client.transport: - client.transport.record_lost_event( - "sample_rate", data_category="profile" - ) - return False - - if self.unique_samples < PROFILE_MINIMUM_SAMPLES: - if client.transport: - client.transport.record_lost_event( - "insufficient_data", data_category="profile" - ) - logger.debug("[Profiling] Discarding profile because insufficient samples.") - return False - - return True - - @property - def hub(self) -> "Optional[sentry_sdk.Hub]": - warnings.warn( - "The `hub` attribute is deprecated. Please do not access it.", - DeprecationWarning, - stacklevel=2, - ) - return self._hub - - @hub.setter - def hub(self, value: "Optional[sentry_sdk.Hub]") -> None: - warnings.warn( - "The `hub` attribute is deprecated. Please do not set it.", - DeprecationWarning, - stacklevel=2, - ) - self._hub = value - - -class Scheduler(ABC): - mode: "ProfilerMode" = "unknown" - - def __init__(self, frequency: int) -> None: - self.interval = 1.0 / frequency - - self.sampler = self.make_sampler() - - # cap the number of new profiles at any time so it does not grow infinitely - self.new_profiles: "Deque[Profile]" = deque(maxlen=128) - self.active_profiles: "Set[Profile]" = set() - - def __enter__(self) -> "Scheduler": - self.setup() - return self - - def __exit__( - self, ty: "Optional[Any]", value: "Optional[Any]", tb: "Optional[Any]" - ) -> None: - self.teardown() - - @abstractmethod - def setup(self) -> None: - pass - - @abstractmethod - def teardown(self) -> None: - pass - - def ensure_running(self) -> None: - """ - Ensure the scheduler is running. By default, this method is a no-op. - The method should be overridden by any implementation for which it is - relevant. - """ - return None - - def start_profiling(self, profile: "Profile") -> None: - self.ensure_running() - self.new_profiles.append(profile) - - def make_sampler(self) -> "Callable[..., None]": - cwd = os.getcwd() - - cache = LRUCache(max_size=256) - - def _sample_stack(*args: "Any", **kwargs: "Any") -> None: - """ - Take a sample of the stack on all the threads in the process. - This should be called at a regular interval to collect samples. - """ - # no profiles taking place, so we can stop early - if not self.new_profiles and not self.active_profiles: - # make sure to clear the cache if we're not profiling so we dont - # keep a reference to the last stack of frames around - return - - # This is the number of profiles we want to pop off. - # It's possible another thread adds a new profile to - # the list and we spend longer than we want inside - # the loop below. - # - # Also make sure to set this value before extracting - # frames so we do not write to any new profiles that - # were started after this point. - new_profiles = len(self.new_profiles) - - now = nanosecond_time() - - try: - sample = [ - (str(tid), extract_stack(frame, cache, cwd)) - for tid, frame in sys._current_frames().items() - ] - except AttributeError: - # For some reason, the frame we get doesn't have certain attributes. - # When this happens, we abandon the current sample as it's bad. - capture_internal_exception(sys.exc_info()) - return - - # Move the new profiles into the active_profiles set. - # - # We cannot directly add the to active_profiles set - # in `start_profiling` because it is called from other - # threads which can cause a RuntimeError when it the - # set sizes changes during iteration without a lock. - # - # We also want to avoid using a lock here so threads - # that are starting profiles are not blocked until it - # can acquire the lock. - for _ in range(new_profiles): - self.active_profiles.add(self.new_profiles.popleft()) - - inactive_profiles = [] - - for profile in self.active_profiles: - if profile.active: - profile.write(now, sample) - else: - # If a profile is marked inactive, we buffer it - # to `inactive_profiles` so it can be removed. - # We cannot remove it here as it would result - # in a RuntimeError. - inactive_profiles.append(profile) - - for profile in inactive_profiles: - self.active_profiles.remove(profile) - - return _sample_stack - - -class ThreadScheduler(Scheduler): - """ - This scheduler is based on running a daemon thread that will call - the sampler at a regular interval. - """ - - mode: "ProfilerMode" = "thread" - name = "sentry.profiler.ThreadScheduler" - - def __init__(self, frequency: int) -> None: - super().__init__(frequency=frequency) - - # used to signal to the thread that it should stop - self.running = False - self.thread: "Optional[threading.Thread]" = None - self.pid: "Optional[int]" = None - self.lock = threading.Lock() - - def setup(self) -> None: - pass - - def teardown(self) -> None: - if self.running: - self.running = False - if self.thread is not None: - self.thread.join() - - def ensure_running(self) -> None: - """ - Check that the profiler has an active thread to run in, and start one if - that's not the case. - - Note that this might fail (e.g. in Python 3.12 it's not possible to - spawn new threads at interpreter shutdown). In that case self.running - will be False after running this function. - """ - pid = os.getpid() - - # is running on the right process - if self.running and self.pid == pid: - return - - with self.lock: - # another thread may have tried to acquire the lock - # at the same time so it may start another thread - # make sure to check again before proceeding - if self.running and self.pid == pid: - return - - self.pid = pid - self.running = True - - # make sure the thread is a daemon here otherwise this - # can keep the application running after other threads - # have exited - self.thread = threading.Thread(name=self.name, target=self.run, daemon=True) - try: - self.thread.start() - except RuntimeError: - # Unfortunately at this point the interpreter is in a state that no - # longer allows us to spawn a thread and we have to bail. - self.running = False - self.thread = None - return - - def run(self) -> None: - last = time.perf_counter() - - while self.running: - self.sampler() - - # some time may have elapsed since the last time - # we sampled, so we need to account for that and - # not sleep for too long - elapsed = time.perf_counter() - last - if elapsed < self.interval: - thread_sleep(self.interval - elapsed) - - # after sleeping, make sure to take the current - # timestamp so we can use it next iteration - last = time.perf_counter() - - -class GeventScheduler(Scheduler): - """ - This scheduler is based on the thread scheduler but adapted to work with - gevent. When using gevent, it may monkey patch the threading modules - (`threading` and `_thread`). This results in the use of greenlets instead - of native threads. - - This is an issue because the sampler CANNOT run in a greenlet because - 1. Other greenlets doing sync work will prevent the sampler from running - 2. The greenlet runs in the same thread as other greenlets so when taking - a sample, other greenlets will have been evicted from the thread. This - results in a sample containing only the sampler's code. - """ - - mode: "ProfilerMode" = "gevent" - name = "sentry.profiler.GeventScheduler" - - def __init__(self, frequency: int) -> None: - if ThreadPool is None: - raise ValueError("Profiler mode: {} is not available".format(self.mode)) - - super().__init__(frequency=frequency) - - # used to signal to the thread that it should stop - self.running = False - self.thread: "Optional[_ThreadPool]" = None - self.pid: "Optional[int]" = None - - # This intentionally uses the gevent patched threading.Lock. - # The lock will be required when first trying to start profiles - # as we need to spawn the profiler thread from the greenlets. - self.lock = threading.Lock() - - def setup(self) -> None: - pass - - def teardown(self) -> None: - if self.running: - self.running = False - if self.thread is not None: - self.thread.join() - - def ensure_running(self) -> None: - pid = os.getpid() - - # is running on the right process - if self.running and self.pid == pid: - return - - with self.lock: - # another thread may have tried to acquire the lock - # at the same time so it may start another thread - # make sure to check again before proceeding - if self.running and self.pid == pid: - return - - self.pid = pid - self.running = True - - self.thread = ThreadPool(1) # type: ignore[misc] - try: - self.thread.spawn(self.run) - except RuntimeError: - # Unfortunately at this point the interpreter is in a state that no - # longer allows us to spawn a thread and we have to bail. - self.running = False - self.thread = None - return - - def run(self) -> None: - last = time.perf_counter() - - while self.running: - self.sampler() - - # some time may have elapsed since the last time - # we sampled, so we need to account for that and - # not sleep for too long - elapsed = time.perf_counter() - last - if elapsed < self.interval: - thread_sleep(self.interval - elapsed) - - # after sleeping, make sure to take the current - # timestamp so we can use it next iteration - last = time.perf_counter() diff --git a/sentry_sdk/scope.py b/sentry_sdk/scope.py index 4d547a3f48..03bb43810f 100644 --- a/sentry_sdk/scope.py +++ b/sentry_sdk/scope.py @@ -1,15 +1,15 @@ import os import platform import sys -import warnings from collections import deque from contextlib import contextmanager +from contextvars import ContextVar from copy import copy, deepcopy from datetime import datetime, timezone from enum import Enum from functools import wraps from itertools import chain -from typing import TYPE_CHECKING, cast +from typing import TYPE_CHECKING import sentry_sdk from sentry_sdk._types import AnnotatedValue @@ -17,39 +17,25 @@ from sentry_sdk.consts import ( DEFAULT_MAX_BREADCRUMBS, FALSE_VALUES, - INSTRUMENTER, SPANDATA, ) from sentry_sdk.feature_flags import DEFAULT_FLAG_CAPACITY, FlagBuffer -from sentry_sdk.profiler.continuous_profiler import ( - get_profiler_id, - try_autostart_continuous_profiler, - try_profile_lifecycle_trace_start, -) -from sentry_sdk.profiler.transaction_profiler import Profile from sentry_sdk.session import Session from sentry_sdk.traces import ( _DEFAULT_PARENT_SPAN, - NoOpStreamedSpan, - StreamedSpan, -) -from sentry_sdk.tracing import ( BAGGAGE_HEADER_NAME, SENTRY_TRACE_HEADER_NAME, NoOpSpan, Span, - Transaction, ) from sentry_sdk.tracing_utils import ( Baggage, PropagationContext, _make_sampling_decision, - has_span_streaming_enabled, has_tracing_enabled, is_ignored_span, ) from sentry_sdk.utils import ( - ContextVar, capture_internal_exception, capture_internal_exceptions, datetime_from_isoformat, @@ -69,7 +55,6 @@ Deque, Dict, Generator, - Iterator, List, Optional, ParamSpec, @@ -78,8 +63,6 @@ Union, ) - from typing_extensions import Unpack - import sentry_sdk from sentry_sdk._types import ( Attributes, @@ -94,10 +77,8 @@ Log, LogLevelStr, Metric, - SamplingContext, Type, ) - from sentry_sdk.tracing import TransactionKwargs P = ParamSpec("P") R = TypeVar("R") @@ -116,11 +97,15 @@ # This is used to isolate data for different requests or users. # The isolation scope is usually created by integrations, but may also # be created manually -_isolation_scope = ContextVar("isolation_scope", default=None) +_isolation_scope: "ContextVar[Optional[Scope]]" = ContextVar( + "isolation_scope", default=None +) # Holds data for the active span. # This can be used to manually add additional data to a span. -_current_scope = ContextVar("current_scope", default=None) +_current_scope: "ContextVar[Optional[Scope]]" = ContextVar( + "current_scope", default=None +) global_event_processors: "List[EventProcessor]" = [] @@ -137,7 +122,7 @@ class ScopeType(Enum): class _ScopeManager: - def __init__(self, hub: "Optional[Any]" = None) -> None: + def __init__(self) -> None: self._old_scopes: "List[Scope]" = [] def __enter__(self) -> "Scope": @@ -224,17 +209,16 @@ class Scope: "_extras", "_breadcrumbs", "_n_breadcrumbs_truncated", - "_gen_ai_original_message_count", "_gen_ai_conversation_id", "_event_processors", "_error_processors", "_should_capture", "_span", "_server_segment_span", + "_agent_framework_chat_generation_entered", "_session", "_attachments", "_force_auto_session_tracking", - "_profile", "_propagation_context", "client", "_type", @@ -256,9 +240,9 @@ def __init__( self._name: "Optional[str]" = None self._propagation_context: "Optional[PropagationContext]" = None self._n_breadcrumbs_truncated: int = 0 - self._gen_ai_original_message_count: "Dict[str, int]" = {} - self._server_segment_span: "Optional[StreamedSpan]" = None + self._server_segment_span: "Optional[Span]" = None + self._agent_framework_chat_generation_entered: "bool" = False self.client: "sentry_sdk.client.BaseClient" = NonRecordingClient() @@ -292,7 +276,6 @@ def __copy__(self) -> "Scope": rv._breadcrumbs = copy(self._breadcrumbs) rv._n_breadcrumbs_truncated = self._n_breadcrumbs_truncated - rv._gen_ai_original_message_count = self._gen_ai_original_message_count.copy() rv._event_processors = self._event_processors.copy() rv._error_processors = self._error_processors.copy() rv._propagation_context = self._propagation_context @@ -300,12 +283,13 @@ def __copy__(self) -> "Scope": rv._should_capture = self._should_capture rv._span = self._span rv._server_segment_span = self._server_segment_span + rv._agent_framework_chat_generation_entered = ( + self._agent_framework_chat_generation_entered + ) rv._session = self._session rv._force_auto_session_tracking = self._force_auto_session_tracking rv._attachments = self._attachments.copy() - rv._profile = self._profile - rv._last_event_id = self._last_event_id rv._flags = deepcopy(self._flags) @@ -469,8 +453,9 @@ def get_client(cls) -> "sentry_sdk.client.BaseClient": If no client is available a :py:class:`sentry_sdk.client.NonRecordingClient` is returned. """ current_scope = _current_scope.get() + try: - client = current_scope.client + client = current_scope.client # type: ignore[union-attr] except AttributeError: client = None @@ -479,7 +464,7 @@ def get_client(cls) -> "sentry_sdk.client.BaseClient": isolation_scope = _isolation_scope.get() try: - client = isolation_scope.client + client = isolation_scope.client # type: ignore[union-attr] except AttributeError: client = None @@ -576,18 +561,6 @@ def generate_propagation_context( if self._propagation_context is None: self.set_new_propagation_context() - def get_dynamic_sampling_context(self) -> "Optional[Dict[str, str]]": - """ - Returns the Dynamic Sampling Context from the Propagation Context. - If not existing, creates a new one. - - Deprecated: Logic moved to PropagationContext, don't use directly. - """ - if self._propagation_context is None: - return None - - return self._propagation_context.dynamic_sampling_context - def get_traceparent(self, *args: "Any", **kwargs: "Any") -> "Optional[str]": """ Returns the Sentry "sentry-trace" header (aka the traceparent) from the @@ -598,11 +571,8 @@ def get_traceparent(self, *args: "Any", **kwargs: "Any") -> "Optional[str]": if not has_tracing_enabled(client.options): return self.get_active_propagation_context().to_traceparent() - span_streaming = has_span_streaming_enabled(client.options) # If we have an active span, return traceparent from there - if span_streaming and self.streamed_span is not None: - return self.streamed_span._to_traceparent() - elif not span_streaming and self.span is not None: + if self.span is not None: return self.span._to_traceparent() # else return traceparent from the propagation context @@ -618,11 +588,8 @@ def get_baggage(self, *args: "Any", **kwargs: "Any") -> "Optional[Baggage]": if not has_tracing_enabled(client.options): return self.get_active_propagation_context().get_baggage() - span_streaming = has_span_streaming_enabled(client.options) # If we have an active span, return baggage from there - if span_streaming and self.streamed_span is not None: - return self.streamed_span._to_baggage() - elif not span_streaming and self.span is not None: + if self.span is not None: return self.span._to_baggage() # else return baggage from the propagation context @@ -632,11 +599,7 @@ def get_trace_context(self) -> "Dict[str, Any]": """ Returns the Sentry "trace" context from the Propagation Context. """ - if ( - has_tracing_enabled(self.get_client().options) - and self._span is not None - and not isinstance(self._span, NoOpSpan) - ): + if has_tracing_enabled(self.get_client().options) and self._span is not None: return self._span._get_trace_context() # if we are tracing externally (otel), those values take precedence @@ -659,12 +622,6 @@ def trace_propagation_meta(self, *args: "Any", **kwargs: "Any") -> str: Return meta tags which should be injected into HTML templates to allow propagation of trace information. """ - span = kwargs.pop("span", None) - if span is not None: - logger.warning( - "The parameter `span` in trace_propagation_meta() is deprecated and will be removed in the future." - ) - meta = "" for name, content in self.iter_trace_propagation_headers(): @@ -672,14 +629,6 @@ def trace_propagation_meta(self, *args: "Any", **kwargs: "Any") -> str: return meta - def iter_headers(self) -> "Iterator[Tuple[str, str]]": - """ - Creates a generator which returns the `sentry-trace` and `baggage` headers from the Propagation Context. - Deprecated: use PropagationContext.iter_headers instead. - """ - if self._propagation_context is not None: - yield from self._propagation_context.iter_headers() - def iter_trace_propagation_headers( self, *args: "Any", **kwargs: "Any" ) -> "Generator[Tuple[str, str], None, None]": @@ -690,24 +639,10 @@ def iter_trace_propagation_headers( If no span is given, the trace data is taken from the scope. """ client = self.get_client() - if not client.options.get("propagate_traces"): - warnings.warn( - "The `propagate_traces` parameter is deprecated. Please use `trace_propagation_targets` instead.", - DeprecationWarning, - stacklevel=2, - ) - return - span = kwargs.pop("span", None) - if not span: - span_streaming = has_span_streaming_enabled(client.options) - span = self.streamed_span if span_streaming else self.span + span = kwargs.pop("span", None) or self.span - if ( - has_tracing_enabled(client.options) - and span is not None - and not isinstance(span, NoOpSpan) - ): + if has_tracing_enabled(client.options) and span is not None: for header in span._iter_headers(): yield header elif has_external_propagation_context(): @@ -756,12 +691,10 @@ def clear(self) -> None: self.clear_breadcrumbs() self._should_capture: bool = True - self._span: "Optional[Union[Span, StreamedSpan]]" = None + self._span: "Optional[Span]" = None self._session: "Optional[Session]" = None self._force_auto_session_tracking: "Optional[bool]" = None - self._profile: "Optional[Profile]" = None - self._propagation_context = None # self._last_event_id is only applicable to isolation scopes @@ -772,22 +705,6 @@ def clear(self) -> None: self._gen_ai_conversation_id: "Optional[str]" = None - @_attr_setter - def level(self, value: "LogLevelStr") -> None: - """ - When set this overrides the level. - - .. deprecated:: 1.0.0 - Use :func:`set_level` instead. - - :param value: The level to set. - """ - logger.warning( - "Deprecated: use .set_level() instead. This will be removed in the future." - ) - - self._level = value - def set_level(self, value: "LogLevelStr") -> None: """ Sets the level for the scope. @@ -801,93 +718,19 @@ def fingerprint(self, value: "Optional[List[str]]") -> None: """When set this overrides the default fingerprint.""" self._fingerprint = value - @property - def transaction(self) -> "Any": - # would be type: () -> Optional[Transaction], see https://github.com/python/mypy/issues/3004 - """Return the transaction (root span) in the scope, if any.""" - - # there is no span/transaction on the scope - if self._span is None: - return None - - if isinstance(self._span, StreamedSpan): - warnings.warn( - "Scope.transaction is not available in streaming mode.", - DeprecationWarning, - stacklevel=2, - ) - return None - - # there is an orphan span on the scope - if self._span.containing_transaction is None: - return None - - # there is either a transaction (which is its own containing - # transaction) or a non-orphan span on the scope - return self._span.containing_transaction - - @transaction.setter - def transaction(self, value: "Any") -> None: - # would be type: (Optional[str]) -> None, see https://github.com/python/mypy/issues/3004 - """When set this forces a specific transaction name to be set. - - Deprecated: use set_transaction_name instead.""" - - # XXX: the docstring above is misleading. The implementation of - # apply_to_event prefers an existing value of event.transaction over - # anything set in the scope. - # XXX: note that with the introduction of the Scope.transaction getter, - # there is a semantic and type mismatch between getter and setter. The - # getter returns a Transaction, the setter sets a transaction name. - # Without breaking version compatibility, we could make the setter set a - # transaction name or transaction (self._span) depending on the type of - # the value argument. - - logger.warning( - "Assigning to scope.transaction directly is deprecated: use scope.set_transaction_name() instead." - ) - self._transaction = value - if self._span: - if isinstance(self._span, StreamedSpan): - warnings.warn( - "Scope.transaction is not available in streaming mode.", - DeprecationWarning, - stacklevel=2, - ) - return None - - if self._span.containing_transaction: - self._span.containing_transaction.name = value - def set_transaction_name(self, name: str, source: "Optional[str]" = None) -> None: """Set the transaction name and optionally the transaction source.""" self._transaction = name if self._span: - if isinstance(self._span, StreamedSpan): - self._span._segment.name = name - if source: - self._span._segment.set_attribute( - "sentry.segment.name.source", getattr(source, "value", source) - ) - - elif self._span.containing_transaction: - self._span.containing_transaction.name = name - if source: - self._span.containing_transaction.source = source + self._span._segment.name = name + if source: + self._span._segment.set_attribute( + "sentry.segment.name.source", getattr(source, "value", source) + ) if source: self._transaction_info["source"] = source - @_attr_setter - def user(self, value: "Optional[Dict[str, Any]]") -> None: - """When set a specific user is bound to the scope. Deprecated in favor of set_user.""" - warnings.warn( - "The `Scope.user` setter is deprecated in favor of `Scope.set_user()`.", - DeprecationWarning, - stacklevel=2, - ) - self.set_user(value) - def set_user(self, value: "Optional[Dict[str, Any]]") -> None: """Sets a user for the scope.""" self._user = value @@ -898,36 +741,19 @@ def set_user(self, value: "Optional[Dict[str, Any]]") -> None: @property def span(self) -> "Optional[Span]": - """Get/set current tracing span or transaction.""" + """Get/set current tracing span.""" return self._span if isinstance(self._span, Span) else None @span.setter def span(self, span: "Optional[Span]") -> None: self._span = span - # XXX: this differs from the implementation in JS, there Scope.setSpan - # does not set Scope._transactionName. - if isinstance(span, Transaction): - transaction = span - if transaction.name: - self._transaction = transaction.name - if transaction.source: - self._transaction_info["source"] = transaction.source - - @property - def streamed_span(self) -> "Optional[StreamedSpan]": - """Get/set current tracing span.""" - return self._span if isinstance(self._span, StreamedSpan) else None - - @streamed_span.setter - def streamed_span(self, span: "Optional[StreamedSpan]") -> None: - self._span = span # Also set _transaction and _transaction_info in streaming mode as this # is used for populating events and linking them to segments - if not isinstance(span, StreamedSpan) or not span._is_segment(): + if not isinstance(span, Span) or not span._is_segment(): return - if type(span) is StreamedSpan: + if type(span) is Span: self._transaction = span.name if span._attributes.get("sentry.segment.name.source"): self._transaction_info["source"] = str( @@ -935,7 +761,7 @@ def streamed_span(self, span: "Optional[StreamedSpan]") -> None: ) return - if type(span) is NoOpStreamedSpan: + if type(span) is NoOpSpan: if span._name is not None: self._transaction = span.name if span._attributes.get("sentry.segment.name.source"): @@ -943,14 +769,6 @@ def streamed_span(self, span: "Optional[StreamedSpan]") -> None: span._attributes["sentry.segment.name.source"] ) - @property - def profile(self) -> "Optional[Profile]": - return self._profile - - @profile.setter - def profile(self, profile: "Optional[Profile]") -> None: - self._profile = profile - def set_tag(self, key: str, value: "Any") -> None: """ Sets a tag for a key to a specific value. @@ -1050,7 +868,6 @@ def add_attachment( filename: "Optional[str]" = None, path: "Optional[str]" = None, content_type: "Optional[str]" = None, - add_to_transactions: bool = False, ) -> None: """Adds an attachment to future events sent from this scope. @@ -1062,7 +879,6 @@ def add_attachment( path=path, filename=filename, content_type=content_type, - add_to_transactions=add_to_transactions, ) ) @@ -1115,203 +931,74 @@ def add_breadcrumb( self._breadcrumbs.popleft() self._n_breadcrumbs_truncated += 1 - def start_transaction( - self, - transaction: "Optional[Transaction]" = None, - instrumenter: str = INSTRUMENTER.SENTRY, - custom_sampling_context: "Optional[SamplingContext]" = None, - **kwargs: "Unpack[TransactionKwargs]", - ) -> "Union[Transaction, NoOpSpan]": - """ - Start and return a transaction. - - Start an existing transaction if given, otherwise create and start a new - transaction with kwargs. - - This is the entry point to manual tracing instrumentation. - - A tree structure can be built by adding child spans to the transaction, - and child spans to other spans. To start a new child span within the - transaction or any span, call the respective `.start_child()` method. - - Every child span must be finished before the transaction is finished, - otherwise the unfinished spans are discarded. - - When used as context managers, spans and transactions are automatically - finished at the end of the `with` block. If not using context managers, - call the `.finish()` method. - - When the transaction is finished, it will be sent to Sentry with all its - finished child spans. - - :param transaction: The transaction to start. If omitted, we create and - start a new transaction. - :param instrumenter: This parameter is meant for internal use only. It - will be removed in the next major version. - :param custom_sampling_context: The transaction's custom sampling context. - :param kwargs: Optional keyword arguments to be passed to the Transaction - constructor. See :py:class:`sentry_sdk.tracing.Transaction` for - available arguments. - """ - client = self.get_client() - if has_span_streaming_enabled(client.options): - warnings.warn( - "Scope.start_transaction is not available in streaming mode.", - DeprecationWarning, - stacklevel=2, - ) - return NoOpSpan() - - kwargs.setdefault("scope", self) - - configuration_instrumenter = client.options["instrumenter"] - - if instrumenter != configuration_instrumenter: - return NoOpSpan() - - try_autostart_continuous_profiler() - - custom_sampling_context = custom_sampling_context or {} - - # kwargs at this point has type TransactionKwargs, since we have removed - # the client and custom_sampling_context from it. - transaction_kwargs: "TransactionKwargs" = kwargs - - # if we haven't been given a transaction, make one - if transaction is None: - transaction = Transaction(**transaction_kwargs) - - # use traces_sample_rate, traces_sampler, and/or inheritance to make a - # sampling decision - sampling_context = { - "transaction_context": transaction.to_json(), - "parent_sampled": transaction.parent_sampled, - } - sampling_context.update(custom_sampling_context) - transaction._set_initial_sampling_decision(sampling_context=sampling_context) - - # update the sample rate in the dsc - if transaction.sample_rate is not None: - propagation_context = self.get_active_propagation_context() - baggage = propagation_context.baggage - - if baggage is not None: - baggage.sentry_items["sample_rate"] = str(transaction.sample_rate) - - if transaction._baggage: - transaction._baggage.sentry_items["sample_rate"] = str( - transaction.sample_rate - ) - - if transaction.sampled: - profile = Profile( - transaction.sampled, transaction._start_timestamp_monotonic_ns - ) - profile._set_initial_sampling_decision(sampling_context=sampling_context) - - transaction._profile = profile - - transaction._continuous_profile = try_profile_lifecycle_trace_start() - - # Typically, the profiler is set when the transaction is created. But when - # using the auto lifecycle, the profiler isn't running when the first - # transaction is started. So make sure we update the profiler id on it. - if transaction._continuous_profile is not None: - transaction.set_profiler_id(get_profiler_id()) - - # we don't bother to keep spans if we already know we're not going to - # send the transaction - max_spans = (client.options["_experiments"].get("max_spans")) or 1000 - transaction.init_span_recorder(maxlen=max_spans) - - return transaction - def start_span( - self, instrumenter: str = INSTRUMENTER.SENTRY, **kwargs: "Any" + self, + name: str, + attributes: "Optional[Attributes]", + parent_span: "Optional[Span]", + active: bool, ) -> "Span": """ - Start a span whose parent is the currently active span or transaction, if any. + Start a span. - The return value is a :py:class:`sentry_sdk.tracing.Span` instance, - typically used as a context manager to start and stop timing in a `with` - block. + The span's parent, unless provided explicitly via the `parent_span` argument, + will be the current active span, if any. If there is none, this span will + become the root of a new span tree. If you explicitly want this span to be + top-level without a parent, set `parent_span=None`. - Only spans contained in a transaction are sent to Sentry. Most - integrations start a transaction at the appropriate time, for example - for every incoming HTTP request. Use - :py:meth:`sentry_sdk.start_transaction` to start a new transaction when - one is not already in progress. + ``start_span()`` can either be used as context manager or you can use the span + object it returns and explicitly end it via ``span.end()``. The following is + equivalent:: - For supported `**kwargs` see :py:class:`sentry_sdk.tracing.Span`. + import sentry_sdk - The instrumenter parameter is deprecated for user code, and it will - be removed in the next major version. Going forward, it should only - be used by the SDK itself. - """ - client = sentry_sdk.get_client() - if has_span_streaming_enabled(client.options): - warnings.warn( - "Scope.start_span is not available in streaming mode.", - DeprecationWarning, - stacklevel=2, - ) - return NoOpSpan() + with sentry_sdk.start_span(name="My Span"): + # do something - if kwargs.get("description") is not None: - warnings.warn( - "The `description` parameter is deprecated. Please use `name` instead.", - DeprecationWarning, - stacklevel=2, - ) + # The span automatically finishes once the ``with`` block is exited - with new_scope(): - kwargs.setdefault("scope", self) + :: - client = self.get_client() + import sentry_sdk - configuration_instrumenter = client.options["instrumenter"] + span = sentry_sdk.start_span(name="My Span") + # do something + span.end() - if instrumenter != configuration_instrumenter: - return NoOpSpan() + To continue a trace from another service, call + `sentry_sdk.continue_trace()` prior to creating a top-level span. - # get current span or transaction - span = self.span or self.get_isolation_scope().span - if isinstance(span, StreamedSpan): - # make mypy happy - return NoOpSpan() + :param name: The name to identify this span by. + :type name: str - if span is None: - # New spans get the `trace_id` from the scope - if "trace_id" not in kwargs: - propagation_context = self.get_active_propagation_context() - kwargs["trace_id"] = propagation_context.trace_id + :param attributes: Key-value attributes to set on the span from the start. + These will also be accessible in the traces sampler. + :type attributes: "Optional[Attributes]" - span = Span(**kwargs) - else: - # Children take `trace_id`` from the parent span. - span = span.start_child(**kwargs) + :param parent_span: A span instance that the new span should consider its + parent. If not provided, the parent will be set to the currently active + span, if any. If set to `None`, this span will become a new root-level + span. + :type parent_span: "Optional[Span]" - return span + :param active: Controls whether spans started while this span is running + will automatically become its children. That's the default behavior. If + you want to create a span that shouldn't have any children (unless + provided explicitly via the `parent_span` argument), set this to `False`. + :type active: bool - def start_streamed_span( - self, - name: str, - attributes: "Optional[Attributes]", - parent_span: "Optional[StreamedSpan]", - active: bool, - ) -> "StreamedSpan": - # TODO: rename to start_span once we drop the old API - if isinstance(parent_span, NoOpStreamedSpan): + :return: The span that has been started. + :rtype: Span + """ + if isinstance(parent_span, NoOpSpan): # parent_span is only set if the user explicitly set it logger.debug( "Ignored parent span provided. Span will be parented to the " "currently active span instead." ) - if parent_span is _DEFAULT_PARENT_SPAN or isinstance( - parent_span, NoOpStreamedSpan - ): - parent_span = self.streamed_span + if parent_span is _DEFAULT_PARENT_SPAN or isinstance(parent_span, NoOpSpan): + parent_span = self.span # If no eligible parent_span was provided and there is no currently # active span, this is a new segment @@ -1319,7 +1006,7 @@ def start_streamed_span( propagation_context = self.get_active_propagation_context() if is_ignored_span(name, attributes): - return NoOpStreamedSpan( + return NoOpSpan( name=name, attributes=attributes, scope=self, @@ -1341,7 +1028,7 @@ def start_streamed_span( self._update_sample_rate(sample_rate) if sampled is False or sampled is None: - return NoOpStreamedSpan( + return NoOpSpan( name=name, attributes=attributes, scope=self, @@ -1356,7 +1043,7 @@ def start_streamed_span( sample_rate=sample_rate, ) - return StreamedSpan( + return Span( name=name, attributes=attributes, active=active, @@ -1373,7 +1060,7 @@ def start_streamed_span( # This is a child span; take propagation context from the parent span with new_scope(): if is_ignored_span(name, attributes): - return NoOpStreamedSpan( + return NoOpSpan( name=name, attributes=attributes, segment=parent_span._segment, @@ -1383,8 +1070,8 @@ def start_streamed_span( unsampled_reason="ignored", ) - if isinstance(parent_span, NoOpStreamedSpan): - return NoOpStreamedSpan( + if isinstance(parent_span, NoOpSpan): + return NoOpSpan( name=name, attributes=attributes, segment=parent_span._segment, @@ -1394,7 +1081,7 @@ def start_streamed_span( unsampled_reason=parent_span._unsampled_reason, ) - return StreamedSpan( + return Span( name=name, attributes=attributes, active=active, @@ -1414,39 +1101,6 @@ def _update_sample_rate(self, sample_rate: float) -> None: if baggage is not None and baggage.sentry_items.get("sample_rate"): baggage.sentry_items["sample_rate"] = str(sample_rate) - def continue_trace( - self, - environ_or_headers: "Dict[str, Any]", - op: "Optional[str]" = None, - name: "Optional[str]" = None, - source: "Optional[str]" = None, - origin: str = "manual", - ) -> "Transaction": - """ - Sets the propagation context from environment or headers and returns a transaction. - """ - self.generate_propagation_context(environ_or_headers) - - # generate_propagation_context ensures that the propagation_context is not None. - propagation_context = cast(PropagationContext, self._propagation_context) - - optional_kwargs = {} - if name: - optional_kwargs["name"] = name - if source: - optional_kwargs["source"] = source - - return Transaction( - op=op, - origin=origin, - baggage=propagation_context.baggage, - parent_sampled=propagation_context.parent_sampled, - trace_id=propagation_context.trace_id, - parent_span_id=propagation_context.parent_span_id, - same_process_as_parent=False, - **optional_kwargs, - ) - def capture_event( self, event: "Event", @@ -1479,7 +1133,7 @@ def capture_event( event_id = self.get_client().capture_event(event=event, hint=hint, scope=scope) - if event_id is not None and event.get("type") != "transaction": + if event_id is not None: self.get_isolation_scope()._last_event_id = event_id return event_id @@ -1516,15 +1170,13 @@ def _capture_metric(self, metric: "Optional[Metric]") -> None: client._capture_metric(metric, scope=merged_scope) - def _capture_span(self, span: "Optional[StreamedSpan]") -> None: + def _capture_span(self, span: "Optional[Span]") -> None: if span is None: return - client = self.get_client() - if not has_span_streaming_enabled(client.options): - return - merged_scope = self._merge_scopes() + + client = self.get_client() client._capture_span(span, scope=merged_scope) def capture_message( @@ -1771,7 +1423,7 @@ def _apply_flags_to_event( ) def _apply_scope_attributes_to_telemetry( - self, telemetry: "Union[Log, Metric, StreamedSpan]" + self, telemetry: "Union[Log, Metric, Span]" ) -> None: # TODO: turn Logs, Metrics into actual classes if isinstance(telemetry, dict): @@ -1784,7 +1436,7 @@ def _apply_scope_attributes_to_telemetry( attributes[attribute] = value def _apply_user_attributes_to_telemetry( - self, telemetry: "Union[Log, Metric, StreamedSpan]" + self, telemetry: "Union[Log, Metric, Span]" ) -> None: if isinstance(telemetry, dict): attributes = telemetry["attributes"] @@ -1874,7 +1526,6 @@ def apply_to_event( ) -> "Optional[Event]": """Applies the information contained on the scope to the given event.""" ty = event.get("type") - is_transaction = ty == "transaction" is_check_in = ty == "check_in" # put all attachments into the hint. This lets callbacks play around @@ -1882,8 +1533,7 @@ def apply_to_event( # create the envelope. attachments_to_send = hint.get("attachments") or [] for attachment in self._attachments: - if not is_transaction or attachment.add_to_transactions: - attachments_to_send.append(attachment) + attachments_to_send.append(attachment) hint["attachments"] = attachments_to_send self._apply_contexts_to_event(event, hint, options) @@ -1902,8 +1552,6 @@ def apply_to_event( self._apply_transaction_info_to_event(event, hint, options) self._apply_tags_to_event(event, hint, options) self._apply_extra_to_event(event, hint, options) - - if not is_transaction and not is_check_in: self._apply_breadcrumbs_to_event(event, hint, options) self._apply_flags_to_event(event, hint, options) @@ -1918,10 +1566,10 @@ def apply_to_event( return event @_disable_capture - def apply_to_telemetry(self, telemetry: "Union[Log, Metric, StreamedSpan]") -> None: + def apply_to_telemetry(self, telemetry: "Union[Log, Metric, Span]") -> None: # Attributes-based events and telemetry go through here (logs, metrics, # spansV2) - if not isinstance(telemetry, StreamedSpan): + if not isinstance(telemetry, Span): trace_context = self.get_trace_context() trace_id = trace_context.get("trace_id") if telemetry.get("trace_id") is None and trace_id is not None: @@ -1931,9 +1579,7 @@ def apply_to_telemetry(self, telemetry: "Union[Log, Metric, StreamedSpan]") -> N # use the trace_context here because it synthesizes a span_id if there # isn't one if telemetry.get("span_id") is None: - if self._span is not None and not isinstance( - self._span, (NoOpStreamedSpan, NoOpSpan) - ): + if self._span is not None and not isinstance(self._span, NoOpSpan): telemetry["span_id"] = self._span.span_id else: external_propagation_context = get_external_propagation_context() @@ -1969,18 +1615,12 @@ def update_from_scope(self, scope: "Scope") -> None: self._n_breadcrumbs_truncated = ( self._n_breadcrumbs_truncated + scope._n_breadcrumbs_truncated ) - if scope._gen_ai_original_message_count: - self._gen_ai_original_message_count.update( - scope._gen_ai_original_message_count - ) if scope._gen_ai_conversation_id: self._gen_ai_conversation_id = scope._gen_ai_conversation_id if scope._span: self._span = scope._span if scope._attachments: self._attachments.extend(scope._attachments) - if scope._profile: - self._profile = scope._profile if scope._propagation_context: self._propagation_context = scope._propagation_context if scope._session: diff --git a/sentry_sdk/sessions.py b/sentry_sdk/sessions.py index aabf874fcd..ea4a9a8757 100644 --- a/sentry_sdk/sessions.py +++ b/sentry_sdk/sessions.py @@ -1,5 +1,4 @@ import os -import warnings from contextlib import contextmanager from threading import Event, Lock, Thread from typing import TYPE_CHECKING @@ -10,76 +9,7 @@ from sentry_sdk.utils import format_timestamp if TYPE_CHECKING: - from typing import Any, Callable, Dict, Generator, List, Optional, Union - - -def is_auto_session_tracking_enabled( - hub: "Optional[sentry_sdk.Hub]" = None, -) -> "Union[Any, bool, None]": - """DEPRECATED: Utility function to find out if session tracking is enabled.""" - - # Internal callers should use private _is_auto_session_tracking_enabled, instead. - warnings.warn( - "This function is deprecated and will be removed in the next major release. " - "There is no public API replacement.", - DeprecationWarning, - stacklevel=2, - ) - - if hub is None: - hub = sentry_sdk.Hub.current - - should_track = hub.scope._force_auto_session_tracking - - if should_track is None: - client_options = hub.client.options if hub.client else {} - should_track = client_options.get("auto_session_tracking", False) - - return should_track - - -@contextmanager -def auto_session_tracking( - hub: "Optional[sentry_sdk.Hub]" = None, session_mode: str = "application" -) -> "Generator[None, None, None]": - """DEPRECATED: Use track_session instead - Starts and stops a session automatically around a block. - """ - warnings.warn( - "This function is deprecated and will be removed in the next major release. " - "Use track_session instead.", - DeprecationWarning, - stacklevel=2, - ) - - if hub is None: - hub = sentry_sdk.Hub.current - with warnings.catch_warnings(): - warnings.simplefilter("ignore", DeprecationWarning) - should_track = is_auto_session_tracking_enabled(hub) - if should_track: - hub.start_session(session_mode=session_mode) - try: - yield - finally: - if should_track: - hub.end_session() - - -def is_auto_session_tracking_enabled_scope(scope: "sentry_sdk.Scope") -> bool: - """ - DEPRECATED: Utility function to find out if session tracking is enabled. - """ - - warnings.warn( - "This function is deprecated and will be removed in the next major release. " - "There is no public API replacement.", - DeprecationWarning, - stacklevel=2, - ) - - # Internal callers should use private _is_auto_session_tracking_enabled, instead. - return _is_auto_session_tracking_enabled(scope) + from typing import Any, Callable, Dict, Generator, List, Optional def _is_auto_session_tracking_enabled(scope: "sentry_sdk.Scope") -> bool: @@ -95,24 +25,6 @@ def _is_auto_session_tracking_enabled(scope: "sentry_sdk.Scope") -> bool: return should_track -@contextmanager -def auto_session_tracking_scope( - scope: "sentry_sdk.Scope", session_mode: str = "application" -) -> "Generator[None, None, None]": - """DEPRECATED: This function is a deprecated alias for track_session. - Starts and stops a session automatically around a block. - """ - - warnings.warn( - "This function is a deprecated alias for track_session and will be removed in the next major release.", - DeprecationWarning, - stacklevel=2, - ) - - with track_session(scope, session_mode=session_mode): - yield - - @contextmanager def track_session( scope: "sentry_sdk.Scope", session_mode: str = "application" diff --git a/sentry_sdk/spotlight.py b/sentry_sdk/spotlight.py index 2dcc86bc47..41877346bc 100644 --- a/sentry_sdk/spotlight.py +++ b/sentry_sdk/spotlight.py @@ -3,20 +3,15 @@ import os import sys import time -import urllib.error -import urllib.parse -import urllib.request -from itertools import chain, product from typing import TYPE_CHECKING import urllib3 if TYPE_CHECKING: - from typing import Any, Callable, Dict, Optional, Self + from typing import Any, Dict, Optional from sentry_sdk.envelope import Envelope from sentry_sdk.utils import ( - capture_internal_exceptions, env_to_bool, ) from sentry_sdk.utils import ( @@ -27,7 +22,6 @@ DEFAULT_SPOTLIGHT_URL = "http://localhost:8969/stream" -DJANGO_SPOTLIGHT_MIDDLEWARE_PATH = "sentry_sdk.spotlight.SpotlightMiddleware" class SpotlightClient: @@ -90,145 +84,6 @@ def capture_envelope(self, envelope: "Envelope") -> None: ) -try: - from django.conf import settings - from django.http import HttpRequest, HttpResponse, HttpResponseServerError - from django.utils.deprecation import MiddlewareMixin - - SPOTLIGHT_JS_ENTRY_PATH = "/assets/main.js" - SPOTLIGHT_JS_SNIPPET_PATTERN = ( - "\n" - '\n' - ) - SPOTLIGHT_ERROR_PAGE_SNIPPET = ( - '\n' - '\n' - ) - CHARSET_PREFIX = "charset=" - BODY_TAG_NAME = "body" - BODY_CLOSE_TAG_POSSIBILITIES = tuple( - "".format("".join(chars)) - for chars in product(*zip(BODY_TAG_NAME.upper(), BODY_TAG_NAME.lower())) - ) - - class SpotlightMiddleware(MiddlewareMixin): # type: ignore[misc] - _spotlight_script: "Optional[str]" = None - _spotlight_url: "Optional[str]" = None - - def __init__(self: "Self", get_response: "Callable[..., HttpResponse]") -> None: - super().__init__(get_response) - - import sentry_sdk.api - - self.sentry_sdk = sentry_sdk.api - - spotlight_client = self.sentry_sdk.get_client().spotlight - if spotlight_client is None: - sentry_logger.warning( - "Cannot find Spotlight client from SpotlightMiddleware, disabling the middleware." - ) - return None - # Spotlight URL has a trailing `/stream` part at the end so split it off - self._spotlight_url = urllib.parse.urljoin(spotlight_client.url, "../") - - @property - def spotlight_script(self: "Self") -> "Optional[str]": - if self._spotlight_url is not None and self._spotlight_script is None: - try: - spotlight_js_url = urllib.parse.urljoin( - self._spotlight_url, SPOTLIGHT_JS_ENTRY_PATH - ) - req = urllib.request.Request( - spotlight_js_url, - method="HEAD", - ) - urllib.request.urlopen(req) - self._spotlight_script = SPOTLIGHT_JS_SNIPPET_PATTERN.format( - spotlight_url=self._spotlight_url, - spotlight_js_url=spotlight_js_url, - ) - except urllib.error.URLError as err: - sentry_logger.debug( - "Cannot get Spotlight JS to inject at %s. SpotlightMiddleware will not be very useful.", - spotlight_js_url, - exc_info=err, - ) - - return self._spotlight_script - - def process_response( - self: "Self", _request: "HttpRequest", response: "HttpResponse" - ) -> "Optional[HttpResponse]": - content_type_header = tuple( - p.strip() - for p in response.headers.get("Content-Type", "").lower().split(";") - ) - content_type = content_type_header[0] - if len(content_type_header) > 1 and content_type_header[1].startswith( - CHARSET_PREFIX - ): - encoding = content_type_header[1][len(CHARSET_PREFIX) :] - else: - encoding = "utf-8" - - if ( - self.spotlight_script is not None - and not response.streaming - and content_type == "text/html" - ): - content_length = len(response.content) - injection = self.spotlight_script.encode(encoding) - injection_site = next( - ( - idx - for idx in ( - response.content.rfind(body_variant.encode(encoding)) - for body_variant in BODY_CLOSE_TAG_POSSIBILITIES - ) - if idx > -1 - ), - content_length, - ) - - # This approach works even when we don't have a `` tag - response.content = ( - response.content[:injection_site] - + injection - + response.content[injection_site:] - ) - - if response.has_header("Content-Length"): - response.headers["Content-Length"] = content_length + len(injection) - - return response - - def process_exception( - self: "Self", _request: "HttpRequest", exception: Exception - ) -> "Optional[HttpResponseServerError]": - if not settings.DEBUG or not self._spotlight_url: - return None - - try: - spotlight = ( - urllib.request.urlopen(self._spotlight_url).read().decode("utf-8") - ) - except urllib.error.URLError: - return None - else: - event_id = self.sentry_sdk.capture_exception(exception) - return HttpResponseServerError( - spotlight.replace( - "", - SPOTLIGHT_ERROR_PAGE_SNIPPET.format( - spotlight_url=self._spotlight_url, event_id=event_id - ), - ) - ) - -except ImportError: - settings = None - - def _resolve_spotlight_url( spotlight_config: "Any", sentry_logger: "Any" ) -> "Optional[str]": @@ -307,20 +162,6 @@ def setup_spotlight(options: "Dict[str, Any]") -> "Optional[SpotlightClient]": # Update options with resolved URL for consistency options["spotlight"] = url - with capture_internal_exceptions(): - if ( - settings is not None - and settings.DEBUG - and env_to_bool(os.environ.get("SENTRY_SPOTLIGHT_ON_ERROR", "1")) - and env_to_bool(os.environ.get("SENTRY_SPOTLIGHT_MIDDLEWARE", "1")) - ): - middleware = settings.MIDDLEWARE - if DJANGO_SPOTLIGHT_MIDDLEWARE_PATH not in middleware: - settings.MIDDLEWARE = type(middleware)( - chain(middleware, (DJANGO_SPOTLIGHT_MIDDLEWARE_PATH,)) - ) - logger.info("Enabled Spotlight integration for Django") - client = SpotlightClient(url) logger.info("Enabled Spotlight using sidecar at %s", url) diff --git a/sentry_sdk/traces.py b/sentry_sdk/traces.py index d9f0d6e596..638c52f6a1 100644 --- a/sentry_sdk/traces.py +++ b/sentry_sdk/traces.py @@ -1,26 +1,5 @@ -""" -The API in this file is only meant to be used in span streaming mode. It should -not be mixed with the legacy tracing API (sentry_sdk.start_transaction, -sentry_sdk.start_span, etc.). - -You can enable span streaming mode via: - -``` -import sentry_sdk - -sentry_sdk.init( - trace_lifecycle="stream", -) -``` - -See -https://docs.sentry.io/platforms/python/tracing/streamed-spans/migration-guide/ -for how to migrate to span streaming. -""" - import sys import uuid -import warnings from datetime import datetime, timedelta, timezone from enum import Enum from typing import TYPE_CHECKING @@ -32,9 +11,9 @@ try_autostart_continuous_profiler, try_profile_lifecycle_trace_start, ) -from sentry_sdk.tracing_utils import Baggage from sentry_sdk.utils import ( capture_internal_exceptions, + deprecation_warning, format_attribute, get_current_thread_meta, logger, @@ -114,94 +93,66 @@ def __str__(self) -> str: _DEFAULT_PARENT_SPAN = object() -def start_span( - name: str, - attributes: "Optional[Attributes]" = None, - parent_span: "Optional[StreamedSpan]" = _DEFAULT_PARENT_SPAN, # type: ignore[assignment] - active: bool = True, -) -> "StreamedSpan": +class _AgentFrameworkChatGenerationContext: """ - Start a span in streaming mode. - - The span's parent, unless provided explicitly via the `parent_span` argument, - will be the current active span, if any. If there is none, this span will - become the root of a new span tree. If you explicitly want this span to be - top-level without a parent, set `parent_span=None`. - - `start_span()` can either be used as context manager or you can use the span - object it returns and explicitly end it via `span.end()`. The following is - equivalent: - - ```python - import sentry_sdk + Starts a span for a chat generation and marks the current scope as being + inside a chat generation as viewed by an agent framework. - with sentry_sdk.traces.start_span(name="My Span"): - # do something - - # The span automatically finishes once the `with` block is exited - ``` + Agent framework integrations should use this class to create chat client spans. By using this context + manager, chat client spans in "lower-level" client libraries can be suppressed by checking the + `_agent_framework_chat_generation_entered` scope flag. + """ - ```python - import sentry_sdk + def __init__( + self, + name: str, + attributes: "Optional[Attributes]" = None, + parent_span: "Optional[Span]" = _DEFAULT_PARENT_SPAN, # type: ignore[assignment] + active: bool = True, + ): + self._span = start_span( + name=name, + attributes=attributes, + parent_span=parent_span, + active=active, + ) + if type(self._span) is not Span: + return - span = sentry_sdk.traces.start_span(name="My Span") - # do something - span.end() - ``` + self.span._scope._agent_framework_chat_generation_entered = True - To continue a trace from another service, call - `sentry_sdk.traces.continue_trace()` prior to creating a top-level span. + @property + def span(self) -> "Span": + return self._span - :param name: The name to identify this span by. - :type name: str + def __enter__(self) -> "_AgentFrameworkChatGenerationContext": + return self - :param attributes: Key-value attributes to set on the span from the start. - These will also be accessible in the traces sampler. - :type attributes: "Optional[Attributes]" + def __exit__( + self, ty: "Optional[Any]", value: "Optional[Any]", tb: "Optional[Any]" + ) -> None: + if type(self._span) is not Span: + self._span.__exit__(ty, value, tb) - :param parent_span: A span instance that the new span should consider its - parent. If not provided, the parent will be set to the currently active - span, if any. If set to `None`, this span will become a new root-level - span. - :type parent_span: "Optional[StreamedSpan]" + try: + self._span.__exit__(ty, value, tb) + finally: + self._span._scope._agent_framework_chat_generation_entered = False - :param active: Controls whether spans started while this span is running - will automatically become its children. That's the default behavior. If - you want to create a span that shouldn't have any children (unless - provided explicitly via the `parent_span` argument), set this to `False`. - :type active: bool - :return: The span that has been started. - :rtype: StreamedSpan - """ - from sentry_sdk.tracing_utils import has_span_streaming_enabled - - client = sentry_sdk.get_client() - if client.is_active() and not has_span_streaming_enabled(client.options): - warnings.warn( - "Using span streaming API in non-span-streaming mode. Use " - "sentry_sdk.start_transaction() and sentry_sdk.start_span() " - "instead.", - stacklevel=2, - ) - return NoOpStreamedSpan() +def start_span( + name: str, + attributes: "Optional[Attributes]" = None, + parent_span: "Optional[Span]" = _DEFAULT_PARENT_SPAN, # type: ignore[assignment] + active: bool = True, +) -> "Span": - return sentry_sdk.get_current_scope().start_streamed_span( + return sentry_sdk.get_current_scope().start_span( name, attributes, parent_span, active ) def continue_trace(incoming: "dict[str, Any]") -> None: - """ - Continue a trace from headers or environment variables in streaming mode. - - This function sets the propagation context on the scope. Any span started - in the updated scope will belong under the trace extracted from the - provided propagation headers or environment variables. - - continue_trace() doesn't start any spans on its own. Use the start_span() - API for that. - """ # This is set both on the isolation and the current scope for compatibility # reasons. Conceptually, it belongs on the isolation scope, and it also # used to be set there in non-span-first mode. But in span first mode, we @@ -216,20 +167,11 @@ def continue_trace(incoming: "dict[str, Any]") -> None: def new_trace() -> None: - """ - Resets the propagation context, forcing a new trace, in streaming mode. - - This function sets the propagation context on the scope. Any span started - in the updated scope will start its own trace. - - new_trace() doesn't start any spans on its own. Use the start_span() API - for that. - """ sentry_sdk.get_isolation_scope().set_new_propagation_context() sentry_sdk.get_current_scope().set_new_propagation_context() -class StreamedSpan: +class Span: """ A span holds timing information of a block of code. @@ -267,7 +209,7 @@ def __init__( attributes: "Optional[Attributes]" = None, active: bool = True, scope: "sentry_sdk.Scope", - segment: "Optional[StreamedSpan]" = None, + segment: "Optional[Span]" = None, trace_id: "Optional[str]" = None, parent_span_id: "Optional[str]" = None, parent_sampled: "Optional[bool]" = None, @@ -328,7 +270,7 @@ def __repr__(self) -> str: f"active={self._active})>" ) - def __enter__(self) -> "StreamedSpan": + def __enter__(self) -> "Span": return self def __exit__( @@ -353,18 +295,16 @@ def end(self, end_timestamp: "Optional[Union[float, datetime]]" = None) -> None: self._end(end_timestamp) def finish(self, end_timestamp: "Optional[Union[float, datetime]]" = None) -> None: - warnings.warn( + deprecation_warning( "span.finish() is deprecated. Use span.end() instead.", - stacklevel=2, - category=DeprecationWarning, ) self.end(end_timestamp) def _start(self) -> None: if self._active: - old_span = self._scope.streamed_span - self._scope.streamed_span = self + old_span = self._scope.span + self._scope.span = self self._previous_span_on_scope = old_span def _end(self, end_timestamp: "Optional[Union[float, datetime]]" = None) -> None: @@ -382,7 +322,7 @@ def _end(self, end_timestamp: "Optional[Union[float, datetime]]" = None) -> None with capture_internal_exceptions(): old_span = self._previous_span_on_scope del self._previous_span_on_scope - self._scope.streamed_span = old_span + self._scope.span = old_span # Set attributes from the segment. These are set on span end on purpose # so that we have the best chance to capture the segment's final name @@ -627,7 +567,7 @@ def _to_json(self) -> "SpanJSON": return res -class NoOpStreamedSpan(StreamedSpan): +class NoOpSpan(Span): __slots__ = ( "_sampled", "_finished", @@ -638,7 +578,7 @@ def __init__( self, name: "Optional[str]" = None, attributes: "Optional[Attributes]" = None, - segment: "Optional[StreamedSpan]" = None, + segment: "Optional[Span]" = None, trace_id: "Optional[str]" = None, parent_span_id: "Optional[str]" = None, parent_sampled: "Optional[bool]" = None, @@ -676,9 +616,9 @@ def __init__( self._start() def __repr__(self) -> str: - return f"<{self.__class__.__name__}(sampled={self.sampled})>" + return f"<{self.__class__.__name__}(name={self.name}, sampled={self.sampled})>" - def __enter__(self) -> "NoOpStreamedSpan": + def __enter__(self) -> "NoOpSpan": return self def __exit__( @@ -690,8 +630,8 @@ def _start(self) -> None: if self._scope is None: return - old_span = self._scope.streamed_span - self._scope.streamed_span = self + old_span = self._scope.span + self._scope.span = self self._previous_span_on_scope = old_span def _end(self, end_timestamp: "Optional[Union[float, datetime]]" = None) -> None: @@ -714,7 +654,7 @@ def _end(self, end_timestamp: "Optional[Union[float, datetime]]" = None) -> None with capture_internal_exceptions(): old_span = self._previous_span_on_scope del self._previous_span_on_scope - self._scope.streamed_span = old_span + self._scope.span = old_span self._finished = True @@ -722,10 +662,8 @@ def end(self, end_timestamp: "Optional[Union[float, datetime]]" = None) -> None: self._end() def finish(self, end_timestamp: "Optional[Union[float, datetime]]" = None) -> None: - warnings.warn( + deprecation_warning( "span.finish() is deprecated. Use span.end() instead.", - stacklevel=2, - category=DeprecationWarning, ) self._end() @@ -790,6 +728,10 @@ def _get_trace_context(self) -> "dict[str, Any]": } +# backwards compat +StreamedSpan = Span +NoOpStreamedSpan = NoOpSpan + if TYPE_CHECKING: @overload @@ -865,10 +807,10 @@ def make_db_query(sql): pass """ from sentry_sdk.tracing_utils import ( - create_streaming_span_decorator, + create_span_decorator, ) - decorator = create_streaming_span_decorator( + decorator = create_span_decorator( name=name, attributes=attributes, active=active, @@ -882,13 +824,11 @@ def make_db_query(sql): def get_current_span( scope: "Optional[sentry_sdk.Scope]" = None, -) -> "Optional[StreamedSpan]": - """ - Returns the currently active span on the scope if the span is a `StreamedSpan`, otherwise `None`. - - This function will only return a non-`None` value when the streaming trace lifecycle is enabled. - To enable the lifecycle, pass `trace_lifecycle="stream"` to `sentry.init()`. - """ +) -> "Optional[Span]": scope = scope or sentry_sdk.get_current_scope() - current_span = scope.streamed_span + current_span = scope.span return current_span + + +# Circular import +from sentry_sdk.tracing_utils import Baggage # noqa: E402, F401, I001 diff --git a/sentry_sdk/tracing.py b/sentry_sdk/tracing.py deleted file mode 100644 index aab2794621..0000000000 --- a/sentry_sdk/tracing.py +++ /dev/null @@ -1,1496 +0,0 @@ -import uuid -import warnings -from datetime import datetime, timedelta, timezone -from enum import Enum -from typing import TYPE_CHECKING, cast - -import sentry_sdk -from sentry_sdk.consts import INSTRUMENTER, SPANDATA, SPANSTATUS, SPANTEMPLATE -from sentry_sdk.profiler.continuous_profiler import get_profiler_id -from sentry_sdk.utils import ( - capture_internal_exceptions, - get_current_thread_meta, - is_valid_sample_rate, - logger, - nanosecond_time, - should_be_treated_as_error, -) - -if TYPE_CHECKING: - from collections.abc import Callable, Mapping, MutableMapping - from typing import ( - Any, - Dict, - Iterator, - List, - Optional, - ParamSpec, - Tuple, - TypeVar, - Union, - overload, - ) - - from typing_extensions import TypedDict, Unpack - - P = ParamSpec("P") - R = TypeVar("R") - - from sentry_sdk._types import ( - Event, - MeasurementUnit, - MeasurementValue, - SamplingContext, - ) - from sentry_sdk.profiler.continuous_profiler import ContinuousProfile - from sentry_sdk.profiler.transaction_profiler import Profile - - class SpanKwargs(TypedDict, total=False): - trace_id: str - """ - The trace ID of the root span. If this new span is to be the root span, - omit this parameter, and a new trace ID will be generated. - """ - - span_id: str - """The span ID of this span. If omitted, a new span ID will be generated.""" - - parent_span_id: str - """The span ID of the parent span, if applicable.""" - - same_process_as_parent: bool - """Whether this span is in the same process as the parent span.""" - - sampled: bool - """ - Whether the span should be sampled. Overrides the default sampling decision - for this span when provided. - """ - - op: str - """ - The span's operation. A list of recommended values is available here: - https://develop.sentry.dev/sdk/performance/span-operations/ - """ - - description: str - """A description of what operation is being performed within the span. This argument is DEPRECATED. Please use the `name` parameter, instead.""" - - hub: "Optional[sentry_sdk.Hub]" - """The hub to use for this span. This argument is DEPRECATED. Please use the `scope` parameter, instead.""" - - status: str - """The span's status. Possible values are listed at https://develop.sentry.dev/sdk/event-payloads/span/""" - - containing_transaction: "Optional[Transaction]" - """The transaction that this span belongs to.""" - - start_timestamp: "Optional[Union[datetime, float]]" - """ - The timestamp when the span started. If omitted, the current time - will be used. - """ - - scope: "sentry_sdk.Scope" - """The scope to use for this span. If not provided, we use the current scope.""" - - origin: str - """ - The origin of the span. - See https://develop.sentry.dev/sdk/performance/trace-origin/ - Default "manual". - """ - - name: str - """A string describing what operation is being performed within the span/transaction.""" - - class TransactionKwargs(SpanKwargs, total=False): - source: str - """ - A string describing the source of the transaction name. This will be used to determine the transaction's type. - See https://develop.sentry.dev/sdk/event-payloads/transaction/#transaction-annotations for more information. - Default "custom". - """ - - parent_sampled: bool - """Whether the parent transaction was sampled. If True this transaction will be kept, if False it will be discarded.""" - - baggage: "Baggage" - """The W3C baggage header value. (see https://www.w3.org/TR/baggage/)""" - - ProfileContext = TypedDict( - "ProfileContext", - { - "profiler_id": str, - }, - ) - -BAGGAGE_HEADER_NAME = "baggage" -SENTRY_TRACE_HEADER_NAME = "sentry-trace" - - -# Transaction source -# see https://develop.sentry.dev/sdk/event-payloads/transaction/#transaction-annotations -class TransactionSource(str, Enum): - COMPONENT = "component" - CUSTOM = "custom" - ROUTE = "route" - TASK = "task" - URL = "url" - VIEW = "view" - - def __str__(self) -> str: - return self.value - - -# These are typically high cardinality and the server hates them -LOW_QUALITY_TRANSACTION_SOURCES = [ - TransactionSource.URL, -] - -SOURCE_FOR_STYLE = { - "endpoint": TransactionSource.COMPONENT, - "function_name": TransactionSource.COMPONENT, - "handler_name": TransactionSource.COMPONENT, - "method_and_path_pattern": TransactionSource.ROUTE, - "path": TransactionSource.URL, - "route_name": TransactionSource.COMPONENT, - "route_pattern": TransactionSource.ROUTE, - "uri_template": TransactionSource.ROUTE, - "url": TransactionSource.ROUTE, -} - - -def get_span_status_from_http_code(http_status_code: int) -> str: - """ - Returns the Sentry status corresponding to the given HTTP status code. - - See: https://develop.sentry.dev/sdk/event-payloads/contexts/#trace-context - """ - if http_status_code < 400: - return SPANSTATUS.OK - - elif 400 <= http_status_code < 500: - if http_status_code == 403: - return SPANSTATUS.PERMISSION_DENIED - elif http_status_code == 404: - return SPANSTATUS.NOT_FOUND - elif http_status_code == 429: - return SPANSTATUS.RESOURCE_EXHAUSTED - elif http_status_code == 413: - return SPANSTATUS.FAILED_PRECONDITION - elif http_status_code == 401: - return SPANSTATUS.UNAUTHENTICATED - elif http_status_code == 409: - return SPANSTATUS.ALREADY_EXISTS - else: - return SPANSTATUS.INVALID_ARGUMENT - - elif 500 <= http_status_code < 600: - if http_status_code == 504: - return SPANSTATUS.DEADLINE_EXCEEDED - elif http_status_code == 501: - return SPANSTATUS.UNIMPLEMENTED - elif http_status_code == 503: - return SPANSTATUS.UNAVAILABLE - else: - return SPANSTATUS.INTERNAL_ERROR - - return SPANSTATUS.UNKNOWN_ERROR - - -class _SpanRecorder: - """Limits the number of spans recorded in a transaction.""" - - __slots__ = ("maxlen", "spans", "dropped_spans") - - def __init__(self, maxlen: int) -> None: - # FIXME: this is `maxlen - 1` only to preserve historical behavior - # enforced by tests. - # Either this should be changed to `maxlen` or the JS SDK implementation - # should be changed to match a consistent interpretation of what maxlen - # limits: either transaction+spans or only child spans. - self.maxlen = maxlen - 1 - self.spans: "List[Span]" = [] - self.dropped_spans: int = 0 - - def add(self, span: "Span") -> None: - if len(self.spans) > self.maxlen: - span._span_recorder = None - self.dropped_spans += 1 - else: - self.spans.append(span) - - -class Span: - """A span holds timing information of a block of code. - Spans can have multiple child spans thus forming a span tree. - - :param trace_id: The trace ID of the root span. If this new span is to be the root span, - omit this parameter, and a new trace ID will be generated. - :param span_id: The span ID of this span. If omitted, a new span ID will be generated. - :param parent_span_id: The span ID of the parent span, if applicable. - :param same_process_as_parent: Whether this span is in the same process as the parent span. - :param sampled: Whether the span should be sampled. Overrides the default sampling decision - for this span when provided. - :param op: The span's operation. A list of recommended values is available here: - https://develop.sentry.dev/sdk/performance/span-operations/ - :param description: A description of what operation is being performed within the span. - - .. deprecated:: 2.15.0 - Please use the `name` parameter, instead. - :param name: A string describing what operation is being performed within the span. - :param hub: The hub to use for this span. - - .. deprecated:: 2.0.0 - Please use the `scope` parameter, instead. - :param status: The span's status. Possible values are listed at - https://develop.sentry.dev/sdk/event-payloads/span/ - :param containing_transaction: The transaction that this span belongs to. - :param start_timestamp: The timestamp when the span started. If omitted, the current time - will be used. - :param scope: The scope to use for this span. If not provided, we use the current scope. - """ - - __slots__ = ( - "_trace_id", - "_span_id", - "parent_span_id", - "same_process_as_parent", - "sampled", - "op", - "description", - "_measurements", - "start_timestamp", - "_start_timestamp_monotonic_ns", - "status", - "timestamp", - "_tags", - "_data", - "_span_recorder", - "hub", - "_context_manager_state", - "_containing_transaction", - "scope", - "origin", - "name", - "_flags", - "_flags_capacity", - ) - - def __init__( - self, - trace_id: "Optional[str]" = None, - span_id: "Optional[str]" = None, - parent_span_id: "Optional[str]" = None, - same_process_as_parent: bool = True, - sampled: "Optional[bool]" = None, - op: "Optional[str]" = None, - description: "Optional[str]" = None, - hub: "Optional[sentry_sdk.Hub]" = None, # deprecated - status: "Optional[str]" = None, - containing_transaction: "Optional[Transaction]" = None, - start_timestamp: "Optional[Union[datetime, float]]" = None, - scope: "Optional[sentry_sdk.Scope]" = None, - origin: str = "manual", - name: "Optional[str]" = None, - ) -> None: - self._trace_id = trace_id - self._span_id = span_id - self.parent_span_id = parent_span_id - self.same_process_as_parent = same_process_as_parent - self.sampled = sampled - self.op = op - self.description = name or description - self.status = status - self.hub = hub # backwards compatibility - self.scope = scope - self.origin = origin - self._measurements: "Dict[str, MeasurementValue]" = {} - self._tags: "MutableMapping[str, str]" = {} - self._data: "Dict[str, Any]" = {} - self._containing_transaction = containing_transaction - self._flags: "Dict[str, bool]" = {} - self._flags_capacity = 10 - - if hub is not None: - warnings.warn( - "The `hub` parameter is deprecated. Please use `scope` instead.", - DeprecationWarning, - stacklevel=2, - ) - - self.scope = self.scope or hub.scope - - if start_timestamp is None: - start_timestamp = datetime.now(timezone.utc) - elif isinstance(start_timestamp, float): - start_timestamp = datetime.fromtimestamp(start_timestamp, timezone.utc) - self.start_timestamp = start_timestamp - try: - # profiling depends on this value and requires that - # it is measured in nanoseconds - self._start_timestamp_monotonic_ns = nanosecond_time() - except AttributeError: - pass - - #: End timestamp of span - self.timestamp: "Optional[datetime]" = None - - self._span_recorder: "Optional[_SpanRecorder]" = None - - self.update_active_thread() - self.set_profiler_id(get_profiler_id()) - - # TODO this should really live on the Transaction class rather than the Span - # class - def init_span_recorder(self, maxlen: int) -> None: - if self._span_recorder is None: - self._span_recorder = _SpanRecorder(maxlen) - - @property - def trace_id(self) -> str: - if not self._trace_id: - self._trace_id = uuid.uuid4().hex - - return self._trace_id - - @trace_id.setter - def trace_id(self, value: str) -> None: - self._trace_id = value - - @property - def span_id(self) -> str: - if not self._span_id: - self._span_id = uuid.uuid4().hex[16:] - - return self._span_id - - @span_id.setter - def span_id(self, value: str) -> None: - self._span_id = value - - def __repr__(self) -> str: - return ( - "<%s(op=%r, description:%r, trace_id=%r, span_id=%r, parent_span_id=%r, sampled=%r, origin=%r)>" - % ( - self.__class__.__name__, - self.op, - self.description, - self.trace_id, - self.span_id, - self.parent_span_id, - self.sampled, - self.origin, - ) - ) - - def __enter__(self) -> "Span": - if has_span_streaming_enabled(sentry_sdk.get_client().options): - self._context_manager_state = None # early return sentinel - return self - - scope = self.scope or sentry_sdk.get_current_scope() - old_span = scope.span - scope.span = self - self._context_manager_state = (scope, old_span) - return self - - def __exit__( - self, ty: "Optional[Any]", value: "Optional[Any]", tb: "Optional[Any]" - ) -> None: - if ( - hasattr(self, "_context_manager_state") - and self._context_manager_state is None - ): - del self._context_manager_state - return - - if value is not None and should_be_treated_as_error(ty, value): - self.set_status(SPANSTATUS.INTERNAL_ERROR) - - with capture_internal_exceptions(): - scope, old_span = cast( - "Tuple[sentry_sdk.Scope, Optional[Span]]", - self._context_manager_state, - ) - del self._context_manager_state - self.finish(scope) - scope.span = old_span - - @property - def containing_transaction(self) -> "Optional[Transaction]": - """The ``Transaction`` that this span belongs to. - The ``Transaction`` is the root of the span tree, - so one could also think of this ``Transaction`` as the "root span".""" - - # this is a getter rather than a regular attribute so that transactions - # can return `self` here instead (as a way to prevent them circularly - # referencing themselves) - return self._containing_transaction - - def start_child( - self, instrumenter: str = INSTRUMENTER.SENTRY, **kwargs: "Any" - ) -> "Span": - """ - Start a sub-span from the current span or transaction. - - Takes the same arguments as the initializer of :py:class:`Span`. The - trace id, sampling decision, transaction pointer, and span recorder are - inherited from the current span/transaction. - - The instrumenter parameter is deprecated for user code, and it will - be removed in the next major version. Going forward, it should only - be used by the SDK itself. - """ - if kwargs.get("description") is not None: - warnings.warn( - "The `description` parameter is deprecated. Please use `name` instead.", - DeprecationWarning, - stacklevel=2, - ) - - configuration_instrumenter = sentry_sdk.get_client().options["instrumenter"] - - if instrumenter != configuration_instrumenter: - return NoOpSpan() - - kwargs.setdefault("sampled", self.sampled) - - child = Span( - trace_id=self.trace_id, - parent_span_id=self.span_id, - containing_transaction=self.containing_transaction, - **kwargs, - ) - - span_recorder = ( - self.containing_transaction and self.containing_transaction._span_recorder - ) - if span_recorder: - span_recorder.add(child) - - return child - - @classmethod - def continue_from_environ( - cls, - environ: "Mapping[str, str]", - **kwargs: "Any", - ) -> "Transaction": - """ - DEPRECATED: Use :py:meth:`sentry_sdk.continue_trace`. - - Create a Transaction with the given params, then add in data pulled from - the ``sentry-trace`` and ``baggage`` headers from the environ (if any) - before returning the Transaction. - - This is different from :py:meth:`~sentry_sdk.tracing.Span.continue_from_headers` - in that it assumes header names in the form ``HTTP_HEADER_NAME`` - - such as you would get from a WSGI/ASGI environ - - rather than the form ``header-name``. - - :param environ: The ASGI/WSGI environ to pull information from. - """ - return Transaction.continue_from_headers(EnvironHeaders(environ), **kwargs) - - @classmethod - def continue_from_headers( - cls, - headers: "Mapping[str, str]", - *, - _sample_rand: "Optional[str]" = None, - **kwargs: "Any", - ) -> "Transaction": - """ - DEPRECATED: Use :py:meth:`sentry_sdk.continue_trace`. - - Create a transaction with the given params (including any data pulled from - the ``sentry-trace`` and ``baggage`` headers). - - :param headers: The dictionary with the HTTP headers to pull information from. - :param _sample_rand: If provided, we override the sample_rand value from the - incoming headers with this value. (internal use only) - """ - logger.warning("Deprecated: use sentry_sdk.continue_trace instead.") - - # TODO-neel move away from this kwargs stuff, it's confusing and opaque - # make more explicit - baggage = Baggage.from_incoming_header( - headers.get(BAGGAGE_HEADER_NAME), _sample_rand=_sample_rand - ) - kwargs.update({BAGGAGE_HEADER_NAME: baggage}) - - sentrytrace_kwargs = extract_sentrytrace_data( - headers.get(SENTRY_TRACE_HEADER_NAME) - ) - - if sentrytrace_kwargs is not None: - kwargs.update(sentrytrace_kwargs) - - # If there's an incoming sentry-trace but no incoming baggage header, - # for instance in traces coming from older SDKs, - # baggage will be empty and immutable and won't be populated as head SDK. - baggage.freeze() - - transaction = Transaction(**kwargs) - transaction.same_process_as_parent = False - - return transaction - - def iter_headers(self) -> "Iterator[Tuple[str, str]]": - """ - Creates a generator which returns the span's ``sentry-trace`` and ``baggage`` headers. - If the span's containing transaction doesn't yet have a ``baggage`` value, - this will cause one to be generated and stored. - """ - if not self.containing_transaction: - # Do not propagate headers if there is no containing transaction. Otherwise, this - # span ends up being the root span of a new trace, and since it does not get sent - # to Sentry, the trace will be missing a root transaction. The dynamic sampling - # context will also be missing, breaking dynamic sampling & traces. - return - - yield SENTRY_TRACE_HEADER_NAME, self.to_traceparent() - - baggage = self.containing_transaction.get_baggage().serialize() - if baggage: - yield BAGGAGE_HEADER_NAME, baggage - - @classmethod - def from_traceparent( - cls, - traceparent: "Optional[str]", - **kwargs: "Any", - ) -> "Optional[Transaction]": - """ - DEPRECATED: Use :py:meth:`sentry_sdk.continue_trace`. - - Create a ``Transaction`` with the given params, then add in data pulled from - the given ``sentry-trace`` header value before returning the ``Transaction``. - """ - if not traceparent: - return None - - return cls.continue_from_headers( - {SENTRY_TRACE_HEADER_NAME: traceparent}, **kwargs - ) - - def to_traceparent(self) -> str: - if self.sampled is True: - sampled = "1" - elif self.sampled is False: - sampled = "0" - else: - sampled = None - - traceparent = "%s-%s" % (self.trace_id, self.span_id) - if sampled is not None: - traceparent += "-%s" % (sampled,) - - return traceparent - - def to_baggage(self) -> "Optional[Baggage]": - """Returns the :py:class:`~sentry_sdk.tracing_utils.Baggage` - associated with this ``Span``, if any. (Taken from the root of the span tree.) - """ - if self.containing_transaction: - return self.containing_transaction.get_baggage() - return None - - def set_tag(self, key: str, value: "Any") -> None: - self._tags[key] = value - - def set_data(self, key: str, value: "Any") -> None: - self._data[key] = value - - def update_data(self, data: "Dict[str, Any]") -> None: - self._data.update(data) - - def set_flag(self, flag: str, result: bool) -> None: - if len(self._flags) < self._flags_capacity: - self._flags[flag] = result - - def set_status(self, value: str) -> None: - self.status = value - - def set_measurement( - self, name: str, value: float, unit: "MeasurementUnit" = "" - ) -> None: - """ - .. deprecated:: 2.28.0 - This function is deprecated and will be removed in the next major release. - """ - - warnings.warn( - "`set_measurement()` is deprecated and will be removed in the next major version. Please use `set_data()` instead.", - DeprecationWarning, - stacklevel=2, - ) - self._measurements[name] = {"value": value, "unit": unit} - - def set_thread( - self, thread_id: "Optional[int]", thread_name: "Optional[str]" - ) -> None: - if thread_id is not None: - self.set_data(SPANDATA.THREAD_ID, str(thread_id)) - - if thread_name is not None: - self.set_data(SPANDATA.THREAD_NAME, thread_name) - - def set_profiler_id(self, profiler_id: "Optional[str]") -> None: - if profiler_id is not None: - self.set_data(SPANDATA.PROFILER_ID, profiler_id) - - def set_http_status(self, http_status: int) -> None: - self.set_tag( - "http.status_code", str(http_status) - ) # TODO-neel remove in major, we keep this for backwards compatibility - self.set_data(SPANDATA.HTTP_STATUS_CODE, http_status) - self.set_status(get_span_status_from_http_code(http_status)) - - def is_success(self) -> bool: - return self.status == "ok" - - def finish( - self, - scope: "Optional[sentry_sdk.Scope]" = None, - end_timestamp: "Optional[Union[float, datetime]]" = None, - ) -> "Optional[str]": - """ - Sets the end timestamp of the span. - - Additionally it also creates a breadcrumb from the span, - if the span represents a database or HTTP request. - - :param scope: The scope to use for this transaction. - If not provided, the current scope will be used. - :param end_timestamp: Optional timestamp that should - be used as timestamp instead of the current time. - - :return: Always ``None``. The type is ``Optional[str]`` to match - the return value of :py:meth:`sentry_sdk.tracing.Transaction.finish`. - """ - if self.timestamp is not None: - # This span is already finished, ignore. - return None - - try: - if end_timestamp: - if isinstance(end_timestamp, float): - end_timestamp = datetime.fromtimestamp(end_timestamp, timezone.utc) - self.timestamp = end_timestamp - else: - elapsed = nanosecond_time() - self._start_timestamp_monotonic_ns - self.timestamp = self.start_timestamp + timedelta( - microseconds=elapsed / 1000 - ) - except AttributeError: - self.timestamp = datetime.now(timezone.utc) - - scope = scope or sentry_sdk.get_current_scope() - - # Copy conversation_id from scope to span data if this is an AI span - conversation_id = scope.get_conversation_id() - if conversation_id: - has_ai_op = SPANDATA.GEN_AI_OPERATION_NAME in self._data - is_ai_span_op = self.op is not None and ( - self.op.startswith("ai.") or self.op.startswith("gen_ai.") - ) - if has_ai_op or is_ai_span_op: - self.set_data("gen_ai.conversation.id", conversation_id) - - return None - - def to_json(self) -> "Dict[str, Any]": - """Returns a JSON-compatible representation of the span.""" - - rv: "Dict[str, Any]" = { - "trace_id": self.trace_id, - "span_id": self.span_id, - "parent_span_id": self.parent_span_id, - "same_process_as_parent": self.same_process_as_parent, - "op": self.op, - "description": self.description, - "start_timestamp": self.start_timestamp, - "timestamp": self.timestamp, - "origin": self.origin, - } - - if self.status: - rv["status"] = self.status - # TODO-neel remove redundant tag in major - self._tags["status"] = self.status - - if len(self._measurements) > 0: - rv["measurements"] = self._measurements - - tags = self._tags - if tags: - rv["tags"] = tags - - data = {} - data.update(self._flags) - data.update(self._data) - if data: - rv["data"] = data - - return rv - - def get_trace_context(self) -> "Any": - rv: "Dict[str, Any]" = { - "trace_id": self.trace_id, - "span_id": self.span_id, - "parent_span_id": self.parent_span_id, - "op": self.op, - "description": self.description, - "origin": self.origin, - } - if self.status: - rv["status"] = self.status - - if self.containing_transaction: - rv["dynamic_sampling_context"] = ( - self.containing_transaction.get_baggage().dynamic_sampling_context() - ) - - data = {} - - thread_id = self._data.get(SPANDATA.THREAD_ID) - if thread_id is not None: - data["thread.id"] = thread_id - - thread_name = self._data.get(SPANDATA.THREAD_NAME) - if thread_name is not None: - data["thread.name"] = thread_name - - if data: - rv["data"] = data - - return rv - - def get_profile_context(self) -> "Optional[ProfileContext]": - profiler_id = self._data.get(SPANDATA.PROFILER_ID) - if profiler_id is None: - return None - - return { - "profiler_id": profiler_id, - } - - def update_active_thread(self) -> None: - thread_id, thread_name = get_current_thread_meta() - self.set_thread(thread_id, thread_name) - - # Private aliases matching StreamedSpan's private API - _to_traceparent = to_traceparent - _to_baggage = to_baggage - _iter_headers = iter_headers - _get_trace_context = get_trace_context - - -class Transaction(Span): - """The Transaction is the root element that holds all the spans - for Sentry performance instrumentation. - - :param name: Identifier of the transaction. - Will show up in the Sentry UI. - :param parent_sampled: Whether the parent transaction was sampled. - If True this transaction will be kept, if False it will be discarded. - :param baggage: The W3C baggage header value. - (see https://www.w3.org/TR/baggage/) - :param source: A string describing the source of the transaction name. - This will be used to determine the transaction's type. - See https://develop.sentry.dev/sdk/event-payloads/transaction/#transaction-annotations - for more information. Default "custom". - :param kwargs: Additional arguments to be passed to the Span constructor. - See :py:class:`sentry_sdk.tracing.Span` for available arguments. - """ - - __slots__ = ( - "name", - "source", - "parent_sampled", - # used to create baggage value for head SDKs in dynamic sampling - "sample_rate", - "_measurements", - "_contexts", - "_profile", - "_continuous_profile", - "_baggage", - "_sample_rand", - ) - - def __init__( # type: ignore[misc] - self, - name: str = "", - parent_sampled: "Optional[bool]" = None, - baggage: "Optional[Baggage]" = None, - source: str = TransactionSource.CUSTOM, - **kwargs: "Unpack[SpanKwargs]", - ) -> None: - super().__init__(**kwargs) - - self.name = name - self.source = source - self.sample_rate: "Optional[float]" = None - self.parent_sampled = parent_sampled - self._measurements: "Dict[str, MeasurementValue]" = {} - self._contexts: "Dict[str, Any]" = {} - self._profile: "Optional[Profile]" = None - self._continuous_profile: "Optional[ContinuousProfile]" = None - self._baggage = baggage - - baggage_sample_rand = ( - None if self._baggage is None else self._baggage._sample_rand() - ) - if baggage_sample_rand is not None: - self._sample_rand = baggage_sample_rand - else: - self._sample_rand = _generate_sample_rand(self.trace_id) - - def __repr__(self) -> str: - return ( - "<%s(name=%r, op=%r, trace_id=%r, span_id=%r, parent_span_id=%r, sampled=%r, source=%r, origin=%r)>" - % ( - self.__class__.__name__, - self.name, - self.op, - self.trace_id, - self.span_id, - self.parent_span_id, - self.sampled, - self.source, - self.origin, - ) - ) - - def _possibly_started(self) -> bool: - """Returns whether the transaction might have been started. - - If this returns False, we know that the transaction was not started - with sentry_sdk.start_transaction, and therefore the transaction will - be discarded. - """ - - # We must explicitly check self.sampled is False since self.sampled can be None - return self._span_recorder is not None or self.sampled is False - - def __enter__(self) -> "Transaction": - if not self._possibly_started(): - logger.debug( - "Transaction was entered without being started with sentry_sdk.start_transaction." - "The transaction will not be sent to Sentry. To fix, start the transaction by" - "passing it to sentry_sdk.start_transaction." - ) - - super().__enter__() - - if self._profile is not None: - self._profile.__enter__() - - return self - - def __exit__( - self, ty: "Optional[Any]", value: "Optional[Any]", tb: "Optional[Any]" - ) -> None: - if self._profile is not None: - self._profile.__exit__(ty, value, tb) - - if self._continuous_profile is not None: - self._continuous_profile.stop() - - super().__exit__(ty, value, tb) - - @property - def containing_transaction(self) -> "Transaction": - """The root element of the span tree. - In the case of a transaction it is the transaction itself. - """ - - # Transactions (as spans) belong to themselves (as transactions). This - # is a getter rather than a regular attribute to avoid having a circular - # reference. - return self - - def _get_scope_from_finish_args( - self, - scope_arg: "Optional[Union[sentry_sdk.Scope, sentry_sdk.Hub]]", - hub_arg: "Optional[Union[sentry_sdk.Scope, sentry_sdk.Hub]]", - ) -> "Optional[sentry_sdk.Scope]": - """ - Logic to get the scope from the arguments passed to finish. This - function exists for backwards compatibility with the old finish. - - TODO: Remove this function in the next major version. - """ - scope_or_hub = scope_arg - if hub_arg is not None: - warnings.warn( - "The `hub` parameter is deprecated. Please use the `scope` parameter, instead.", - DeprecationWarning, - stacklevel=3, - ) - - scope_or_hub = hub_arg - - if isinstance(scope_or_hub, sentry_sdk.Hub): - warnings.warn( - "Passing a Hub to finish is deprecated. Please pass a Scope, instead.", - DeprecationWarning, - stacklevel=3, - ) - - return scope_or_hub.scope - - return scope_or_hub - - def _get_log_representation(self) -> str: - return "{op}transaction <{name}>".format( - op=("<" + self.op + "> " if self.op else ""), name=self.name - ) - - def finish( - self, - scope: "Optional[sentry_sdk.Scope]" = None, - end_timestamp: "Optional[Union[float, datetime]]" = None, - *, - hub: "Optional[sentry_sdk.Hub]" = None, - ) -> "Optional[str]": - """Finishes the transaction and sends it to Sentry. - All finished spans in the transaction will also be sent to Sentry. - - :param scope: The Scope to use for this transaction. - If not provided, the current Scope will be used. - :param end_timestamp: Optional timestamp that should - be used as timestamp instead of the current time. - :param hub: The hub to use for this transaction. - This argument is DEPRECATED. Please use the `scope` - parameter, instead. - - :return: The event ID if the transaction was sent to Sentry, - otherwise None. - """ - if self.timestamp is not None: - # This transaction is already finished, ignore. - return None - - # For backwards compatibility, we must handle the case where `scope` - # or `hub` could both either be a `Scope` or a `Hub`. - scope = self._get_scope_from_finish_args(scope, hub) - - scope = scope or self.scope or sentry_sdk.get_current_scope() - client = sentry_sdk.get_client() - - if not client.is_active(): - # We have no active client and therefore nowhere to send this transaction. - return None - - if self._span_recorder is None: - # Explicit check against False needed because self.sampled might be None - if self.sampled is False: - logger.debug("Discarding transaction because sampled = False") - else: - logger.debug( - "Discarding transaction because it was not started with sentry_sdk.start_transaction" - ) - - # This is not entirely accurate because discards here are not - # exclusively based on sample rate but also traces sampler, but - # we handle this the same here. - if client.transport and has_tracing_enabled(client.options): - if client.monitor and client.monitor.downsample_factor > 0: - reason = "backpressure" - else: - reason = "sample_rate" - - client.transport.record_lost_event(reason, data_category="transaction") - - # Only one span (the transaction itself) is discarded, since we did not record any spans here. - client.transport.record_lost_event(reason, data_category="span") - return None - - if not self.name: - logger.warning( - "Transaction has no name, falling back to ``." - ) - self.name = "" - - super().finish(scope, end_timestamp) - - status_code = self._data.get(SPANDATA.HTTP_STATUS_CODE) - if ( - status_code is not None - and status_code in client.options["trace_ignore_status_codes"] - ): - logger.debug( - "[Tracing] Discarding {transaction_description} because the HTTP status code {status_code} is matched by trace_ignore_status_codes: {trace_ignore_status_codes}".format( - transaction_description=self._get_log_representation(), - status_code=self._data[SPANDATA.HTTP_STATUS_CODE], - trace_ignore_status_codes=client.options[ - "trace_ignore_status_codes" - ], - ) - ) - if client.transport: - client.transport.record_lost_event( - "event_processor", data_category="transaction" - ) - - num_spans = len(self._span_recorder.spans) + 1 - client.transport.record_lost_event( - "event_processor", data_category="span", quantity=num_spans - ) - - self.sampled = False - - if not self.sampled: - # At this point a `sampled = None` should have already been resolved - # to a concrete decision. - if self.sampled is None: - logger.warning("Discarding transaction without sampling decision.") - - return None - - finished_spans = [] - has_gen_ai_span = False - if client.options.get("stream_gen_ai_spans", True): - for span in self._span_recorder.spans: - if span.timestamp is None: - continue - - if isinstance(span.op, str) and span.op.startswith("gen_ai."): - has_gen_ai_span = True - - finished_spans.append(span.to_json()) - else: - finished_spans = [ - span.to_json() - for span in self._span_recorder.spans - if span.timestamp is not None - ] - - len_diff = len(self._span_recorder.spans) - len(finished_spans) - dropped_spans = len_diff + self._span_recorder.dropped_spans - - # we do this to break the circular reference of transaction -> span - # recorder -> span -> containing transaction (which is where we started) - # before either the spans or the transaction goes out of scope and has - # to be garbage collected - self._span_recorder = None - - contexts = {} - contexts.update(self._contexts) - contexts.update({"trace": self.get_trace_context()}) - profile_context = self.get_profile_context() - if profile_context is not None: - contexts.update({"profile": profile_context}) - - event: "Event" = { - "type": "transaction", - "transaction": self.name, - "transaction_info": {"source": self.source}, - "contexts": contexts, - "tags": self._tags, - "timestamp": self.timestamp, - "start_timestamp": self.start_timestamp, - "spans": finished_spans, - } - - if dropped_spans > 0: - event["_dropped_spans"] = dropped_spans - - if has_gen_ai_span: - event["_has_gen_ai_span"] = True - - if self._profile is not None and self._profile.valid(): - event["profile"] = self._profile - self._profile = None - - event["measurements"] = self._measurements - - return scope.capture_event(event) - - def set_measurement( - self, name: str, value: float, unit: "MeasurementUnit" = "" - ) -> None: - """ - .. deprecated:: 2.28.0 - This function is deprecated and will be removed in the next major release. - """ - - warnings.warn( - "`set_measurement()` is deprecated and will be removed in the next major version. Please use `set_data()` instead.", - DeprecationWarning, - stacklevel=2, - ) - self._measurements[name] = {"value": value, "unit": unit} - - def set_context(self, key: str, value: "dict[str, Any]") -> None: - """Sets a context. Transactions can have multiple contexts - and they should follow the format described in the "Contexts Interface" - documentation. - - :param key: The name of the context. - :param value: The information about the context. - """ - self._contexts[key] = value - - def set_http_status(self, http_status: int) -> None: - """Sets the status of the Transaction according to the given HTTP status. - - :param http_status: The HTTP status code.""" - super().set_http_status(http_status) - self.set_context("response", {"status_code": http_status}) - - def to_json(self) -> "Dict[str, Any]": - """Returns a JSON-compatible representation of the transaction.""" - rv = super().to_json() - - rv["name"] = self.name - rv["source"] = self.source - rv["sampled"] = self.sampled - - return rv - - def get_trace_context(self) -> "Any": - trace_context = super().get_trace_context() - - if self._data: - trace_context["data"] = self._data - - return trace_context - - def get_baggage(self) -> "Baggage": - """Returns the :py:class:`~sentry_sdk.tracing_utils.Baggage` - associated with the Transaction. - - The first time a new baggage with Sentry items is made, - it will be frozen.""" - if not self._baggage or self._baggage.mutable: - self._baggage = Baggage.populate_from_transaction(self) - - return self._baggage - - def _set_initial_sampling_decision( - self, sampling_context: "SamplingContext" - ) -> None: - """ - Sets the transaction's sampling decision, according to the following - precedence rules: - - 1. If a sampling decision is passed to `start_transaction` - (`start_transaction(name: "my transaction", sampled: True)`), that - decision will be used, regardless of anything else - - 2. If `traces_sampler` is defined, its decision will be used. It can - choose to keep or ignore any parent sampling decision, or use the - sampling context data to make its own decision or to choose a sample - rate for the transaction. - - 3. If `traces_sampler` is not defined, but there's a parent sampling - decision, the parent sampling decision will be used. - - 4. If `traces_sampler` is not defined and there's no parent sampling - decision, `traces_sample_rate` will be used. - """ - client = sentry_sdk.get_client() - - transaction_description = self._get_log_representation() - - # nothing to do if tracing is disabled - if not has_tracing_enabled(client.options): - self.sampled = False - return - - # if the user has forced a sampling decision by passing a `sampled` - # value when starting the transaction, go with that - if self.sampled is not None: - self.sample_rate = float(self.sampled) - return - - # we would have bailed already if neither `traces_sampler` nor - # `traces_sample_rate` were defined, so one of these should work; prefer - # the hook if so - if callable(client.options.get("traces_sampler")): - try: - sample_rate = client.options["traces_sampler"](sampling_context) - except Exception: - logger.warning( - "[Tracing] traces_sampler raised; falling back to parent sample rate or traces_sample_rate", - exc_info=True, - ) - sample_rate = ( - sampling_context["parent_sampled"] - if sampling_context["parent_sampled"] is not None - else client.options["traces_sample_rate"] - ) - else: - sample_rate = ( - sampling_context["parent_sampled"] - if sampling_context["parent_sampled"] is not None - else client.options["traces_sample_rate"] - ) - - # Since this is coming from the user (or from a function provided by the - # user), who knows what we might get. (The only valid values are - # booleans or numbers between 0 and 1.) - if not is_valid_sample_rate(sample_rate, source="Tracing"): - logger.warning( - "[Tracing] Discarding {transaction_description} because of invalid sample rate.".format( - transaction_description=transaction_description, - ) - ) - self.sampled = False - return - - self.sample_rate = float(sample_rate) - - if client.monitor: - self.sample_rate /= 2**client.monitor.downsample_factor - - # if the function returned 0 (or false), or if `traces_sample_rate` is - # 0, it's a sign the transaction should be dropped - if not self.sample_rate: - logger.debug( - "[Tracing] Discarding {transaction_description} because {reason}".format( - transaction_description=transaction_description, - reason=( - "traces_sampler returned 0 or False, or is using a fallback sample rate that is 0 or False" - if callable(client.options.get("traces_sampler")) - else "traces_sample_rate is set to 0" - ), - ) - ) - self.sampled = False - return - - # Now we roll the dice. - self.sampled = self._sample_rand < self.sample_rate - - if self.sampled: - logger.debug( - "[Tracing] Starting {transaction_description}".format( - transaction_description=transaction_description, - ) - ) - else: - logger.debug( - "[Tracing] Discarding {transaction_description} because it's not included in the random sample (sampling rate = {sample_rate})".format( - transaction_description=transaction_description, - sample_rate=self.sample_rate, - ) - ) - - # Private aliases matching StreamedSpan's private API - _get_baggage = get_baggage - _get_trace_context = get_trace_context - - -class NoOpSpan(Span): - def __repr__(self) -> str: - return "<%s>" % self.__class__.__name__ - - @property - def containing_transaction(self) -> "Optional[Transaction]": - return None - - def start_child( - self, instrumenter: str = INSTRUMENTER.SENTRY, **kwargs: "Any" - ) -> "NoOpSpan": - return NoOpSpan() - - def to_traceparent(self) -> str: - return "" - - def to_baggage(self) -> "Optional[Baggage]": - return None - - def get_baggage(self) -> "Optional[Baggage]": - return None - - def iter_headers(self) -> "Iterator[Tuple[str, str]]": - return iter(()) - - def set_tag(self, key: str, value: "Any") -> None: - pass - - def set_data(self, key: str, value: "Any") -> None: - pass - - def update_data(self, data: "Dict[str, Any]") -> None: - pass - - def set_status(self, value: str) -> None: - pass - - def set_http_status(self, http_status: int) -> None: - pass - - def is_success(self) -> bool: - return True - - def to_json(self) -> "Dict[str, Any]": - return {} - - def get_trace_context(self) -> "Any": - return {} - - def get_profile_context(self) -> "Any": - return {} - - def finish( - self, - scope: "Optional[sentry_sdk.Scope]" = None, - end_timestamp: "Optional[Union[float, datetime]]" = None, - *, - hub: "Optional[sentry_sdk.Hub]" = None, - ) -> "Optional[str]": - """ - The `hub` parameter is deprecated. Please use the `scope` parameter, instead. - """ - pass - - def set_measurement( - self, name: str, value: float, unit: "MeasurementUnit" = "" - ) -> None: - pass - - def set_context(self, key: str, value: "dict[str, Any]") -> None: - pass - - def init_span_recorder(self, maxlen: int) -> None: - pass - - def _set_initial_sampling_decision( - self, sampling_context: "SamplingContext" - ) -> None: - pass - - # Private aliases matching StreamedSpan's private API - _to_traceparent = to_traceparent - _to_baggage = to_baggage - _get_baggage = get_baggage - _iter_headers = iter_headers - _get_trace_context = get_trace_context - - -if TYPE_CHECKING: - - @overload - def trace( - func: None = None, - *, - op: "Optional[str]" = None, - name: "Optional[str]" = None, - attributes: "Optional[dict[str, Any]]" = None, - template: "SPANTEMPLATE" = SPANTEMPLATE.DEFAULT, - ) -> "Callable[[Callable[P, R]], Callable[P, R]]": - # Handles: @trace() and @trace(op="custom") - pass - - @overload - def trace(func: "Callable[P, R]") -> "Callable[P, R]": - # Handles: @trace - pass - - -def trace( - func: "Optional[Callable[P, R]]" = None, - *, - op: "Optional[str]" = None, - name: "Optional[str]" = None, - attributes: "Optional[dict[str, Any]]" = None, - template: "SPANTEMPLATE" = SPANTEMPLATE.DEFAULT, -) -> "Union[Callable[P, R], Callable[[Callable[P, R]], Callable[P, R]]]": - """ - Decorator to start a child span around a function call. - - This decorator automatically creates a new span when the decorated function - is called, and finishes the span when the function returns or raises an exception. - - :param func: The function to trace. When used as a decorator without parentheses, - this is the function being decorated. When used with parameters (e.g., - ``@trace(op="custom")``, this should be None. - :type func: Callable or None - - :param op: The operation name for the span. This is a high-level description - of what the span represents (e.g., "http.client", "db.query"). - You can use predefined constants from :py:class:`sentry_sdk.consts.OP` - or provide your own string. If not provided, a default operation will - be assigned based on the template. - :type op: str or None - - :param name: The human-readable name/description for the span. If not provided, - defaults to the function name. This provides more specific details about - what the span represents (e.g., "GET /api/users", "process_user_data"). - :type name: str or None - - :param attributes: A dictionary of key-value pairs to add as attributes to the span. - Attribute values must be strings, integers, floats, or booleans. These - attributes provide additional context about the span's execution. - :type attributes: dict[str, Any] or None - - :param template: The type of span to create. This determines what kind of - span instrumentation and data collection will be applied. Use predefined - constants from :py:class:`sentry_sdk.consts.SPANTEMPLATE`. - The default is `SPANTEMPLATE.DEFAULT` which is the right choice for most - use cases. - :type template: :py:class:`sentry_sdk.consts.SPANTEMPLATE` - - :returns: When used as ``@trace``, returns the decorated function. When used as - ``@trace(...)`` with parameters, returns a decorator function. - :rtype: Callable or decorator function - - Example:: - - import sentry_sdk - from sentry_sdk.consts import OP, SPANTEMPLATE - - # Simple usage with default values - @sentry_sdk.trace - def process_data(): - # Function implementation - pass - - # With custom parameters - @sentry_sdk.trace( - op=OP.DB_QUERY, - name="Get user data", - attributes={"postgres": True} - ) - def make_db_query(sql): - # Function implementation - pass - - # With a custom template - @sentry_sdk.trace(template=SPANTEMPLATE.AI_TOOL) - def calculate_interest_rate(amount, rate, years): - # Function implementation - pass - """ - from sentry_sdk.tracing_utils import create_span_decorator - - decorator = create_span_decorator( - op=op, - name=name, - attributes=attributes, - template=template, - ) - - if func: - return decorator(func) - else: - return decorator - - -# Circular imports - -from sentry_sdk.tracing_utils import ( - Baggage, - EnvironHeaders, - _generate_sample_rand, - extract_sentrytrace_data, - has_span_streaming_enabled, - has_tracing_enabled, -) diff --git a/sentry_sdk/tracing_utils.py b/sentry_sdk/tracing_utils.py index 42ebc7f1b3..a7d4bb84b0 100644 --- a/sentry_sdk/tracing_utils.py +++ b/sentry_sdk/tracing_utils.py @@ -5,22 +5,15 @@ import re import sys import uuid -import warnings from collections.abc import Mapping, MutableMapping from datetime import datetime, timedelta, timezone from random import Random -from urllib.parse import quote, unquote - -try: - from re import Pattern -except ImportError: - # 3.6 - from typing import Pattern - +from re import Pattern from typing import TYPE_CHECKING +from urllib.parse import quote, unquote import sentry_sdk -from sentry_sdk.consts import OP, SPANDATA, SPANTEMPLATE +from sentry_sdk.consts import OP, SPANDATA from sentry_sdk.data_collection import ( _apply_data_collection_filtering_to_query_string, ) @@ -36,7 +29,6 @@ logger, match_regex_list, qualname_from_function, - safe_repr, to_string, try_convert, ) @@ -48,7 +40,6 @@ Dict, Generator, Iterator, - Literal, Optional, Tuple, Union, @@ -109,43 +100,17 @@ def __iter__(self) -> "Generator[str, None, None]": def has_tracing_enabled(options: "Optional[Dict[str, Any]]") -> bool: """ Returns True if either traces_sample_rate or traces_sampler is - defined and enable_tracing is set and not false. + defined. """ if options is None: return False return bool( - options.get("enable_tracing") is not False - and ( - options.get("traces_sample_rate") is not None - or options.get("traces_sampler") is not None - ) + options.get("traces_sample_rate") is not None + or options.get("traces_sampler") is not None ) -def has_span_streaming_enabled(options: "Optional[dict[str, Any]]") -> bool: - if options is None: - return False - - is_enabled_in_experiment_config = (options.get("_experiments") or {}).get( - "trace_lifecycle" - ) == "stream" - - if options.get("trace_lifecycle") is not None: - return options.get("trace_lifecycle") == "stream" - - return is_enabled_in_experiment_config - - -def should_truncate_gen_ai_input(options: "Optional[dict[str, Any]]") -> bool: - if options is None: - return True - - return not options.get( - "stream_gen_ai_spans", True - ) and not has_span_streaming_enabled(options) - - @contextlib.contextmanager def record_sql_queries( cursor: "Any", @@ -156,7 +121,7 @@ def record_sql_queries( record_cursor_repr: bool = False, span_origin: str = "manual", span_op_override_value: "Optional[str]" = None, -) -> "Generator[Union[sentry_sdk.tracing.Span, sentry_sdk.traces.StreamedSpan], None, None]": +) -> "Generator[sentry_sdk.traces.Span, None, None]": # TODO: Bring back capturing of params by default client = sentry_sdk.get_client() if has_data_collection_enabled(client.options): @@ -196,31 +161,19 @@ def record_sql_queries( with capture_internal_exceptions(): sentry_sdk.add_breadcrumb(message=query, category="query", data=data) - if has_span_streaming_enabled(client.options): - additional_attributes = {} - if query is not None: - additional_attributes["db.query.text"] = query - - with sentry_sdk.traces.start_span( - name="" if query is None else query, - attributes={ - "sentry.origin": span_origin, - "sentry.op": span_op_override_value - if span_op_override_value - else OP.DB, - **additional_attributes, - }, - ) as span: - yield span - else: - with sentry_sdk.start_span( - op=span_op_override_value if span_op_override_value is not None else OP.DB, - name=query, - origin=span_origin, - ) as span: - for k, v in data.items(): - span.set_data(k, v) - yield span + additional_attributes = {} + if query is not None: + additional_attributes["db.query.text"] = query + + with sentry_sdk.start_span( + name="" if query is None else query, + attributes={ + "sentry.origin": span_origin, + "sentry.op": span_op_override_value if span_op_override_value else OP.DB, + **additional_attributes, + }, + ) as span: + yield span def add_http_breadcrumb(status_code: "Optional[int]", data: "dict[str, Any]") -> None: @@ -238,8 +191,9 @@ def add_http_breadcrumb(status_code: "Optional[int]", data: "dict[str, Any]") -> sentry_sdk.add_breadcrumb(**kwargs) -def get_url_attributes( - client: "sentry_sdk.client.BaseClient", parsed_url: "Optional[ParsedUrl]" +def get_url_attributes_legacy( + client: "sentry_sdk.client.BaseClient", + parsed_url: "Optional[ParsedUrl]", ) -> "Attributes": """Build the `url.*` span attributes for an outgoing HTTP request. @@ -278,6 +232,40 @@ def get_url_attributes( return attributes +def get_url_attributes( + client: "sentry_sdk.client.BaseClient", + parsed_url: "Optional[ParsedUrl]", +) -> "Attributes": + """Build the `url.*` span attributes for an outgoing HTTP request. + + The query string is filtered through the resolved `data_collection` + settings. + """ + attributes: "Attributes" = {} + if parsed_url is None: + return attributes + + query: "Optional[str]" = None + if parsed_url.query: + query = _apply_data_collection_filtering_to_query_string( + query_string=parsed_url.query, + behaviour=client.options["data_collection"]["url_query_params"], + ) + + url_full = parsed_url.url + if query: + attributes[SPANDATA.URL_QUERY] = query + url_full += "?" + query + + if parsed_url.fragment: + attributes[SPANDATA.URL_FRAGMENT] = parsed_url.fragment + url_full += "#" + parsed_url.fragment + + attributes[SPANDATA.URL_FULL] = url_full + + return attributes + + def _get_frame_module_abs_path(frame: "FrameType") -> "Optional[str]": try: return frame.f_code.co_filename @@ -305,7 +293,7 @@ def _should_be_included( def add_source( - span: "Union[sentry_sdk.tracing.Span, sentry_sdk.traces.StreamedSpan]", + span: "sentry_sdk.traces.Span", project_root: "Optional[str]", in_app_include: "Optional[list[str]]", in_app_exclude: "Optional[list[str]]", @@ -349,20 +337,14 @@ def add_source( except Exception: lineno = None if lineno is not None: - if isinstance(span, Span): - span.set_data(SPANDATA.CODE_LINENO, lineno) - else: - span.set_attribute("code.line.number", lineno) + span.set_attribute("code.line.number", lineno) try: namespace = frame.f_globals.get("__name__") except Exception: namespace = None if namespace is not None: - if isinstance(span, Span): - span.set_data(SPANDATA.CODE_NAMESPACE, namespace) - else: - span.set_attribute(SPANDATA.CODE_NAMESPACE, namespace) + span.set_attribute(SPANDATA.CODE_NAMESPACE, namespace) filepath = _get_frame_module_abs_path(frame) if filepath is not None: @@ -373,11 +355,8 @@ def add_source( else: in_app_path = filepath - if isinstance(span, Span): - span.set_data(SPANDATA.CODE_FILEPATH, in_app_path) - else: - if in_app_path is not None: - span.set_attribute("code.file.path", in_app_path) + if in_app_path is not None: + span.set_attribute("code.file.path", in_app_path) try: code_function = frame.f_code.co_name @@ -385,14 +364,11 @@ def add_source( code_function = None if code_function is not None: - if isinstance(span, Span): - span.set_data(SPANDATA.CODE_FUNCTION, frame.f_code.co_name) - else: - span.set_attribute(SPANDATA.CODE_FUNCTION, frame.f_code.co_name) + span.set_attribute(SPANDATA.CODE_FUNCTION, frame.f_code.co_name) def add_query_source( - span: "Union[sentry_sdk.tracing.Span, sentry_sdk.traces.StreamedSpan]", + span: "sentry_sdk.traces.Span", ) -> None: """ Adds OTel compatible source code information to a database query span @@ -401,13 +377,6 @@ def add_query_source( if not client.is_active(): return - if isinstance(span, Span): - # In the StreamedSpan case, we need to add the extra span information before - # the span finishes, so it's expected that this will be None. In the Span case, - # it should already be finished. - if span.timestamp is None: - return - if span.start_timestamp is None: return @@ -415,12 +384,7 @@ def add_query_source( if not should_add_query_source: return - if isinstance(span, StreamedSpan): - end_timestamp = span.end_timestamp - else: - end_timestamp = span.timestamp - - end_timestamp = end_timestamp or datetime.now(timezone.utc) + end_timestamp = span.end_timestamp or datetime.now(timezone.utc) duration = end_timestamp - span.start_timestamp threshold = client.options.get("db_query_source_threshold_ms", 0) @@ -437,9 +401,7 @@ def add_query_source( ) -def add_http_request_source( - span: "Union[sentry_sdk.tracing.Span, sentry_sdk.traces.StreamedSpan]", -) -> None: +def add_http_request_source(span: "sentry_sdk.traces.Span") -> None: """ Adds OTel compatible source code information to a span for an outgoing HTTP request """ @@ -447,13 +409,6 @@ def add_http_request_source( if not client.is_active(): return - if isinstance(span, Span): - # In the StreamedSpan case, we need to add the extra span information before - # the span finishes, so it's expected that this will be None. In the Span case, - # it should already be finished. - if span.timestamp is None: - return - if span.start_timestamp is None: return @@ -461,12 +416,7 @@ def add_http_request_source( if not should_add_request_source: return - if isinstance(span, StreamedSpan): - end_timestamp = span.end_timestamp - else: - end_timestamp = span.timestamp - - end_timestamp = end_timestamp or datetime.now(timezone.utc) + end_timestamp = span.end_timestamp or datetime.now(timezone.utc) duration = end_timestamp - span.start_timestamp threshold = client.options.get("http_request_source_threshold_ms", 0) @@ -811,16 +761,6 @@ def from_incoming_header( return Baggage(sentry_items, third_party_items, mutable) - @classmethod - def from_options(cls, scope: "sentry_sdk.scope.Scope") -> "Optional[Baggage]": - """ - Deprecated: use populate_from_propagation_context - """ - if scope._propagation_context is None: - return Baggage({}) - - return Baggage.populate_from_propagation_context(scope._propagation_context) - @classmethod def populate_from_propagation_context( cls, propagation_context: "PropagationContext" @@ -855,57 +795,7 @@ def populate_from_propagation_context( return Baggage(sentry_items, third_party_items, mutable) @classmethod - def populate_from_transaction( - cls, transaction: "sentry_sdk.tracing.Transaction" - ) -> "Baggage": - """ - Populate fresh baggage entry with sentry_items and make it immutable - if this is the head SDK which originates traces. - """ - client = sentry_sdk.get_client() - sentry_items: "Dict[str, str]" = {} - - if not client.is_active(): - return Baggage(sentry_items) - - options = client.options or {} - - sentry_items["trace_id"] = transaction.trace_id - sentry_items["sample_rand"] = f"{transaction._sample_rand:.6f}" # noqa: E231 - - if options.get("environment"): - sentry_items["environment"] = options["environment"] - - if options.get("release"): - sentry_items["release"] = options["release"] - - if client.parsed_dsn: - sentry_items["public_key"] = client.parsed_dsn.public_key - if client.parsed_dsn.org_id: - sentry_items["org_id"] = client.parsed_dsn.org_id - - if ( - transaction.name - and transaction.source not in LOW_QUALITY_TRANSACTION_SOURCES - ): - sentry_items["transaction"] = transaction.name - - if transaction.sample_rate is not None: - sentry_items["sample_rate"] = str(transaction.sample_rate) - - if transaction.sampled is not None: - sentry_items["sampled"] = "true" if transaction.sampled else "false" - - # there's an existing baggage but it was mutable, - # which is why we are creating this new baggage. - # However, if by chance the user put some sentry items in there, give them precedence. - if transaction._baggage and transaction._baggage.sentry_items: - sentry_items.update(transaction._baggage.sentry_items) - - return Baggage(sentry_items, mutable=False) - - @classmethod - def populate_from_segment(cls, segment: "StreamedSpan") -> "Baggage": + def populate_from_segment(cls, segment: "Span") -> "Baggage": """ Populate fresh baggage entry with sentry_items and make it immutable if this is the head SDK which originates traces. @@ -1068,134 +958,6 @@ def normalize_incoming_data(incoming_data: "Dict[str, Any]") -> "Dict[str, Any]" def create_span_decorator( - op: "Optional[Union[str, OP]]" = None, - name: "Optional[str]" = None, - attributes: "Optional[dict[str, Any]]" = None, - template: "SPANTEMPLATE" = SPANTEMPLATE.DEFAULT, -) -> "Any": - """ - Create a span decorator that can wrap both sync and async functions. - - :param op: The operation type for the span. - :type op: str or :py:class:`sentry_sdk.consts.OP` or None - :param name: The name of the span. - :type name: str or None - :param attributes: Additional attributes to set on the span. - :type attributes: dict or None - :param template: The type of span to create. This determines what kind of - span instrumentation and data collection will be applied. Use predefined - constants from :py:class:`sentry_sdk.consts.SPANTEMPLATE`. - The default is `SPANTEMPLATE.DEFAULT` which is the right choice for most - use cases. - :type template: :py:class:`sentry_sdk.consts.SPANTEMPLATE` - """ - - def span_decorator(f: "Any") -> "Any": - """ - Decorator to create a span for the given function. - """ - - @functools.wraps(f) - async def async_wrapper(*args: "Any", **kwargs: "Any") -> "Any": - current_span = get_current_span() - - if current_span is None: - logger.debug( - "Cannot create a child span for %s. " - "Please start a Sentry transaction before calling this function.", - qualname_from_function(f), - ) - return await f(*args, **kwargs) - - if isinstance(current_span, StreamedSpan): - warnings.warn( - "Use the @sentry_sdk.traces.trace decorator in span streaming mode.", - DeprecationWarning, - stacklevel=2, - ) - return await f(*args, **kwargs) - - span_op = op or _get_span_op(template) - function_name = name or qualname_from_function(f) or "" - span_name = _get_span_name(template, function_name, kwargs) - collect_inputs = _should_collect_gen_ai("inputs") - collect_outputs = _should_collect_gen_ai("outputs") - - with current_span.start_child( - op=span_op, - name=span_name, - ) as span: - span.update_data(attributes or {}) - _set_input_attributes( - span, template, collect_inputs, function_name, f, args, kwargs - ) - - result = await f(*args, **kwargs) - - _set_output_attributes(span, template, collect_outputs, result) - - return result - - try: - async_wrapper.__signature__ = inspect.signature(f) # type: ignore[attr-defined] - except Exception: - pass - - @functools.wraps(f) - def sync_wrapper(*args: "Any", **kwargs: "Any") -> "Any": - current_span = get_current_span() - - if current_span is None: - logger.debug( - "Cannot create a child span for %s. " - "Please start a Sentry transaction before calling this function.", - qualname_from_function(f), - ) - return f(*args, **kwargs) - - if isinstance(current_span, StreamedSpan): - warnings.warn( - "Use the @sentry_sdk.traces.trace decorator in span streaming mode.", - DeprecationWarning, - stacklevel=2, - ) - return f(*args, **kwargs) - - span_op = op or _get_span_op(template) - function_name = name or qualname_from_function(f) or "" - span_name = _get_span_name(template, function_name, kwargs) - collect_inputs = _should_collect_gen_ai("inputs") - collect_outputs = _should_collect_gen_ai("outputs") - - with current_span.start_child( - op=span_op, - name=span_name, - ) as span: - span.update_data(attributes or {}) - _set_input_attributes( - span, template, collect_inputs, function_name, f, args, kwargs - ) - - result = f(*args, **kwargs) - - _set_output_attributes(span, template, collect_outputs, result) - - return result - - try: - sync_wrapper.__signature__ = inspect.signature(f) # type: ignore[attr-defined] - except Exception: - pass - - if inspect.iscoroutinefunction(f): - return async_wrapper - else: - return sync_wrapper - - return span_decorator - - -def create_streaming_span_decorator( name: "Optional[str]" = None, attributes: "Optional[dict[str, Any]]" = None, active: bool = True, @@ -1214,17 +976,9 @@ def span_decorator(f: "Any") -> "Any": @functools.wraps(f) async def async_wrapper(*args: "Any", **kwargs: "Any") -> "Any": - client = sentry_sdk.get_client() - if client.is_active() and not has_span_streaming_enabled(client.options): - warnings.warn( - "Using span streaming API in non-span-streaming mode. Use " - "@sentry_sdk.trace instead.", - stacklevel=2, - ) - span_name = name or qualname_from_function(f) or "" - with start_streaming_span( + with sentry_sdk.start_span( name=span_name, attributes=new_attributes, active=active ): result = await f(*args, **kwargs) @@ -1237,17 +991,9 @@ async def async_wrapper(*args: "Any", **kwargs: "Any") -> "Any": @functools.wraps(f) def sync_wrapper(*args: "Any", **kwargs: "Any") -> "Any": - client = sentry_sdk.get_client() - if client.is_active() and not has_span_streaming_enabled(client.options): - warnings.warn( - "Using span streaming API in non-span-streaming mode. Use " - "@sentry_sdk.trace instead.", - stacklevel=2, - ) - span_name = name or qualname_from_function(f) or "" - with start_streaming_span( + with sentry_sdk.start_span( name=span_name, attributes=new_attributes, active=active ): return f(*args, **kwargs) @@ -1265,17 +1011,6 @@ def sync_wrapper(*args: "Any", **kwargs: "Any") -> "Any": return span_decorator -def get_current_span( - scope: "Optional[sentry_sdk.Scope]" = None, -) -> "Optional[Span]": - """ - Returns the currently active span if there is one running, otherwise `None` - """ - scope = scope or sentry_sdk.get_current_scope() - current_span = scope.span - return current_span - - def _generate_sample_rand( trace_id: "Optional[str]", *, @@ -1340,125 +1075,6 @@ def _get_value(source: "Any", key: str) -> "Optional[Any]": return value -def _get_span_name( - template: "Union[str, SPANTEMPLATE]", - name: str, - kwargs: "Optional[dict[str, Any]]" = None, -) -> str: - """ - Get the name of the span based on the template and the name. - """ - span_name = name - - if template == SPANTEMPLATE.AI_CHAT: - model = None - if kwargs: - for key in ("model", "model_name"): - if kwargs.get(key) and isinstance(kwargs[key], str): - model = kwargs[key] - break - - span_name = f"chat {model}" if model else "chat" - - elif template == SPANTEMPLATE.AI_AGENT: - span_name = f"invoke_agent {name}" - - elif template == SPANTEMPLATE.AI_TOOL: - span_name = f"execute_tool {name}" - - return span_name - - -def _get_span_op(template: "Union[str, SPANTEMPLATE]") -> str: - """ - Get the operation of the span based on the template. - """ - mapping: "dict[Union[str, SPANTEMPLATE], Union[str, OP]]" = { - SPANTEMPLATE.AI_CHAT: OP.GEN_AI_CHAT, - SPANTEMPLATE.AI_AGENT: OP.GEN_AI_INVOKE_AGENT, - SPANTEMPLATE.AI_TOOL: OP.GEN_AI_EXECUTE_TOOL, - } - op = mapping.get(template, OP.FUNCTION) - - return str(op) - - -_AI_TEMPLATES = frozenset( - {SPANTEMPLATE.AI_AGENT, SPANTEMPLATE.AI_CHAT, SPANTEMPLATE.AI_TOOL} -) - - -def _should_collect_gen_ai(kind: 'Literal["inputs", "outputs"]') -> bool: - client = sentry_sdk.get_client() - if has_data_collection_enabled(client.options): - return bool(client.options["data_collection"]["gen_ai"][kind]) - - return client.should_send_default_pii() - - -def _get_input_attributes( - template: "Union[str, SPANTEMPLATE]", - collect_inputs: bool, - args: "tuple[Any, ...]", - kwargs: "dict[str, Any]", -) -> "dict[str, Any]": - """ - Get input attributes for the given span template. - """ - attributes: "dict[str, Any]" = {} - - if template in _AI_TEMPLATES: - mapping = { - "model": (SPANDATA.GEN_AI_REQUEST_MODEL, str), - "model_name": (SPANDATA.GEN_AI_REQUEST_MODEL, str), - "agent": (SPANDATA.GEN_AI_AGENT_NAME, str), - "agent_name": (SPANDATA.GEN_AI_AGENT_NAME, str), - "max_tokens": (SPANDATA.GEN_AI_REQUEST_MAX_TOKENS, int), - "frequency_penalty": (SPANDATA.GEN_AI_REQUEST_FREQUENCY_PENALTY, float), - "presence_penalty": (SPANDATA.GEN_AI_REQUEST_PRESENCE_PENALTY, float), - "temperature": (SPANDATA.GEN_AI_REQUEST_TEMPERATURE, float), - "top_p": (SPANDATA.GEN_AI_REQUEST_TOP_P, float), - "top_k": (SPANDATA.GEN_AI_REQUEST_TOP_K, int), - } - - def _set_from_key(key: str, value: "Any") -> None: - if key in mapping: - (attribute, data_type) = mapping[key] - if value is not None and isinstance(value, data_type): - attributes[attribute] = value - - # Pre-data collection, prompts were always recorded here, so they stay - # ungated until `send_default_pii` is removed. - collect_messages = True - if has_data_collection_enabled(sentry_sdk.get_client().options): - collect_messages = collect_inputs - - roles = {"prompt": "user", "system_prompt": "system"} - - for key, value in list(kwargs.items()): - if key in roles: - if collect_messages and isinstance(value, str): - attributes.setdefault(SPANDATA.GEN_AI_REQUEST_MESSAGES, []).append( - {"role": roles[key], "content": value} - ) - continue - - _set_from_key(key, value) - - if template == SPANTEMPLATE.AI_TOOL and collect_inputs: - attributes[SPANDATA.GEN_AI_TOOL_INPUT] = safe_repr( - {"args": args, "kwargs": kwargs} - ) - - # Coerce to string - if SPANDATA.GEN_AI_REQUEST_MESSAGES in attributes: - attributes[SPANDATA.GEN_AI_REQUEST_MESSAGES] = safe_repr( - attributes[SPANDATA.GEN_AI_REQUEST_MESSAGES] - ) - - return attributes - - def _get_usage_attributes(usage: "Any") -> "dict[str, Any]": """ Get usage attributes. @@ -1487,107 +1103,6 @@ def _set_from_keys(attribute: str, keys: "tuple[str, ...]") -> None: return attributes -def _get_output_attributes( - template: "Union[str, SPANTEMPLATE]", collect_outputs: bool, result: "Any" -) -> "dict[str, Any]": - """ - Get output attributes for the given span template. - """ - attributes: "dict[str, Any]" = {} - - if template in _AI_TEMPLATES: - with capture_internal_exceptions(): - # Usage from result, result.usage, and result.metadata.usage - usage_candidates = [result] - - usage = _get_value(result, "usage") - usage_candidates.append(usage) - - meta = _get_value(result, "metadata") - usage = _get_value(meta, "usage") - usage_candidates.append(usage) - - for usage_candidate in usage_candidates: - if usage_candidate is not None: - attributes.update(_get_usage_attributes(usage_candidate)) - - # Response model - model_name = _get_value(result, "model") - if model_name is not None and isinstance(model_name, str): - attributes[SPANDATA.GEN_AI_RESPONSE_MODEL] = model_name - - model_name = _get_value(result, "model_name") - if model_name is not None and isinstance(model_name, str): - attributes[SPANDATA.GEN_AI_RESPONSE_MODEL] = model_name - - # Tool output - if template == SPANTEMPLATE.AI_TOOL and collect_outputs: - attributes[SPANDATA.GEN_AI_TOOL_OUTPUT] = safe_repr(result) - - return attributes - - -def _set_input_attributes( - span: "Span", - template: "Union[str, SPANTEMPLATE]", - collect_inputs: bool, - name: str, - f: "Any", - args: "tuple[Any, ...]", - kwargs: "dict[str, Any]", -) -> None: - """ - Set span input attributes based on the given span template. - - :param span: The span to set attributes on. - :param template: The template to use to set attributes on the span. - :param collect_inputs: Whether gen_ai inputs may be collected. - :param f: The wrapped function. - :param args: The arguments to the wrapped function. - :param kwargs: The keyword arguments to the wrapped function. - """ - attributes: "dict[str, Any]" = {} - - if template == SPANTEMPLATE.AI_AGENT: - attributes = { - SPANDATA.GEN_AI_OPERATION_NAME: "invoke_agent", - SPANDATA.GEN_AI_AGENT_NAME: name, - } - elif template == SPANTEMPLATE.AI_CHAT: - attributes = { - SPANDATA.GEN_AI_OPERATION_NAME: "chat", - } - elif template == SPANTEMPLATE.AI_TOOL: - attributes = { - SPANDATA.GEN_AI_OPERATION_NAME: "execute_tool", - SPANDATA.GEN_AI_TOOL_NAME: name, - } - - docstring = f.__doc__ - if docstring is not None: - attributes[SPANDATA.GEN_AI_TOOL_DESCRIPTION] = docstring - - attributes.update(_get_input_attributes(template, collect_inputs, args, kwargs)) - span.update_data(attributes or {}) - - -def _set_output_attributes( - span: "Span", - template: "Union[str, SPANTEMPLATE]", - collect_outputs: bool, - result: "Any", -) -> None: - """ - Set span output attributes based on the given span template. - - :param span: The span to set attributes on. - :param template: The template to use to set attributes on the span. - :param collect_outputs: Whether gen_ai outputs may be collected. - :param result: The result of the wrapped function. - """ - span.update_data(_get_output_attributes(template, collect_outputs, result) or {}) - - def _should_continue_trace(baggage: "Optional[Baggage]") -> bool: """ Check if we should continue the incoming trace according to the strict_trace_continuation spec. @@ -1772,16 +1287,7 @@ def _make_sampling_decision( def is_ignored_span(name: str, attributes: "Optional[Attributes]") -> bool: """Determine if a span fits one of the rules in ignore_spans.""" client = sentry_sdk.get_client() - is_ignored_at_top_level = client.options.get("ignore_spans", None) - is_ignored_in_experiment_config = (client.options.get("_experiments") or {}).get( - "ignore_spans" - ) - - ignore_spans = ( - is_ignored_at_top_level - if is_ignored_at_top_level is not None - else is_ignored_in_experiment_config - ) + ignore_spans = client.options.get("ignore_spans", None) if not ignore_spans: return False @@ -1825,18 +1331,8 @@ def _matches(rule: "Any", value: "Any") -> bool: # Circular imports from sentry_sdk.traces import ( - LOW_QUALITY_SEGMENT_SOURCES, - StreamedSpan, -) -from sentry_sdk.traces import ( - start_span as start_streaming_span, -) -from sentry_sdk.tracing import ( BAGGAGE_HEADER_NAME, - LOW_QUALITY_TRANSACTION_SOURCES, + LOW_QUALITY_SEGMENT_SOURCES, SENTRY_TRACE_HEADER_NAME, Span, ) - -if TYPE_CHECKING: - from sentry_sdk.tracing import Span diff --git a/sentry_sdk/transport.py b/sentry_sdk/transport.py index 3f89e8c418..42b795f681 100644 --- a/sentry_sdk/transport.py +++ b/sentry_sdk/transport.py @@ -7,7 +7,6 @@ import socket import ssl import time -import warnings from abc import ABC, abstractmethod from collections import defaultdict from datetime import datetime, timedelta, timezone @@ -37,12 +36,11 @@ except ImportError: ASYNC_TRANSPORT_AVAILABLE = False -from typing import TYPE_CHECKING, Dict, List, cast +from typing import TYPE_CHECKING, Dict, List import certifi import urllib3 -import sentry_sdk from sentry_sdk.consts import EndpointType from sentry_sdk.envelope import Envelope, Item, PayloadRef from sentry_sdk.utils import ( @@ -69,7 +67,7 @@ from urllib3.poolmanager import PoolManager, ProxyManager - from sentry_sdk._types import Event, EventDataCategory + from sentry_sdk._types import EventDataCategory KEEP_ALIVE_SOCKET_OPTIONS = [] for option in [ @@ -114,24 +112,6 @@ def __init__(self: "Self", options: "Optional[Dict[str, Any]]" = None) -> None: else: self.parsed_dsn = None - def capture_event(self: "Self", event: "Event") -> None: - """ - DEPRECATED: Please use capture_envelope instead. - - This gets invoked with the event dictionary when an event should - be sent to sentry. - """ - - warnings.warn( - "capture_event is deprecated, please use capture_envelope instead!", - DeprecationWarning, - stacklevel=2, - ) - - envelope = Envelope() - envelope.add_event(event) - self.capture_envelope(envelope) - @abstractmethod def capture_envelope(self: "Self", envelope: "Envelope") -> None: """ @@ -179,13 +159,6 @@ def record_lost_event( If an item is provided, the data category and quantity are extracted from the item, and the values passed for data_category and quantity are ignored. - - When recording a lost transaction via data_category="transaction", - the calling code should also record the lost spans via this method. - When recording lost spans, `quantity` should be set to the number - of contained spans, plus one for the transaction itself. When - passing an Item containing a transaction via the `item` parameter, - this method automatically records the lost spans. """ return None @@ -234,9 +207,6 @@ def __init__(self: "Self", options: "Dict[str, Any]") -> None: self._pool = self._make_pool() - # Backwards compatibility for deprecated `self.hub_class` attribute - self._hub_cls = sentry_sdk.Hub - experiments = options.get("_experiments", {}) compression_level = experiments.get( "transport_compression_level", @@ -294,17 +264,7 @@ def record_lost_event( data_category = item.data_category quantity = 1 # If an item is provided, we always count it as 1 (except for attachments, handled below). - if data_category == "transaction": - # Also record the lost spans - event = item.get_transaction_event() or {} - - # +1 for the transaction itself - span_count = ( - len(cast(List[Dict[str, object]], event.get("spans") or [])) + 1 - ) - self.record_lost_event(reason, "span", quantity=span_count) - - elif data_category == "log_item" and item: + if data_category == "log_item" and item: # Also record size of lost logs in bytes bytes_size = len(item.get_bytes()) self.record_lost_event(reason, "log_byte", quantity=bytes_size) @@ -476,7 +436,7 @@ def _prepare_envelope( new_items = [] for item in envelope.items: if self._check_disabled(item.data_category): - if item.data_category in ("transaction", "error", "default", "statsd"): + if item.data_category in ("error", "default", "statsd"): self.on_dropped_event("self_rate_limits") self.record_lost_event("ratelimit_backoff", item=item) else: @@ -715,27 +675,6 @@ def flush( self._worker.submit(lambda: self._flush_client_reports(force=True)) self._worker.flush(timeout, callback) - @staticmethod - def _warn_hub_cls() -> None: - """Convenience method to warn users about the deprecation of the `hub_cls` attribute.""" - warnings.warn( - "The `hub_cls` attribute is deprecated and will be removed in a future release.", - DeprecationWarning, - stacklevel=3, - ) - - @property - def hub_cls(self: "Self") -> "type[sentry_sdk.Hub]": - """DEPRECATED: This attribute is deprecated and will be removed in a future release.""" - HttpTransport._warn_hub_cls() - return self._hub_cls - - @hub_cls.setter - def hub_cls(self: "Self", value: "type[sentry_sdk.Hub]") -> None: - """DEPRECATED: This attribute is deprecated and will be removed in a future release.""" - HttpTransport._warn_hub_cls() - self._hub_cls = value - class HttpTransport(BaseHttpTransport): if TYPE_CHECKING: @@ -1161,35 +1100,6 @@ def __getattr__(self, name: str) -> "Any": return getattr(self._inner, name) -class _FunctionTransport(Transport): - """ - DEPRECATED: Users wishing to provide a custom transport should subclass - the Transport class, rather than providing a function. - """ - - def __init__( - self, - func: "Callable[[Event], None]", - ) -> None: - Transport.__init__(self) - self._func = func - - def capture_event( - self, - event: "Event", - ) -> None: - self._func(event) - return None - - def capture_envelope(self, envelope: "Envelope") -> None: - # Since function transports expect to be called with an event, we need - # to iterate over the envelope and call the function for each event, via - # the deprecated capture_event method. - event = envelope.get_event() - if event is not None: - self.capture_event(event) - - def make_transport(options: "Dict[str, Any]") -> "Optional[Transport]": ref_transport = options["transport"] @@ -1233,14 +1143,6 @@ def make_transport(options: "Dict[str, Any]") -> "Optional[Transport]": transport = ref_transport elif isinstance(ref_transport, type) and issubclass(ref_transport, Transport): transport_cls = ref_transport - elif callable(ref_transport): - warnings.warn( - "Function transports are deprecated and will be removed in a future release." - "Please provide a Transport instance or subclass, instead.", - DeprecationWarning, - stacklevel=2, - ) - transport = _FunctionTransport(ref_transport) # if a transport class is given only instantiate it if the dsn is not # empty or None diff --git a/sentry_sdk/utils.py b/sentry_sdk/utils.py index 2e20a789b8..2c27743e79 100644 --- a/sentry_sdk/utils.py +++ b/sentry_sdk/utils.py @@ -4,14 +4,15 @@ import logging import math import os -import random import re import subprocess import sys import threading import time +import warnings from collections import namedtuple from contextlib import contextmanager +from contextvars import ContextVar from datetime import datetime, timezone from decimal import Decimal from functools import partial, partialmethod, wraps @@ -267,7 +268,8 @@ def datetime_from_isoformat(value: str) -> "datetime": try: result = datetime.fromisoformat(value) except (AttributeError, ValueError): - # py 3.6 + # until 3.11, datetime.fromisoformat didn't support all possible formats, + # so we still need this manual fallback timestamp_format = ( "%Y-%m-%dT%H:%M:%S.%f" if "." in value else "%Y-%m-%dT%H:%M:%S" ) @@ -1356,133 +1358,6 @@ def parse_version(version: str) -> "Optional[Tuple[int, ...]]": return release_tuple -def _is_contextvars_broken() -> bool: - """ - Returns whether gevent/eventlet have patched the stdlib in a way where thread locals are now more "correct" than contextvars. - """ - try: - import gevent - from gevent.monkey import is_object_patched - - # Get the MAJOR and MINOR version numbers of Gevent - version_tuple = tuple( - [int(part) for part in re.split(r"a|b|rc|\.", gevent.__version__)[:2]] - ) - if is_object_patched("threading", "local"): - # Gevent 20.9.0 depends on Greenlet 0.4.17 which natively handles switching - # context vars when greenlets are switched, so, Gevent 20.9.0+ is all fine. - # Ref: https://github.com/gevent/gevent/blob/83c9e2ae5b0834b8f84233760aabe82c3ba065b4/src/gevent/monkey.py#L604-L609 - # Gevent 20.5, that doesn't depend on Greenlet 0.4.17 with native support - # for contextvars, is able to patch both thread locals and contextvars, in - # that case, check if contextvars are effectively patched. - if ( - # Gevent 20.9.0+ - (sys.version_info >= (3, 7) and version_tuple >= (20, 9)) - # Gevent 20.5.0+ or Python < 3.7 - or (is_object_patched("contextvars", "ContextVar")) - ): - return False - - return True - except ImportError: - pass - - try: - import greenlet - from eventlet.patcher import is_monkey_patched # type: ignore - - greenlet_version = parse_version(greenlet.__version__) - - if greenlet_version is None: - logger.error( - "Internal error in Sentry SDK: Could not parse Greenlet version from greenlet.__version__." - ) - return False - - if is_monkey_patched("thread") and greenlet_version < (0, 5): - return True - except ImportError: - pass - - return False - - -def _make_threadlocal_contextvars(local: type) -> type: - class ContextVar: - # Super-limited impl of ContextVar - - def __init__(self, name: str, default: "Any" = None) -> None: - self._name = name - self._default = default - self._local = local() - self._original_local = local() - - def get(self, default: "Any" = None) -> "Any": - return getattr(self._local, "value", default or self._default) - - def set(self, value: "Any") -> "Any": - token = str(random.getrandbits(64)) - original_value = self.get() - setattr(self._original_local, token, original_value) - self._local.value = value - return token - - def reset(self, token: "Any") -> None: - self._local.value = getattr(self._original_local, token) - # delete the original value (this way it works in Python 3.6+) - del self._original_local.__dict__[token] - - return ContextVar - - -def _get_contextvars() -> "Tuple[bool, type]": - """ - Figure out the "right" contextvars installation to use. Returns a - `contextvars.ContextVar`-like class with a limited API. - - See https://docs.sentry.io/platforms/python/contextvars/ for more information. - """ - if not _is_contextvars_broken(): - # aiocontextvars is a PyPI package that ensures that the contextvars - # backport (also a PyPI package) works with asyncio under Python 3.6 - # - # Import it if available. - if sys.version_info < (3, 7): - # `aiocontextvars` is absolutely required for functional - # contextvars on Python 3.6. - try: - from aiocontextvars import ContextVar - - return True, ContextVar - except ImportError: - pass - else: - # On Python 3.7 contextvars are functional. - try: - from contextvars import ContextVar - - return True, ContextVar - except ImportError: - pass - - # Fall back to basic thread-local usage. - - from threading import local - - return False, _make_threadlocal_contextvars(local) - - -HAS_REAL_CONTEXTVARS, ContextVar = _get_contextvars() - -CONTEXTVARS_ERROR_MESSAGE = """ - -With asyncio/ASGI applications, the Sentry SDK requires a functional -installation of `contextvars` to avoid leaking scope/context data across -requests. - -Please refer to https://docs.sentry.io/platforms/python/contextvars/ for more information. -""" - _is_sentry_internal_task = ContextVar("is_sentry_internal_task", default=False) # These exceptions won't set the span status to error if they occur. Use @@ -1540,7 +1415,7 @@ def transaction_from_function(func: "Callable[..., Any]") -> "Optional[str]": return qualname_from_function(func) -disable_capture_event = ContextVar("disable_capture_event") +disable_capture_event: "ContextVar[bool]" = ContextVar("disable_capture_event") class ServerlessTimeoutWarning(Exception): # noqa: N818 @@ -1592,30 +1467,18 @@ def run(self) -> None: if self._stop_event.is_set(): return - integer_configured_timeout = int(self.configured_timeout) - - # Setting up the exact integer value of configured time(in seconds) - if integer_configured_timeout < self.configured_timeout: - integer_configured_timeout = integer_configured_timeout + 1 - # Raising Exception after timeout duration is reached if self.isolation_scope is not None and self.current_scope is not None: with sentry_sdk.scope.use_isolation_scope(self.isolation_scope): with sentry_sdk.scope.use_scope(self.current_scope): try: raise ServerlessTimeoutWarning( - "WARNING : Function is expected to get timed out. Configured timeout duration = {} seconds.".format( - integer_configured_timeout - ) + "WARNING: Function is about to time out." ) except Exception: reraise(*self._capture_exception()) - raise ServerlessTimeoutWarning( - "WARNING : Function is expected to get timed out. Configured timeout duration = {} seconds.".format( - integer_configured_timeout - ) - ) + raise ServerlessTimeoutWarning("WARNING: Function is about to time out.") Components = namedtuple("Components", ["scheme", "netloc", "path", "query", "fragment"]) @@ -1905,7 +1768,7 @@ def ensure_integration_enabled( ```python @ensure_integration_enabled(MyIntegration, my_function) def patch_my_function(): - with sentry_sdk.start_transaction(...): + with sentry_sdk.start_span(...): return my_function() ``` """ @@ -2125,9 +1988,7 @@ def get_before_send_log( if options is None: return None - return options.get("before_send_log") or options["_experiments"].get( - "before_send_log" - ) + return options.get("before_send_log") def get_before_send_metric( @@ -2136,9 +1997,7 @@ def get_before_send_metric( if options is None: return None - return options.get("before_send_metric") or options["_experiments"].get( - "before_send_metric" - ) + return options.get("before_send_metric") def get_before_send_span( @@ -2147,9 +2006,7 @@ def get_before_send_span( if options is None: return None - return options.get("before_send_span") or options["_experiments"].get( - "before_send_span" - ) + return options.get("before_send_span") def format_attribute(val: "Any") -> "AttributeValue": @@ -2205,7 +2062,10 @@ def serialize_attribute(val: "AttributeValue") -> "SerializedAttributeValue": return {"value": safe_repr(val), "type": "string"} -# This noop context manager can be replaced with "from contextlib import nullcontext" when we drop Python 3.6 support -@contextmanager -def nullcontext() -> "Iterator[None]": - yield +def deprecation_warning(msg: str) -> None: + """ + Emit a warnings.warn about a deprecation. + + For other types of warnings, use logger.warning(). + """ + warnings.warn(msg, stacklevel=3, category=DeprecationWarning) diff --git a/setup.py b/setup.py index a9e8bb1eaa..e7f9ff8428 100644 --- a/setup.py +++ b/setup.py @@ -38,63 +38,22 @@ def get_file_text(file_name): package_data={"sentry_sdk": ["py.typed"]}, zip_safe=False, license_expression="MIT", - python_requires=">=3.6", + python_requires=">=3.7", install_requires=[ "urllib3>=1.26.11", "certifi", ], extras_require={ - "aiohttp": ["aiohttp>=3.5"], - "anthropic": ["anthropic>=0.16"], - "arq": ["arq>=0.23"], - "asyncpg": ["asyncpg>=0.23"], - "beam": ["apache-beam>=2.12"], - "bottle": ["bottle>=0.12.13"], - "celery": ["celery>=3"], - "celery-redbeat": ["celery-redbeat>=2"], - "chalice": ["chalice>=1.16.0"], - "clickhouse-driver": ["clickhouse-driver>=0.2.0"], - "django": ["django>=1.8"], - "falcon": ["falcon>=1.4"], - "fastapi": ["fastapi>=0.79.0"], - "flask": ["flask>=0.11", "blinker>=1.1", "markupsafe"], + # Only add an extra if our integration needs something additional to + # work with the framework (a dependency or an extra). For instance, + # our Flask integration has a hard dependency on blinker. + "asyncio": ["httpcore[asyncio]==1.*"], + "flask": ["flask", "blinker>=1.1", "markupsafe"], "grpcio": ["grpcio>=1.21.1", "protobuf>=3.8.0"], "http2": ["httpcore[http2]==1.*"], - "asyncio": ["httpcore[asyncio]==1.*"], - "httpx": ["httpx>=0.16.0"], - "huey": ["huey>=2"], - "huggingface_hub": ["huggingface_hub>=0.22"], - "langchain": ["langchain>=0.0.210"], - "langgraph": ["langgraph>=0.6.6"], - "launchdarkly": ["launchdarkly-server-sdk>=9.8.0"], - "litellm": ["litellm>=1.77.5,!=1.82.7,!=1.82.8"], - "litestar": ["litestar>=2.0.0"], - "loguru": ["loguru>=0.5"], - "mcp": ["mcp>=1.15.0"], - "openai": ["openai>=1.0.0", "tiktoken>=0.3.0"], - "openfeature": ["openfeature-sdk>=0.7.1"], - "opentelemetry": ["opentelemetry-distro>=0.35b0"], - "opentelemetry-experimental": ["opentelemetry-distro"], "opentelemetry-otlp": ["opentelemetry-distro[otlp]>=0.35b0"], "pure-eval": ["pure_eval", "executing", "asttokens"], - "pydantic_ai": ["pydantic-ai>=1.0.0"], - "pymongo": ["pymongo>=3.1"], - "pyspark": ["pyspark>=2.4.4"], - "quart": ["quart>=0.16.1", "blinker>=1.1"], - "rq": ["rq>=0.6"], - "sanic": ["sanic>=0.8"], - "sqlalchemy": ["sqlalchemy>=1.2"], - "starlette": ["starlette>=0.19.1"], - "starlite": ["starlite>=1.48"], - "statsig": ["statsig>=0.55.3"], - "tornado": ["tornado>=6"], - "unleash": ["UnleashClient>=6.0.1"], - "google-genai": ["google-genai>=1.29.0"], - }, - entry_points={ - "opentelemetry_propagator": [ - "sentry=sentry_sdk.integrations.opentelemetry:SentryPropagator" - ] + "quart": ["quart", "blinker>=1.1"], }, classifiers=[ "Development Status :: 5 - Production/Stable", @@ -103,7 +62,6 @@ def get_file_text(file_name): "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", diff --git a/tests/conftest.py b/tests/conftest.py index 9145506be2..ff63c8dc17 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -7,11 +7,9 @@ import threading import warnings from collections import namedtuple -from contextlib import contextmanager from dataclasses import dataclass from http.server import BaseHTTPRequestHandler, HTTPServer from threading import Thread -from unittest import mock from urllib.parse import parse_qs, urlparse try: @@ -49,11 +47,6 @@ except ImportError: gevent = None -try: - import eventlet -except ImportError: - eventlet = None - import sentry_sdk import sentry_sdk.utils from sentry_sdk.envelope import Envelope, parse_json @@ -62,7 +55,6 @@ _installed_integrations, _processed_integrations, ) -from sentry_sdk.profiler import teardown_profiler from sentry_sdk.profiler.continuous_profiler import teardown_continuous_profiler from sentry_sdk.transport import Transport from sentry_sdk.utils import package_version, reraise @@ -91,7 +83,7 @@ if TYPE_CHECKING: from collections.abc import Iterator - from typing import Any, Callable, MutableMapping, Optional + from typing import Any, Callable, MutableMapping try: from httpx import ( @@ -273,12 +265,7 @@ def reset_integrations(): but this also means some other stuff will be monkeypatched twice. """ global _DEFAULT_INTEGRATIONS, _processed_integrations - try: - _DEFAULT_INTEGRATIONS.remove( - "sentry_sdk.integrations.opentelemetry.integration.OpenTelemetryIntegration" - ) - except ValueError: - pass + _processed_integrations.clear() _installed_integrations.clear() @@ -410,7 +397,7 @@ def inner(): def append_event(envelope): for item in envelope: - if item.headers.get("type") in ("event", "transaction"): + if item.headers.get("type") == "event": events.append(item.payload.json) return old_capture_envelope(envelope) @@ -516,7 +503,7 @@ def inner(): old_capture_envelope = test_client.transport.capture_envelope def append(envelope): - event = envelope.get_event() or envelope.get_transaction_event() + event = envelope.get_event() if event is not None: events_w.write(json.dumps(event).encode("utf-8")) events_w.write(b"\n") @@ -594,23 +581,11 @@ def read_flush(self): # scope=session ensures that fixture is run earlier @pytest.fixture( scope="session", - params=[None, "eventlet", "gevent"], - ids=("threads", "eventlet", "greenlet"), + params=[None, "gevent"], + ids=("threads", "greenlet"), ) def maybe_monkeypatched_threading(request): - if request.param == "eventlet": - if eventlet is None: - pytest.skip("no eventlet installed") - - try: - eventlet.monkey_patch() - except AttributeError as e: - if "'thread.RLock' object has no attribute" in str(e): - # https://bitbucket.org/pypy/pypy/issues/2962/gevent-cannot-patch-rlock-under-pypy-27-7 - pytest.skip("https://github.com/eventlet/eventlet/issues/546") - else: - raise - elif request.param == "gevent": + if request.param == "gevent": if gevent is None: pytest.skip("no gevent installed") try: @@ -628,11 +603,7 @@ def maybe_monkeypatched_threading(request): @pytest.fixture def render_span_tree(): - def inner(spans, root_span=None): - streamed_spans = False - if root_span is None: - streamed_spans = True - + def inner(spans): by_parent = {} for span in spans: if "parent_span_id" not in span: @@ -642,15 +613,10 @@ def inner(spans, root_span=None): by_parent.setdefault(span["parent_span_id"], []).append(span) def render_span(span): - if streamed_spans: - yield "- sentry.op={}: name={}".format( - json.dumps(span["attributes"].get("sentry.op")), - json.dumps(span["name"]), - ) - else: - yield "- op={}: description={}".format( - json.dumps(span.get("op")), json.dumps(span.get("description")) - ) + yield "- sentry.op={}: name={}".format( + json.dumps(span["attributes"].get("sentry.op")), + json.dumps(span["name"]), + ) for subspan in by_parent.get(span["span_id"]) or (): for line in render_span(subspan): @@ -841,13 +807,11 @@ def __ne__(self, test_obj): @pytest.fixture def teardown_profiling(): # Make sure that a previous test didn't leave the profiler running - teardown_profiler() teardown_continuous_profiler() yield - # Make sure that to shut down the profiler after the test - teardown_profiler() + # Make sure to shut down the profiler after the test teardown_continuous_profiler() @@ -1024,35 +988,6 @@ def inner(app, method: str, params, request_id: str): return inner -@pytest.fixture() -def select_mcp_transactions(): - def inner(events): - return [ - event - for event in events - if event["type"] == "transaction" - and event["contexts"]["trace"]["op"] == "mcp.server" - ] - - return inner - - -@pytest.fixture() -def select_transactions_with_mcp_spans(): - def inner(events, method_name): - return [ - transaction - for transaction in events - if transaction.get("type") == "transaction" - and any( - span["data"].get("mcp.method.name") == method_name - for span in transaction.get("spans", []) - ) - ] - - return inner - - @pytest.fixture() def json_rpc_sse(): class StreamingASGITransport(ASGITransport): @@ -1797,24 +1732,6 @@ def werkzeug_set_cookie(client, servername, key, value): client.set_cookie(key, value) -@contextmanager -def patch_start_tracing_child( - fake_transaction_is_none: bool = False, -) -> "Iterator[Optional[mock.MagicMock]]": - if not fake_transaction_is_none: - fake_transaction = mock.MagicMock() - fake_start_child = mock.MagicMock() - fake_transaction.start_child = fake_start_child - else: - fake_transaction = None - fake_start_child = None - - with mock.patch( - "sentry_sdk.tracing_utils.get_current_span", return_value=fake_transaction - ): - yield fake_start_child - - class ApproxDict(dict): def __eq__(self, other): # For an ApproxDict to equal another dict, the other dict just needs to contain diff --git a/tests/integrations/aiohttp/test_aiohttp.py b/tests/integrations/aiohttp/test_aiohttp.py index 1c3166de64..e92992cb86 100644 --- a/tests/integrations/aiohttp/test_aiohttp.py +++ b/tests/integrations/aiohttp/test_aiohttp.py @@ -1,5 +1,4 @@ import asyncio -import datetime import json import os from contextlib import suppress @@ -18,12 +17,11 @@ from aiohttp.web_request import Request import sentry_sdk -from sentry_sdk import capture_message, start_transaction +from sentry_sdk import capture_message from sentry_sdk._types import OVER_SIZE_LIMIT_SUBSTITUTE from sentry_sdk.consts import SPANDATA from sentry_sdk.integrations.aiohttp import ( AioHttpIntegration, - create_trace_config, ) from sentry_sdk.utils import SENSITIVE_DATA_SUBSTITUTE from tests.conftest import ApproxDict @@ -35,7 +33,7 @@ @pytest.mark.asyncio async def test_basic(sentry_init, aiohttp_client, capture_events): - sentry_init(integrations=[AioHttpIntegration()]) + sentry_init(integrations=[AioHttpIntegration()], data_collection={}) async def hello(request): 1 / 0 @@ -63,7 +61,6 @@ async def hello(request): assert request["env"] == {"REMOTE_ADDR": "127.0.0.1"} assert request["method"] == "GET" - assert request["query_string"] == "" assert request.get("data") is None assert request["url"] == "http://{host}/".format(host=host) assert request["headers"] == { @@ -80,7 +77,7 @@ async def hello(request): async def test_post_body_not_read(sentry_init, aiohttp_client, capture_events): from sentry_sdk.integrations.aiohttp import BODY_NOT_READ_MESSAGE - sentry_init(integrations=[AioHttpIntegration()]) + sentry_init(integrations=[AioHttpIntegration()], data_collection={}) body = {"some": "value"} @@ -108,7 +105,7 @@ async def hello(request): @pytest.mark.asyncio async def test_post_body_read(sentry_init, aiohttp_client, capture_events): - sentry_init(integrations=[AioHttpIntegration()]) + sentry_init(integrations=[AioHttpIntegration()], data_collection={}) body = {"some": "value"} @@ -238,7 +235,7 @@ async def hello(request): @pytest.mark.asyncio async def test_403_not_captured(sentry_init, aiohttp_client, capture_events): - sentry_init(integrations=[AioHttpIntegration()]) + sentry_init(integrations=[AioHttpIntegration()], data_collection={}) async def hello(request): raise web.HTTPForbidden() @@ -259,7 +256,7 @@ async def hello(request): async def test_cancelled_error_not_captured( sentry_init, aiohttp_client, capture_events ): - sentry_init(integrations=[AioHttpIntegration()]) + sentry_init(integrations=[AioHttpIntegration()], data_collection={}) async def hello(request): raise asyncio.CancelledError() @@ -280,8 +277,9 @@ async def hello(request): @pytest.mark.asyncio async def test_half_initialized(sentry_init, aiohttp_client, capture_events): - sentry_init(integrations=[AioHttpIntegration()]) + # Note: the first sentry_init is intentional sentry_init() + sentry_init(integrations=[AioHttpIntegration()], data_collection={}) async def hello(request): return web.Response(text="hello") @@ -298,94 +296,22 @@ async def hello(request): assert events == [] +@pytest.mark.tests_internal_exceptions @pytest.mark.asyncio -async def test_tracing(sentry_init, aiohttp_client, capture_events): - sentry_init(integrations=[AioHttpIntegration()], traces_sample_rate=1.0) - - async def hello(request): - return web.Response(text="hello") - - app = web.Application() - app.router.add_get("/", hello) - - events = capture_events() - - client = await aiohttp_client(app) - resp = await client.get("/") - assert resp.status == 200 - - (event,) = events - - assert event["type"] == "transaction" - assert ( - event["transaction"] - == "tests.integrations.aiohttp.test_aiohttp.test_tracing..hello" - ) - - -@pytest.mark.asyncio -@pytest.mark.parametrize( - "url,transaction_style,expected_transaction,expected_source", - [ - ( - "/message", - "handler_name", - "tests.integrations.aiohttp.test_aiohttp.test_transaction_style..hello", - "component", - ), - ( - "/message", - "method_and_path_pattern", - "GET /{var}", - "route", - ), - ], -) -async def test_transaction_style( - sentry_init, - aiohttp_client, - capture_events, - url, - transaction_style, - expected_transaction, - expected_source, -): +async def test_tracing_unparseable_url(sentry_init, aiohttp_client, capture_items): sentry_init( - integrations=[AioHttpIntegration(transaction_style=transaction_style)], + integrations=[AioHttpIntegration()], traces_sample_rate=1.0, + data_collection={}, ) - async def hello(request): - return web.Response(text="hello") - - app = web.Application() - app.router.add_get(r"/{var}", hello) - - events = capture_events() - - client = await aiohttp_client(app) - resp = await client.get(url) - assert resp.status == 200 - - (event,) = events - - assert event["type"] == "transaction" - assert event["transaction"] == expected_transaction - assert event["transaction_info"] == {"source": expected_source} - - -@pytest.mark.tests_internal_exceptions -@pytest.mark.asyncio -async def test_tracing_unparseable_url(sentry_init, aiohttp_client, capture_events): - sentry_init(integrations=[AioHttpIntegration()], traces_sample_rate=1.0) - async def hello(request): return web.Response(text="hello") app = web.Application() app.router.add_get("/", hello) - events = capture_events() + items = capture_items("span") client = await aiohttp_client(app) with mock.patch( @@ -395,11 +321,12 @@ async def hello(request): assert resp.status == 200 - (event,) = events + sentry_sdk.flush() + + (span,) = [item.payload for item in items] - assert event["type"] == "transaction" assert ( - event["transaction"] + span["name"] == "tests.integrations.aiohttp.test_aiohttp.test_tracing_unparseable_url..hello" ) @@ -415,6 +342,7 @@ async def test_traces_sampler_gets_request_object_in_sampling_context( sentry_init( integrations=[AioHttpIntegration()], traces_sampler=traces_sampler, + data_collection={}, ) async def kangaroo_handler(request): @@ -439,9 +367,13 @@ async def kangaroo_handler(request): @pytest.mark.asyncio async def test_has_trace_if_performance_enabled( - sentry_init, aiohttp_client, capture_events + sentry_init, aiohttp_client, capture_items ): - sentry_init(integrations=[AioHttpIntegration()], traces_sample_rate=1.0) + sentry_init( + integrations=[AioHttpIntegration()], + traces_sample_rate=1.0, + data_collection={}, + ) async def hello(request): capture_message("It's a good day to try dividing by 0") @@ -450,13 +382,29 @@ async def hello(request): app = web.Application() app.router.add_get("/", hello) - events = capture_events() + items = capture_items("event", "span") client = await aiohttp_client(app) resp = await client.get("/") assert resp.status == 500 - msg_event, error_event, transaction_event = events + sentry_sdk.flush() + + msg_events = [ + i.payload for i in items if i.type == "event" and "exception" not in i.payload + ] + error_events = [ + i.payload for i in items if i.type == "event" and "exception" in i.payload + ] + spans = [i.payload for i in items if i.type == "span"] + + assert len(msg_events) == 1 + assert len(error_events) == 1 + assert len(spans) == 1 + + (msg_event,) = msg_events + (error_event,) = error_events + (span,) = spans assert msg_event["contexts"]["trace"] assert "trace_id" in msg_event["contexts"]["trace"] @@ -464,12 +412,9 @@ async def hello(request): assert error_event["contexts"]["trace"] assert "trace_id" in error_event["contexts"]["trace"] - assert transaction_event["contexts"]["trace"] - assert "trace_id" in transaction_event["contexts"]["trace"] - assert ( error_event["contexts"]["trace"]["trace_id"] - == transaction_event["contexts"]["trace"]["trace_id"] + == span["trace_id"] == msg_event["contexts"]["trace"]["trace_id"] ) @@ -478,7 +423,7 @@ async def hello(request): async def test_has_trace_if_performance_disabled( sentry_init, aiohttp_client, capture_events ): - sentry_init(integrations=[AioHttpIntegration()]) + sentry_init(integrations=[AioHttpIntegration()], data_collection={}) async def hello(request): capture_message("It's a good day to try dividing by 0") @@ -509,9 +454,13 @@ async def hello(request): @pytest.mark.asyncio async def test_trace_from_headers_if_performance_enabled( - sentry_init, aiohttp_client, capture_events + sentry_init, aiohttp_client, capture_items ): - sentry_init(integrations=[AioHttpIntegration()], traces_sample_rate=1.0) + sentry_init( + integrations=[AioHttpIntegration()], + traces_sample_rate=1.0, + data_collection={}, + ) async def hello(request): capture_message("It's a good day to try dividing by 0") @@ -520,22 +469,33 @@ async def hello(request): app = web.Application() app.router.add_get("/", hello) - events = capture_events() + items = capture_items("event", "span") - # The aiohttp_client is instrumented so will generate the sentry-trace header and add request. - # Get the sentry-trace header from the request so we can later compare with transaction events. client = await aiohttp_client(app) - with start_transaction(): - # Headers are only added to the span if there is an active transaction - resp = await client.get("/") + resp = await client.get("/") sentry_trace_header = resp.request_info.headers.get("sentry-trace") trace_id = sentry_trace_header.split("-")[0] assert resp.status == 500 - # Last item is the custom transaction event wrapping `client.get("/")` - msg_event, error_event, transaction_event, _ = events + sentry_sdk.flush() + + msg_events = [ + i.payload for i in items if i.type == "event" and "exception" not in i.payload + ] + error_events = [ + i.payload for i in items if i.type == "event" and "exception" in i.payload + ] + spans = [i.payload for i in items if i.type == "span"] + + assert len(msg_events) == 1 + assert len(error_events) == 1 + assert len(spans) == 1 + + (msg_event,) = msg_events + (error_event,) = error_events + (span,) = spans assert msg_event["contexts"]["trace"] assert "trace_id" in msg_event["contexts"]["trace"] @@ -543,19 +503,17 @@ async def hello(request): assert error_event["contexts"]["trace"] assert "trace_id" in error_event["contexts"]["trace"] - assert transaction_event["contexts"]["trace"] - assert "trace_id" in transaction_event["contexts"]["trace"] - assert msg_event["contexts"]["trace"]["trace_id"] == trace_id assert error_event["contexts"]["trace"]["trace_id"] == trace_id - assert transaction_event["contexts"]["trace"]["trace_id"] == trace_id + + assert span["trace_id"] == trace_id @pytest.mark.asyncio async def test_trace_from_headers_if_performance_disabled( sentry_init, aiohttp_client, capture_events ): - sentry_init(integrations=[AioHttpIntegration()]) + sentry_init(integrations=[AioHttpIntegration()], data_collection={}) async def hello(request): capture_message("It's a good day to try dividing by 0") @@ -587,60 +545,11 @@ async def hello(request): assert error_event["contexts"]["trace"]["trace_id"] == trace_id -@pytest.mark.asyncio -async def test_crumb_capture( - sentry_init, - aiohttp_raw_server, - aiohttp_client, - capture_events, -): - def before_breadcrumb(crumb, hint): - crumb["data"]["extra"] = "foo" - return crumb - - sentry_init( - integrations=[AioHttpIntegration()], - before_breadcrumb=before_breadcrumb, - ) - - async def handler(request): - return web.Response(text="OK") - - raw_server = await aiohttp_raw_server(handler) - - with start_transaction(): - events = capture_events() - - client = await aiohttp_client(raw_server) - resp = await client.get("/") - assert resp.status == 200 - capture_message("Testing!") - - (event,) = events - - crumb = event["breadcrumbs"]["values"][0] - assert crumb["type"] == "http" - assert crumb["category"] == "httplib" - assert crumb["data"] == ApproxDict( - { - "url": "http://127.0.0.1:{}/".format(raw_server.port), - "http.fragment": "", - "http.method": "GET", - "http.query": "", - "http.response.status_code": 200, - "reason": "OK", - "extra": "foo", - } - ) - - @pytest.mark.asyncio @pytest.mark.parametrize( "pii_options,url_expected,query_expected", [ ({}, False, False), - ({"send_default_pii": True}, True, True), - ({"send_default_pii": False}, False, False), ( { "data_collection": { @@ -661,7 +570,7 @@ async def handler(request): ), ], ) -async def test_crumb_capture_span_streaming( +async def test_crumb_capture( sentry_init, aiohttp_raw_server, aiohttp_client, @@ -677,7 +586,6 @@ def before_breadcrumb(crumb, hint): sentry_init( integrations=[AioHttpIntegration()], before_breadcrumb=before_breadcrumb, - trace_lifecycle="stream", **pii_options, ) @@ -718,60 +626,6 @@ async def handler(request): assert crumb["data"] == ApproxDict(expected) -@pytest.mark.parametrize( - "status_code,level", - [ - (200, None), - (301, None), - (403, "warning"), - (405, "warning"), - (500, "error"), - ], -) -@pytest.mark.asyncio -async def test_crumb_capture_client_error( - sentry_init, - aiohttp_raw_server, - aiohttp_client, - capture_events, - status_code, - level, -): - sentry_init(integrations=[AioHttpIntegration()]) - - async def handler(request): - return web.Response(status=status_code) - - raw_server = await aiohttp_raw_server(handler) - - with start_transaction(): - events = capture_events() - - client = await aiohttp_client(raw_server) - resp = await client.get("/") - assert resp.status == status_code - capture_message("Testing!") - - (event,) = events - - crumb = event["breadcrumbs"]["values"][0] - assert crumb["type"] == "http" - if level is None: - assert "level" not in crumb - else: - assert crumb["level"] == level - assert crumb["category"] == "httplib" - assert crumb["data"] == ApproxDict( - { - "url": "http://127.0.0.1:{}/".format(raw_server.port), - "http.fragment": "", - "http.method": "GET", - "http.query": "", - "http.response.status_code": status_code, - } - ) - - @pytest.mark.parametrize( "status_code,level,reason", [ @@ -786,8 +640,6 @@ async def handler(request): "pii_options,url_expected,query_expected", [ ({}, False, False), - ({"send_default_pii": True}, True, True), - ({"send_default_pii": False}, False, False), ( { "data_collection": { @@ -809,7 +661,7 @@ async def handler(request): ], ) @pytest.mark.asyncio -async def test_crumb_capture_client_error_span_streaming( +async def test_crumb_capture_client_error( sentry_init, aiohttp_raw_server, aiohttp_client, @@ -821,9 +673,7 @@ async def test_crumb_capture_client_error_span_streaming( url_expected, query_expected, ): - sentry_init( - integrations=[AioHttpIntegration()], trace_lifecycle="stream", **pii_options - ) + sentry_init(integrations=[AioHttpIntegration()], **pii_options) async def handler(request): return web.Response(status=status_code) @@ -868,11 +718,12 @@ async def handler(request): @pytest.mark.asyncio async def test_outgoing_trace_headers_adds_missing_unsigned_propagation_headers( - sentry_init, aiohttp_raw_server, aiohttp_client + sentry_init, capture_items, aiohttp_raw_server, aiohttp_client ): sentry_init( integrations=[AioHttpIntegration()], traces_sample_rate=1.0, + data_collection={}, ) async def handler(request): @@ -880,24 +731,31 @@ async def handler(request): raw_server = await aiohttp_raw_server(handler) - with start_transaction( + items = capture_items("span") + + with sentry_sdk.start_span( name="/interactions/other-dogs/new-dog", - op="greeting.sniff", - # make trace_id difference between transactions - trace_id="0123456789012345678901234567890", - ) as transaction: + attributes={ + "sentry.op": "greeting.sniff", + }, + ): client = await aiohttp_client(raw_server) resp = await client.get("/") - request_span = transaction._span_recorder.spans[-1] - - assert resp.request_info.headers[ - "sentry-trace" - ] == "{trace_id}-{parent_span_id}-{sampled}".format( - trace_id=transaction.trace_id, - parent_span_id=request_span.span_id, - sampled=1, - ) - assert resp.request_info.headers["baggage"].count("sentry-trace_id=") == 1 + + sentry_sdk.flush() + spans = [item.payload for item in items] + (request_span,) = ( + span for span in spans if span["attributes"].get("sentry.op") == "http.client" + ) + + assert resp.request_info.headers[ + "sentry-trace" + ] == "{trace_id}-{parent_span_id}-{sampled}".format( + trace_id=request_span["trace_id"], + parent_span_id=request_span["span_id"], + sampled=1, + ) + assert resp.request_info.headers["baggage"].count("sentry-trace_id=") == 1 @pytest.mark.asyncio @@ -908,6 +766,7 @@ async def test_outgoing_trace_headers_appends_baggage_but_preserves_sentry_trace integrations=[AioHttpIntegration()], traces_sample_rate=1.0, release="d08ebdb9309e1b004c6f52202de58a09c2268e42", + data_collection={}, ) async def handler(request): @@ -916,10 +775,8 @@ async def handler(request): raw_server = await aiohttp_raw_server(handler) with mock.patch("sentry_sdk.tracing_utils.Random.randrange", return_value=500000): - with start_transaction( + with sentry_sdk.start_span( name="/interactions/other-dogs/new-dog", - op="greeting.sniff", - trace_id="0123456789012345678901234567890", ): client = await aiohttp_client(raw_server) resp = await client.get( @@ -930,12 +787,10 @@ async def handler(request): }, ) - assert ( - resp.request_info.headers["baggage"] - == "custom=value,sentry-trace_id=0123456789012345678901234567890,sentry-sample_rand=0.500000,sentry-environment=production,sentry-release=d08ebdb9309e1b004c6f52202de58a09c2268e42,sentry-transaction=/interactions/other-dogs/new-dog,sentry-sample_rate=1.0,sentry-sampled=true" - ) - # existing `sentry-trace`: leave as-is. - assert resp.request_info.headers["sentry-trace"] == "existing-trace" + baggage = resp.request_info.headers["baggage"] + assert baggage.startswith("custom=value,") + assert "sentry-sample_rand=0.500000" in baggage + assert "sentry-sampled=true" in baggage @pytest.mark.asyncio @@ -945,6 +800,7 @@ async def test_outgoing_trace_headers_preserves_signed_propagation_headers( sentry_init( integrations=[AioHttpIntegration()], traces_sample_rate=1.0, + data_collection={}, ) async def handler(request): @@ -959,7 +815,7 @@ async def handler(request): "Signature=sixtyseven" ) - with start_transaction(name="test", sampled=True): + with sentry_sdk.start_span(name="test"): client = await aiohttp_client(raw_server) resp = await client.get( "/", @@ -984,6 +840,7 @@ async def test_outgoing_trace_headers_preserves_query_signed_baggage( sentry_init( integrations=[AioHttpIntegration()], traces_sample_rate=1.0, + data_collection={}, ) async def handler(request): @@ -1001,7 +858,7 @@ async def handler(request): "&X-Amz-Signature=sixtyseven" ) - with start_transaction(name="test", sampled=True): + with sentry_sdk.start_span(name="test"): client = await aiohttp_client(raw_server) resp = await client.get(path, headers={"baggage": "vendor=value"}) @@ -1017,16 +874,15 @@ async def test_request_source_disabled( sentry_init, aiohttp_raw_server, aiohttp_client, - capture_events, + capture_items, ): - sentry_options = { - "integrations": [AioHttpIntegration()], - "traces_sample_rate": 1.0, - "enable_http_request_source": False, - "http_request_source_threshold_ms": 0, - } - - sentry_init(**sentry_options) + sentry_init( + integrations=[AioHttpIntegration()], + traces_sample_rate=1.0, + enable_http_request_source=False, + http_request_source_threshold_ms=0, + data_collection={}, + ) # server for making span request async def handler(request): @@ -1042,22 +898,21 @@ async def hello(request): app = web.Application() app.router.add_get(r"/", hello) - events = capture_events() + items = capture_items("span") client = await aiohttp_client(app) await client.get("/") - (event,) = events + sentry_sdk.flush() - span = event["spans"][-1] - assert span["description"].startswith("GET") + (span, segment) = [item.payload for item in items] - data = span.get("data", {}) + assert span["name"].startswith("GET") - assert SPANDATA.CODE_LINENO not in data - assert SPANDATA.CODE_NAMESPACE not in data - assert SPANDATA.CODE_FILEPATH not in data - assert SPANDATA.CODE_FUNCTION not in data + assert SPANDATA.CODE_LINENO not in span["attributes"] + assert SPANDATA.CODE_NAMESPACE not in span["attributes"] + assert SPANDATA.CODE_FILEPATH not in span["attributes"] + assert SPANDATA.CODE_FUNCTION not in span["attributes"] @pytest.mark.asyncio @@ -1066,18 +921,20 @@ async def test_request_source_enabled( sentry_init, aiohttp_raw_server, aiohttp_client, - capture_events, + capture_items, enable_http_request_source, ): - sentry_options = { - "integrations": [AioHttpIntegration()], - "traces_sample_rate": 1.0, - "http_request_source_threshold_ms": 0, - } + extra_options = {} if enable_http_request_source is not None: - sentry_options["enable_http_request_source"] = enable_http_request_source + extra_options["enable_http_request_source"] = enable_http_request_source - sentry_init(**sentry_options) + sentry_init( + integrations=[AioHttpIntegration()], + traces_sample_rate=1.0, + http_request_source_threshold_ms=0, + data_collection={}, + **extra_options, + ) # server for making span request async def handler(request): @@ -1093,33 +950,33 @@ async def hello(request): app = web.Application() app.router.add_get(r"/", hello) - events = capture_events() + items = capture_items("span") client = await aiohttp_client(app) await client.get("/") - (event,) = events + sentry_sdk.flush() - span = event["spans"][-1] - assert span["description"].startswith("GET") + (span, segment) = [item.payload for item in items] - data = span.get("data", {}) + assert span["name"].startswith("GET") - assert SPANDATA.CODE_LINENO in data - assert SPANDATA.CODE_NAMESPACE in data - assert SPANDATA.CODE_FILEPATH in data - assert SPANDATA.CODE_FUNCTION in data + assert "code.line.number" in span["attributes"] + assert "code.namespace" in span["attributes"] + assert "code.file.path" in span["attributes"] + assert "code.function" in span["attributes"] @pytest.mark.asyncio async def test_request_source( - sentry_init, aiohttp_raw_server, aiohttp_client, capture_events + sentry_init, aiohttp_raw_server, aiohttp_client, capture_items ): sentry_init( integrations=[AioHttpIntegration()], traces_sample_rate=1.0, enable_http_request_source=True, http_request_source_threshold_ms=0, + data_collection={}, ) # server for making span request @@ -1136,41 +993,41 @@ async def handler_with_outgoing_request(request): app = web.Application() app.router.add_get(r"/", handler_with_outgoing_request) - events = capture_events() + items = capture_items("span") client = await aiohttp_client(app) await client.get("/") - (event,) = events + sentry_sdk.flush() - span = event["spans"][-1] - assert span["description"].startswith("GET") + (span, segment) = [item.payload for item in items] - data = span.get("data", {}) + assert span["name"].startswith("GET") - assert SPANDATA.CODE_LINENO in data - assert SPANDATA.CODE_NAMESPACE in data - assert SPANDATA.CODE_FILEPATH in data - assert SPANDATA.CODE_FUNCTION in data + assert "code.line.number" in span["attributes"] + assert "code.namespace" in span["attributes"] + assert "code.file.path" in span["attributes"] + assert "code.function" in span["attributes"] - assert type(data.get(SPANDATA.CODE_LINENO)) == int - assert data.get(SPANDATA.CODE_LINENO) > 0 + assert type(span["attributes"]["code.line.number"]) == int + assert span["attributes"]["code.line.number"] > 0 assert ( - data.get(SPANDATA.CODE_NAMESPACE) == "tests.integrations.aiohttp.test_aiohttp" + span["attributes"]["code.namespace"] + == "tests.integrations.aiohttp.test_aiohttp" ) - assert data.get(SPANDATA.CODE_FILEPATH).endswith( + assert span["attributes"]["code.file.path"].endswith( "tests/integrations/aiohttp/test_aiohttp.py" ) - is_relative_path = data.get(SPANDATA.CODE_FILEPATH)[0] != os.sep + is_relative_path = span["attributes"]["code.file.path"][0] != os.sep assert is_relative_path - assert data.get(SPANDATA.CODE_FUNCTION) == "handler_with_outgoing_request" + assert span["attributes"]["code.function"] == "handler_with_outgoing_request" @pytest.mark.asyncio async def test_request_source_with_module_in_search_path( - sentry_init, aiohttp_raw_server, aiohttp_client, capture_events + sentry_init, aiohttp_raw_server, aiohttp_client, capture_items ): """ Test that request source is relative to the path of the module it ran in @@ -1180,6 +1037,7 @@ async def test_request_source_with_module_in_search_path( traces_sample_rate=1.0, enable_http_request_source=True, http_request_source_threshold_ms=0, + data_collection={}, ) # server for making span request @@ -1198,43 +1056,43 @@ async def handler_with_outgoing_request(request): app = web.Application() app.router.add_get(r"/", handler_with_outgoing_request) - events = capture_events() + items = capture_items("span") client = await aiohttp_client(app) await client.get("/") - (event,) = events + sentry_sdk.flush() - span = event["spans"][-1] - assert span["description"].startswith("GET") + (span, segment) = [item.payload for item in items] - data = span.get("data", {}) + assert span["name"].startswith("GET") - assert SPANDATA.CODE_LINENO in data - assert SPANDATA.CODE_NAMESPACE in data - assert SPANDATA.CODE_FILEPATH in data - assert SPANDATA.CODE_FUNCTION in data + assert "code.line.number" in span["attributes"] + assert "code.namespace" in span["attributes"] + assert "code.file.path" in span["attributes"] + assert "code.function" in span["attributes"] - assert type(data.get(SPANDATA.CODE_LINENO)) == int - assert data.get(SPANDATA.CODE_LINENO) > 0 - assert data.get(SPANDATA.CODE_NAMESPACE) == "aiohttp_helpers.helpers" - assert data.get(SPANDATA.CODE_FILEPATH) == "aiohttp_helpers/helpers.py" + assert type(span["attributes"]["code.line.number"]) == int + assert span["attributes"]["code.line.number"] > 0 + assert span["attributes"]["code.namespace"] == "aiohttp_helpers.helpers" + assert span["attributes"]["code.file.path"] == "aiohttp_helpers/helpers.py" - is_relative_path = data.get(SPANDATA.CODE_FILEPATH)[0] != os.sep + is_relative_path = span["attributes"]["code.file.path"][0] != os.sep assert is_relative_path - assert data.get(SPANDATA.CODE_FUNCTION) == "get_request_with_client" + assert span["attributes"]["code.function"] == "get_request_with_client" @pytest.mark.asyncio async def test_no_request_source_if_duration_too_short( - sentry_init, aiohttp_raw_server, aiohttp_client, capture_events + sentry_init, aiohttp_raw_server, aiohttp_client, capture_items ): sentry_init( integrations=[AioHttpIntegration()], traces_sample_rate=1.0, enable_http_request_source=True, - http_request_source_threshold_ms=100, + http_request_source_threshold_ms=10**10, + data_collection={}, ) # server for making span request @@ -1251,49 +1109,36 @@ async def handler_with_outgoing_request(request): app = web.Application() app.router.add_get(r"/", handler_with_outgoing_request) - events = capture_events() - - def fake_create_trace_context(*args, **kwargs): - trace_context = create_trace_config() - - async def overwrite_timestamps(session, trace_config_ctx, params): - span = trace_config_ctx._sentry_span - span.start_timestamp = datetime.datetime(2024, 1, 1, microsecond=0) - span.timestamp = datetime.datetime(2024, 1, 1, microsecond=99999) - - trace_context.on_request_end.insert(0, overwrite_timestamps) - - return trace_context + items = capture_items("span") - with mock.patch( - "sentry_sdk.integrations.aiohttp.create_trace_config", - fake_create_trace_context, - ): - client = await aiohttp_client(app) - await client.get("/") + client = await aiohttp_client(app) + await client.get("/") - (event,) = events + sentry_sdk.flush() - span = event["spans"][-1] - assert span["description"].startswith("GET") + ( + span, + segment, + ) = [item.payload for item in items] - data = span.get("data", {}) + assert span["name"].startswith("GET") - assert SPANDATA.CODE_LINENO not in data - assert SPANDATA.CODE_NAMESPACE not in data - assert SPANDATA.CODE_FILEPATH not in data - assert SPANDATA.CODE_FUNCTION not in data + assert SPANDATA.CODE_LINENO not in span["attributes"] + assert SPANDATA.CODE_NAMESPACE not in span["attributes"] + assert SPANDATA.CODE_FILEPATH not in span["attributes"] + assert SPANDATA.CODE_FUNCTION not in span["attributes"] @pytest.mark.asyncio async def test_request_source_if_duration_over_threshold( - sentry_init, aiohttp_raw_server, aiohttp_client, capture_events + sentry_init, aiohttp_raw_server, aiohttp_client, capture_items ): sentry_init( integrations=[AioHttpIntegration()], traces_sample_rate=1.0, enable_http_request_source=True, - http_request_source_threshold_ms=100, + http_request_source_threshold_ms=0, + data_collection={}, ) # server for making span request @@ -1310,52 +1155,36 @@ async def handler_with_outgoing_request(request): app = web.Application() app.router.add_get(r"/", handler_with_outgoing_request) - events = capture_events() - - def fake_create_trace_context(*args, **kwargs): - trace_context = create_trace_config() - - async def overwrite_timestamps(session, trace_config_ctx, params): - span = trace_config_ctx._sentry_span - span.start_timestamp = datetime.datetime(2024, 1, 1, microsecond=0) - span.timestamp = datetime.datetime(2024, 1, 1, microsecond=100001) - - trace_context.on_request_end.insert(0, overwrite_timestamps) - - return trace_context + items = capture_items("span") - with mock.patch( - "sentry_sdk.integrations.aiohttp.create_trace_config", - fake_create_trace_context, - ): - client = await aiohttp_client(app) - await client.get("/") + client = await aiohttp_client(app) + await client.get("/") - (event,) = events + sentry_sdk.flush() - span = event["spans"][-1] - assert span["description"].startswith("GET") + (span, segment) = [item.payload for item in items] - data = span.get("data", {}) + assert span["name"].startswith("GET") - assert SPANDATA.CODE_LINENO in data - assert SPANDATA.CODE_NAMESPACE in data - assert SPANDATA.CODE_FILEPATH in data - assert SPANDATA.CODE_FUNCTION in data + assert "code.line.number" in span["attributes"] + assert "code.namespace" in span["attributes"] + assert "code.file.path" in span["attributes"] + assert "code.function" in span["attributes"] - assert type(data.get(SPANDATA.CODE_LINENO)) == int - assert data.get(SPANDATA.CODE_LINENO) > 0 + assert type(span["attributes"]["code.line.number"]) == int + assert span["attributes"]["code.line.number"] > 0 assert ( - data.get(SPANDATA.CODE_NAMESPACE) == "tests.integrations.aiohttp.test_aiohttp" + span["attributes"]["code.namespace"] + == "tests.integrations.aiohttp.test_aiohttp" ) - assert data.get(SPANDATA.CODE_FILEPATH).endswith( + assert span["attributes"]["code.file.path"].endswith( "tests/integrations/aiohttp/test_aiohttp.py" ) - is_relative_path = data.get(SPANDATA.CODE_FILEPATH)[0] != os.sep + is_relative_path = span["attributes"]["code.file.path"][0] != os.sep assert is_relative_path - assert data.get(SPANDATA.CODE_FUNCTION) == "handler_with_outgoing_request" + assert span["attributes"]["code.function"] == "handler_with_outgoing_request" @pytest.mark.asyncio @@ -1363,11 +1192,12 @@ async def test_span_origin( sentry_init, aiohttp_raw_server, aiohttp_client, - capture_events, + capture_items, ): sentry_init( integrations=[AioHttpIntegration()], traces_sample_rate=1.0, + data_collection={}, ) # server for making span request @@ -1384,14 +1214,16 @@ async def hello(request): app = web.Application() app.router.add_get(r"/", hello) - events = capture_events() + items = capture_items("span") client = await aiohttp_client(app) await client.get("/") - (event,) = events - assert event["contexts"]["trace"]["origin"] == "auto.http.aiohttp" - assert event["spans"][0]["origin"] == "auto.http.aiohttp" + sentry_sdk.flush() + + (span, segment) = [item.payload for item in items] + assert span["attributes"]["sentry.origin"] == "auto.http.aiohttp" + assert segment["attributes"]["sentry.origin"] == "auto.http.aiohttp" @pytest.mark.parametrize( @@ -1434,7 +1266,9 @@ async def test_failed_request_status_codes( exception_to_raise, should_capture, ): - sentry_init(integrations=[AioHttpIntegration(**integration_kwargs)]) + sentry_init( + integrations=[AioHttpIntegration(**integration_kwargs)], data_collection={} + ) events = capture_events() async def handle(_): @@ -1468,7 +1302,10 @@ async def test_failed_request_status_codes_with_returned_status( """ Returning a web.Response with a failed_request_status_code should not be reported to Sentry. """ - sentry_init(integrations=[AioHttpIntegration(failed_request_status_codes={500})]) + sentry_init( + integrations=[AioHttpIntegration(failed_request_status_codes={500})], + data_collection={}, + ) events = capture_events() async def handle(_): @@ -1492,7 +1329,10 @@ async def test_failed_request_status_codes_non_http_exception( If an exception, which is not an instance of HTTPException, is raised, it should be captured, even if failed_request_status_codes is empty. """ - sentry_init(integrations=[AioHttpIntegration(failed_request_status_codes=set())]) + sentry_init( + integrations=[AioHttpIntegration(failed_request_status_codes=set())], + data_collection={}, + ) events = capture_events() async def handle(_): @@ -1510,15 +1350,11 @@ async def handle(_): @pytest.mark.asyncio -@pytest.mark.parametrize("send_pii", [True, False]) -async def test_tracing_span_streaming( - sentry_init, aiohttp_client, capture_items, send_pii -): +async def test_tracing(sentry_init, aiohttp_client, capture_items): sentry_init( integrations=[AioHttpIntegration()], traces_sample_rate=1.0, - send_default_pii=send_pii, - trace_lifecycle="stream", + data_collection={}, ) async def hello(request): @@ -1545,7 +1381,7 @@ async def hello(request): assert server_span["is_segment"] is True assert ( server_span["name"] - == "tests.integrations.aiohttp.test_aiohttp.test_tracing_span_streaming..hello" + == "tests.integrations.aiohttp.test_aiohttp.test_tracing..hello" ) assert server_span["attributes"]["sentry.op"] == "http.server" assert server_span["attributes"]["sentry.origin"] == "auto.http.aiohttp" @@ -1558,23 +1394,15 @@ async def hello(request): # Request attributes derived directly from the aiohttp request. assert server_span["attributes"]["http.request.method"] == "GET" - if send_pii: - assert "client.address" in server_span["attributes"] - assert "user.ip_address" in server_span["attributes"] - - url_full = server_span["attributes"]["url.full"] - assert url_full.startswith("http://127.0.0.1:") - assert url_full.endswith("/") + assert "client.address" in server_span["attributes"] + assert "user.ip_address" in server_span["attributes"] - url_path = server_span["attributes"]["url.path"] - assert url_path == "/" - else: - assert "url.full" not in server_span["attributes"] - assert "url.path" not in server_span["attributes"] - assert "url.query" not in server_span["attributes"] + url_full = server_span["attributes"]["url.full"] + assert url_full.startswith("http://127.0.0.1:") + assert url_full.endswith("/") - assert "client.address" not in server_span["attributes"] - assert "user.ip_address" not in server_span["attributes"] + url_path = server_span["attributes"]["url.path"] + assert url_path == "/" # aiohttp's test client always sends a Host header; we assert it propagates # into the span attributes via _filter_headers. @@ -1583,13 +1411,12 @@ async def hello(request): @pytest.mark.asyncio @pytest.mark.parametrize("init_kwargs, expect_ip", DATA_COLLECTION_USER_INFO_CASES) -async def test_user_address_with_data_collection_and_span_streaming( +async def test_user_address_with_data_collection( sentry_init, aiohttp_client, capture_items, init_kwargs, expect_ip ): sentry_init( integrations=[AioHttpIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", **init_kwargs, ) @@ -1619,13 +1446,11 @@ async def hello(request): @pytest.mark.asyncio -async def test_sensitive_header_scrubbing_span_streaming( - sentry_init, aiohttp_client, capture_items -): +async def test_sensitive_header_scrubbing(sentry_init, aiohttp_client, capture_items): sentry_init( integrations=[AioHttpIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", + data_collection={}, ) async def hello(request): @@ -1665,44 +1490,18 @@ async def hello(request): @pytest.mark.parametrize( - "options,expected", + "data_collection,expected", [ pytest.param( { - "send_default_pii": True, - "data_collection": {}, - }, - { - "authorization": "[Filtered]", - "custom": "foobar", - "cookie": "[Filtered]", - }, - id="enabled_send_default_pii_redacts_auth_header_due_to_data_collection_default_settings", - ), - pytest.param( - { - "send_default_pii": False, - "data_collection": {}, - }, - { - "authorization": "[Filtered]", - "custom": "foobar", - "cookie": "[Filtered]", - }, - id="disabled_send_default_pii_redacts_auth_header_due_to_data_collection_default_settings", - ), - pytest.param( - { - "send_default_pii": False, - "data_collection": {"http_headers": {"request": {"mode": "off"}}}, + "http_headers": {"request": {"mode": "off"}}, }, None, id="data_collection_off_does_not_add_headers", ), pytest.param( { - "send_default_pii": False, - "data_collection": {"http_headers": {"request": {"mode": "allowlist"}}}, + "http_headers": {"request": {"mode": "allowlist"}}, }, { "authorization": "[Filtered]", @@ -1713,12 +1512,9 @@ async def hello(request): ), pytest.param( { - "send_default_pii": False, - "data_collection": { - "http_headers": { - "request": {"mode": "allowlist", "terms": ["Authorization"]} - } - }, + "http_headers": { + "request": {"mode": "allowlist", "terms": ["Authorization"]} + } }, { "authorization": "[Filtered]", @@ -1728,14 +1524,7 @@ async def hello(request): id="data_collection_allow_list_redacts_sensitive_terms_even_when_provided_by_user", ), pytest.param( - { - "send_default_pii": False, - "data_collection": { - "http_headers": { - "request": {"mode": "allowlist", "terms": ["custom"]} - } - }, - }, + {"http_headers": {"request": {"mode": "allowlist", "terms": ["custom"]}}}, { "authorization": "[Filtered]", "custom": "foobar", @@ -1744,14 +1533,7 @@ async def hello(request): id="data_collection_allow_list_does_not_redact_provided_term", ), pytest.param( - { - "send_default_pii": False, - "data_collection": { - "http_headers": { - "request": {"mode": "denylist", "terms": ["custom"]} - } - }, - }, + {"http_headers": {"request": {"mode": "denylist", "terms": ["custom"]}}}, { "authorization": "[Filtered]", "custom": "[Filtered]", @@ -1760,14 +1542,7 @@ async def hello(request): id="data_collection_deny_list_redacts_sensitive_terms_when_provided_by_user", ), pytest.param( - { - "send_default_pii": False, - "data_collection": { - "http_headers": { - "request": {"mode": "allowlist", "terms": ["cookie"]} - } - }, - }, + {"http_headers": {"request": {"mode": "allowlist", "terms": ["cookie"]}}}, { "authorization": "[Filtered]", "custom": "[Filtered]", @@ -1778,15 +1553,13 @@ async def hello(request): ], ) @pytest.mark.asyncio -async def test_sensitive_header_passthrough_with_pii_span_streaming( - sentry_init, aiohttp_client, capture_items, options, expected, request +async def test_sensitive_header_passthrough_with_pii( + sentry_init, aiohttp_client, capture_items, data_collection, expected, request ): sentry_init( integrations=[AioHttpIntegration()], traces_sample_rate=1.0, - send_default_pii=options["send_default_pii"], - trace_lifecycle="stream", - data_collection=options["data_collection"], + data_collection=data_collection, ) async def hello(request): @@ -1829,78 +1602,6 @@ async def hello(request): ) -@pytest.mark.asyncio -async def test_sensitive_header_passthrough_with_pii_span_streaming_without_data_collection( - sentry_init, aiohttp_client, capture_items -): - sentry_init( - integrations=[AioHttpIntegration()], - traces_sample_rate=1.0, - send_default_pii=True, - trace_lifecycle="stream", - ) - - async def hello(request): - return web.Response(text="hello") - - app = web.Application() - app.router.add_get("/", hello) - - items = capture_items("span") - - client = await aiohttp_client(app) - await client.get("/", headers={"Authorization": "Bearer secret-token"}) - - sentry_sdk.flush() - - (server_span,) = [item.payload for item in items] - - # With send_default_pii=True, _filter_headers is a no-op and the original - # value reaches the span attribute. - assert ( - server_span["attributes"]["http.request.header.authorization"] - == "Bearer secret-token" - ) - # client.address and user.ip_address is captured under send_default_pii=True. - assert server_span["attributes"]["client.address"] == "127.0.0.1" - assert server_span["attributes"]["user.ip_address"] == "127.0.0.1" - - -@pytest.mark.asyncio -@pytest.mark.parametrize("send_pii", [True, False]) -async def test_url_query_attribute_span_streaming( - sentry_init, aiohttp_client, capture_items, send_pii -): - sentry_init( - integrations=[AioHttpIntegration()], - traces_sample_rate=1.0, - send_default_pii=send_pii, - trace_lifecycle="stream", - ) - - async def hello(request): - return web.Response(text="hello") - - app = web.Application() - app.router.add_get("/", hello) - - items = capture_items("span") - - client = await aiohttp_client(app) - resp = await client.get("/?foo=bar&baz=qux") - assert resp.status == 200 - - sentry_sdk.flush() - - assert len(items) == 1 - (server_segment,) = [item.payload for item in items] - - if send_pii: - assert server_segment["attributes"]["url.query"] == "foo=bar&baz=qux" - else: - assert "url.query" not in server_segment["attributes"] - - @pytest.mark.asyncio @pytest.mark.parametrize( "url,transaction_style,expected_name,expected_source", @@ -1909,7 +1610,7 @@ async def hello(request): "/message", "handler_name", "tests.integrations.aiohttp.test_aiohttp." - "test_transaction_style_span_streaming..hello", + "test_transaction_style..hello", "component", ), ( @@ -1920,7 +1621,7 @@ async def hello(request): ), ], ) -async def test_transaction_style_span_streaming( +async def test_transaction_style( sentry_init, aiohttp_client, capture_items, @@ -1932,7 +1633,7 @@ async def test_transaction_style_span_streaming( sentry_init( integrations=[AioHttpIntegration(transaction_style=transaction_style)], traces_sample_rate=1.0, - trace_lifecycle="stream", + data_collection={}, ) async def hello(request): @@ -1974,7 +1675,7 @@ async def test_http_route( sentry_init( integrations=[AioHttpIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", + data_collection={}, ) async def hello(request): @@ -1994,11 +1695,11 @@ async def hello(request): @pytest.mark.asyncio -async def test_server_error_span_streaming(sentry_init, aiohttp_client, capture_items): +async def test_server_error(sentry_init, aiohttp_client, capture_items): sentry_init( integrations=[AioHttpIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", + data_collection={}, ) async def hello(request): @@ -2025,7 +1726,7 @@ async def hello(request): server_span = items[1].payload # The integration's generic Exception path reraises without recording - # http.response.status_code on the server span. StreamedSpan.__exit__ + # http.response.status_code on the server span. Span.__exit__ # observes the propagating exception and sets status to "error". assert server_span["attributes"]["sentry.op"] == "http.server" assert "http.response.status_code" not in server_span["attributes"] @@ -2033,13 +1734,11 @@ async def hello(request): @pytest.mark.asyncio -async def test_http_exception_span_streaming( - sentry_init, aiohttp_client, capture_items -): +async def test_http_exception(sentry_init, aiohttp_client, capture_items): sentry_init( integrations=[AioHttpIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", + data_collection={}, ) async def hello(request): @@ -2065,13 +1764,13 @@ async def hello(request): @pytest.mark.asyncio -async def test_http_exception_ok_status_not_overridden_span_streaming( +async def test_http_exception_ok_status_not_overridden( sentry_init, aiohttp_client, capture_items ): sentry_init( integrations=[AioHttpIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", + data_collection={}, ) async def hello(request): @@ -2098,14 +1797,13 @@ async def hello(request): @pytest.mark.asyncio @pytest.mark.parametrize("send_pii", [True, False]) -async def test_outgoing_client_span_span_streaming( +async def test_outgoing_client_span( sentry_init, aiohttp_raw_server, aiohttp_client, capture_items, send_pii ): sentry_init( integrations=[AioHttpIntegration()], traces_sample_rate=1.0, send_default_pii=send_pii, - trace_lifecycle="stream", ) async def handler(request): @@ -2158,13 +1856,13 @@ async def hello(request): @pytest.mark.asyncio -async def test_outgoing_trace_headers_span_streaming( +async def test_outgoing_trace_headers( sentry_init, aiohttp_raw_server, aiohttp_client, capture_items ): sentry_init( integrations=[AioHttpIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", + data_collection={}, ) async def handler(request): @@ -2198,11 +1896,10 @@ async def test_user_ip_address_on_all_spans( integrations=[AioHttpIntegration()], traces_sample_rate=1.0, send_default_pii=send_default_pii, - trace_lifecycle="stream", ) async def hello(request): - with sentry_sdk.traces.start_span(name="child-span"): + with sentry_sdk.start_span(name="child-span"): pass return web.Response(text="hello") @@ -2230,21 +1927,6 @@ async def hello(request): _QUERY_PARAM_DATA_COLLECTION_CASES = [ - pytest.param( - {"send_default_pii": True}, - "toy=tennisball&color=red&auth=secret", - id="send_default_pii_true", - ), - pytest.param( - {"send_default_pii": False}, - None, - id="send_default_pii_false", - ), - pytest.param( - {}, - None, - id="defaults", - ), pytest.param( {"data_collection": {}}, "toy=tennisball&color=red&auth=%5BFiltered%5D", @@ -2282,14 +1964,6 @@ async def hello(request): None, id="data_collection_off", ), - pytest.param( - { - "send_default_pii": True, - "data_collection": {"url_query_params": {"mode": "off"}}, - }, - None, - id="data_collection_wins_over_send_default_pii", - ), ] @@ -2297,14 +1971,13 @@ async def hello(request): @pytest.mark.parametrize( "init_kwargs, expected_query", _QUERY_PARAM_DATA_COLLECTION_CASES ) -async def test_server_url_query_data_collection_span_streaming( +async def test_server_url_query_data_collection( sentry_init, aiohttp_client, capture_items, init_kwargs, expected_query ): init_kwargs = dict(init_kwargs) sentry_init( integrations=[AioHttpIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", **init_kwargs, ) @@ -2334,7 +2007,7 @@ async def hello(request): @pytest.mark.parametrize( "init_kwargs, expected_query", _QUERY_PARAM_DATA_COLLECTION_CASES ) -async def test_client_url_query_data_collection_span_streaming( +async def test_client_url_query_data_collection( sentry_init, aiohttp_raw_server, aiohttp_client, @@ -2346,7 +2019,6 @@ async def test_client_url_query_data_collection_span_streaming( sentry_init( integrations=[AioHttpIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", **init_kwargs, ) diff --git a/tests/integrations/aiomysql/test_aiomysql.py b/tests/integrations/aiomysql/test_aiomysql.py index 28f24c27a4..f7c1ca0cab 100644 --- a/tests/integrations/aiomysql/test_aiomysql.py +++ b/tests/integrations/aiomysql/test_aiomysql.py @@ -20,7 +20,7 @@ import pytest_asyncio import sentry_sdk -from sentry_sdk import capture_message, start_transaction +from sentry_sdk import capture_message from sentry_sdk.consts import SPANDATA from sentry_sdk.integrations.aiomysql import AioMySQLIntegration from sentry_sdk.tracing_utils import record_sql_queries @@ -44,8 +44,8 @@ def _get_db_name(): "category": "query", "data": ApproxDict( { - "db.name": MYSQL_DB, - "db.system": "mysql", + "db.namespace": MYSQL_DB, + "db.system.name": "mysql", "db.user": MYSQL_USER, "server.address": MYSQL_HOST, "server.port": MYSQL_PORT, @@ -684,629 +684,319 @@ async def test_connection_pool(sentry_init, capture_events) -> None: connect_crumbs = [c for c in crumbs if c.get("message") == "connect"] assert len(connect_crumbs) >= pool_size # One connect span per pooled connection for crumb in connect_crumbs: - assert crumb["data"]["db.system"] == "mysql" + assert crumb["data"]["db.system.name"] == "mysql" assert crumb["data"]["server.address"] == MYSQL_HOST @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) -async def test_query_source_disabled( - sentry_init, capture_events, capture_items, span_streaming -): - sentry_options = { - "integrations": [AioMySQLIntegration()], - "traces_sample_rate": 1.0, - "enable_db_query_source": False, - "db_query_source_threshold_ms": 0, - "trace_lifecycle": "stream" if span_streaming else "static", - } - - sentry_init(**sentry_options) - - if span_streaming: - items = capture_items("span") - - with sentry_sdk.traces.start_span(name="test_segment"): - conn = await aiomysql.connect(**_connect_args()) - - async with conn.cursor() as cur: - await cur.execute( - "INSERT INTO users(name, password, dob) VALUES ('Alice', 'secret', '1990-12-25')", - ) - - conn.close() - - sentry_sdk.flush() - - spans = [item.payload for item in items] +async def test_query_source_disabled(sentry_init, capture_items): + sentry_init( + integrations=[AioMySQLIntegration()], + traces_sample_rate=1.0, + enable_db_query_source=False, + db_query_source_threshold_ms=0, + ) - assert len(spans) == 3 + items = capture_items("span") - connect_span = spans[0] - insert_span = spans[1] - segment = spans[2] + with sentry_sdk.start_span(name="test_segment"): + conn = await aiomysql.connect(**_connect_args()) - assert segment["is_segment"] is True - assert connect_span["name"] == "connect" - assert insert_span["name"].startswith("INSERT INTO") + async with conn.cursor() as cur: + await cur.execute( + "INSERT INTO users(name, password, dob) VALUES ('Alice', 'secret', '1990-12-25')", + ) - data = insert_span.get("attributes", {}) + conn.close() - assert "code.line.number" not in data - assert "code.namespace" not in data - assert "code.file.path" not in data - assert "code.function" not in data - else: - events = capture_events() + sentry_sdk.flush() - with start_transaction(name="test_transaction", sampled=True): - conn = await aiomysql.connect(**_connect_args()) + spans = [item.payload for item in items] - async with conn.cursor() as cur: - await cur.execute( - "INSERT INTO users(name, password, dob) VALUES ('Alice', 'secret', '1990-12-25')", - ) + assert len(spans) == 3 - conn.close() + connect_span = spans[0] + insert_span = spans[1] + segment = spans[2] - (event,) = events + assert segment["is_segment"] is True + assert connect_span["name"] == "connect" + assert insert_span["name"].startswith("INSERT INTO") - span = event["spans"][-1] - assert span["description"].startswith("INSERT INTO") - data = span.get("data", {}) + data = insert_span.get("attributes", {}) - assert SPANDATA.CODE_LINENO not in data - assert SPANDATA.CODE_NAMESPACE not in data - assert SPANDATA.CODE_FILEPATH not in data - assert SPANDATA.CODE_FUNCTION not in data + assert "code.line.number" not in data + assert "code.namespace" not in data + assert "code.file.path" not in data + assert "code.function" not in data @pytest.mark.asyncio @pytest.mark.parametrize("enable_db_query_source", [None, True]) -@pytest.mark.parametrize("span_streaming", [True, False]) -async def test_query_source_enabled( - sentry_init, capture_events, capture_items, enable_db_query_source, span_streaming -): +async def test_query_source_enabled(sentry_init, capture_items, enable_db_query_source): sentry_options = { "integrations": [AioMySQLIntegration()], "traces_sample_rate": 1.0, "db_query_source_threshold_ms": 0, - "trace_lifecycle": "stream" if span_streaming else "static", } if enable_db_query_source is not None: sentry_options["enable_db_query_source"] = enable_db_query_source sentry_init(**sentry_options) - if span_streaming: - items = capture_items("span") - - with sentry_sdk.traces.start_span(name="test_segment"): - conn = await aiomysql.connect(**_connect_args()) - - async with conn.cursor() as cur: - await cur.execute( - "INSERT INTO users(name, password, dob) VALUES ('Alice', 'secret', '1990-12-25')", - ) - - conn.close() - - sentry_sdk.flush() - - spans = [item.payload for item in items] - - assert len(spans) == 3 + items = capture_items("span") - connect_span = spans[0] - insert_span = spans[1] - segment = spans[2] + with sentry_sdk.start_span(name="test_segment"): + conn = await aiomysql.connect(**_connect_args()) - assert segment["is_segment"] is True - assert connect_span["name"] == "connect" - assert insert_span["name"].startswith("INSERT INTO") + async with conn.cursor() as cur: + await cur.execute( + "INSERT INTO users(name, password, dob) VALUES ('Alice', 'secret', '1990-12-25')", + ) - data = insert_span.get("attributes", {}) + conn.close() - assert "code.line.number" in data - assert "code.namespace" in data - assert "code.file.path" in data - assert "code.function" in data - else: - events = capture_events() + sentry_sdk.flush() - with start_transaction(name="test_transaction", sampled=True): - conn = await aiomysql.connect(**_connect_args()) + spans = [item.payload for item in items] - async with conn.cursor() as cur: - await cur.execute( - "INSERT INTO users(name, password, dob) VALUES ('Alice', 'secret', '1990-12-25')", - ) + assert len(spans) == 3 - conn.close() + connect_span = spans[0] + insert_span = spans[1] + segment = spans[2] - (event,) = events + assert segment["is_segment"] is True + assert connect_span["name"] == "connect" + assert insert_span["name"].startswith("INSERT INTO") - span = event["spans"][-1] - assert span["description"].startswith("INSERT INTO") - data = span.get("data", {}) + data = insert_span.get("attributes", {}) - assert SPANDATA.CODE_LINENO in data - assert SPANDATA.CODE_NAMESPACE in data - assert SPANDATA.CODE_FILEPATH in data - assert SPANDATA.CODE_FUNCTION in data + assert "code.line.number" in data + assert "code.namespace" in data + assert "code.file.path" in data + assert "code.function" in data @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) -async def test_query_source(sentry_init, capture_events, capture_items, span_streaming): +async def test_query_source(sentry_init, capture_items): sentry_init( integrations=[AioMySQLIntegration()], traces_sample_rate=1.0, enable_db_query_source=True, db_query_source_threshold_ms=0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") - - with sentry_sdk.traces.start_span(name="test_segment"): - conn = await aiomysql.connect(**_connect_args()) - - async with conn.cursor() as cur: - await cur.execute( - "INSERT INTO users(name, password, dob) VALUES ('Alice', 'secret', '1990-12-25')", - ) - - conn.close() - - sentry_sdk.flush() - - spans = [item.payload for item in items] - - assert len(spans) == 3 - - connect_span = spans[0] - insert_span = spans[1] - segment = spans[2] - - assert segment["is_segment"] is True - assert connect_span["name"] == "connect" - assert insert_span["name"].startswith("INSERT INTO") + items = capture_items("span") - data = insert_span.get("attributes", {}) - - assert "code.line.number" in data - assert "code.namespace" in data - assert "code.file.path" in data - assert "code.function" in data + with sentry_sdk.start_span(name="test_segment"): + conn = await aiomysql.connect(**_connect_args()) - assert type(data.get("code.line.number")) == int - assert data.get("code.line.number") > 0 - assert data.get("code.namespace") == "tests.integrations.aiomysql.test_aiomysql" - assert data.get("code.file.path").endswith( - "tests/integrations/aiomysql/test_aiomysql.py" - ) + async with conn.cursor() as cur: + await cur.execute( + "INSERT INTO users(name, password, dob) VALUES ('Alice', 'secret', '1990-12-25')", + ) - is_relative_path = data.get("code.file.path")[0] != os.sep - assert is_relative_path + conn.close() - assert data.get("code.function") == "test_query_source" - else: - events = capture_events() + sentry_sdk.flush() - with start_transaction(name="test_transaction", sampled=True): - conn = await aiomysql.connect(**_connect_args()) + spans = [item.payload for item in items] - async with conn.cursor() as cur: - await cur.execute( - "INSERT INTO users(name, password, dob) VALUES ('Alice', 'secret', '1990-12-25')", - ) + assert len(spans) == 3 - conn.close() + connect_span = spans[0] + insert_span = spans[1] + segment = spans[2] - (event,) = events + assert segment["is_segment"] is True + assert connect_span["name"] == "connect" + assert insert_span["name"].startswith("INSERT INTO") - span = event["spans"][-1] - assert span["description"].startswith("INSERT INTO") + data = insert_span.get("attributes", {}) - data = span.get("data", {}) + assert "code.line.number" in data + assert "code.namespace" in data + assert "code.file.path" in data + assert "code.function" in data - assert SPANDATA.CODE_LINENO in data - assert SPANDATA.CODE_NAMESPACE in data - assert SPANDATA.CODE_FILEPATH in data - assert SPANDATA.CODE_FUNCTION in data - - assert type(data.get(SPANDATA.CODE_LINENO)) == int - assert data.get(SPANDATA.CODE_LINENO) > 0 - assert ( - data.get(SPANDATA.CODE_NAMESPACE) - == "tests.integrations.aiomysql.test_aiomysql" - ) - assert data.get(SPANDATA.CODE_FILEPATH).endswith( - "tests/integrations/aiomysql/test_aiomysql.py" - ) + assert type(data.get("code.line.number")) == int + assert data.get("code.line.number") > 0 + assert data.get("code.namespace") == "tests.integrations.aiomysql.test_aiomysql" + assert data.get("code.file.path").endswith( + "tests/integrations/aiomysql/test_aiomysql.py" + ) - is_relative_path = data.get(SPANDATA.CODE_FILEPATH)[0] != os.sep - assert is_relative_path + is_relative_path = data.get("code.file.path")[0] != os.sep + assert is_relative_path - assert data.get(SPANDATA.CODE_FUNCTION) == "test_query_source" + assert data.get("code.function") == "test_query_source" @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) -async def test_no_query_source_if_duration_too_short( - sentry_init, capture_events, capture_items, span_streaming -): +async def test_no_query_source_if_duration_too_short(sentry_init, capture_items): sentry_init( integrations=[AioMySQLIntegration()], traces_sample_rate=1.0, enable_db_query_source=True, db_query_source_threshold_ms=100, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") - - @contextmanager - def fake_record_sql_queries_streaming(*args, **kwargs): - with record_sql_queries(*args, **kwargs) as span: - pass - span._start_timestamp = datetime.datetime(2024, 1, 1, microsecond=0) - span._end_timestamp = datetime.datetime(2024, 1, 1, microsecond=99999) - yield span - - with sentry_sdk.traces.start_span(name="test_segment"): - conn = await aiomysql.connect(**_connect_args()) - - async with conn.cursor() as cur: - with mock.patch( - "sentry_sdk.integrations.aiomysql.record_sql_queries", - fake_record_sql_queries_streaming, - ): - await cur.execute( - "INSERT INTO users(name, password, dob) VALUES ('Alice', 'secret', '1990-12-25')", - ) - - conn.close() + items = capture_items("span") - sentry_sdk.flush() + @contextmanager + def fake_record_sql_queries_streaming(*args, **kwargs): + with record_sql_queries(*args, **kwargs) as span: + pass + span._start_timestamp = datetime.datetime(2024, 1, 1, microsecond=0) + span._end_timestamp = datetime.datetime(2024, 1, 1, microsecond=99999) + yield span - spans = [item.payload for item in items] - - assert len(spans) == 3 - - connect_span = spans[0] - insert_span = spans[1] - segment = spans[2] - - assert segment["name"] == "test_segment" - assert insert_span["name"].startswith("INSERT INTO") - assert connect_span["name"] == "connect" - data = insert_span.get("attributes", {}) - - assert "code.line.number" not in data - assert "code.namespace" not in data - assert "code.file.path" not in data - assert "code.function" not in data - else: - events = capture_events() + with sentry_sdk.start_span(name="test_segment"): + conn = await aiomysql.connect(**_connect_args()) - with start_transaction(name="test_transaction", sampled=True): - conn = await aiomysql.connect(**_connect_args()) + async with conn.cursor() as cur: + with mock.patch( + "sentry_sdk.integrations.aiomysql.record_sql_queries", + fake_record_sql_queries_streaming, + ): + await cur.execute( + "INSERT INTO users(name, password, dob) VALUES ('Alice', 'secret', '1990-12-25')", + ) - @contextmanager - def fake_record_sql_queries(*args, **kwargs): - with record_sql_queries(*args, **kwargs) as span: - pass - span.start_timestamp = datetime.datetime(2024, 1, 1, microsecond=0) - span.timestamp = datetime.datetime(2024, 1, 1, microsecond=99999) - yield span + conn.close() - async with conn.cursor() as cur: - with mock.patch( - "sentry_sdk.integrations.aiomysql.record_sql_queries", - fake_record_sql_queries, - ): - await cur.execute( - "INSERT INTO users(name, password, dob) VALUES ('Alice', 'secret', '1990-12-25')", - ) + sentry_sdk.flush() - conn.close() + spans = [item.payload for item in items] - (event,) = events + assert len(spans) == 3 - span = event["spans"][-1] - assert span["description"].startswith("INSERT INTO") + connect_span = spans[0] + insert_span = spans[1] + segment = spans[2] - data = span.get("data", {}) + assert segment["name"] == "test_segment" + assert insert_span["name"].startswith("INSERT INTO") + assert connect_span["name"] == "connect" + data = insert_span.get("attributes", {}) - assert SPANDATA.CODE_LINENO not in data - assert SPANDATA.CODE_NAMESPACE not in data - assert SPANDATA.CODE_FILEPATH not in data - assert SPANDATA.CODE_FUNCTION not in data + assert "code.line.number" not in data + assert "code.namespace" not in data + assert "code.file.path" not in data + assert "code.function" not in data @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) -async def test_query_source_if_duration_over_threshold( - sentry_init, capture_events, capture_items, span_streaming -): +async def test_query_source_if_duration_over_threshold(sentry_init, capture_items): sentry_init( integrations=[AioMySQLIntegration()], traces_sample_rate=1.0, enable_db_query_source=True, db_query_source_threshold_ms=100, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") + items = capture_items("span") - @contextmanager - def fake_record_sql_queries_streaming(*args, **kwargs): - with record_sql_queries(*args, **kwargs) as span: - span._start_timestamp = datetime.datetime( - 2024, 1, 1, microsecond=0, tzinfo=datetime.timezone.utc - ) - yield span - - with sentry_sdk.traces.start_span(name="test_segment"): - conn = await aiomysql.connect(**_connect_args()) - - async with conn.cursor() as cur: - with mock.patch( - "sentry_sdk.integrations.aiomysql.record_sql_queries", - fake_record_sql_queries_streaming, - ): - await cur.execute( - "INSERT INTO users(name, password, dob) VALUES ('Alice', 'secret', '1990-12-25')", - ) - - conn.close() - - sentry_sdk.flush() - - spans = [item.payload for item in items] - - assert len(spans) == 3 + @contextmanager + def fake_record_sql_queries_streaming(*args, **kwargs): + with record_sql_queries(*args, **kwargs) as span: + span._start_timestamp = datetime.datetime( + 2024, 1, 1, microsecond=0, tzinfo=datetime.timezone.utc + ) + yield span - connect_span = spans[0] - insert_span = spans[1] - segment = spans[2] + with sentry_sdk.start_span(name="test_segment"): + conn = await aiomysql.connect(**_connect_args()) - assert segment["name"] == "test_segment" - assert insert_span["name"].startswith("INSERT INTO") - assert connect_span["name"] == "connect" + async with conn.cursor() as cur: + with mock.patch( + "sentry_sdk.integrations.aiomysql.record_sql_queries", + fake_record_sql_queries_streaming, + ): + await cur.execute( + "INSERT INTO users(name, password, dob) VALUES ('Alice', 'secret', '1990-12-25')", + ) - data = insert_span.get("attributes", {}) + conn.close() - assert "code.line.number" in data - assert "code.namespace" in data - assert "code.file.path" in data - assert "code.function" in data + sentry_sdk.flush() - assert type(data.get("code.line.number")) == int - assert data.get("code.line.number") > 0 - assert data.get("code.namespace") == "tests.integrations.aiomysql.test_aiomysql" - assert data.get("code.file.path").endswith( - "tests/integrations/aiomysql/test_aiomysql.py" - ) + spans = [item.payload for item in items] - is_relative_path = data.get("code.file.path")[0] != os.sep - assert is_relative_path + assert len(spans) == 3 - assert ( - data.get("code.function") == "test_query_source_if_duration_over_threshold" - ) - else: - events = capture_events() - - with start_transaction(name="test_transaction", sampled=True): - conn = await aiomysql.connect(**_connect_args()) - - @contextmanager - def fake_record_sql_queries(*args, **kwargs): - with record_sql_queries(*args, **kwargs) as span: - pass - span.start_timestamp = datetime.datetime(2024, 1, 1, microsecond=0) - span.timestamp = datetime.datetime(2024, 1, 1, microsecond=100001) - yield span - - async with conn.cursor() as cur: - with mock.patch( - "sentry_sdk.integrations.aiomysql.record_sql_queries", - fake_record_sql_queries, - ): - await cur.execute( - "INSERT INTO users(name, password, dob) VALUES ('Alice', 'secret', '1990-12-25')", - ) - - conn.close() - - (event,) = events - - span = event["spans"][-1] - assert span["description"].startswith("INSERT INTO") - - data = span.get("data", {}) - - assert SPANDATA.CODE_LINENO in data - assert SPANDATA.CODE_NAMESPACE in data - assert SPANDATA.CODE_FILEPATH in data - assert SPANDATA.CODE_FUNCTION in data - - assert type(data.get(SPANDATA.CODE_LINENO)) == int - assert data.get(SPANDATA.CODE_LINENO) > 0 - assert ( - data.get(SPANDATA.CODE_NAMESPACE) - == "tests.integrations.aiomysql.test_aiomysql" - ) - assert data.get(SPANDATA.CODE_FILEPATH).endswith( - "tests/integrations/aiomysql/test_aiomysql.py" - ) + connect_span = spans[0] + insert_span = spans[1] + segment = spans[2] - is_relative_path = data.get(SPANDATA.CODE_FILEPATH)[0] != os.sep - assert is_relative_path + assert segment["name"] == "test_segment" + assert insert_span["name"].startswith("INSERT INTO") + assert connect_span["name"] == "connect" - assert ( - data.get(SPANDATA.CODE_FUNCTION) - == "test_query_source_if_duration_over_threshold" - ) + data = insert_span.get("attributes", {}) + assert "code.line.number" in data + assert "code.namespace" in data + assert "code.file.path" in data + assert "code.function" in data -@pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) -async def test_span_origin(sentry_init, capture_events, capture_items, span_streaming): - sentry_init( - integrations=[AioMySQLIntegration()], - traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", + assert type(data.get("code.line.number")) == int + assert data.get("code.line.number") > 0 + assert data.get("code.namespace") == "tests.integrations.aiomysql.test_aiomysql" + assert data.get("code.file.path").endswith( + "tests/integrations/aiomysql/test_aiomysql.py" ) - if span_streaming: - items = capture_items("span") - - with sentry_sdk.traces.start_span(name="test_segment"): - conn = await aiomysql.connect(**_connect_args()) - - async with conn.cursor() as cur: - await cur.execute("SELECT 1") - await cur.execute("SELECT 2") - - conn.close() - - sentry_sdk.flush() + is_relative_path = data.get("code.file.path")[0] != os.sep + assert is_relative_path - spans = [item.payload for item in items] - - non_segment_spans = [s for s in spans if not s.get("is_segment")] - segment_spans = [s for s in spans if s.get("is_segment")] - - assert len(segment_spans) == 1 - assert segment_spans[0]["attributes"]["sentry.origin"] == "manual" - - for span in non_segment_spans: - assert span["attributes"]["sentry.origin"] == "auto.db.aiomysql" - else: - events = capture_events() - - with start_transaction(name="test_transaction"): - conn = await aiomysql.connect(**_connect_args()) - - async with conn.cursor() as cur: - await cur.execute("SELECT 1") - await cur.execute("SELECT 2") - - conn.close() - - (event,) = events - - assert event["contexts"]["trace"]["origin"] == "manual" - - for span in event["spans"]: - assert span["origin"] == "auto.db.aiomysql" + assert data.get("code.function") == "test_query_source_if_duration_over_threshold" @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) -async def test_multiline_query_description_normalized( - sentry_init, capture_events, capture_items, span_streaming -): +async def test_span_origin(sentry_init, capture_items): sentry_init( integrations=[AioMySQLIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") - - with sentry_sdk.traces.start_span(name="test_segment"): - conn = await aiomysql.connect(**_connect_args()) + items = capture_items("span") - async with conn.cursor() as cur: - await cur.execute( - """ - SELECT - id, - name - FROM - users - WHERE - name = 'Alice' - """ - ) - - conn.close() - - sentry_sdk.flush() + with sentry_sdk.start_span(name="test_segment"): + conn = await aiomysql.connect(**_connect_args()) - spans = [item.payload for item in items] + async with conn.cursor() as cur: + await cur.execute("SELECT 1") + await cur.execute("SELECT 2") - select_spans = [ - s - for s in spans - if not s.get("is_segment") and "SELECT" in s.get("name", "") - ] - assert len(select_spans) == 1 - assert ( - select_spans[0]["name"] == "SELECT id, name FROM users WHERE name = 'Alice'" - ) - else: - events = capture_events() + conn.close() - with start_transaction(name="test_transaction"): - conn = await aiomysql.connect(**_connect_args()) + sentry_sdk.flush() - async with conn.cursor() as cur: - await cur.execute( - """ - SELECT - id, - name - FROM - users - WHERE - name = 'Alice' - """ - ) + spans = [item.payload for item in items] - conn.close() + non_segment_spans = [s for s in spans if not s.get("is_segment")] + segment_spans = [s for s in spans if s.get("is_segment")] - (event,) = events + assert len(segment_spans) == 1 + assert segment_spans[0]["attributes"]["sentry.origin"] == "manual" - spans = [ - s - for s in event["spans"] - if s["op"] == "db" and "SELECT" in s.get("description", "") - ] - assert len(spans) == 1 - assert ( - spans[0]["description"] == "SELECT id, name FROM users WHERE name = 'Alice'" - ) + assert len(non_segment_spans) == 3 + for span in non_segment_spans: + assert span["attributes"]["sentry.origin"] == "auto.db.aiomysql" @pytest.mark.asyncio -async def test_before_send_transaction_sees_normalized_description( - sentry_init, capture_events -): - def before_send_transaction(event, hint): - for span in event.get("spans", []): - desc = span.get("description", "") - if "SELECT id, name FROM users" in desc: - span["description"] = "filtered" - return event - +async def test_multiline_query_description_normalized(sentry_init, capture_items): sentry_init( integrations=[AioMySQLIntegration()], traces_sample_rate=1.0, - before_send_transaction=before_send_transaction, ) - events = capture_events() - with start_transaction(name="test_transaction"): + items = capture_items("span") + + with sentry_sdk.start_span(name="test_segment"): conn = await aiomysql.connect(**_connect_args()) async with conn.cursor() as cur: @@ -1317,79 +1007,52 @@ def before_send_transaction(event, hint): name FROM users + WHERE + name = 'Alice' """ ) conn.close() - (event,) = events - spans = [ - s - for s in event["spans"] - if s["op"] == "db" and "filtered" in s.get("description", "") - ] + sentry_sdk.flush() - assert len(spans) == 1 - assert spans[0]["description"] == "filtered" + spans = [item.payload for item in items] + + select_spans = [ + s for s in spans if not s.get("is_segment") and "SELECT" in s.get("name", "") + ] + assert len(select_spans) == 1 + assert select_spans[0]["name"] == "SELECT id, name FROM users WHERE name = 'Alice'" @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) -async def test_db_data_on_spans( - sentry_init, capture_events, capture_items, span_streaming -): +async def test_db_data_on_spans(sentry_init, capture_items): """Test that database connection data is properly set on spans.""" sentry_init( integrations=[AioMySQLIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") + items = capture_items("span") - with sentry_sdk.traces.start_span(name="test_segment"): - conn = await aiomysql.connect(**_connect_args()) - - async with conn.cursor() as cur: - await cur.execute("SELECT 1") - - conn.close() - - sentry_sdk.flush() - - spans = [item.payload for item in items] - - query_span = [ - s - for s in spans - if not s.get("is_segment") and "SELECT" in s.get("name", "") - ][0] - data = query_span.get("attributes", {}) - assert data.get(SPANDATA.DB_SYSTEM_NAME) == "mysql" - assert data.get(SPANDATA.SERVER_ADDRESS) == MYSQL_HOST - assert data.get(SPANDATA.SERVER_PORT) == MYSQL_PORT - assert data.get(SPANDATA.DB_NAMESPACE) == MYSQL_DB - assert data.get(SPANDATA.DB_USER) == MYSQL_USER - else: - events = capture_events() - - with start_transaction(name="test_transaction"): - conn = await aiomysql.connect(**_connect_args()) + with sentry_sdk.start_span(name="test_segment"): + conn = await aiomysql.connect(**_connect_args()) - async with conn.cursor() as cur: - await cur.execute("SELECT 1") + async with conn.cursor() as cur: + await cur.execute("SELECT 1") - conn.close() + conn.close() - (event,) = events + sentry_sdk.flush() - db_spans = [s for s in event["spans"] if s["op"] == "db"] - assert len(db_spans) > 0 + spans = [item.payload for item in items] - query_span = [s for s in db_spans if "SELECT" in s.get("description", "")][0] - assert query_span["data"].get(SPANDATA.DB_SYSTEM) == "mysql" - assert query_span["data"].get(SPANDATA.SERVER_ADDRESS) == MYSQL_HOST - assert query_span["data"].get(SPANDATA.SERVER_PORT) == MYSQL_PORT - assert query_span["data"].get(SPANDATA.DB_NAME) == MYSQL_DB - assert query_span["data"].get(SPANDATA.DB_USER) == MYSQL_USER + query_span = [ + s for s in spans if not s.get("is_segment") and "SELECT" in s.get("name", "") + ][0] + data = query_span.get("attributes", {}) + assert data.get(SPANDATA.DB_SYSTEM_NAME) == "mysql" + assert data.get(SPANDATA.SERVER_ADDRESS) == MYSQL_HOST + assert data.get(SPANDATA.SERVER_PORT) == MYSQL_PORT + assert data.get(SPANDATA.DB_NAMESPACE) == MYSQL_DB + assert data.get(SPANDATA.DB_USER) == MYSQL_USER diff --git a/tests/integrations/anthropic/test_anthropic.py b/tests/integrations/anthropic/test_anthropic.py index b3835c4b72..3bd3b3c3f0 100644 --- a/tests/integrations/anthropic/test_anthropic.py +++ b/tests/integrations/anthropic/test_anthropic.py @@ -57,9 +57,7 @@ async def __call__(self, *args, **kwargs): except ImportError: from anthropic.types.content_block import ContentBlock as TextBlock -from sentry_sdk import start_span, start_transaction -from sentry_sdk._types import BLOB_DATA_SUBSTITUTE -from sentry_sdk.ai.utils import transform_content_part, transform_message_content +from sentry_sdk.ai.utils import transform_content_part from sentry_sdk.consts import OP, SPANDATA from sentry_sdk.integrations.anthropic import ( AnthropicIntegration, @@ -69,7 +67,6 @@ async def __call__(self, *args, **kwargs): _transform_anthropic_content_block, ) from sentry_sdk.integrations.stdlib import StdlibIntegration -from sentry_sdk.traces import SpanStatus from sentry_sdk.utils import package_version ANTHROPIC_VERSION = package_version("anthropic") @@ -138,33 +135,20 @@ def data_collection_tool_use_message(): ) -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize( - "send_default_pii, include_prompts", - [ - (True, True), - (True, False), - (False, True), - (False, False), - ], + "send_default_pii", + [True, False], ) def test_nonstreaming_create_message( sentry_init, - capture_events, capture_items, send_default_pii, - include_prompts, - stream_gen_ai_spans, - span_streaming, ): sentry_init( - integrations=[AnthropicIntegration(include_prompts=include_prompts)], + integrations=[AnthropicIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = Anthropic(api_key="z") @@ -180,194 +164,75 @@ def test_nonstreaming_create_message( "content": "Hello, Claude", }, ] + items = capture_items("span") - if span_streaming: - items = capture_items("transaction", "span") - - with sentry_sdk.traces.start_span(name="anthropic"): - response = client.messages.create( - max_tokens=1024, messages=messages, model="model" - ) - - assert response == EXAMPLE_MESSAGE - usage = response.usage - - assert usage.input_tokens == 10 - assert usage.output_tokens == 20 - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert len(spans) == 2 - - assert spans[1]["name"] == "anthropic" - (span, _) = spans - - assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - assert span["name"] == "chat model" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - - if send_default_pii and include_prompts: - assert json.loads(span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) == [ - { - "role": "user", - "content": "Message demonstrating the absence of truncation.", - }, - { - "role": "user", - "content": "Hello, Claude", - }, - ] - assert ( - span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi, I'm Claude." - ) - else: - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] - - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 20 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is False - assert ( - span["attributes"][SPANDATA.GEN_AI_RESPONSE_ID] - == "msg_01XFDUDYJgAACzvnptvVoYEL" - ) - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS] == [ - "end_turn" - ] - elif stream_gen_ai_spans: - items = capture_items("transaction", "span") - - with start_transaction(name="anthropic"): - response = client.messages.create( - max_tokens=1024, messages=messages, model="model" - ) + response = client.messages.create(max_tokens=1024, messages=messages, model="model") - assert response == EXAMPLE_MESSAGE - usage = response.usage + assert response == EXAMPLE_MESSAGE + usage = response.usage - assert usage.input_tokens == 10 - assert usage.output_tokens == 20 + assert usage.input_tokens == 10 + assert usage.output_tokens == 20 - (event,) = (item.payload for item in items if item.type == "transaction") - assert event["transaction"] == "anthropic" + sentry_sdk.flush() + spans = [item.payload for item in items] + assert len(spans) == 1 - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert len(spans) == 1 - (span,) = spans + (span,) = spans - assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - assert span["name"] == "chat model" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" + assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT + assert span["name"] == "chat model" + assert span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "anthropic" + assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - if send_default_pii and include_prompts: - assert json.loads(span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) == [ - { - "role": "user", - "content": "Message demonstrating the absence of truncation.", - }, - { - "role": "user", - "content": "Hello, Claude", - }, - ] - assert ( - span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi, I'm Claude." - ) - else: - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] - - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 20 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is False - assert ( - span["attributes"][SPANDATA.GEN_AI_RESPONSE_ID] - == "msg_01XFDUDYJgAACzvnptvVoYEL" - ) - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS] == [ - "end_turn" + if send_default_pii: + assert json.loads(span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) == [ + { + "role": "user", + "content": "Message demonstrating the absence of truncation.", + }, + { + "role": "user", + "content": "Hello, Claude", + }, ] + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi, I'm Claude." else: - events = capture_events() - - with start_transaction(name="anthropic"): - response = client.messages.create( - max_tokens=1024, messages=messages, model="model" - ) - - assert response == EXAMPLE_MESSAGE - usage = response.usage - - assert usage.input_tokens == 10 - assert usage.output_tokens == 20 - - assert len(events) == 1 - (event,) = events - - assert event["type"] == "transaction" - assert event["transaction"] == "anthropic" - - assert len(event["spans"]) == 1 - (span,) = event["spans"] - - assert span["op"] == OP.GEN_AI_CHAT - assert span["description"] == "chat model" - assert span["data"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["data"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["data"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - - if send_default_pii and include_prompts: - assert ( - span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - == '[{"role": "user", "content": "Hello, Claude"}]' - ) - assert span["data"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi, I'm Claude." - else: - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["data"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["data"] - - assert span["data"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["data"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 20 - assert span["data"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 - assert span["data"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is False - assert ( - span["data"][SPANDATA.GEN_AI_RESPONSE_ID] == "msg_01XFDUDYJgAACzvnptvVoYEL" - ) - assert span["data"][SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS] == ["end_turn"] + assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] + assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] + + assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 20 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is False + assert ( + span["attributes"][SPANDATA.GEN_AI_RESPONSE_ID] + == "msg_01XFDUDYJgAACzvnptvVoYEL" + ) + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS] == ["end_turn"] -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize( - "data_collection,send_default_pii,include_prompts,expected_present,expected_absent", + "data_collection,send_default_pii,expected_present,expected_absent", [ pytest.param( {"gen_ai": {"inputs": True}}, False, - False, DATA_COLLECTION_EXPECTED_INPUT_DATA, [], - id="gen-ai-inputs-enabled-overrides-pii-and-include-prompts", + id="gen-ai-inputs-enabled-overrides-pii", ), pytest.param( {"gen_ai": {"inputs": False}}, True, - True, {}, DATA_COLLECTION_INPUT_DATA_KEYS, - id="gen-ai-inputs-disabled-overrides-pii-and-include-prompts", + id="gen-ai-inputs-disabled-overrides-pii", ), pytest.param( {"gen_ai": {}}, True, - True, DATA_COLLECTION_EXPECTED_INPUT_DATA, [], id="gen-ai-inputs-omitted-defaults-to-enabled", @@ -375,32 +240,25 @@ def test_nonstreaming_create_message( pytest.param( None, True, - True, DATA_COLLECTION_EXPECTED_INPUT_DATA, [], - id="legacy-pii-and-include-prompts-enabled", + id="legacy-pii", ), ], ) def test_nonstreaming_create_message_data_collection( sentry_init, - capture_events, capture_items, data_collection, send_default_pii, - include_prompts, expected_present, expected_absent, - stream_gen_ai_spans, - span_streaming, ): sentry_init_kwargs = dict( - integrations=[AnthropicIntegration(include_prompts=include_prompts)], + integrations=[AnthropicIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) if data_collection is not None: sentry_init_kwargs["data_collection"] = data_collection @@ -415,28 +273,16 @@ def test_nonstreaming_create_message_data_collection( system="You are a helpful assistant.", messages=[{"role": "user", "content": "Hello, Claude"}], ) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("transaction", "span") - - with start_transaction(name="anthropic"): - client.messages.create(**create_kwargs) + client.messages.create(**create_kwargs) - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - (span,) = [s for s in spans if s["attributes"]["sentry.op"] == OP.GEN_AI_CHAT] - span_data = span["attributes"] - else: - events = capture_events() - - with start_transaction(name="anthropic"): - client.messages.create(**create_kwargs) + sentry_sdk.flush() + spans = [item.payload for item in items] + (span,) = [s for s in spans if s["attributes"]["sentry.op"] == OP.GEN_AI_CHAT] + span_data = span["attributes"] - (event,) = events - (span,) = event["spans"] - span_data = span["data"] - - assert span_data[SPANDATA.GEN_AI_SYSTEM] == "anthropic" + assert span_data[SPANDATA.GEN_AI_PROVIDER_NAME] == "anthropic" assert span_data[SPANDATA.GEN_AI_OPERATION_NAME] == "chat" assert span_data[SPANDATA.GEN_AI_REQUEST_MODEL] == "model" assert span_data[SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 1024 @@ -452,8 +298,6 @@ def test_nonstreaming_create_message_data_collection( ANTHROPIC_VERSION < (0, 27), reason="Tools are not supported in this version of the anthropic package", ) -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize( "data_collection,tools_collected", [ @@ -476,20 +320,15 @@ def test_nonstreaming_create_message_data_collection( ) def test_nonstreaming_create_message_data_collection_tools( sentry_init, - capture_events, capture_items, data_collection, tools_collected, - stream_gen_ai_spans, - span_streaming, ): sentry_init_kwargs = dict( - integrations=[AnthropicIntegration(include_prompts=False)], + integrations=[AnthropicIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=False, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) if data_collection is not None: sentry_init_kwargs["data_collection"] = data_collection @@ -504,26 +343,14 @@ def test_nonstreaming_create_message_data_collection_tools( messages=[], tools=DATA_COLLECTION_EXAMPLE_TOOLS, ) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("transaction", "span") + client.messages.create(**create_kwargs) - with start_transaction(name="anthropic"): - client.messages.create(**create_kwargs) - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - (span,) = [s for s in spans if s["attributes"]["sentry.op"] == OP.GEN_AI_CHAT] - span_data = span["attributes"] - else: - events = capture_events() - - with start_transaction(name="anthropic"): - client.messages.create(**create_kwargs) - - (event,) = events - (span,) = event["spans"] - span_data = span["data"] + sentry_sdk.flush() + spans = [item.payload for item in items] + (span,) = [s for s in spans if s["attributes"]["sentry.op"] == OP.GEN_AI_CHAT] + span_data = span["attributes"] if tools_collected: assert ( @@ -534,57 +361,46 @@ def test_nonstreaming_create_message_data_collection_tools( assert SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS not in span_data -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio @pytest.mark.parametrize( - "data_collection,send_default_pii,include_prompts,expected_present,expected_absent", + "data_collection,send_default_pii,expected_present,expected_absent", [ pytest.param( {"gen_ai": {"inputs": True}}, False, - False, DATA_COLLECTION_EXPECTED_INPUT_DATA, [], - id="gen-ai-inputs-enabled-overrides-pii-and-include-prompts", + id="gen-ai-inputs-enabled-overrides-pii", ), pytest.param( {"gen_ai": {"inputs": False}}, True, - True, {}, DATA_COLLECTION_INPUT_DATA_KEYS, - id="gen-ai-inputs-disabled-overrides-pii-and-include-prompts", + id="gen-ai-inputs-disabled-overrides-pii", ), pytest.param( None, True, - True, DATA_COLLECTION_EXPECTED_INPUT_DATA, [], - id="legacy-pii-and-include-prompts-enabled", + id="legacy-pii", ), ], ) async def test_nonstreaming_create_message_data_collection_async( sentry_init, - capture_events, capture_items, data_collection, send_default_pii, - include_prompts, expected_present, expected_absent, - stream_gen_ai_spans, - span_streaming, ): sentry_init_kwargs = dict( - integrations=[AnthropicIntegration(include_prompts=include_prompts)], + integrations=[AnthropicIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) if data_collection is not None: sentry_init_kwargs["data_collection"] = data_collection @@ -599,28 +415,16 @@ async def test_nonstreaming_create_message_data_collection_async( system="You are a helpful assistant.", messages=[{"role": "user", "content": "Hello, Claude"}], ) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("transaction", "span") + await client.messages.create(**create_kwargs) - with start_transaction(name="anthropic"): - await client.messages.create(**create_kwargs) + sentry_sdk.flush() + spans = [item.payload for item in items] + (span,) = [s for s in spans if s["attributes"]["sentry.op"] == OP.GEN_AI_CHAT] + span_data = span["attributes"] - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - (span,) = [s for s in spans if s["attributes"]["sentry.op"] == OP.GEN_AI_CHAT] - span_data = span["attributes"] - else: - events = capture_events() - - with start_transaction(name="anthropic"): - await client.messages.create(**create_kwargs) - - (event,) = events - (span,) = event["spans"] - span_data = span["data"] - - assert span_data[SPANDATA.GEN_AI_SYSTEM] == "anthropic" + assert span_data[SPANDATA.GEN_AI_PROVIDER_NAME] == "anthropic" assert span_data[SPANDATA.GEN_AI_OPERATION_NAME] == "chat" assert span_data[SPANDATA.GEN_AI_REQUEST_MODEL] == "model" assert span_data[SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 1024 @@ -636,36 +440,30 @@ async def test_nonstreaming_create_message_data_collection_async( ANTHROPIC_VERSION < (0, 27), reason="anthropic.types.ToolUseBlock was added in 0.27.0. Before that, tool use was only available under the beta namespace and could not appear in a standard Message.", ) -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize( - "data_collection,send_default_pii,include_prompts,outputs_collected", + "data_collection,send_default_pii,outputs_collected", [ pytest.param( {"gen_ai": {"outputs": True}}, False, - False, True, - id="gen-ai-outputs-enabled-overrides-pii-and-include-prompts", + id="gen-ai-outputs-enabled-overrides-pii", ), pytest.param( {"gen_ai": {"outputs": False}}, True, - True, False, - id="gen-ai-outputs-disabled-overrides-pii-and-include-prompts", + id="gen-ai-outputs-disabled-overrides-pii", ), pytest.param( {"gen_ai": {"inputs": False, "outputs": False}}, True, - True, False, - id="gen-ai-inputs-and-outputs-disabled-overrides-pii-and-include-prompts", + id="gen-ai-inputs-and-outputs-disabled-overrides-pii", ), pytest.param( {"gen_ai": {}}, False, - False, True, id="gen-ai-inputs-and-outputs-omitted-defaults-to-enabled", ), @@ -673,13 +471,11 @@ async def test_nonstreaming_create_message_data_collection_async( None, True, True, - True, - id="legacy-pii-and-include-prompts-enabled", + id="legacy-pii", ), pytest.param( None, False, - True, False, id="legacy-pii-disabled", ), @@ -687,22 +483,16 @@ async def test_nonstreaming_create_message_data_collection_async( ) def test_nonstreaming_create_message_data_collection_outputs( sentry_init, - capture_events, capture_items, data_collection, send_default_pii, - include_prompts, outputs_collected, - stream_gen_ai_spans, - span_streaming, ): sentry_init_kwargs = dict( - integrations=[AnthropicIntegration(include_prompts=include_prompts)], + integrations=[AnthropicIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) if data_collection is not None: sentry_init_kwargs["data_collection"] = data_collection @@ -717,26 +507,14 @@ def test_nonstreaming_create_message_data_collection_outputs( messages=[{"role": "user", "content": "What is the weather in San Francisco?"}], tools=DATA_COLLECTION_EXAMPLE_TOOLS, ) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("transaction", "span") - - with start_transaction(name="anthropic"): - client.messages.create(**create_kwargs) + client.messages.create(**create_kwargs) - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - (span,) = [s for s in spans if s["attributes"]["sentry.op"] == OP.GEN_AI_CHAT] - span_data = span["attributes"] - else: - events = capture_events() - - with start_transaction(name="anthropic"): - client.messages.create(**create_kwargs) - - (event,) = events - (span,) = event["spans"] - span_data = span["data"] + sentry_sdk.flush() + spans = [item.payload for item in items] + (span,) = [s for s in spans if s["attributes"]["sentry.op"] == OP.GEN_AI_CHAT] + span_data = span["attributes"] # Output data that is not gated on data collection assert span_data[SPANDATA.GEN_AI_RESPONSE_MODEL] == "model" @@ -763,37 +541,31 @@ def test_nonstreaming_create_message_data_collection_outputs( ANTHROPIC_VERSION < (0, 27), reason="anthropic.types.ToolUseBlock was added in 0.27.0. Before that, tool use was only available under the beta namespace and could not appear in a standard Message.", ) -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio @pytest.mark.parametrize( - "data_collection,send_default_pii,include_prompts,outputs_collected", + "data_collection,send_default_pii,outputs_collected", [ pytest.param( {"gen_ai": {"outputs": True}}, False, - False, True, - id="gen-ai-outputs-enabled-overrides-pii-and-include-prompts", + id="gen-ai-outputs-enabled-overrides-pii", ), pytest.param( {"gen_ai": {"outputs": False}}, True, - True, False, - id="gen-ai-outputs-disabled-overrides-pii-and-include-prompts", + id="gen-ai-outputs-disabled-overrides-pii", ), pytest.param( {"gen_ai": {"inputs": False, "outputs": False}}, True, - True, False, - id="gen-ai-inputs-and-outputs-disabled-overrides-pii-and-include-prompts", + id="gen-ai-inputs-and-outputs-disabled-overrides-pii", ), pytest.param( {"gen_ai": {}}, False, - False, True, id="gen-ai-inputs-and-outputs-omitted-defaults-to-enabled", ), @@ -801,13 +573,11 @@ def test_nonstreaming_create_message_data_collection_outputs( None, True, True, - True, - id="legacy-pii-and-include-prompts-enabled", + id="legacy-pii", ), pytest.param( None, False, - True, False, id="legacy-pii-disabled", ), @@ -815,22 +585,16 @@ def test_nonstreaming_create_message_data_collection_outputs( ) async def test_nonstreaming_create_message_data_collection_outputs_async( sentry_init, - capture_events, capture_items, data_collection, send_default_pii, - include_prompts, outputs_collected, - stream_gen_ai_spans, - span_streaming, ): sentry_init_kwargs = dict( - integrations=[AnthropicIntegration(include_prompts=include_prompts)], + integrations=[AnthropicIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) if data_collection is not None: sentry_init_kwargs["data_collection"] = data_collection @@ -845,26 +609,14 @@ async def test_nonstreaming_create_message_data_collection_outputs_async( messages=[{"role": "user", "content": "What is the weather in San Francisco?"}], tools=DATA_COLLECTION_EXAMPLE_TOOLS, ) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("transaction", "span") - - with start_transaction(name="anthropic"): - await client.messages.create(**create_kwargs) - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - (span,) = [s for s in spans if s["attributes"]["sentry.op"] == OP.GEN_AI_CHAT] - span_data = span["attributes"] - else: - events = capture_events() - - with start_transaction(name="anthropic"): - await client.messages.create(**create_kwargs) + await client.messages.create(**create_kwargs) - (event,) = events - (span,) = event["spans"] - span_data = span["data"] + sentry_sdk.flush() + spans = [item.payload for item in items] + (span,) = [s for s in spans if s["attributes"]["sentry.op"] == OP.GEN_AI_CHAT] + span_data = span["attributes"] # Output data that is not gated on data collection assert span_data[SPANDATA.GEN_AI_RESPONSE_MODEL] == "model" @@ -887,34 +639,21 @@ async def test_nonstreaming_create_message_data_collection_outputs_async( assert SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS not in span_data -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio @pytest.mark.parametrize( - "send_default_pii, include_prompts", - [ - (True, True), - (True, False), - (False, True), - (False, False), - ], + "send_default_pii", + [True, False], ) async def test_nonstreaming_create_message_async( sentry_init, - capture_events, capture_items, send_default_pii, - include_prompts, - stream_gen_ai_spans, - span_streaming, ): sentry_init( - integrations=[AnthropicIntegration(include_prompts=include_prompts)], + integrations=[AnthropicIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = AsyncAnthropic(api_key="z") @@ -930,184 +669,66 @@ async def test_nonstreaming_create_message_async( "content": "Hello, Claude", }, ] + items = capture_items("span") - if span_streaming: - items = capture_items("transaction", "span") - - with sentry_sdk.traces.start_span(name="anthropic"): - response = await client.messages.create( - max_tokens=1024, messages=messages, model="model" - ) - - assert response == EXAMPLE_MESSAGE - usage = response.usage - - assert usage.input_tokens == 10 - assert usage.output_tokens == 20 - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert len(spans) == 2 - - assert spans[1]["name"] == "anthropic" - (span, _) = spans - - assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - assert span["name"] == "chat model" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - - if send_default_pii and include_prompts: - assert json.loads(span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) == [ - { - "role": "user", - "content": "Message demonstrating the absence of truncation.", - }, - { - "role": "user", - "content": "Hello, Claude", - }, - ] - assert ( - span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi, I'm Claude." - ) - else: - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] - - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 20 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is False - assert ( - span["attributes"][SPANDATA.GEN_AI_RESPONSE_ID] - == "msg_01XFDUDYJgAACzvnptvVoYEL" - ) - - elif stream_gen_ai_spans: - items = capture_items("transaction", "span") - - with start_transaction(name="anthropic"): - response = await client.messages.create( - max_tokens=1024, messages=messages, model="model" - ) + response = await client.messages.create( + max_tokens=1024, messages=messages, model="model" + ) - assert response == EXAMPLE_MESSAGE - usage = response.usage + assert response == EXAMPLE_MESSAGE + usage = response.usage - assert usage.input_tokens == 10 - assert usage.output_tokens == 20 + assert usage.input_tokens == 10 + assert usage.output_tokens == 20 - (event,) = (item.payload for item in items if item.type == "transaction") - assert event["transaction"] == "anthropic" + sentry_sdk.flush() + spans = [item.payload for item in items] + assert len(spans) == 1 - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert len(spans) == 1 - (span,) = spans + (span,) = spans - assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - assert span["name"] == "chat model" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" + assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT + assert span["name"] == "chat model" + assert span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "anthropic" + assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - if send_default_pii and include_prompts: - assert json.loads(span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) == [ - { - "role": "user", - "content": "Message demonstrating the absence of truncation.", - }, - { - "role": "user", - "content": "Hello, Claude", - }, - ] - assert ( - span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi, I'm Claude." - ) - else: - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] - - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 20 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is False - assert ( - span["attributes"][SPANDATA.GEN_AI_RESPONSE_ID] - == "msg_01XFDUDYJgAACzvnptvVoYEL" - ) + if send_default_pii: + assert json.loads(span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) == [ + { + "role": "user", + "content": "Message demonstrating the absence of truncation.", + }, + { + "role": "user", + "content": "Hello, Claude", + }, + ] + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi, I'm Claude." else: - events = capture_events() - - with start_transaction(name="anthropic"): - response = await client.messages.create( - max_tokens=1024, messages=messages, model="model" - ) - - assert response == EXAMPLE_MESSAGE - usage = response.usage - - assert usage.input_tokens == 10 - assert usage.output_tokens == 20 - - assert len(events) == 1 - (event,) = events - - assert event["type"] == "transaction" - assert event["transaction"] == "anthropic" - - assert len(event["spans"]) == 1 - (span,) = event["spans"] - - assert span["op"] == OP.GEN_AI_CHAT - assert span["description"] == "chat model" - assert span["data"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["data"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["data"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - - if send_default_pii and include_prompts: - assert ( - span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - == '[{"role": "user", "content": "Hello, Claude"}]' - ) - assert span["data"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi, I'm Claude." - else: - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["data"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["data"] - - assert span["data"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["data"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 20 - assert span["data"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 - assert span["data"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is False - assert ( - span["data"][SPANDATA.GEN_AI_RESPONSE_ID] == "msg_01XFDUDYJgAACzvnptvVoYEL" - ) + assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] + assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] + + assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 20 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is False + assert ( + span["attributes"][SPANDATA.GEN_AI_RESPONSE_ID] + == "msg_01XFDUDYJgAACzvnptvVoYEL" + ) -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize( - "send_default_pii, include_prompts", - [ - (True, True), - (True, False), - (False, True), - (False, False), - ], + "send_default_pii", + [True, False], ) def test_streaming_create_message( sentry_init, - capture_events, capture_items, send_default_pii, - include_prompts, get_model_response, server_side_event_chunks, - stream_gen_ai_spans, - span_streaming, ): client = Anthropic(api_key="z") @@ -1149,12 +770,10 @@ def test_streaming_create_message( ) sentry_init( - integrations=[AnthropicIntegration(include_prompts=include_prompts)], + integrations=[AnthropicIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) messages = [ @@ -1167,227 +786,101 @@ def test_streaming_create_message( "content": "Hello, Claude", }, ] + items = capture_items("span") - if span_streaming: - items = capture_items("transaction", "span") - - with mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, sentry_sdk.traces.start_span(name="anthropic"): - message = client.messages.create( - max_tokens=1024, messages=messages, model="model", stream=True - ) - - for _ in message: - pass - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert spans[1]["name"] == "anthropic" - span = next( - span for span in spans if span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT + with mock.patch.object( + client._client, + "send", + return_value=response, + ): + message = client.messages.create( + max_tokens=1024, messages=messages, model="model", stream=True ) - assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - assert span["name"] == "chat model" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - - if send_default_pii and include_prompts: - assert json.loads(span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) == [ - { - "role": "user", - "content": "Message demonstrating the absence of truncation.", - }, - { - "role": "user", - "content": "Hello, Claude", - }, - ] - assert ( - span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi! I'm Claude!" - ) + for _ in message: + pass - else: - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] + sentry_sdk.flush() + spans = [item.payload for item in items] + span = next( + span for span in spans if span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT + ) - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 10 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 20 - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True - assert ( - span["attributes"][SPANDATA.GEN_AI_RESPONSE_ID] - == "msg_01XFDUDYJgAACzvnptvVoYEL" - ) - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS] == [ - "max_tokens" + assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT + assert span["name"] == "chat model" + assert span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "anthropic" + assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" + + if send_default_pii: + assert json.loads(span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) == [ + { + "role": "user", + "content": "Message demonstrating the absence of truncation.", + }, + { + "role": "user", + "content": "Hello, Claude", + }, ] - elif stream_gen_ai_spans: - items = capture_items("transaction", "span") - - with mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, start_transaction(name="anthropic"): - message = client.messages.create( - max_tokens=1024, messages=messages, model="model", stream=True - ) - - for _ in message: - pass - - (event,) = (item.payload for item in items if item.type == "transaction") - assert event["transaction"] == "anthropic" - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - span = next( - span for span in spans if span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - ) - - assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - assert span["name"] == "chat model" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - - if send_default_pii and include_prompts: - assert json.loads(span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) == [ - { - "role": "user", - "content": "Message demonstrating the absence of truncation.", - }, - { - "role": "user", - "content": "Hello, Claude", - }, - ] - assert ( - span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi! I'm Claude!" - ) + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi! I'm Claude!" - else: - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] - - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 10 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 20 - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True - assert ( - span["attributes"][SPANDATA.GEN_AI_RESPONSE_ID] - == "msg_01XFDUDYJgAACzvnptvVoYEL" - ) - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS] == [ - "max_tokens" - ] else: - events = capture_events() - - with mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, start_transaction(name="anthropic"): - message = client.messages.create( - max_tokens=1024, messages=messages, model="model", stream=True - ) - - for _ in message: - pass - - assert len(events) == 1 - (event,) = events - - assert event["type"] == "transaction" - assert event["transaction"] == "anthropic" - - span = next(span for span in event["spans"] if span["op"] == OP.GEN_AI_CHAT) - - assert span["op"] == OP.GEN_AI_CHAT - assert span["description"] == "chat model" - assert span["data"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["data"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["data"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - - if send_default_pii and include_prompts: - assert ( - span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - == '[{"role": "user", "content": "Hello, Claude"}]' - ) - assert span["data"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi! I'm Claude!" - - else: - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["data"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["data"] - - assert span["data"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["data"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 10 - assert span["data"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 20 - assert span["data"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True - assert ( - span["data"][SPANDATA.GEN_AI_RESPONSE_ID] == "msg_01XFDUDYJgAACzvnptvVoYEL" - ) - assert span["data"][SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS] == ["max_tokens"] + assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] + assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] + + assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 10 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 20 + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True + assert ( + span["attributes"][SPANDATA.GEN_AI_RESPONSE_ID] + == "msg_01XFDUDYJgAACzvnptvVoYEL" + ) + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS] == ["max_tokens"] -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize( - "data_collection,send_default_pii,include_prompts,expected_present,expected_absent", + "data_collection,send_default_pii,expected_present,expected_absent", [ pytest.param( {"gen_ai": {"inputs": True}}, False, - False, DATA_COLLECTION_EXPECTED_INPUT_DATA, [], - id="gen-ai-inputs-enabled-overrides-pii-and-include-prompts", + id="gen-ai-inputs-enabled-overrides-pii", ), pytest.param( {"gen_ai": {"inputs": False}}, True, - True, {}, DATA_COLLECTION_INPUT_DATA_KEYS, - id="gen-ai-inputs-disabled-overrides-pii-and-include-prompts", + id="gen-ai-inputs-disabled-overrides-pii", ), pytest.param( None, True, - True, DATA_COLLECTION_EXPECTED_INPUT_DATA, [], - id="legacy-pii-and-include-prompts-enabled", + id="legacy-pii", ), ], ) def test_streaming_create_message_data_collection( sentry_init, - capture_events, capture_items, data_collection, send_default_pii, - include_prompts, expected_present, expected_absent, get_model_response, server_side_event_chunks, - stream_gen_ai_spans, - span_streaming, ): sentry_init_kwargs = dict( - integrations=[AnthropicIntegration(include_prompts=include_prompts)], + integrations=[AnthropicIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) if data_collection is not None: sentry_init_kwargs["data_collection"] = data_collection @@ -1429,40 +922,23 @@ def test_streaming_create_message_data_collection( messages=[{"role": "user", "content": "Hello, Claude"}], stream=True, ) - - if span_streaming or stream_gen_ai_spans: - items = capture_items("transaction", "span") - - with mock.patch.object( - client._client, - "send", - return_value=response, - ), start_transaction(name="anthropic"): - message = client.messages.create(**create_kwargs) - for _ in message: - pass - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - (span,) = [s for s in spans if s["attributes"]["sentry.op"] == OP.GEN_AI_CHAT] - span_data = span["attributes"] - else: - events = capture_events() - - with mock.patch.object( - client._client, - "send", - return_value=response, - ), start_transaction(name="anthropic"): - message = client.messages.create(**create_kwargs) - for _ in message: - pass - - (event,) = events - span = next(s for s in event["spans"] if s["op"] == OP.GEN_AI_CHAT) - span_data = span["data"] - - assert span_data[SPANDATA.GEN_AI_SYSTEM] == "anthropic" + items = capture_items("span") + + with mock.patch.object( + client._client, + "send", + return_value=response, + ): + message = client.messages.create(**create_kwargs) + for _ in message: + pass + + sentry_sdk.flush() + spans = [item.payload for item in items] + (span,) = [s for s in spans if s["attributes"]["sentry.op"] == OP.GEN_AI_CHAT] + span_data = span["attributes"] + + assert span_data[SPANDATA.GEN_AI_PROVIDER_NAME] == "anthropic" assert span_data[SPANDATA.GEN_AI_OPERATION_NAME] == "chat" assert span_data[SPANDATA.GEN_AI_REQUEST_MODEL] == "model" assert span_data[SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 1024 @@ -1475,29 +951,24 @@ def test_streaming_create_message_data_collection( assert key not in span_data -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize( - "data_collection,send_default_pii,include_prompts,outputs_collected", + "data_collection,send_default_pii,outputs_collected", [ pytest.param( {"gen_ai": {"outputs": True}}, False, - False, True, - id="gen-ai-outputs-enabled-overrides-pii-and-include-prompts", + id="gen-ai-outputs-enabled-overrides-pii", ), pytest.param( {"gen_ai": {"outputs": False}}, True, - True, False, - id="gen-ai-outputs-disabled-overrides-pii-and-include-prompts", + id="gen-ai-outputs-disabled-overrides-pii", ), pytest.param( {"gen_ai": {}}, False, - False, True, id="gen-ai-outputs-omitted-defaults-to-enabled", ), @@ -1505,13 +976,11 @@ def test_streaming_create_message_data_collection( None, True, True, - True, - id="legacy-pii-and-include-prompts-enabled", + id="legacy-pii", ), pytest.param( None, False, - True, False, id="legacy-pii-disabled", ), @@ -1519,24 +988,18 @@ def test_streaming_create_message_data_collection( ) def test_streaming_create_message_data_collection_outputs( sentry_init, - capture_events, capture_items, data_collection, send_default_pii, - include_prompts, outputs_collected, get_model_response, server_side_event_chunks, - stream_gen_ai_spans, - span_streaming, ): sentry_init_kwargs = dict( - integrations=[AnthropicIntegration(include_prompts=include_prompts)], + integrations=[AnthropicIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) if data_collection is not None: sentry_init_kwargs["data_collection"] = data_collection @@ -1582,38 +1045,21 @@ def test_streaming_create_message_data_collection_outputs( messages=[{"role": "user", "content": "Hello, Claude"}], stream=True, ) - - if span_streaming or stream_gen_ai_spans: - items = capture_items("transaction", "span") - - with mock.patch.object( - client._client, - "send", - return_value=response, - ), start_transaction(name="anthropic"): - message = client.messages.create(**create_kwargs) - for _ in message: - pass - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - (span,) = [s for s in spans if s["attributes"]["sentry.op"] == OP.GEN_AI_CHAT] - span_data = span["attributes"] - else: - events = capture_events() - - with mock.patch.object( - client._client, - "send", - return_value=response, - ), start_transaction(name="anthropic"): - message = client.messages.create(**create_kwargs) - for _ in message: - pass - - (event,) = events - span = next(s for s in event["spans"] if s["op"] == OP.GEN_AI_CHAT) - span_data = span["data"] + items = capture_items("span") + + with mock.patch.object( + client._client, + "send", + return_value=response, + ): + message = client.messages.create(**create_kwargs) + for _ in message: + pass + + sentry_sdk.flush() + spans = [item.payload for item in items] + (span,) = [s for s in spans if s["attributes"]["sentry.op"] == OP.GEN_AI_CHAT] + span_data = span["attributes"] # Output data that is not gated on data collection assert span_data[SPANDATA.GEN_AI_RESPONSE_MODEL] == "model" @@ -1628,16 +1074,11 @@ def test_streaming_create_message_data_collection_outputs( assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span_data -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_streaming_create_message_close( sentry_init, - capture_events, capture_items, get_model_response, server_side_event_chunks, - stream_gen_ai_spans, - span_streaming, ): client = Anthropic(api_key="z") @@ -1679,12 +1120,10 @@ def test_streaming_create_message_close( ) sentry_init( - integrations=[AnthropicIntegration(include_prompts=True)], + integrations=[AnthropicIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) messages = [ @@ -1693,159 +1132,61 @@ def test_streaming_create_message_close( "content": "Hello, Claude", } ] + items = capture_items("span") - if span_streaming: - items = capture_items("transaction", "span") - - with mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, sentry_sdk.traces.start_span(name="anthropic"): - messages = client.messages.create( - max_tokens=1024, messages=messages, model="model", stream=True - ) - - for _ in range(4): - next(messages) - - messages.close() - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert spans[1]["name"] == "anthropic" - span = next( - span for span in spans if span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - ) - - assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - assert span["name"] == "chat model" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - - assert ( - span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - == '[{"role": "user", "content": "Hello, Claude"}]' - ) - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi!" - - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 20 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True - assert ( - span["attributes"][SPANDATA.GEN_AI_RESPONSE_ID] - == "msg_01XFDUDYJgAACzvnptvVoYEL" + with mock.patch.object( + client._client, + "send", + return_value=response, + ): + messages = client.messages.create( + max_tokens=1024, messages=messages, model="model", stream=True ) - elif stream_gen_ai_spans: - items = capture_items("transaction", "span") - - with mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, start_transaction(name="anthropic"): - messages = client.messages.create( - max_tokens=1024, messages=messages, model="model", stream=True - ) - for _ in range(4): - next(messages) + for _ in range(4): + next(messages) - messages.close() + messages.close() - (event,) = (item.payload for item in items if item.type == "transaction") - assert event["transaction"] == "anthropic" + sentry_sdk.flush() + spans = [item.payload for item in items] + span = next( + span for span in spans if span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT + ) - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - span = next( - span for span in spans if span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - ) + assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT + assert span["name"] == "chat model" + assert span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "anthropic" + assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - assert span["name"] == "chat model" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" + assert ( + span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] + == '[{"role": "user", "content": "Hello, Claude"}]' + ) + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi!" + + assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 20 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True + assert ( + span["attributes"][SPANDATA.GEN_AI_RESPONSE_ID] + == "msg_01XFDUDYJgAACzvnptvVoYEL" + ) - assert ( - span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - == '[{"role": "user", "content": "Hello, Claude"}]' - ) - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi!" - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 20 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True - assert ( - span["attributes"][SPANDATA.GEN_AI_RESPONSE_ID] - == "msg_01XFDUDYJgAACzvnptvVoYEL" - ) - else: - events = capture_events() - - with mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, start_transaction(name="anthropic"): - messages = client.messages.create( - max_tokens=1024, messages=messages, model="model", stream=True - ) - - for _ in range(4): - next(messages) - - messages.close() - - assert len(events) == 1 - (event,) = events - - assert event["type"] == "transaction" - assert event["transaction"] == "anthropic" - - span = next(span for span in event["spans"] if span["op"] == OP.GEN_AI_CHAT) - - assert span["op"] == OP.GEN_AI_CHAT - assert span["description"] == "chat model" - assert span["data"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["data"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["data"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - - assert ( - span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - == '[{"role": "user", "content": "Hello, Claude"}]' - ) - assert span["data"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi!" - - assert span["data"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["data"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 20 - assert span["data"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 - assert span["data"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True - assert ( - span["data"][SPANDATA.GEN_AI_RESPONSE_ID] == "msg_01XFDUDYJgAACzvnptvVoYEL" - ) - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) -@pytest.mark.skipif( - ANTHROPIC_VERSION < (0, 41), - reason="Error classes moved in https://github.com/anthropics/anthropic-sdk-python/commit/4e0b15e22fe40e9aa513459564f641bf97c90954.", -) -def test_streaming_create_message_api_error( - sentry_init, - capture_events, - capture_items, - get_model_response, - server_side_event_chunks, - stream_gen_ai_spans, - span_streaming, -): - client = Anthropic(api_key="z") +@pytest.mark.skipif( + ANTHROPIC_VERSION < (0, 41), + reason="Error classes moved in https://github.com/anthropics/anthropic-sdk-python/commit/4e0b15e22fe40e9aa513459564f641bf97c90954.", +) +def test_streaming_create_message_api_error( + sentry_init, + capture_items, + get_model_response, + server_side_event_chunks, +): + client = Anthropic(api_key="z") response = get_model_response( server_side_event_chunks( @@ -1880,12 +1221,10 @@ def test_streaming_create_message_api_error( ) sentry_init( - integrations=[AnthropicIntegration(include_prompts=True)], + integrations=[AnthropicIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) messages = [ @@ -1894,167 +1233,60 @@ def test_streaming_create_message_api_error( "content": "Hello, Claude", } ] + items = capture_items("span") - if span_streaming: - items = capture_items("transaction", "span") - - with pytest.raises(APIStatusError), mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, sentry_sdk.traces.start_span(name="anthropic"): - message = client.messages.create( - max_tokens=1024, messages=messages, model="model", stream=True - ) - - for _ in message: - pass - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert spans[1]["name"] == "anthropic" - assert spans[1]["status"] == SpanStatus.ERROR - span = next( - span for span in spans if span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - ) - - assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - assert span["name"] == "chat model" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - - assert ( - span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - == '[{"role": "user", "content": "Hello, Claude"}]' - ) - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi!" - - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 20 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True - assert ( - span["attributes"][SPANDATA.GEN_AI_RESPONSE_ID] - == "msg_01XFDUDYJgAACzvnptvVoYEL" - ) - - assert span["status"] == "error" - elif stream_gen_ai_spans: - items = capture_items("transaction", "span") - - with pytest.raises(APIStatusError), mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, start_transaction(name="anthropic"): - message = client.messages.create( - max_tokens=1024, messages=messages, model="model", stream=True - ) - - for _ in message: - pass - (event,) = (item.payload for item in items if item.type == "transaction") - assert event["transaction"] == "anthropic" - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - span = next( - span for span in spans if span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - ) - - assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - assert span["name"] == "chat model" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - - assert ( - span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - == '[{"role": "user", "content": "Hello, Claude"}]' - ) - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi!" - - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 20 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True - assert ( - span["attributes"][SPANDATA.GEN_AI_RESPONSE_ID] - == "msg_01XFDUDYJgAACzvnptvVoYEL" + with pytest.raises(APIStatusError), mock.patch.object( + client._client, + "send", + return_value=response, + ): + message = client.messages.create( + max_tokens=1024, messages=messages, model="model", stream=True ) - assert span["status"] == "error" - assert event["contexts"]["trace"]["status"] == "internal_error" - else: - events = capture_events() - - with pytest.raises(APIStatusError), mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, start_transaction(name="anthropic"): - message = client.messages.create( - max_tokens=1024, messages=messages, model="model", stream=True - ) - - for _ in message: - pass - - assert len(events) == 1 - (event,) = events - - assert event["type"] == "transaction" - assert event["transaction"] == "anthropic" - - span = next(span for span in event["spans"] if span["op"] == OP.GEN_AI_CHAT) + for _ in message: + pass - assert span["op"] == OP.GEN_AI_CHAT - assert span["description"] == "chat model" - assert span["data"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["data"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["data"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" + sentry_sdk.flush() + spans = [item.payload for item in items] + span = next( + span for span in spans if span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT + ) - assert ( - span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - == '[{"role": "user", "content": "Hello, Claude"}]' - ) - assert span["data"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi!" + assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT + assert span["name"] == "chat model" + assert span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "anthropic" + assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - assert span["data"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["data"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 20 - assert span["data"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 - assert span["data"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True - assert ( - span["data"][SPANDATA.GEN_AI_RESPONSE_ID] == "msg_01XFDUDYJgAACzvnptvVoYEL" - ) + assert ( + span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] + == '[{"role": "user", "content": "Hello, Claude"}]' + ) + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi!" + + assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 20 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True + assert ( + span["attributes"][SPANDATA.GEN_AI_RESPONSE_ID] + == "msg_01XFDUDYJgAACzvnptvVoYEL" + ) - assert span["status"] == "internal_error" - assert span["tags"]["status"] == "internal_error" - assert event["contexts"]["trace"]["status"] == "internal_error" + assert span["status"] == "error" -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize( - "send_default_pii, include_prompts", - [ - (True, True), - (True, False), - (False, True), - (False, False), - ], + "send_default_pii", + [True, False], ) def test_stream_messages( sentry_init, - capture_events, capture_items, send_default_pii, - include_prompts, get_model_response, server_side_event_chunks, - stream_gen_ai_spans, - span_streaming, ): client = Anthropic(api_key="z") @@ -2096,12 +1328,10 @@ def test_stream_messages( ) sentry_init( - integrations=[AnthropicIntegration(include_prompts=include_prompts)], + integrations=[AnthropicIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) messages = [ @@ -2114,197 +1344,78 @@ def test_stream_messages( "content": "Hello, Claude", }, ] + items = capture_items("span") - if span_streaming: - items = capture_items("transaction", "span") - - with mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, sentry_sdk.traces.start_span(name="anthropic"), client.messages.stream( - max_tokens=1024, - messages=messages, - model="model", - ) as stream: - for event in stream: - pass - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert spans[1]["name"] == "anthropic" - span = next( - span for span in spans if span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - ) - - assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - assert span["name"] == "chat model" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - - if send_default_pii and include_prompts: - assert json.loads(span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) == [ - { - "role": "user", - "content": "Message demonstrating the absence of truncation.", - }, - { - "role": "user", - "content": "Hello, Claude", - }, - ] - assert ( - span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi! I'm Claude!" - ) - - else: - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] + with mock.patch.object( + client._client, + "send", + return_value=response, + ), client.messages.stream( + max_tokens=1024, + messages=messages, + model="model", + ) as stream: + for event in stream: + pass + + sentry_sdk.flush() + spans = [item.payload for item in items] + span = next( + span for span in spans if span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT + ) - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 10 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 20 - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True - assert ( - span["attributes"][SPANDATA.GEN_AI_RESPONSE_ID] - == "msg_01XFDUDYJgAACzvnptvVoYEL" - ) - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS] == [ - "max_tokens" + assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT + assert span["name"] == "chat model" + assert span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "anthropic" + assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" + + if send_default_pii: + assert json.loads(span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) == [ + { + "role": "user", + "content": "Message demonstrating the absence of truncation.", + }, + { + "role": "user", + "content": "Hello, Claude", + }, ] - elif stream_gen_ai_spans: - items = capture_items("transaction", "span") - - with mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, start_transaction(name="anthropic"), client.messages.stream( - max_tokens=1024, - messages=messages, - model="model", - ) as stream: - for event in stream: - pass - - (event,) = (item.payload for item in items if item.type == "transaction") - assert event["transaction"] == "anthropic" - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - span = next( - span for span in spans if span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - ) - - assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - assert span["name"] == "chat model" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - - if send_default_pii and include_prompts: - assert json.loads(span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) == [ - { - "role": "user", - "content": "Message demonstrating the absence of truncation.", - }, - { - "role": "user", - "content": "Hello, Claude", - }, - ] - assert ( - span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi! I'm Claude!" - ) + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi! I'm Claude!" - else: - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] - - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 10 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 20 - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True - assert ( - span["attributes"][SPANDATA.GEN_AI_RESPONSE_ID] - == "msg_01XFDUDYJgAACzvnptvVoYEL" - ) - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS] == [ - "max_tokens" - ] else: - events = capture_events() - - with mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, start_transaction(name="anthropic"), client.messages.stream( - max_tokens=1024, - messages=messages, - model="model", - ) as stream: - for event in stream: - pass - - assert len(events) == 1 - (event,) = events - - assert event["type"] == "transaction" - assert event["transaction"] == "anthropic" - - span = next(span for span in event["spans"] if span["op"] == OP.GEN_AI_CHAT) - - assert span["op"] == OP.GEN_AI_CHAT - assert span["description"] == "chat model" - assert span["data"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["data"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["data"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - - if send_default_pii and include_prompts: - assert ( - span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - == '[{"role": "user", "content": "Hello, Claude"}]' - ) - assert span["data"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi! I'm Claude!" - else: - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["data"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["data"] - - assert span["data"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["data"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 10 - assert span["data"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 20 - assert span["data"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True - assert ( - span["data"][SPANDATA.GEN_AI_RESPONSE_ID] == "msg_01XFDUDYJgAACzvnptvVoYEL" - ) - assert span["data"][SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS] == ["max_tokens"] + assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] + assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] + + assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 10 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 20 + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True + assert ( + span["attributes"][SPANDATA.GEN_AI_RESPONSE_ID] + == "msg_01XFDUDYJgAACzvnptvVoYEL" + ) + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS] == ["max_tokens"] -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize( - "data_collection,send_default_pii,include_prompts,outputs_collected", + "data_collection,send_default_pii,outputs_collected", [ pytest.param( {"gen_ai": {"outputs": True}}, False, - False, True, - id="gen-ai-outputs-enabled-overrides-pii-and-include-prompts", + id="gen-ai-outputs-enabled-overrides-pii", ), pytest.param( {"gen_ai": {"outputs": False}}, True, - True, False, - id="gen-ai-outputs-disabled-overrides-pii-and-include-prompts", + id="gen-ai-outputs-disabled-overrides-pii", ), pytest.param( {"gen_ai": {}}, False, - False, True, id="gen-ai-outputs-omitted-defaults-to-enabled", ), @@ -2312,13 +1423,11 @@ def test_stream_messages( None, True, True, - True, - id="legacy-pii-and-include-prompts-enabled", + id="legacy-pii", ), pytest.param( None, False, - True, False, id="legacy-pii-disabled", ), @@ -2326,24 +1435,18 @@ def test_stream_messages( ) def test_stream_messages_data_collection_outputs( sentry_init, - capture_events, capture_items, data_collection, send_default_pii, - include_prompts, outputs_collected, get_model_response, server_side_event_chunks, - stream_gen_ai_spans, - span_streaming, ): sentry_init_kwargs = dict( - integrations=[AnthropicIntegration(include_prompts=include_prompts)], + integrations=[AnthropicIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) if data_collection is not None: sentry_init_kwargs["data_collection"] = data_collection @@ -2388,40 +1491,20 @@ def test_stream_messages_data_collection_outputs( model="model", messages=[{"role": "user", "content": "Hello, Claude"}], ) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("transaction", "span") + with mock.patch.object( + client._client, + "send", + return_value=response, + ), client.messages.stream(**stream_kwargs) as stream: + for _ in stream: + pass - with mock.patch.object( - client._client, - "send", - return_value=response, - ), start_transaction(name="anthropic"), client.messages.stream( - **stream_kwargs - ) as stream: - for _ in stream: - pass - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - (span,) = [s for s in spans if s["attributes"]["sentry.op"] == OP.GEN_AI_CHAT] - span_data = span["attributes"] - else: - events = capture_events() - - with mock.patch.object( - client._client, - "send", - return_value=response, - ), start_transaction(name="anthropic"), client.messages.stream( - **stream_kwargs - ) as stream: - for _ in stream: - pass - - (event,) = events - span = next(s for s in event["spans"] if s["op"] == OP.GEN_AI_CHAT) - span_data = span["data"] + sentry_sdk.flush() + spans = [item.payload for item in items] + (span,) = [s for s in spans if s["attributes"]["sentry.op"] == OP.GEN_AI_CHAT] + span_data = span["attributes"] # Output data that is not gated on data collection assert span_data[SPANDATA.GEN_AI_RESPONSE_MODEL] == "model" @@ -2436,16 +1519,11 @@ def test_stream_messages_data_collection_outputs( assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span_data -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_stream_messages_close( sentry_init, - capture_events, capture_items, get_model_response, server_side_event_chunks, - stream_gen_ai_spans, - span_streaming, ): client = Anthropic(api_key="z") @@ -2487,12 +1565,10 @@ def test_stream_messages_close( ) sentry_init( - integrations=[AnthropicIntegration(include_prompts=True)], + integrations=[AnthropicIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) messages = [ @@ -2501,169 +1577,63 @@ def test_stream_messages_close( "content": "Hello, Claude", } ] + items = capture_items("span") - if span_streaming: - items = capture_items("transaction", "span") - - with mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, sentry_sdk.traces.start_span(name="anthropic"), client.messages.stream( - max_tokens=1024, - messages=messages, - model="model", - ) as stream: - for _ in range(4): - next(stream) - - # New versions add TextEvent, so consume one more event. - if TextEvent is not None and isinstance(next(stream), TextEvent): - next(stream) - - stream.close() - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert spans[1]["name"] == "anthropic" - span = next( - span for span in spans if span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - ) - - assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - assert span["name"] == "chat model" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - - assert ( - span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - == '[{"role": "user", "content": "Hello, Claude"}]' - ) - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi!" - - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 20 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True - assert ( - span["attributes"][SPANDATA.GEN_AI_RESPONSE_ID] - == "msg_01XFDUDYJgAACzvnptvVoYEL" - ) - elif stream_gen_ai_spans: - items = capture_items("transaction", "span") - - with mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, start_transaction(name="anthropic"), client.messages.stream( - max_tokens=1024, - messages=messages, - model="model", - ) as stream: - for _ in range(4): - next(stream) - - # New versions add TextEvent, so consume one more event. - if TextEvent is not None and isinstance(next(stream), TextEvent): - next(stream) - - stream.close() - - (event,) = (item.payload for item in items if item.type == "transaction") - assert event["transaction"] == "anthropic" - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - span = next( - span for span in spans if span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - ) - - assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - assert span["name"] == "chat model" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - - assert ( - span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - == '[{"role": "user", "content": "Hello, Claude"}]' - ) - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi!" - - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 20 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True - assert ( - span["attributes"][SPANDATA.GEN_AI_RESPONSE_ID] - == "msg_01XFDUDYJgAACzvnptvVoYEL" - ) - else: - events = capture_events() - - with mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, start_transaction(name="anthropic"), client.messages.stream( - max_tokens=1024, - messages=messages, - model="model", - ) as stream: - for _ in range(4): - next(stream) - - # New versions add TextEvent, so consume one more event. - if TextEvent is not None and isinstance(next(stream), TextEvent): - next(stream) - - stream.close() - - assert len(events) == 1 - (event,) = events + with mock.patch.object( + client._client, + "send", + return_value=response, + ), client.messages.stream( + max_tokens=1024, + messages=messages, + model="model", + ) as stream: + for _ in range(4): + next(stream) - assert event["type"] == "transaction" - assert event["transaction"] == "anthropic" + # New versions add TextEvent, so consume one more event. + if TextEvent is not None and isinstance(next(stream), TextEvent): + next(stream) - span = next(span for span in event["spans"] if span["op"] == OP.GEN_AI_CHAT) + stream.close() - assert span["op"] == OP.GEN_AI_CHAT - assert span["description"] == "chat model" - assert span["data"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["data"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["data"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" + sentry_sdk.flush() + spans = [item.payload for item in items] + span = next( + span for span in spans if span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT + ) - assert ( - span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - == '[{"role": "user", "content": "Hello, Claude"}]' - ) - assert span["data"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi!" + assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT + assert span["name"] == "chat model" + assert span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "anthropic" + assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - assert span["data"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["data"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 20 - assert span["data"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 - assert span["data"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True - assert ( - span["data"][SPANDATA.GEN_AI_RESPONSE_ID] == "msg_01XFDUDYJgAACzvnptvVoYEL" - ) + assert ( + span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] + == '[{"role": "user", "content": "Hello, Claude"}]' + ) + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi!" + + assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 20 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True + assert ( + span["attributes"][SPANDATA.GEN_AI_RESPONSE_ID] + == "msg_01XFDUDYJgAACzvnptvVoYEL" + ) -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.skipif( ANTHROPIC_VERSION < (0, 41), reason="Error classes moved in https://github.com/anthropics/anthropic-sdk-python/commit/4e0b15e22fe40e9aa513459564f641bf97c90954.", ) def test_stream_messages_api_error( sentry_init, - capture_events, capture_items, get_model_response, server_side_event_chunks, - stream_gen_ai_spans, - span_streaming, ): client = Anthropic(api_key="z") @@ -2700,12 +1670,10 @@ def test_stream_messages_api_error( ) sentry_init( - integrations=[AnthropicIntegration(include_prompts=True)], + integrations=[AnthropicIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) messages = [ @@ -2714,172 +1682,64 @@ def test_stream_messages_api_error( "content": "Hello, Claude", } ] + items = capture_items("span") - if span_streaming: - items = capture_items("transaction", "span") - - with pytest.raises(APIStatusError), mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, sentry_sdk.traces.start_span(name="anthropic"), client.messages.stream( - max_tokens=1024, - messages=messages, - model="model", - ) as stream: - for event in stream: - pass - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert spans[1]["name"] == "anthropic" - assert spans[1]["status"] == SpanStatus.ERROR - span = next( - span for span in spans if span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - ) - - assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - assert span["name"] == "chat model" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - - assert ( - span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - == '[{"role": "user", "content": "Hello, Claude"}]' - ) - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi!" - - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 20 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True - assert ( - span["attributes"][SPANDATA.GEN_AI_RESPONSE_ID] - == "msg_01XFDUDYJgAACzvnptvVoYEL" - ) - - assert span["status"] == "error" - elif stream_gen_ai_spans: - items = capture_items("transaction", "span") - - with pytest.raises(APIStatusError), mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, start_transaction(name="anthropic"), client.messages.stream( - max_tokens=1024, - messages=messages, - model="model", - ) as stream: - for event in stream: - pass - - (event,) = (item.payload for item in items if item.type == "transaction") - assert event["transaction"] == "anthropic" + with pytest.raises(APIStatusError), mock.patch.object( + client._client, + "send", + return_value=response, + ), client.messages.stream( + max_tokens=1024, + messages=messages, + model="model", + ) as stream: + for event in stream: + pass + + sentry_sdk.flush() + spans = [item.payload for item in items] + span = next( + span for span in spans if span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT + ) - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - span = next( - span for span in spans if span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - ) + assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT + assert span["name"] == "chat model" + assert span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "anthropic" + assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - assert span["name"] == "chat model" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" + assert ( + span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] + == '[{"role": "user", "content": "Hello, Claude"}]' + ) + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi!" + + assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 20 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True + assert ( + span["attributes"][SPANDATA.GEN_AI_RESPONSE_ID] + == "msg_01XFDUDYJgAACzvnptvVoYEL" + ) - assert ( - span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - == '[{"role": "user", "content": "Hello, Claude"}]' - ) - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi!" + assert span["status"] == "error" - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 20 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True - assert ( - span["attributes"][SPANDATA.GEN_AI_RESPONSE_ID] - == "msg_01XFDUDYJgAACzvnptvVoYEL" - ) - assert span["status"] == "error" - assert event["contexts"]["trace"]["status"] == "internal_error" - else: - events = capture_events() - - with pytest.raises(APIStatusError), mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, start_transaction(name="anthropic"), client.messages.stream( - max_tokens=1024, - messages=messages, - model="model", - ) as stream: - for event in stream: - pass - - assert len(events) == 1 - (event,) = events - - assert event["type"] == "transaction" - assert event["transaction"] == "anthropic" - - span = next(span for span in event["spans"] if span["op"] == OP.GEN_AI_CHAT) - - assert span["op"] == OP.GEN_AI_CHAT - assert span["description"] == "chat model" - assert span["data"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["data"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["data"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - - assert ( - span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - == '[{"role": "user", "content": "Hello, Claude"}]' - ) - assert span["data"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi!" - - assert span["data"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["data"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 20 - assert span["data"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 - assert span["data"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True - assert ( - span["data"][SPANDATA.GEN_AI_RESPONSE_ID] == "msg_01XFDUDYJgAACzvnptvVoYEL" - ) - - assert span["status"] == "internal_error" - assert span["tags"]["status"] == "internal_error" - assert event["contexts"]["trace"]["status"] == "internal_error" - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) -@pytest.mark.asyncio -@pytest.mark.parametrize( - "send_default_pii, include_prompts", - [ - (True, True), - (True, False), - (False, True), - (False, False), - ], -) -async def test_streaming_create_message_async( - sentry_init, - capture_events, - capture_items, - send_default_pii, - include_prompts, - get_model_response, - async_iterator, - server_side_event_chunks, - stream_gen_ai_spans, - span_streaming, -): - client = AsyncAnthropic(api_key="z") +@pytest.mark.asyncio +@pytest.mark.parametrize( + "send_default_pii", + [True, False], +) +async def test_streaming_create_message_async( + sentry_init, + capture_items, + send_default_pii, + get_model_response, + async_iterator, + server_side_event_chunks, +): + client = AsyncAnthropic(api_key="z") response = get_model_response( async_iterator( @@ -2921,13 +1781,11 @@ async def test_streaming_create_message_async( ) sentry_init( - integrations=[AnthropicIntegration(include_prompts=include_prompts)], + integrations=[AnthropicIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, default_integrations=False, send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) messages = [ @@ -2940,199 +1798,79 @@ async def test_streaming_create_message_async( "content": "Hello, Claude", }, ] + items = capture_items("span") - if span_streaming: - items = capture_items("transaction", "span") - - with mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, sentry_sdk.traces.start_span(name="anthropic"): - message = await client.messages.create( - max_tokens=1024, messages=messages, model="model", stream=True - ) - - async for _ in message: - pass - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert len(spans) == 2 - - assert spans[1]["name"] == "anthropic" - (span, _) = spans - - assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - assert span["name"] == "chat model" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - - if send_default_pii and include_prompts: - assert json.loads(span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) == [ - { - "role": "user", - "content": "Message demonstrating the absence of truncation.", - }, - { - "role": "user", - "content": "Hello, Claude", - }, - ] - assert ( - span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi! I'm Claude!" - ) - - else: - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] - - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 10 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 20 - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True - assert ( - span["attributes"][SPANDATA.GEN_AI_RESPONSE_ID] - == "msg_01XFDUDYJgAACzvnptvVoYEL" + with mock.patch.object( + client._client, + "send", + return_value=response, + ): + message = await client.messages.create( + max_tokens=1024, messages=messages, model="model", stream=True ) - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS] == [ - "max_tokens" - ] - elif stream_gen_ai_spans: - items = capture_items("transaction", "span") - - with mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, start_transaction(name="anthropic"): - message = await client.messages.create( - max_tokens=1024, messages=messages, model="model", stream=True - ) - async for _ in message: - pass - - (event,) = (item.payload for item in items if item.type == "transaction") - assert event["transaction"] == "anthropic" + async for _ in message: + pass - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert len(spans) == 1 - (span,) = spans + sentry_sdk.flush() + spans = [item.payload for item in items] + assert len(spans) == 1 - assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - assert span["name"] == "chat model" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - - if send_default_pii and include_prompts: - assert json.loads(span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) == [ - { - "role": "user", - "content": "Message demonstrating the absence of truncation.", - }, - { - "role": "user", - "content": "Hello, Claude", - }, - ] - assert ( - span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi! I'm Claude!" - ) + (span,) = spans - else: - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] + assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT + assert span["name"] == "chat model" + assert span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "anthropic" + assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 10 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 20 - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True - assert ( - span["attributes"][SPANDATA.GEN_AI_RESPONSE_ID] - == "msg_01XFDUDYJgAACzvnptvVoYEL" - ) - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS] == [ - "max_tokens" + if send_default_pii: + assert json.loads(span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) == [ + { + "role": "user", + "content": "Message demonstrating the absence of truncation.", + }, + { + "role": "user", + "content": "Hello, Claude", + }, ] - else: - events = capture_events() - - with mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, start_transaction(name="anthropic"): - message = await client.messages.create( - max_tokens=1024, messages=messages, model="model", stream=True - ) - - async for _ in message: - pass - - assert len(events) == 1 - (event,) = events - - assert event["type"] == "transaction" - assert event["transaction"] == "anthropic" - - assert len(event["spans"]) == 1 - (span,) = event["spans"] - - assert span["op"] == OP.GEN_AI_CHAT - assert span["description"] == "chat model" - assert span["data"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["data"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["data"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - - if send_default_pii and include_prompts: - assert ( - span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - == '[{"role": "user", "content": "Hello, Claude"}]' - ) - assert span["data"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi! I'm Claude!" - - else: - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["data"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["data"] + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi! I'm Claude!" - assert span["data"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["data"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 10 - assert span["data"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 20 - assert span["data"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True - assert ( - span["data"][SPANDATA.GEN_AI_RESPONSE_ID] == "msg_01XFDUDYJgAACzvnptvVoYEL" - ) - assert span["data"][SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS] == ["max_tokens"] + else: + assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] + assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] + + assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 10 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 20 + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True + assert ( + span["attributes"][SPANDATA.GEN_AI_RESPONSE_ID] + == "msg_01XFDUDYJgAACzvnptvVoYEL" + ) + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS] == ["max_tokens"] -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio @pytest.mark.parametrize( - "data_collection,send_default_pii,include_prompts,outputs_collected", + "data_collection,send_default_pii,outputs_collected", [ pytest.param( {"gen_ai": {"outputs": True}}, False, - False, True, - id="gen-ai-outputs-enabled-overrides-pii-and-include-prompts", + id="gen-ai-outputs-enabled-overrides-pii", ), pytest.param( {"gen_ai": {"outputs": False}}, True, - True, False, - id="gen-ai-outputs-disabled-overrides-pii-and-include-prompts", + id="gen-ai-outputs-disabled-overrides-pii", ), pytest.param( {"gen_ai": {}}, False, - False, True, id="gen-ai-outputs-omitted-defaults-to-enabled", ), @@ -3140,13 +1878,11 @@ async def test_streaming_create_message_async( None, True, True, - True, - id="legacy-pii-and-include-prompts-enabled", + id="legacy-pii", ), pytest.param( None, False, - True, False, id="legacy-pii-disabled", ), @@ -3154,25 +1890,19 @@ async def test_streaming_create_message_async( ) async def test_streaming_create_message_data_collection_outputs_async( sentry_init, - capture_events, capture_items, data_collection, send_default_pii, - include_prompts, outputs_collected, get_model_response, async_iterator, server_side_event_chunks, - stream_gen_ai_spans, - span_streaming, ): sentry_init_kwargs = dict( - integrations=[AnthropicIntegration(include_prompts=include_prompts)], + integrations=[AnthropicIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) if data_collection is not None: sentry_init_kwargs["data_collection"] = data_collection @@ -3220,38 +1950,21 @@ async def test_streaming_create_message_data_collection_outputs_async( messages=[{"role": "user", "content": "Hello, Claude"}], stream=True, ) - - if span_streaming or stream_gen_ai_spans: - items = capture_items("transaction", "span") - - with mock.patch.object( - client._client, - "send", - return_value=response, - ), start_transaction(name="anthropic"): - message = await client.messages.create(**create_kwargs) - async for _ in message: - pass - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - (span,) = [s for s in spans if s["attributes"]["sentry.op"] == OP.GEN_AI_CHAT] - span_data = span["attributes"] - else: - events = capture_events() - - with mock.patch.object( - client._client, - "send", - return_value=response, - ), start_transaction(name="anthropic"): - message = await client.messages.create(**create_kwargs) - async for _ in message: - pass - - (event,) = events - span = next(s for s in event["spans"] if s["op"] == OP.GEN_AI_CHAT) - span_data = span["data"] + items = capture_items("span") + + with mock.patch.object( + client._client, + "send", + return_value=response, + ): + message = await client.messages.create(**create_kwargs) + async for _ in message: + pass + + sentry_sdk.flush() + spans = [item.payload for item in items] + (span,) = [s for s in spans if s["attributes"]["sentry.op"] == OP.GEN_AI_CHAT] + span_data = span["attributes"] # Output data that is not gated on data collection assert span_data[SPANDATA.GEN_AI_RESPONSE_MODEL] == "model" @@ -3266,18 +1979,13 @@ async def test_streaming_create_message_data_collection_outputs_async( assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span_data -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio async def test_streaming_create_message_async_close( sentry_init, - capture_events, capture_items, get_model_response, async_iterator, server_side_event_chunks, - stream_gen_ai_spans, - span_streaming, ): client = AsyncAnthropic(api_key="z") @@ -3321,12 +2029,10 @@ async def test_streaming_create_message_async_close( ) sentry_init( - integrations=[AnthropicIntegration(include_prompts=True)], + integrations=[AnthropicIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) messages = [ @@ -3335,142 +2041,49 @@ async def test_streaming_create_message_async_close( "content": "Hello, Claude", } ] + items = capture_items("span") - if span_streaming: - items = capture_items("transaction", "span") - - with mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, sentry_sdk.traces.start_span(name="anthropic"): - messages = await client.messages.create( - max_tokens=1024, messages=messages, model="model", stream=True - ) - - for _ in range(4): - await messages.__anext__() - await messages.close() - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert spans[1]["name"] == "anthropic" - span = next( - span for span in spans if span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - ) - - assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - assert span["name"] == "chat model" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - - assert ( - span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - == '[{"role": "user", "content": "Hello, Claude"}]' - ) - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi!" - - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 20 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True - assert ( - span["attributes"][SPANDATA.GEN_AI_RESPONSE_ID] - == "msg_01XFDUDYJgAACzvnptvVoYEL" - ) - elif stream_gen_ai_spans: - items = capture_items("transaction", "span") - - with mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, start_transaction(name="anthropic"): - messages = await client.messages.create( - max_tokens=1024, messages=messages, model="model", stream=True - ) - - for _ in range(4): - await messages.__anext__() - await messages.close() - - (event,) = (item.payload for item in items if item.type == "transaction") - assert event["transaction"] == "anthropic" - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - span = next( - span for span in spans if span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - ) - - assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - assert span["name"] == "chat model" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - - assert ( - span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - == '[{"role": "user", "content": "Hello, Claude"}]' - ) - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi!" - - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 20 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True - assert ( - span["attributes"][SPANDATA.GEN_AI_RESPONSE_ID] - == "msg_01XFDUDYJgAACzvnptvVoYEL" + with mock.patch.object( + client._client, + "send", + return_value=response, + ): + messages = await client.messages.create( + max_tokens=1024, messages=messages, model="model", stream=True ) - else: - events = capture_events() - - with mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, start_transaction(name="anthropic"): - messages = await client.messages.create( - max_tokens=1024, messages=messages, model="model", stream=True - ) - - for _ in range(4): - await messages.__anext__() - await messages.close() - - assert len(events) == 1 - (event,) = events - assert event["type"] == "transaction" - assert event["transaction"] == "anthropic" + for _ in range(4): + await messages.__anext__() + await messages.close() - span = next(span for span in event["spans"] if span["op"] == OP.GEN_AI_CHAT) - - assert span["op"] == OP.GEN_AI_CHAT - assert span["description"] == "chat model" - assert span["data"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["data"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["data"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" + sentry_sdk.flush() + spans = [item.payload for item in items] + span = next( + span for span in spans if span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT + ) - assert ( - span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - == '[{"role": "user", "content": "Hello, Claude"}]' - ) - assert span["data"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi!" + assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT + assert span["name"] == "chat model" + assert span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "anthropic" + assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - assert span["data"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["data"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 20 - assert span["data"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 - assert span["data"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True - assert ( - span["data"][SPANDATA.GEN_AI_RESPONSE_ID] == "msg_01XFDUDYJgAACzvnptvVoYEL" - ) + assert ( + span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] + == '[{"role": "user", "content": "Hello, Claude"}]' + ) + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi!" + + assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 20 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True + assert ( + span["attributes"][SPANDATA.GEN_AI_RESPONSE_ID] + == "msg_01XFDUDYJgAACzvnptvVoYEL" + ) -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.skipif( ANTHROPIC_VERSION < (0, 41), reason="Error classes moved in https://github.com/anthropics/anthropic-sdk-python/commit/4e0b15e22fe40e9aa513459564f641bf97c90954.", @@ -3478,13 +2091,10 @@ async def test_streaming_create_message_async_close( @pytest.mark.asyncio async def test_streaming_create_message_async_api_error( sentry_init, - capture_events, capture_items, get_model_response, async_iterator, server_side_event_chunks, - stream_gen_ai_spans, - span_streaming, ): client = AsyncAnthropic(api_key="z") @@ -3523,12 +2133,10 @@ async def test_streaming_create_message_async_api_error( ) sentry_init( - integrations=[AnthropicIntegration(include_prompts=True)], + integrations=[AnthropicIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) messages = [ @@ -3537,170 +2145,62 @@ async def test_streaming_create_message_async_api_error( "content": "Hello, Claude", } ] + items = capture_items("span") - if span_streaming: - items = capture_items("transaction", "span") - - with pytest.raises(APIStatusError), mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, sentry_sdk.traces.start_span(name="anthropic"): - message = await client.messages.create( - max_tokens=1024, messages=messages, model="model", stream=True - ) - - async for _ in message: - pass - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert spans[1]["name"] == "anthropic" - assert spans[1]["status"] == SpanStatus.ERROR - span = next( - span for span in spans if span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - ) - - assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - assert span["name"] == "chat model" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - - assert ( - span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - == '[{"role": "user", "content": "Hello, Claude"}]' - ) - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi!" - - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 20 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True - assert ( - span["attributes"][SPANDATA.GEN_AI_RESPONSE_ID] - == "msg_01XFDUDYJgAACzvnptvVoYEL" - ) - - assert span["status"] == "error" - elif stream_gen_ai_spans: - items = capture_items("transaction", "span") - - with pytest.raises(APIStatusError), mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, start_transaction(name="anthropic"): - message = await client.messages.create( - max_tokens=1024, messages=messages, model="model", stream=True - ) - - async for _ in message: - pass - - (event,) = (item.payload for item in items if item.type == "transaction") - assert event["transaction"] == "anthropic" - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - span = next( - span for span in spans if span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - ) - - assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - assert span["name"] == "chat model" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - - assert ( - span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - == '[{"role": "user", "content": "Hello, Claude"}]' - ) - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi!" - - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 20 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True - assert ( - span["attributes"][SPANDATA.GEN_AI_RESPONSE_ID] - == "msg_01XFDUDYJgAACzvnptvVoYEL" + with pytest.raises(APIStatusError), mock.patch.object( + client._client, + "send", + return_value=response, + ): + message = await client.messages.create( + max_tokens=1024, messages=messages, model="model", stream=True ) - assert span["status"] == "error" - assert event["contexts"]["trace"]["status"] == "internal_error" - else: - events = capture_events() - - with pytest.raises(APIStatusError), mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, start_transaction(name="anthropic"): - message = await client.messages.create( - max_tokens=1024, messages=messages, model="model", stream=True - ) - - async for _ in message: - pass - - assert len(events) == 1 - (event,) = events + async for _ in message: + pass - assert event["type"] == "transaction" - assert event["transaction"] == "anthropic" - - span = next(span for span in event["spans"] if span["op"] == OP.GEN_AI_CHAT) - - assert span["op"] == OP.GEN_AI_CHAT - assert span["description"] == "chat model" - assert span["data"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["data"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["data"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" + sentry_sdk.flush() + spans = [item.payload for item in items] + span = next( + span for span in spans if span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT + ) - assert ( - span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - == '[{"role": "user", "content": "Hello, Claude"}]' - ) - assert span["data"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi!" + assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT + assert span["name"] == "chat model" + assert span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "anthropic" + assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - assert span["data"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["data"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 20 - assert span["data"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 - assert span["data"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True - assert ( - span["data"][SPANDATA.GEN_AI_RESPONSE_ID] == "msg_01XFDUDYJgAACzvnptvVoYEL" - ) + assert ( + span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] + == '[{"role": "user", "content": "Hello, Claude"}]' + ) + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi!" + + assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 20 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True + assert ( + span["attributes"][SPANDATA.GEN_AI_RESPONSE_ID] + == "msg_01XFDUDYJgAACzvnptvVoYEL" + ) - assert span["status"] == "internal_error" - assert span["tags"]["status"] == "internal_error" - assert event["contexts"]["trace"]["status"] == "internal_error" + assert span["status"] == "error" -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio @pytest.mark.parametrize( - "send_default_pii, include_prompts", - [ - (True, True), - (True, False), - (False, True), - (False, False), - ], + "send_default_pii", + [True, False], ) async def test_stream_message_async( sentry_init, - capture_events, capture_items, send_default_pii, - include_prompts, get_model_response, async_iterator, server_side_event_chunks, - stream_gen_ai_spans, - span_streaming, ): client = AsyncAnthropic(api_key="z") @@ -3744,12 +2244,10 @@ async def test_stream_message_async( ) sentry_init( - integrations=[AnthropicIntegration(include_prompts=include_prompts)], + integrations=[AnthropicIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) messages = [ @@ -3762,194 +2260,79 @@ async def test_stream_message_async( "content": "Hello, Claude", }, ] + items = capture_items("span") + + with mock.patch.object( + client._client, + "send", + return_value=response, + ): + async with client.messages.stream( + max_tokens=1024, + messages=messages, + model="model", + ) as stream: + async for event in stream: + pass - if span_streaming: - items = capture_items("transaction", "span") - - with mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, sentry_sdk.traces.start_span(name="anthropic"): - async with client.messages.stream( - max_tokens=1024, - messages=messages, - model="model", - ) as stream: - async for event in stream: - pass - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert len(spans) == 2 - - assert spans[1]["name"] == "anthropic" - (span, _) = spans - - assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - assert span["name"] == "chat model" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - - if send_default_pii and include_prompts: - assert json.loads(span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) == [ - { - "role": "user", - "content": "Message demonstrating the absence of truncation.", - }, - { - "role": "user", - "content": "Hello, Claude", - }, - ] - assert ( - span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi! I'm Claude!" - ) + sentry_sdk.flush() + spans = [item.payload for item in items] + assert len(spans) == 1 - else: - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] + (span,) = spans - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 10 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 20 - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True - assert ( - span["attributes"][SPANDATA.GEN_AI_RESPONSE_ID] - == "msg_01XFDUDYJgAACzvnptvVoYEL" - ) - elif stream_gen_ai_spans: - items = capture_items("transaction", "span") - - with mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, start_transaction(name="anthropic"): - async with client.messages.stream( - max_tokens=1024, - messages=messages, - model="model", - ) as stream: - async for event in stream: - pass - - (event,) = (item.payload for item in items if item.type == "transaction") - assert event["transaction"] == "anthropic" - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert len(spans) == 1 - (span,) = spans - - assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - assert span["name"] == "chat model" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - - if send_default_pii and include_prompts: - assert json.loads(span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) == [ - { - "role": "user", - "content": "Message demonstrating the absence of truncation.", - }, - { - "role": "user", - "content": "Hello, Claude", - }, - ] - assert ( - span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi! I'm Claude!" - ) + assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT + assert span["name"] == "chat model" + assert span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "anthropic" + assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - else: - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] + if send_default_pii: + assert json.loads(span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) == [ + { + "role": "user", + "content": "Message demonstrating the absence of truncation.", + }, + { + "role": "user", + "content": "Hello, Claude", + }, + ] + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi! I'm Claude!" - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 10 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 20 - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True - assert ( - span["attributes"][SPANDATA.GEN_AI_RESPONSE_ID] - == "msg_01XFDUDYJgAACzvnptvVoYEL" - ) else: - events = capture_events() - - with mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, start_transaction(name="anthropic"): - async with client.messages.stream( - max_tokens=1024, - messages=messages, - model="model", - ) as stream: - async for event in stream: - pass - assert len(events) == 1 - (event,) = events - - assert event["type"] == "transaction" - assert event["transaction"] == "anthropic" - - assert len(event["spans"]) == 1 - (span,) = event["spans"] - - assert span["op"] == OP.GEN_AI_CHAT - assert span["description"] == "chat model" - assert span["data"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["data"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["data"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - - if send_default_pii and include_prompts: - assert ( - span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - == '[{"role": "user", "content": "Hello, Claude"}]' - ) - assert span["data"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi! I'm Claude!" - - else: - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["data"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["data"] - - assert span["data"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["data"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 10 - assert span["data"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 20 - assert span["data"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True - assert ( - span["data"][SPANDATA.GEN_AI_RESPONSE_ID] == "msg_01XFDUDYJgAACzvnptvVoYEL" - ) + assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] + assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] + + assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 10 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 20 + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True + assert ( + span["attributes"][SPANDATA.GEN_AI_RESPONSE_ID] + == "msg_01XFDUDYJgAACzvnptvVoYEL" + ) -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio @pytest.mark.parametrize( - "data_collection,send_default_pii,include_prompts,outputs_collected", + "data_collection,send_default_pii,outputs_collected", [ pytest.param( {"gen_ai": {"outputs": True}}, False, - False, True, - id="gen-ai-outputs-enabled-overrides-pii-and-include-prompts", + id="gen-ai-outputs-enabled-overrides-pii", ), pytest.param( {"gen_ai": {"outputs": False}}, True, - True, False, - id="gen-ai-outputs-disabled-overrides-pii-and-include-prompts", + id="gen-ai-outputs-disabled-overrides-pii", ), pytest.param( {"gen_ai": {}}, False, - False, True, id="gen-ai-outputs-omitted-defaults-to-enabled", ), @@ -3957,13 +2340,11 @@ async def test_stream_message_async( None, True, True, - True, - id="legacy-pii-and-include-prompts-enabled", + id="legacy-pii", ), pytest.param( None, False, - True, False, id="legacy-pii-disabled", ), @@ -3971,25 +2352,19 @@ async def test_stream_message_async( ) async def test_stream_messages_data_collection_outputs_async( sentry_init, - capture_events, capture_items, data_collection, send_default_pii, - include_prompts, outputs_collected, get_model_response, async_iterator, server_side_event_chunks, - stream_gen_ai_spans, - span_streaming, ): sentry_init_kwargs = dict( - integrations=[AnthropicIntegration(include_prompts=include_prompts)], + integrations=[AnthropicIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) if data_collection is not None: sentry_init_kwargs["data_collection"] = data_collection @@ -4036,38 +2411,21 @@ async def test_stream_messages_data_collection_outputs_async( model="model", messages=[{"role": "user", "content": "Hello, Claude"}], ) + items = capture_items("span") + + with mock.patch.object( + client._client, + "send", + return_value=response, + ): + async with client.messages.stream(**stream_kwargs) as stream: + async for _ in stream: + pass - if span_streaming or stream_gen_ai_spans: - items = capture_items("transaction", "span") - - with mock.patch.object( - client._client, - "send", - return_value=response, - ), start_transaction(name="anthropic"): - async with client.messages.stream(**stream_kwargs) as stream: - async for _ in stream: - pass - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - (span,) = [s for s in spans if s["attributes"]["sentry.op"] == OP.GEN_AI_CHAT] - span_data = span["attributes"] - else: - events = capture_events() - - with mock.patch.object( - client._client, - "send", - return_value=response, - ), start_transaction(name="anthropic"): - async with client.messages.stream(**stream_kwargs) as stream: - async for _ in stream: - pass - - (event,) = events - span = next(s for s in event["spans"] if s["op"] == OP.GEN_AI_CHAT) - span_data = span["data"] + sentry_sdk.flush() + spans = [item.payload for item in items] + (span,) = [s for s in spans if s["attributes"]["sentry.op"] == OP.GEN_AI_CHAT] + span_data = span["attributes"] # Output data that is not gated on data collection assert span_data[SPANDATA.GEN_AI_RESPONSE_MODEL] == "model" @@ -4082,8 +2440,6 @@ async def test_stream_messages_data_collection_outputs_async( assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span_data -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.skipif( ANTHROPIC_VERSION < (0, 41), reason="Error classes moved in https://github.com/anthropics/anthropic-sdk-python/commit/4e0b15e22fe40e9aa513459564f641bf97c90954.", @@ -4091,13 +2447,10 @@ async def test_stream_messages_data_collection_outputs_async( @pytest.mark.asyncio async def test_stream_messages_async_api_error( sentry_init, - capture_events, capture_items, get_model_response, async_iterator, server_side_event_chunks, - stream_gen_ai_spans, - span_streaming, ): client = AsyncAnthropic(api_key="z") @@ -4136,12 +2489,10 @@ async def test_stream_messages_async_api_error( ) sentry_init( - integrations=[AnthropicIntegration(include_prompts=True)], + integrations=[AnthropicIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) messages = [ @@ -4150,157 +2501,58 @@ async def test_stream_messages_async_api_error( "content": "Hello, Claude", } ] + items = capture_items("span") + + with pytest.raises(APIStatusError), mock.patch.object( + client._client, + "send", + return_value=response, + ): + async with client.messages.stream( + max_tokens=1024, + messages=messages, + model="model", + ) as stream: + async for event in stream: + pass - if span_streaming: - items = capture_items("transaction", "span") - - with pytest.raises(APIStatusError), mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, sentry_sdk.traces.start_span(name="anthropic"): - async with client.messages.stream( - max_tokens=1024, - messages=messages, - model="model", - ) as stream: - async for event in stream: - pass - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert spans[1]["name"] == "anthropic" - span = next( - span for span in spans if span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - ) - - assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - assert span["name"] == "chat model" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - - assert ( - span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - == '[{"role": "user", "content": "Hello, Claude"}]' - ) - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi!" - - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 20 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True - assert ( - span["attributes"][SPANDATA.GEN_AI_RESPONSE_ID] - == "msg_01XFDUDYJgAACzvnptvVoYEL" - ) - - assert span["status"] == "error" - elif stream_gen_ai_spans: - items = capture_items("transaction", "span") - - with pytest.raises(APIStatusError), mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, start_transaction(name="anthropic"): - async with client.messages.stream( - max_tokens=1024, - messages=messages, - model="model", - ) as stream: - async for event in stream: - pass - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - span = next( - span for span in spans if span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - ) - - assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - assert span["name"] == "chat model" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - - assert ( - span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - == '[{"role": "user", "content": "Hello, Claude"}]' - ) - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi!" - - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 20 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True - assert ( - span["attributes"][SPANDATA.GEN_AI_RESPONSE_ID] - == "msg_01XFDUDYJgAACzvnptvVoYEL" - ) - - assert span["status"] == "error" - else: - events = capture_events() - - with pytest.raises(APIStatusError), mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, start_transaction(name="anthropic"): - async with client.messages.stream( - max_tokens=1024, - messages=messages, - model="model", - ) as stream: - async for event in stream: - pass - - assert len(events) == 1 - (event,) = events - - assert event["type"] == "transaction" - assert event["transaction"] == "anthropic" - - span = next(span for span in event["spans"] if span["op"] == OP.GEN_AI_CHAT) - - assert span["op"] == OP.GEN_AI_CHAT - assert span["description"] == "chat model" - assert span["data"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["data"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["data"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" + sentry_sdk.flush() + spans = [item.payload for item in items] + span = next( + span for span in spans if span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT + ) - assert ( - span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - == '[{"role": "user", "content": "Hello, Claude"}]' - ) - assert span["data"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi!" + assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT + assert span["name"] == "chat model" + assert span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "anthropic" + assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - assert span["data"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["data"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 20 - assert span["data"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 - assert span["data"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True - assert ( - span["data"][SPANDATA.GEN_AI_RESPONSE_ID] == "msg_01XFDUDYJgAACzvnptvVoYEL" - ) + assert ( + span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] + == '[{"role": "user", "content": "Hello, Claude"}]' + ) + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi!" + + assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 20 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True + assert ( + span["attributes"][SPANDATA.GEN_AI_RESPONSE_ID] + == "msg_01XFDUDYJgAACzvnptvVoYEL" + ) - assert span["status"] == "internal_error" - assert span["tags"]["status"] == "internal_error" - assert event["contexts"]["trace"]["status"] == "internal_error" + assert span["status"] == "error" -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio async def test_stream_messages_async_close( sentry_init, - capture_events, capture_items, get_model_response, async_iterator, server_side_event_chunks, - stream_gen_ai_spans, - span_streaming, ): client = AsyncAnthropic(api_key="z") @@ -4344,12 +2596,10 @@ async def test_stream_messages_async_close( ) sentry_init( - integrations=[AnthropicIntegration(include_prompts=True)], + integrations=[AnthropicIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) messages = [ @@ -4358,186 +2608,71 @@ async def test_stream_messages_async_close( "content": "Hello, Claude", } ] + items = capture_items("span") + + with mock.patch.object( + client._client, + "send", + return_value=response, + ): + async with client.messages.stream( + max_tokens=1024, + messages=messages, + model="model", + ) as stream: + for _ in range(4): + await stream.__anext__() - if span_streaming: - items = capture_items("transaction", "span") - - with mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, sentry_sdk.traces.start_span(name="anthropic"): - async with client.messages.stream( - max_tokens=1024, - messages=messages, - model="model", - ) as stream: - for _ in range(4): - await stream.__anext__() - - # New versions add TextEvent, so consume one more event. - if TextEvent is not None and isinstance( - await stream.__anext__(), TextEvent - ): - await stream.__anext__() - - await stream.close() - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert spans[1]["name"] == "anthropic" - span = next( - span for span in spans if span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - ) - - assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - assert span["name"] == "chat model" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - - assert ( - span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - == '[{"role": "user", "content": "Hello, Claude"}]' - ) - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi!" - - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 20 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True - assert ( - span["attributes"][SPANDATA.GEN_AI_RESPONSE_ID] - == "msg_01XFDUDYJgAACzvnptvVoYEL" - ) - elif stream_gen_ai_spans: - items = capture_items("transaction", "span") - - with mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, start_transaction(name="anthropic"): - async with client.messages.stream( - max_tokens=1024, - messages=messages, - model="model", - ) as stream: - for _ in range(4): - await stream.__anext__() - - # New versions add TextEvent, so consume one more event. - if TextEvent is not None and isinstance( - await stream.__anext__(), TextEvent - ): - await stream.__anext__() - - await stream.close() - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - span = next( - span for span in spans if span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - ) - - assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - assert span["name"] == "chat model" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" + # New versions add TextEvent, so consume one more event. + if TextEvent is not None and isinstance( + await stream.__anext__(), TextEvent + ): + await stream.__anext__() - assert ( - span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - == '[{"role": "user", "content": "Hello, Claude"}]' - ) - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi!" + await stream.close() - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 20 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True - assert ( - span["attributes"][SPANDATA.GEN_AI_RESPONSE_ID] - == "msg_01XFDUDYJgAACzvnptvVoYEL" - ) - else: - events = capture_events() - - with mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, start_transaction(name="anthropic"): - async with client.messages.stream( - max_tokens=1024, - messages=messages, - model="model", - ) as stream: - for _ in range(4): - await stream.__anext__() - - # New versions add TextEvent, so consume one more event. - if TextEvent is not None and isinstance( - await stream.__anext__(), TextEvent - ): - await stream.__anext__() - - await stream.close() - - assert len(events) == 1 - (event,) = events - - assert event["type"] == "transaction" - assert event["transaction"] == "anthropic" - - span = next(span for span in event["spans"] if span["op"] == OP.GEN_AI_CHAT) - - assert span["op"] == OP.GEN_AI_CHAT - assert span["description"] == "chat model" - assert span["data"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["data"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["data"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" + sentry_sdk.flush() + spans = [item.payload for item in items] + span = next( + span for span in spans if span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT + ) - assert ( - span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - == '[{"role": "user", "content": "Hello, Claude"}]' - ) - assert span["data"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi!" + assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT + assert span["name"] == "chat model" + assert span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "anthropic" + assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - assert span["data"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["data"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 20 - assert span["data"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 - assert span["data"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True - assert ( - span["data"][SPANDATA.GEN_AI_RESPONSE_ID] == "msg_01XFDUDYJgAACzvnptvVoYEL" - ) + assert ( + span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] + == '[{"role": "user", "content": "Hello, Claude"}]' + ) + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi!" + + assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 20 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True + assert ( + span["attributes"][SPANDATA.GEN_AI_RESPONSE_ID] + == "msg_01XFDUDYJgAACzvnptvVoYEL" + ) -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.skipif( ANTHROPIC_VERSION < (0, 27), reason="Versions <0.27.0 do not include InputJSONDelta, which was introduced in >=0.27.0 along with a new message delta type for tool calling.", ) @pytest.mark.parametrize( - "send_default_pii, include_prompts", - [ - (True, True), - (True, False), - (False, True), - (False, False), - ], + "send_default_pii", + [True, False], ) def test_streaming_create_message_with_input_json_delta( sentry_init, - capture_events, capture_items, send_default_pii, - include_prompts, get_model_response, server_side_event_chunks, - stream_gen_ai_spans, - span_streaming, ): client = Anthropic(api_key="z") @@ -4609,12 +2744,10 @@ def test_streaming_create_message_with_input_json_delta( ) sentry_init( - integrations=[AnthropicIntegration(include_prompts=include_prompts)], + integrations=[AnthropicIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) messages = [ @@ -4623,174 +2756,65 @@ def test_streaming_create_message_with_input_json_delta( "content": "What is the weather like in San Francisco?", } ] + items = capture_items("span") - if span_streaming: - items = capture_items("transaction", "span") - - with mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, sentry_sdk.traces.start_span(name="anthropic"): - message = client.messages.create( - max_tokens=1024, messages=messages, model="model", stream=True - ) - - for _ in message: - pass - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert len(spans) == 2 - - assert spans[1]["name"] == "anthropic" - (span, _) = spans - - assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - assert span["name"] == "chat model" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - - if send_default_pii and include_prompts: - assert ( - span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - == '[{"role": "user", "content": "What is the weather like in San Francisco?"}]' - ) - assert ( - span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] - == '{"location": "San Francisco, CA"}' - ) - else: - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] - - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 366 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 41 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 407 - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True - - elif stream_gen_ai_spans: - items = capture_items("transaction", "span") - - with mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, start_transaction(name="anthropic"): - message = client.messages.create( - max_tokens=1024, messages=messages, model="model", stream=True - ) - - for _ in message: - pass - - (event,) = (item.payload for item in items if item.type == "transaction") - assert event["transaction"] == "anthropic" + with mock.patch.object( + client._client, + "send", + return_value=response, + ): + message = client.messages.create( + max_tokens=1024, messages=messages, model="model", stream=True + ) - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert len(spans) == 1 - (span,) = spans + for _ in message: + pass - assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - assert span["name"] == "chat model" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" + sentry_sdk.flush() + spans = [item.payload for item in items] + assert len(spans) == 1 - if send_default_pii and include_prompts: - assert ( - span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - == '[{"role": "user", "content": "What is the weather like in San Francisco?"}]' - ) - assert ( - span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] - == '{"location": "San Francisco, CA"}' - ) - else: - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] + (span,) = spans - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 366 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 41 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 407 - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True + assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT + assert span["name"] == "chat model" + assert span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "anthropic" + assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" + if send_default_pii: + assert ( + span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] + == '[{"role": "user", "content": "What is the weather like in San Francisco?"}]' + ) + assert ( + span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] + == '{"location": "San Francisco, CA"}' + ) else: - events = capture_events() - - with mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, start_transaction(name="anthropic"): - message = client.messages.create( - max_tokens=1024, messages=messages, model="model", stream=True - ) - - for _ in message: - pass - - assert len(events) == 1 - (event,) = events - - assert event["type"] == "transaction" - assert event["transaction"] == "anthropic" - - assert len(event["spans"]) == 1 - (span,) = event["spans"] - - assert span["op"] == OP.GEN_AI_CHAT - assert span["description"] == "chat model" - assert span["data"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["data"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["data"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - - if send_default_pii and include_prompts: - assert ( - span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - == '[{"role": "user", "content": "What is the weather like in San Francisco?"}]' - ) - assert ( - span["data"][SPANDATA.GEN_AI_RESPONSE_TEXT] - == '{"location": "San Francisco, CA"}' - ) - else: - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["data"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["data"] + assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] + assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] - assert span["data"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 366 - assert span["data"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 41 - assert span["data"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 407 - assert span["data"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True + assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 366 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 41 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 407 + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.skipif( ANTHROPIC_VERSION < (0, 27), reason="Versions <0.27.0 do not include InputJSONDelta, which was introduced in >=0.27.0 along with a new message delta type for tool calling.", ) @pytest.mark.parametrize( - "send_default_pii, include_prompts", - [ - (True, True), - (True, False), - (False, True), - (False, False), - ], + "send_default_pii", + [True, False], ) def test_stream_messages_with_input_json_delta( sentry_init, - capture_events, capture_items, send_default_pii, - include_prompts, get_model_response, server_side_event_chunks, - stream_gen_ai_spans, - span_streaming, ): client = Anthropic(api_key="z") @@ -4862,12 +2886,10 @@ def test_stream_messages_with_input_json_delta( ) sentry_init( - integrations=[AnthropicIntegration(include_prompts=include_prompts)], + integrations=[AnthropicIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) messages = [ @@ -4876,175 +2898,67 @@ def test_stream_messages_with_input_json_delta( "content": "What is the weather like in San Francisco?", } ] + items = capture_items("span") - if span_streaming: - items = capture_items("transaction", "span") - - with mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, sentry_sdk.traces.start_span(name="anthropic"), client.messages.stream( - max_tokens=1024, - messages=messages, - model="model", - ) as stream: - for event in stream: - pass - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert len(spans) == 2 - - assert spans[1]["name"] == "anthropic" - (span, _) = spans - - assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - assert span["name"] == "chat model" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - - if send_default_pii and include_prompts: - assert ( - span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - == '[{"role": "user", "content": "What is the weather like in San Francisco?"}]' - ) - assert ( - span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] - == '{"location": "San Francisco, CA"}' - ) - else: - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] - - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 366 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 41 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 407 - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True - - elif stream_gen_ai_spans: - items = capture_items("transaction", "span") - - with mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, start_transaction(name="anthropic"), client.messages.stream( - max_tokens=1024, - messages=messages, - model="model", - ) as stream: - for event in stream: - pass + with mock.patch.object( + client._client, + "send", + return_value=response, + ), client.messages.stream( + max_tokens=1024, + messages=messages, + model="model", + ) as stream: + for event in stream: + pass - (event,) = (item.payload for item in items if item.type == "transaction") - assert event["transaction"] == "anthropic" + sentry_sdk.flush() + spans = [item.payload for item in items] + assert len(spans) == 1 - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert len(spans) == 1 - (span,) = spans + (span,) = spans - assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - assert span["name"] == "chat model" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" + assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT + assert span["name"] == "chat model" + assert span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "anthropic" + assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - if send_default_pii and include_prompts: - assert ( - span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - == '[{"role": "user", "content": "What is the weather like in San Francisco?"}]' - ) - assert ( - span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] - == '{"location": "San Francisco, CA"}' - ) - else: - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] - - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 366 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 41 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 407 - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True + if send_default_pii: + assert ( + span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] + == '[{"role": "user", "content": "What is the weather like in San Francisco?"}]' + ) + assert ( + span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] + == '{"location": "San Francisco, CA"}' + ) else: - events = capture_events() - - with mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, start_transaction(name="anthropic"), client.messages.stream( - max_tokens=1024, - messages=messages, - model="model", - ) as stream: - for event in stream: - pass - - assert len(events) == 1 - (event,) = events - - assert event["type"] == "transaction" - assert event["transaction"] == "anthropic" - - assert len(event["spans"]) == 1 - (span,) = event["spans"] - - assert span["op"] == OP.GEN_AI_CHAT - assert span["description"] == "chat model" - assert span["data"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["data"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["data"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - - if send_default_pii and include_prompts: - assert ( - span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - == '[{"role": "user", "content": "What is the weather like in San Francisco?"}]' - ) - assert ( - span["data"][SPANDATA.GEN_AI_RESPONSE_TEXT] - == '{"location": "San Francisco, CA"}' - ) - else: - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["data"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["data"] + assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] + assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] - assert span["data"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 366 - assert span["data"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 41 - assert span["data"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 407 - assert span["data"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True + assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 366 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 41 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 407 + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio @pytest.mark.skipif( ANTHROPIC_VERSION < (0, 27), reason="Versions <0.27.0 do not include InputJSONDelta, which was introduced in >=0.27.0 along with a new message delta type for tool calling.", ) @pytest.mark.parametrize( - "send_default_pii, include_prompts", - [ - (True, True), - (True, False), - (False, True), - (False, False), - ], + "send_default_pii", + [True, False], ) async def test_streaming_create_message_with_input_json_delta_async( sentry_init, - capture_events, capture_items, send_default_pii, - include_prompts, get_model_response, async_iterator, server_side_event_chunks, - stream_gen_ai_spans, - span_streaming, ): client = AsyncAnthropic(api_key="z") response = get_model_response( @@ -5121,12 +3035,10 @@ async def test_streaming_create_message_with_input_json_delta_async( ) sentry_init( - integrations=[AnthropicIntegration(include_prompts=include_prompts)], + integrations=[AnthropicIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) messages = [ @@ -5135,178 +3047,68 @@ async def test_streaming_create_message_with_input_json_delta_async( "content": "What is the weather like in San Francisco?", } ] + items = capture_items("span") - if span_streaming: - items = capture_items("transaction", "span") - - with mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, sentry_sdk.traces.start_span(name="anthropic"): - message = await client.messages.create( - max_tokens=1024, messages=messages, model="model", stream=True - ) - - async for _ in message: - pass - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert len(spans) == 2 - - assert spans[1]["name"] == "anthropic" - (span, _) = spans - - assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - assert span["name"] == "chat model" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - - if send_default_pii and include_prompts: - assert ( - span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - == '[{"role": "user", "content": "What is the weather like in San Francisco?"}]' - ) - assert ( - span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] - == '{"location": "San Francisco, CA"}' - ) - - else: - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] - - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 366 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 41 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 407 - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True - - elif stream_gen_ai_spans: - items = capture_items("transaction", "span") - - with mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, start_transaction(name="anthropic"): - message = await client.messages.create( - max_tokens=1024, messages=messages, model="model", stream=True - ) - - async for _ in message: - pass + with mock.patch.object( + client._client, + "send", + return_value=response, + ): + message = await client.messages.create( + max_tokens=1024, messages=messages, model="model", stream=True + ) - (event,) = (item.payload for item in items if item.type == "transaction") - assert event["transaction"] == "anthropic" + async for _ in message: + pass - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert len(spans) == 1 - (span,) = spans + sentry_sdk.flush() + spans = [item.payload for item in items] + assert len(spans) == 1 - assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - assert span["name"] == "chat model" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" + (span,) = spans - if send_default_pii and include_prompts: - assert ( - span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - == '[{"role": "user", "content": "What is the weather like in San Francisco?"}]' - ) - assert ( - span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] - == '{"location": "San Francisco, CA"}' - ) + assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT + assert span["name"] == "chat model" + assert span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "anthropic" + assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - else: - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] + if send_default_pii: + assert ( + span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] + == '[{"role": "user", "content": "What is the weather like in San Francisco?"}]' + ) + assert ( + span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] + == '{"location": "San Francisco, CA"}' + ) - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 366 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 41 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 407 - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True else: - events = capture_events() - - with mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, start_transaction(name="anthropic"): - message = await client.messages.create( - max_tokens=1024, messages=messages, model="model", stream=True - ) - - async for _ in message: - pass - - assert len(events) == 1 - (event,) = events - - assert event["type"] == "transaction" - assert event["transaction"] == "anthropic" - - assert len(event["spans"]) == 1 - (span,) = event["spans"] - - assert span["op"] == OP.GEN_AI_CHAT - assert span["description"] == "chat model" - assert span["data"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["data"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["data"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - - if send_default_pii and include_prompts: - assert ( - span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - == '[{"role": "user", "content": "What is the weather like in San Francisco?"}]' - ) - assert ( - span["data"][SPANDATA.GEN_AI_RESPONSE_TEXT] - == '{"location": "San Francisco, CA"}' - ) - - else: - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["data"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["data"] + assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] + assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] - assert span["data"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 366 - assert span["data"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 41 - assert span["data"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 407 - assert span["data"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True + assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 366 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 41 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 407 + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio @pytest.mark.skipif( ANTHROPIC_VERSION < (0, 27), reason="Versions <0.27.0 do not include InputJSONDelta, which was introduced in >=0.27.0 along with a new message delta type for tool calling.", ) @pytest.mark.parametrize( - "send_default_pii, include_prompts", - [ - (True, True), - (True, False), - (False, True), - (False, False), - ], + "send_default_pii", + [True, False], ) async def test_stream_message_with_input_json_delta_async( sentry_init, - capture_events, capture_items, send_default_pii, - include_prompts, get_model_response, async_iterator, server_side_event_chunks, - stream_gen_ai_spans, - span_streaming, ): client = AsyncAnthropic(api_key="z") response = get_model_response( @@ -5383,12 +3185,10 @@ async def test_stream_message_with_input_json_delta_async( ) sentry_init( - integrations=[AnthropicIntegration(include_prompts=include_prompts)], + integrations=[AnthropicIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) messages = [ @@ -5397,481 +3197,180 @@ async def test_stream_message_with_input_json_delta_async( "content": "What is the weather like in San Francisco?", } ] + items = capture_items("span") + + with mock.patch.object( + client._client, + "send", + return_value=response, + ): + async with client.messages.stream( + max_tokens=1024, + messages=messages, + model="model", + ) as stream: + async for event in stream: + pass - if span_streaming: - items = capture_items("transaction", "span") - - with mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, sentry_sdk.traces.start_span(name="anthropic"): - async with client.messages.stream( - max_tokens=1024, - messages=messages, - model="model", - ) as stream: - async for event in stream: - pass - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert len(spans) == 2 - - assert spans[1]["name"] == "anthropic" - (span, _) = spans - - assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - assert span["name"] == "chat model" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - - if send_default_pii and include_prompts: - assert ( - span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - == '[{"role": "user", "content": "What is the weather like in San Francisco?"}]' - ) - assert ( - span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] - == '{"location": "San Francisco, CA"}' - ) - else: - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] - - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 366 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 41 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 407 - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True - - elif stream_gen_ai_spans: - items = capture_items("transaction", "span") - - with mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, start_transaction(name="anthropic"): - async with client.messages.stream( - max_tokens=1024, - messages=messages, - model="model", - ) as stream: - async for event in stream: - pass - - (event,) = (item.payload for item in items if item.type == "transaction") - assert event["transaction"] == "anthropic" - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert len(spans) == 1 - (span,) = spans - - assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - assert span["name"] == "chat model" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - - if send_default_pii and include_prompts: - assert ( - span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - == '[{"role": "user", "content": "What is the weather like in San Francisco?"}]' - ) - assert ( - span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] - == '{"location": "San Francisco, CA"}' - ) - else: - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] - - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 366 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 41 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 407 - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True - else: - events = capture_events() - - with mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, start_transaction(name="anthropic"): - async with client.messages.stream( - max_tokens=1024, - messages=messages, - model="model", - ) as stream: - async for event in stream: - pass - - assert len(events) == 1 - (event,) = events - - assert event["type"] == "transaction" - assert event["transaction"] == "anthropic" - - assert len(event["spans"]) == 1 - (span,) = event["spans"] - - assert span["op"] == OP.GEN_AI_CHAT - assert span["description"] == "chat model" - assert span["data"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["data"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["data"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - - if send_default_pii and include_prompts: - assert ( - span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - == '[{"role": "user", "content": "What is the weather like in San Francisco?"}]' - ) - assert ( - span["data"][SPANDATA.GEN_AI_RESPONSE_TEXT] - == '{"location": "San Francisco, CA"}' - ) + sentry_sdk.flush() + spans = [item.payload for item in items] + assert len(spans) == 1 - else: - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["data"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["data"] + (span,) = spans - assert span["data"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 366 - assert span["data"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 41 - assert span["data"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 407 - assert span["data"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True + assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT + assert span["name"] == "chat model" + assert span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "anthropic" + assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" + + if send_default_pii: + assert ( + span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] + == '[{"role": "user", "content": "What is the weather like in San Francisco?"}]' + ) + assert ( + span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] + == '{"location": "San Francisco, CA"}' + ) + else: + assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] + assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] + + assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 366 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 41 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 407 + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_exception_message_create( sentry_init, - capture_events, capture_items, - stream_gen_ai_spans, - span_streaming, ): sentry_init( integrations=[AnthropicIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = Anthropic(api_key="z") client.messages._post = mock.Mock( side_effect=AnthropicError("API rate limit reached") ) + items = capture_items("event") - if span_streaming: - items = capture_items("event") - - with pytest.raises(AnthropicError): - client.messages.create( - model="some-model", - messages=[{"role": "system", "content": "I'm throwing an exception"}], - max_tokens=1024, - ) - - (event,) = (item.payload for item in items) - assert event["level"] == "error" - elif stream_gen_ai_spans: - items = capture_items("event", "transaction") - - with pytest.raises(AnthropicError): - client.messages.create( - model="some-model", - messages=[{"role": "system", "content": "I'm throwing an exception"}], - max_tokens=1024, - ) - - (event,) = (item.payload for item in items if item.type == "event") - assert event["level"] == "error" - - (transaction,) = (item.payload for item in items if item.type == "transaction") - assert transaction["contexts"]["trace"]["status"] == "internal_error" - else: - events = capture_events() - - with pytest.raises(AnthropicError): - client.messages.create( - model="some-model", - messages=[{"role": "system", "content": "I'm throwing an exception"}], - max_tokens=1024, - ) + with pytest.raises(AnthropicError): + client.messages.create( + model="some-model", + messages=[{"role": "system", "content": "I'm throwing an exception"}], + max_tokens=1024, + ) - (event, transaction) = events - assert event["level"] == "error" - assert transaction["contexts"]["trace"]["status"] == "internal_error" + (event,) = (item.payload for item in items) + assert event["level"] == "error" -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_span_status_error( sentry_init, - capture_events, capture_items, - stream_gen_ai_spans, - span_streaming, ): sentry_init( integrations=[AnthropicIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) + items = capture_items("event", "span") + + client = Anthropic(api_key="z") + client.messages._post = mock.Mock( + side_effect=AnthropicError("API rate limit reached") + ) + with pytest.raises(AnthropicError): + client.messages.create( + model="some-model", + messages=[{"role": "system", "content": "I'm throwing an exception"}], + max_tokens=1024, + ) - if span_streaming: - items = capture_items("event", "span") + (error,) = (item.payload for item in items if item.type == "event") + assert error["level"] == "error" + + sentry_sdk.flush() + spans = [item.payload for item in items if item.type == "span"] + assert spans[0]["status"] == "error" + assert spans[0]["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "anthropic" + assert spans[0]["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - with sentry_sdk.traces.start_span(name="anthropic"): - client = Anthropic(api_key="z") - client.messages._post = mock.Mock( - side_effect=AnthropicError("API rate limit reached") - ) - with pytest.raises(AnthropicError): - client.messages.create( - model="some-model", - messages=[ - {"role": "system", "content": "I'm throwing an exception"} - ], - max_tokens=1024, - ) - - (error,) = (item.payload for item in items if item.type == "event") - assert error["level"] == "error" - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert spans[0]["status"] == "error" - assert spans[0]["attributes"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert spans[0]["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - - elif stream_gen_ai_spans: - items = capture_items("event", "span") - - with start_transaction(name="anthropic"): - client = Anthropic(api_key="z") - client.messages._post = mock.Mock( - side_effect=AnthropicError("API rate limit reached") - ) - with pytest.raises(AnthropicError): - client.messages.create( - model="some-model", - messages=[ - {"role": "system", "content": "I'm throwing an exception"} - ], - max_tokens=1024, - ) - - (error,) = (item.payload for item in items if item.type == "event") - assert error["level"] == "error" - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert spans[0]["status"] == "error" - assert spans[0]["attributes"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert spans[0]["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - else: - events = capture_events() - with start_transaction(name="anthropic"): - client = Anthropic(api_key="z") - client.messages._post = mock.Mock( - side_effect=AnthropicError("API rate limit reached") - ) - with pytest.raises(AnthropicError): - client.messages.create( - model="some-model", - messages=[ - {"role": "system", "content": "I'm throwing an exception"} - ], - max_tokens=1024, - ) - - (error, transaction) = events - assert error["level"] == "error" - assert transaction["spans"][0]["status"] == "internal_error" - assert transaction["spans"][0]["tags"]["status"] == "internal_error" - assert transaction["spans"][0]["data"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert transaction["spans"][0]["data"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio async def test_span_status_error_async( sentry_init, - capture_events, capture_items, - stream_gen_ai_spans, - span_streaming, ): sentry_init( integrations=[AnthropicIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("event", "span") + items = capture_items("event", "span") + + client = AsyncAnthropic(api_key="z") + client.messages._post = AsyncMock( + side_effect=AnthropicError("API rate limit reached") + ) + with pytest.raises(AnthropicError): + await client.messages.create( + model="some-model", + messages=[{"role": "system", "content": "I'm throwing an exception"}], + max_tokens=1024, + ) + + (error,) = (item.payload for item in items if item.type == "event") + assert error["level"] == "error" + + sentry_sdk.flush() + spans = [item.payload for item in items if item.type == "span"] + assert spans[0]["status"] == "error" + assert spans[0]["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "anthropic" + assert spans[0]["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - with sentry_sdk.traces.start_span(name="anthropic"): - client = AsyncAnthropic(api_key="z") - client.messages._post = AsyncMock( - side_effect=AnthropicError("API rate limit reached") - ) - with pytest.raises(AnthropicError): - await client.messages.create( - model="some-model", - messages=[ - {"role": "system", "content": "I'm throwing an exception"} - ], - max_tokens=1024, - ) - - (error,) = (item.payload for item in items if item.type == "event") - assert error["level"] == "error" - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert spans[0]["status"] == "error" - assert spans[0]["attributes"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert spans[0]["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - elif stream_gen_ai_spans: - items = capture_items("event", "span") - - with start_transaction(name="anthropic"): - client = AsyncAnthropic(api_key="z") - client.messages._post = AsyncMock( - side_effect=AnthropicError("API rate limit reached") - ) - with pytest.raises(AnthropicError): - await client.messages.create( - model="some-model", - messages=[ - {"role": "system", "content": "I'm throwing an exception"} - ], - max_tokens=1024, - ) - - (error,) = (item.payload for item in items if item.type == "event") - assert error["level"] == "error" - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert spans[0]["status"] == "error" - assert spans[0]["attributes"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert spans[0]["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - else: - events = capture_events() - with start_transaction(name="anthropic"): - client = AsyncAnthropic(api_key="z") - client.messages._post = AsyncMock( - side_effect=AnthropicError("API rate limit reached") - ) - with pytest.raises(AnthropicError): - await client.messages.create( - model="some-model", - messages=[ - {"role": "system", "content": "I'm throwing an exception"} - ], - max_tokens=1024, - ) - - (error, transaction) = events - assert error["level"] == "error" - assert transaction["spans"][0]["status"] == "internal_error" - assert transaction["spans"][0]["tags"]["status"] == "internal_error" - assert transaction["spans"][0]["data"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert transaction["spans"][0]["data"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio async def test_exception_message_create_async( sentry_init, - capture_events, capture_items, - stream_gen_ai_spans, - span_streaming, ): sentry_init( integrations=[AnthropicIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = AsyncAnthropic(api_key="z") client.messages._post = AsyncMock( side_effect=AnthropicError("API rate limit reached") ) + items = capture_items("event") - if span_streaming: - items = capture_items("event") - - with pytest.raises(AnthropicError): - await client.messages.create( - model="some-model", - messages=[{"role": "system", "content": "I'm throwing an exception"}], - max_tokens=1024, - ) - - (event,) = (item.payload for item in items) - assert event["level"] == "error" - elif stream_gen_ai_spans: - items = capture_items("event", "transaction") - - with pytest.raises(AnthropicError): - await client.messages.create( - model="some-model", - messages=[{"role": "system", "content": "I'm throwing an exception"}], - max_tokens=1024, - ) - - (event,) = (item.payload for item in items if item.type == "event") - assert event["level"] == "error" - - (transaction,) = (item.payload for item in items if item.type == "transaction") - assert transaction["contexts"]["trace"]["status"] == "internal_error" - else: - events = capture_events() - - with pytest.raises(AnthropicError): - await client.messages.create( - model="some-model", - messages=[{"role": "system", "content": "I'm throwing an exception"}], - max_tokens=1024, - ) + with pytest.raises(AnthropicError): + await client.messages.create( + model="some-model", + messages=[{"role": "system", "content": "I'm throwing an exception"}], + max_tokens=1024, + ) - (event, transaction) = events - assert event["level"] == "error" - assert transaction["contexts"]["trace"]["status"] == "internal_error" + (event,) = (item.payload for item in items) + assert event["level"] == "error" -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_span_origin( sentry_init, - capture_events, capture_items, - stream_gen_ai_spans, - span_streaming, ): sentry_init( integrations=[AnthropicIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = Anthropic(api_key="z") @@ -5883,63 +3382,26 @@ def test_span_origin( "content": "Hello, Claude", } ] + items = capture_items("span") - if span_streaming: - items = capture_items("transaction", "span") - - with sentry_sdk.traces.start_span(name="anthropic"): - client.messages.create(max_tokens=1024, messages=messages, model="model") - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert spans[1]["attributes"]["sentry.origin"] == "manual" - assert spans[0]["attributes"]["sentry.origin"] == "auto.ai.anthropic" - assert spans[0]["attributes"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert spans[0]["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - - elif stream_gen_ai_spans: - items = capture_items("transaction", "span") - - with start_transaction(name="anthropic"): - client.messages.create(max_tokens=1024, messages=messages, model="model") - - (event,) = (item.payload for item in items if item.type == "transaction") - assert event["contexts"]["trace"]["origin"] == "manual" - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert spans[0]["attributes"]["sentry.origin"] == "auto.ai.anthropic" - assert spans[0]["attributes"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert spans[0]["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - else: - events = capture_events() - - with start_transaction(name="anthropic"): - client.messages.create(max_tokens=1024, messages=messages, model="model") + client.messages.create(max_tokens=1024, messages=messages, model="model") - (event,) = events - assert event["contexts"]["trace"]["origin"] == "manual" - assert event["spans"][0]["origin"] == "auto.ai.anthropic" - assert event["spans"][0]["data"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert event["spans"][0]["data"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" + sentry_sdk.flush() + spans = [item.payload for item in items] + assert spans[0]["attributes"]["sentry.origin"] == "auto.ai.anthropic" + assert spans[0]["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "anthropic" + assert spans[0]["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio async def test_span_origin_async( sentry_init, - capture_events, capture_items, - stream_gen_ai_spans, - span_streaming, ): sentry_init( integrations=[AnthropicIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = AsyncAnthropic(api_key="z") @@ -5951,59 +3413,22 @@ async def test_span_origin_async( "content": "Hello, Claude", } ] + items = capture_items("span") - if span_streaming: - items = capture_items("transaction", "span") - - with sentry_sdk.traces.start_span(name="anthropic"): - await client.messages.create( - max_tokens=1024, messages=messages, model="model" - ) - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert spans[1]["attributes"]["sentry.origin"] == "manual" - assert spans[0]["attributes"]["sentry.origin"] == "auto.ai.anthropic" - assert spans[0]["attributes"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert spans[0]["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - elif stream_gen_ai_spans: - items = capture_items("transaction", "span") - - with start_transaction(name="anthropic"): - await client.messages.create( - max_tokens=1024, messages=messages, model="model" - ) - - (event,) = (item.payload for item in items if item.type == "transaction") - assert event["contexts"]["trace"]["origin"] == "manual" - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert spans[0]["attributes"]["sentry.origin"] == "auto.ai.anthropic" - assert spans[0]["attributes"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert spans[0]["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - else: - events = capture_events() - - with start_transaction(name="anthropic"): - await client.messages.create( - max_tokens=1024, messages=messages, model="model" - ) - - (event,) = events + await client.messages.create(max_tokens=1024, messages=messages, model="model") - assert event["contexts"]["trace"]["origin"] == "manual" - assert event["spans"][0]["origin"] == "auto.ai.anthropic" - assert event["spans"][0]["data"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert event["spans"][0]["data"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" + sentry_sdk.flush() + spans = [item.payload for item in items] + assert spans[0]["attributes"]["sentry.origin"] == "auto.ai.anthropic" + assert spans[0]["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "anthropic" + assert spans[0]["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" @pytest.mark.skipif( ANTHROPIC_VERSION < (0, 27), reason="Versions <0.27.0 do not include InputJSONDelta.", ) -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_collect_ai_data_with_input_json_delta(span_streaming): +def test_collect_ai_data_with_input_json_delta(): event = ContentBlockDeltaEvent( delta=InputJSONDelta(partial_json="test", type="input_json_delta"), index=0, @@ -6034,39 +3459,36 @@ def test_collect_ai_data_with_input_json_delta(span_streaming): ) def test_set_output_data_with_input_json_delta(sentry_init): sentry_init( - integrations=[AnthropicIntegration(include_prompts=True)], + integrations=[AnthropicIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=True, ) - with start_transaction(name="test"): - span = start_span() - integration = AnthropicIntegration() - json_deltas = ["{'test': 'data',", "'more': 'json'}"] - _set_output_data( - span, - integration, - model="", - input_tokens=10, - output_tokens=20, - cache_read_input_tokens=0, - cache_write_input_tokens=0, - content_blocks=[{"text": "".join(json_deltas), "type": "text"}], - ) + span = sentry_sdk.start_span(name="test") + integration = AnthropicIntegration() + json_deltas = ["{'test': 'data',", "'more': 'json'}"] + _set_output_data( + span, + integration, + model="", + input_tokens=10, + output_tokens=20, + cache_read_input_tokens=0, + cache_write_input_tokens=0, + content_blocks=[{"text": "".join(json_deltas), "type": "text"}], + ) - assert ( - span._data.get(SPANDATA.GEN_AI_RESPONSE_TEXT) - == "{'test': 'data','more': 'json'}" - ) - assert span._data.get(SPANDATA.GEN_AI_USAGE_INPUT_TOKENS) == 10 - assert span._data.get(SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS) == 20 - assert span._data.get(SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS) == 30 + assert ( + span._attributes.get(SPANDATA.GEN_AI_RESPONSE_TEXT) + == "{'test': 'data','more': 'json'}" + ) + assert span._attributes.get(SPANDATA.GEN_AI_USAGE_INPUT_TOKENS) == 10 + assert span._attributes.get(SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS) == 20 + assert span._attributes.get(SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS) == 30 # Test messages with mixed roles including "ai" that should be mapped to "assistant" -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize( "test_message,expected_role", [ @@ -6084,21 +3506,16 @@ def test_set_output_data_with_input_json_delta(sentry_init): ) def test_anthropic_message_role_mapping( sentry_init, - capture_events, capture_items, test_message, expected_role, - stream_gen_ai_spans, - span_streaming, ): """Test that Anthropic integration properly maps message roles like 'ai' to 'assistant'""" sentry_init( - integrations=[AnthropicIntegration(include_prompts=True)], + integrations=[AnthropicIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = Anthropic(api_key="z") @@ -6118,186 +3535,40 @@ def mock_messages_create(*args, **kwargs): client.messages._post = mock.Mock(return_value=mock_messages_create()) test_messages = [test_message] + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with start_transaction(name="anthropic tx"): - client.messages.create( - model="claude-3-opus", max_tokens=10, messages=test_messages - ) - - sentry_sdk.flush() - span = next(item.payload for item in items) - - # Verify that the span was created correctly - assert span["attributes"]["sentry.op"] == "gen_ai.chat" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert SPANDATA.GEN_AI_REQUEST_MESSAGES in span["attributes"] - - # Parse the stored messages - stored_messages = json.loads( - span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - ) - else: - events = capture_events() - - with start_transaction(name="anthropic tx"): - client.messages.create( - model="claude-3-opus", max_tokens=10, messages=test_messages - ) + client.messages.create(model="claude-3-opus", max_tokens=10, messages=test_messages) - (event,) = events - span = event["spans"][0] + sentry_sdk.flush() + span = next(item.payload for item in items) - # Verify that the span was created correctly - assert span["op"] == "gen_ai.chat" - assert span["data"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["data"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert SPANDATA.GEN_AI_REQUEST_MESSAGES in span["data"] + # Verify that the span was created correctly + assert span["attributes"]["sentry.op"] == "gen_ai.chat" + assert span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "anthropic" + assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" + assert SPANDATA.GEN_AI_REQUEST_MESSAGES in span["attributes"] - # Parse the stored messages - stored_messages = json.loads(span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) + # Parse the stored messages + stored_messages = json.loads(span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) assert stored_messages[0]["role"] == expected_role -def test_anthropic_message_truncation(sentry_init, capture_events): - """Test that large messages are truncated properly in Anthropic integration.""" - sentry_init( - integrations=[AnthropicIntegration(include_prompts=True)], - disabled_integrations=[StdlibIntegration], - traces_sample_rate=1.0, - send_default_pii=True, - stream_gen_ai_spans=False, - ) - events = capture_events() - - client = Anthropic(api_key="z") - client.messages._post = mock.Mock(return_value=EXAMPLE_MESSAGE) - - large_content = ( - "This is a very long message that will exceed our size limits. " * 1000 - ) - messages = [ - {"role": "user", "content": "small message 1"}, - {"role": "assistant", "content": large_content}, - {"role": "user", "content": large_content}, - {"role": "assistant", "content": "small message 4"}, - {"role": "user", "content": "small message 5"}, - ] - - with start_transaction(): - client.messages.create(max_tokens=1024, messages=messages, model="model") - - assert len(events) > 0 - tx = events[0] - assert tx["type"] == "transaction" - - chat_spans = [ - span for span in tx.get("spans", []) if span.get("op") == OP.GEN_AI_CHAT - ] - assert len(chat_spans) > 0 - - chat_span = chat_spans[0] - assert chat_span["data"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert chat_span["data"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert SPANDATA.GEN_AI_REQUEST_MESSAGES in chat_span["data"] - - messages_data = chat_span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - assert isinstance(messages_data, str) - - parsed_messages = json.loads(messages_data) - assert isinstance(parsed_messages, list) - assert len(parsed_messages) == 1 - assert "small message 5" in str(parsed_messages[0]) - - assert tx["_meta"]["spans"]["0"]["data"]["gen_ai.request.messages"][""]["len"] == 5 - - -@pytest.mark.asyncio -async def test_anthropic_message_truncation_async(sentry_init, capture_events): - """Test that large messages are truncated properly in Anthropic integration.""" - sentry_init( - integrations=[AnthropicIntegration(include_prompts=True)], - disabled_integrations=[StdlibIntegration], - traces_sample_rate=1.0, - send_default_pii=True, - stream_gen_ai_spans=False, - ) - events = capture_events() - - client = AsyncAnthropic(api_key="z") - client.messages._post = mock.AsyncMock(return_value=EXAMPLE_MESSAGE) - - large_content = ( - "This is a very long message that will exceed our size limits. " * 1000 - ) - messages = [ - {"role": "user", "content": "small message 1"}, - {"role": "assistant", "content": large_content}, - {"role": "user", "content": large_content}, - {"role": "assistant", "content": "small message 4"}, - {"role": "user", "content": "small message 5"}, - ] - - with start_transaction(): - await client.messages.create(max_tokens=1024, messages=messages, model="model") - - assert len(events) > 0 - tx = events[0] - assert tx["type"] == "transaction" - - chat_spans = [ - span for span in tx.get("spans", []) if span.get("op") == OP.GEN_AI_CHAT - ] - assert len(chat_spans) > 0 - - chat_span = chat_spans[0] - assert chat_span["data"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert chat_span["data"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert SPANDATA.GEN_AI_REQUEST_MESSAGES in chat_span["data"] - - messages_data = chat_span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - assert isinstance(messages_data, str) - - parsed_messages = json.loads(messages_data) - assert isinstance(parsed_messages, list) - assert len(parsed_messages) == 1 - assert "small message 5" in str(parsed_messages[0]) - - assert tx["_meta"]["spans"]["0"]["data"]["gen_ai.request.messages"][""]["len"] == 5 - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize( - "send_default_pii, include_prompts", - [ - (True, True), - (True, False), - (False, True), - (False, False), - ], + "send_default_pii", + [True, False], ) def test_nonstreaming_create_message_with_system_prompt( sentry_init, - capture_events, capture_items, send_default_pii, - include_prompts, - stream_gen_ai_spans, - span_streaming, ): """Test that system prompts are properly captured in GEN_AI_REQUEST_MESSAGES.""" sentry_init( - integrations=[AnthropicIntegration(include_prompts=include_prompts)], + integrations=[AnthropicIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = Anthropic(api_key="z") @@ -6309,218 +3580,78 @@ def test_nonstreaming_create_message_with_system_prompt( "content": "Hello, Claude", } ] + items = capture_items("span") - if span_streaming: - items = capture_items("transaction", "span") - - with sentry_sdk.traces.start_span(name="anthropic"): - response = client.messages.create( - max_tokens=1024, - messages=messages, - model="model", - system="You are a helpful assistant.", - ) - - assert response == EXAMPLE_MESSAGE - usage = response.usage + response = client.messages.create( + max_tokens=1024, + messages=messages, + model="model", + system="You are a helpful assistant.", + ) - assert usage.input_tokens == 10 - assert usage.output_tokens == 20 + assert response == EXAMPLE_MESSAGE + usage = response.usage - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert len(spans) == 2 + assert usage.input_tokens == 10 + assert usage.output_tokens == 20 - assert spans[1]["name"] == "anthropic" - (span, _) = spans + sentry_sdk.flush() + spans = [item.payload for item in items] + assert len(spans) == 1 - assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - assert span["name"] == "chat model" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" + (span,) = spans - if send_default_pii and include_prompts: - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS in span["attributes"] - system_instructions = json.loads( - span["attributes"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS] - ) - assert system_instructions == [ - {"type": "text", "content": "You are a helpful assistant."} - ] + assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT + assert span["name"] == "chat model" + assert span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "anthropic" + assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - assert SPANDATA.GEN_AI_REQUEST_MESSAGES in span["attributes"] - stored_messages = json.loads( - span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - ) - assert len(stored_messages) == 1 - assert stored_messages[0]["role"] == "user" - assert stored_messages[0]["content"] == "Hello, Claude" - assert ( - span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi, I'm Claude." - ) - else: - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in span["attributes"] - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] - - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 20 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is False - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS] == [ - "end_turn" + if send_default_pii: + assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS in span["attributes"] + system_instructions = json.loads( + span["attributes"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS] + ) + assert system_instructions == [ + {"type": "text", "content": "You are a helpful assistant."} ] - elif stream_gen_ai_spans: - items = capture_items("transaction", "span") - - with start_transaction(name="anthropic"): - response = client.messages.create( - max_tokens=1024, - messages=messages, - model="model", - system="You are a helpful assistant.", - ) - - assert response == EXAMPLE_MESSAGE - usage = response.usage - assert usage.input_tokens == 10 - assert usage.output_tokens == 20 - - (event,) = (item.payload for item in items if item.type == "transaction") - assert event["transaction"] == "anthropic" - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert len(spans) == 1 - (span,) = spans - - assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - assert span["name"] == "chat model" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - - if send_default_pii and include_prompts: - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS in span["attributes"] - system_instructions = json.loads( - span["attributes"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS] - ) - assert system_instructions == [ - {"type": "text", "content": "You are a helpful assistant."} - ] - - assert SPANDATA.GEN_AI_REQUEST_MESSAGES in span["attributes"] - stored_messages = json.loads( - span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - ) - assert len(stored_messages) == 1 - assert stored_messages[0]["role"] == "user" - assert stored_messages[0]["content"] == "Hello, Claude" - assert ( - span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi, I'm Claude." - ) - else: - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in span["attributes"] - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] - - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 20 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is False - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS] == [ - "end_turn" - ] + assert SPANDATA.GEN_AI_REQUEST_MESSAGES in span["attributes"] + stored_messages = json.loads( + span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] + ) + assert len(stored_messages) == 1 + assert stored_messages[0]["role"] == "user" + assert stored_messages[0]["content"] == "Hello, Claude" + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi, I'm Claude." else: - events = capture_events() - - with start_transaction(name="anthropic"): - response = client.messages.create( - max_tokens=1024, - messages=messages, - model="model", - system="You are a helpful assistant.", - ) - - assert response == EXAMPLE_MESSAGE - usage = response.usage - - assert usage.input_tokens == 10 - assert usage.output_tokens == 20 - - assert len(events) == 1 - (event,) = events - - assert event["type"] == "transaction" - assert event["transaction"] == "anthropic" - - assert len(event["spans"]) == 1 - (span,) = event["spans"] + assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in span["attributes"] + assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] + assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] - assert span["op"] == OP.GEN_AI_CHAT - assert span["description"] == "chat model" - assert span["data"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["data"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["data"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" + assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 20 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is False + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS] == ["end_turn"] - if send_default_pii and include_prompts: - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS in span["data"] - system_instructions = json.loads( - span["data"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS] - ) - assert system_instructions == [ - {"type": "text", "content": "You are a helpful assistant."} - ] - assert SPANDATA.GEN_AI_REQUEST_MESSAGES in span["data"] - stored_messages = json.loads(span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) - assert len(stored_messages) == 1 - assert stored_messages[0]["role"] == "user" - assert stored_messages[0]["content"] == "Hello, Claude" - assert span["data"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi, I'm Claude." - else: - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in span["data"] - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["data"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["data"] - - assert span["data"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["data"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 20 - assert span["data"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 - assert span["data"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is False - assert span["data"][SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS] == ["end_turn"] - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio @pytest.mark.parametrize( - "send_default_pii, include_prompts", - [ - (True, True), - (True, False), - (False, True), - (False, False), - ], + "send_default_pii", + [True, False], ) async def test_nonstreaming_create_message_with_system_prompt_async( sentry_init, - capture_events, capture_items, send_default_pii, - include_prompts, - stream_gen_ai_spans, - span_streaming, ): """Test that system prompts are properly captured in GEN_AI_REQUEST_MESSAGES (async).""" sentry_init( - integrations=[AnthropicIntegration(include_prompts=include_prompts)], + integrations=[AnthropicIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = AsyncAnthropic(api_key="z") @@ -6532,210 +3663,72 @@ async def test_nonstreaming_create_message_with_system_prompt_async( "content": "Hello, Claude", } ] + items = capture_items("span") - if span_streaming: - items = capture_items("transaction", "span") - - with sentry_sdk.traces.start_span(name="anthropic"): - response = await client.messages.create( - max_tokens=1024, - messages=messages, - model="model", - system="You are a helpful assistant.", - ) - - assert response == EXAMPLE_MESSAGE - usage = response.usage + response = await client.messages.create( + max_tokens=1024, + messages=messages, + model="model", + system="You are a helpful assistant.", + ) - assert usage.input_tokens == 10 - assert usage.output_tokens == 20 + assert response == EXAMPLE_MESSAGE + usage = response.usage - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert len(spans) == 2 + assert usage.input_tokens == 10 + assert usage.output_tokens == 20 - assert spans[1]["name"] == "anthropic" - (span, _) = spans + sentry_sdk.flush() + spans = [item.payload for item in items] + assert len(spans) == 1 - assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - assert span["name"] == "chat model" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" + (span,) = spans - if send_default_pii and include_prompts: - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS in span["attributes"] - system_instructions = json.loads( - span["attributes"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS] - ) - assert system_instructions == [ - {"type": "text", "content": "You are a helpful assistant."} - ] + assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT + assert span["name"] == "chat model" + assert span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "anthropic" + assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - assert SPANDATA.GEN_AI_REQUEST_MESSAGES in span["attributes"] - stored_messages = json.loads( - span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - ) - assert len(stored_messages) == 1 - assert stored_messages[0]["role"] == "user" - assert stored_messages[0]["content"] == "Hello, Claude" - assert ( - span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi, I'm Claude." - ) - else: - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in span["attributes"] - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] - - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 20 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is False - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS] == [ - "end_turn" + if send_default_pii: + assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS in span["attributes"] + system_instructions = json.loads( + span["attributes"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS] + ) + assert system_instructions == [ + {"type": "text", "content": "You are a helpful assistant."} ] - elif stream_gen_ai_spans: - items = capture_items("transaction", "span") - - with start_transaction(name="anthropic"): - response = await client.messages.create( - max_tokens=1024, - messages=messages, - model="model", - system="You are a helpful assistant.", - ) - - assert response == EXAMPLE_MESSAGE - usage = response.usage - - assert usage.input_tokens == 10 - assert usage.output_tokens == 20 - - (event,) = (item.payload for item in items if item.type == "transaction") - assert event["transaction"] == "anthropic" - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert len(spans) == 1 - (span,) = spans - - assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - assert span["name"] == "chat model" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - if send_default_pii and include_prompts: - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS in span["attributes"] - system_instructions = json.loads( - span["attributes"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS] - ) - assert system_instructions == [ - {"type": "text", "content": "You are a helpful assistant."} - ] - - assert SPANDATA.GEN_AI_REQUEST_MESSAGES in span["attributes"] - stored_messages = json.loads( - span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - ) - assert len(stored_messages) == 1 - assert stored_messages[0]["role"] == "user" - assert stored_messages[0]["content"] == "Hello, Claude" - assert ( - span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi, I'm Claude." - ) - else: - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in span["attributes"] - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] - - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 20 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is False - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS] == [ - "end_turn" - ] + assert SPANDATA.GEN_AI_REQUEST_MESSAGES in span["attributes"] + stored_messages = json.loads( + span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] + ) + assert len(stored_messages) == 1 + assert stored_messages[0]["role"] == "user" + assert stored_messages[0]["content"] == "Hello, Claude" + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi, I'm Claude." else: - events = capture_events() - - with start_transaction(name="anthropic"): - response = await client.messages.create( - max_tokens=1024, - messages=messages, - model="model", - system="You are a helpful assistant.", - ) - - assert response == EXAMPLE_MESSAGE - usage = response.usage - - assert usage.input_tokens == 10 - assert usage.output_tokens == 20 - - assert len(events) == 1 - (event,) = events - - assert event["type"] == "transaction" - assert event["transaction"] == "anthropic" - - assert len(event["spans"]) == 1 - (span,) = event["spans"] + assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in span["attributes"] + assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] + assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] - assert span["op"] == OP.GEN_AI_CHAT - assert span["description"] == "chat model" - assert span["data"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["data"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["data"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" + assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 20 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is False + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS] == ["end_turn"] - if send_default_pii and include_prompts: - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS in span["data"] - system_instructions = json.loads( - span["data"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS] - ) - assert system_instructions == [ - {"type": "text", "content": "You are a helpful assistant."} - ] - assert SPANDATA.GEN_AI_REQUEST_MESSAGES in span["data"] - stored_messages = json.loads(span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) - assert len(stored_messages) == 1 - assert stored_messages[0]["role"] == "user" - assert stored_messages[0]["content"] == "Hello, Claude" - assert span["data"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi, I'm Claude." - else: - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in span["data"] - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["data"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["data"] - - assert span["data"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["data"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 20 - assert span["data"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 - assert span["data"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is False - assert span["data"][SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS] == ["end_turn"] - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize( - "send_default_pii, include_prompts", - [ - (True, True), - (True, False), - (False, True), - (False, False), - ], + "send_default_pii", + [True, False], ) def test_streaming_create_message_with_system_prompt( sentry_init, - capture_events, capture_items, send_default_pii, - include_prompts, get_model_response, server_side_event_chunks, - stream_gen_ai_spans, - span_streaming, ): """Test that system prompts are properly captured in streaming mode.""" client = Anthropic(api_key="z") @@ -6778,12 +3771,10 @@ def test_streaming_create_message_with_system_prompt( ) sentry_init( - integrations=[AnthropicIntegration(include_prompts=include_prompts)], + integrations=[AnthropicIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) messages = [ @@ -6792,214 +3783,75 @@ def test_streaming_create_message_with_system_prompt( "content": "Hello, Claude", } ] + items = capture_items("span") + + with mock.patch.object( + client._client, + "send", + return_value=response, + ): + message = client.messages.create( + max_tokens=1024, + messages=messages, + model="model", + stream=True, + system="You are a helpful assistant.", + ) - if span_streaming: - items = capture_items("transaction", "span") - - with mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, sentry_sdk.traces.start_span(name="anthropic"): - message = client.messages.create( - max_tokens=1024, - messages=messages, - model="model", - stream=True, - system="You are a helpful assistant.", - ) - - for _ in message: - pass - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert len(spans) == 2 - - assert spans[1]["name"] == "anthropic" - (span, _) = spans - - assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - assert span["name"] == "chat model" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - - if send_default_pii and include_prompts: - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS in span["attributes"] - system_instructions = json.loads( - span["attributes"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS] - ) - assert system_instructions == [ - {"type": "text", "content": "You are a helpful assistant."} - ] - - assert SPANDATA.GEN_AI_REQUEST_MESSAGES in span["attributes"] - stored_messages = json.loads( - span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - ) - assert len(stored_messages) == 1 - assert stored_messages[0]["role"] == "user" - assert stored_messages[0]["content"] == "Hello, Claude" - assert ( - span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi! I'm Claude!" - ) - - else: - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in span["attributes"] - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] - - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 10 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 20 - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True - - elif stream_gen_ai_spans: - items = capture_items("transaction", "span") - - with mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, start_transaction(name="anthropic"): - message = client.messages.create( - max_tokens=1024, - messages=messages, - model="model", - stream=True, - system="You are a helpful assistant.", - ) - - for _ in message: - pass - - (event,) = (item.payload for item in items if item.type == "transaction") - assert event["transaction"] == "anthropic" - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert len(spans) == 1 - (span,) = spans + for _ in message: + pass - assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - assert span["name"] == "chat model" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" + sentry_sdk.flush() + spans = [item.payload for item in items] + assert len(spans) == 1 - if send_default_pii and include_prompts: - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS in span["attributes"] - system_instructions = json.loads( - span["attributes"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS] - ) - assert system_instructions == [ - {"type": "text", "content": "You are a helpful assistant."} - ] + (span,) = spans - assert SPANDATA.GEN_AI_REQUEST_MESSAGES in span["attributes"] - stored_messages = json.loads( - span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - ) - assert len(stored_messages) == 1 - assert stored_messages[0]["role"] == "user" - assert stored_messages[0]["content"] == "Hello, Claude" - assert ( - span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi! I'm Claude!" - ) + assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT + assert span["name"] == "chat model" + assert span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "anthropic" + assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - else: - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in span["attributes"] - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] + if send_default_pii: + assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS in span["attributes"] + system_instructions = json.loads( + span["attributes"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS] + ) + assert system_instructions == [ + {"type": "text", "content": "You are a helpful assistant."} + ] - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 10 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 20 - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True + assert SPANDATA.GEN_AI_REQUEST_MESSAGES in span["attributes"] + stored_messages = json.loads( + span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] + ) + assert len(stored_messages) == 1 + assert stored_messages[0]["role"] == "user" + assert stored_messages[0]["content"] == "Hello, Claude" + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi! I'm Claude!" else: - events = capture_events() - - with mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, start_transaction(name="anthropic"): - message = client.messages.create( - max_tokens=1024, - messages=messages, - model="model", - stream=True, - system="You are a helpful assistant.", - ) - - for _ in message: - pass - - assert len(events) == 1 - (event,) = events - - assert event["type"] == "transaction" - assert event["transaction"] == "anthropic" - - assert len(event["spans"]) == 1 - (span,) = event["spans"] - - assert span["op"] == OP.GEN_AI_CHAT - assert span["description"] == "chat model" - assert span["data"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["data"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["data"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - - if send_default_pii and include_prompts: - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS in span["data"] - system_instructions = json.loads( - span["data"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS] - ) - assert system_instructions == [ - {"type": "text", "content": "You are a helpful assistant."} - ] - - assert SPANDATA.GEN_AI_REQUEST_MESSAGES in span["data"] - stored_messages = json.loads(span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) - assert len(stored_messages) == 1 - assert stored_messages[0]["role"] == "user" - assert stored_messages[0]["content"] == "Hello, Claude" - assert span["data"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi! I'm Claude!" - - else: - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in span["data"] - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["data"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["data"] + assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in span["attributes"] + assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] + assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] - assert span["data"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["data"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 10 - assert span["data"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 20 - assert span["data"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True + assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 10 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 20 + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize( - "send_default_pii, include_prompts", - [ - (True, True), - (True, False), - (False, True), - (False, False), - ], + "send_default_pii", + [True, False], ) def test_stream_messages_with_system_prompt( sentry_init, - capture_events, capture_items, send_default_pii, - include_prompts, get_model_response, server_side_event_chunks, - stream_gen_ai_spans, - span_streaming, ): """Test that system prompts are properly captured in streaming mode.""" client = Anthropic(api_key="z") @@ -7042,12 +3894,10 @@ def test_stream_messages_with_system_prompt( ) sentry_init( - integrations=[AnthropicIntegration(include_prompts=include_prompts)], + integrations=[AnthropicIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) messages = [ @@ -7056,200 +3906,72 @@ def test_stream_messages_with_system_prompt( "content": "Hello, Claude", } ] + items = capture_items("span") - if span_streaming: - items = capture_items("transaction", "span") - - with mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, sentry_sdk.traces.start_span(name="anthropic"), client.messages.stream( - max_tokens=1024, - messages=messages, - model="model", - system="You are a helpful assistant.", - ) as stream: - for event in stream: - pass - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert len(spans) == 2 - - assert spans[1]["name"] == "anthropic" - (span, _) = spans - - assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - assert span["name"] == "chat model" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - - if send_default_pii and include_prompts: - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS in span["attributes"] - system_instructions = json.loads( - span["attributes"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS] - ) - assert system_instructions == [ - {"type": "text", "content": "You are a helpful assistant."} - ] - assert SPANDATA.GEN_AI_REQUEST_MESSAGES in span["attributes"] - stored_messages = json.loads( - span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - ) - assert len(stored_messages) == 1 - assert stored_messages[0]["role"] == "user" - assert stored_messages[0]["content"] == "Hello, Claude" - assert ( - span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi! I'm Claude!" - ) - else: - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in span["attributes"] - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] - - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 10 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 20 - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True - - elif stream_gen_ai_spans: - items = capture_items("transaction", "span") - - with mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, start_transaction(name="anthropic"), client.messages.stream( - max_tokens=1024, - messages=messages, - model="model", - system="You are a helpful assistant.", - ) as stream: - for event in stream: - pass + with mock.patch.object( + client._client, + "send", + return_value=response, + ), client.messages.stream( + max_tokens=1024, + messages=messages, + model="model", + system="You are a helpful assistant.", + ) as stream: + for event in stream: + pass - (event,) = (item.payload for item in items if item.type == "transaction") - assert event["transaction"] == "anthropic" + sentry_sdk.flush() + spans = [item.payload for item in items] + assert len(spans) == 1 - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert len(spans) == 1 - (span,) = spans + (span,) = spans - assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - assert span["name"] == "chat model" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" + assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT + assert span["name"] == "chat model" + assert span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "anthropic" + assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - if send_default_pii and include_prompts: - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS in span["attributes"] - system_instructions = json.loads( - span["attributes"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS] - ) - assert system_instructions == [ - {"type": "text", "content": "You are a helpful assistant."} - ] - assert SPANDATA.GEN_AI_REQUEST_MESSAGES in span["attributes"] - stored_messages = json.loads( - span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - ) - assert len(stored_messages) == 1 - assert stored_messages[0]["role"] == "user" - assert stored_messages[0]["content"] == "Hello, Claude" - assert ( - span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi! I'm Claude!" - ) - else: - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in span["attributes"] - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] - - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 10 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 20 - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True + if send_default_pii: + assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS in span["attributes"] + system_instructions = json.loads( + span["attributes"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS] + ) + assert system_instructions == [ + {"type": "text", "content": "You are a helpful assistant."} + ] + assert SPANDATA.GEN_AI_REQUEST_MESSAGES in span["attributes"] + stored_messages = json.loads( + span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] + ) + assert len(stored_messages) == 1 + assert stored_messages[0]["role"] == "user" + assert stored_messages[0]["content"] == "Hello, Claude" + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi! I'm Claude!" else: - events = capture_events() - - with mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, start_transaction(name="anthropic"), client.messages.stream( - max_tokens=1024, - messages=messages, - model="model", - system="You are a helpful assistant.", - ) as stream: - for event in stream: - pass - - assert len(events) == 1 - (event,) = events - - assert event["type"] == "transaction" - assert event["transaction"] == "anthropic" + assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in span["attributes"] + assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] + assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] - assert len(event["spans"]) == 1 - (span,) = event["spans"] + assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 10 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 20 + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True - assert span["op"] == OP.GEN_AI_CHAT - assert span["description"] == "chat model" - assert span["data"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["data"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["data"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - if send_default_pii and include_prompts: - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS in span["data"] - system_instructions = json.loads( - span["data"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS] - ) - assert system_instructions == [ - {"type": "text", "content": "You are a helpful assistant."} - ] - assert SPANDATA.GEN_AI_REQUEST_MESSAGES in span["data"] - stored_messages = json.loads(span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) - assert len(stored_messages) == 1 - assert stored_messages[0]["role"] == "user" - assert stored_messages[0]["content"] == "Hello, Claude" - assert span["data"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi! I'm Claude!" - else: - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in span["data"] - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["data"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["data"] - - assert span["data"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["data"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 10 - assert span["data"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 20 - assert span["data"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio @pytest.mark.parametrize( - "send_default_pii, include_prompts", - [ - (True, True), - (True, False), - (False, True), - (False, False), - ], + "send_default_pii", + [True, False], ) async def test_stream_message_with_system_prompt_async( sentry_init, - capture_events, capture_items, send_default_pii, - include_prompts, get_model_response, async_iterator, server_side_event_chunks, - stream_gen_ai_spans, - span_streaming, ): """Test that system prompts are properly captured in streaming mode (async).""" client = AsyncAnthropic(api_key="z") @@ -7294,12 +4016,10 @@ async def test_stream_message_with_system_prompt_async( ) sentry_init( - integrations=[AnthropicIntegration(include_prompts=include_prompts)], + integrations=[AnthropicIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) messages = [ @@ -7308,207 +4028,74 @@ async def test_stream_message_with_system_prompt_async( "content": "Hello, Claude", } ] + items = capture_items("span") + + with mock.patch.object( + client._client, + "send", + return_value=response, + ): + async with client.messages.stream( + max_tokens=1024, + messages=messages, + model="model", + system="You are a helpful assistant.", + ) as stream: + async for event in stream: + pass - if span_streaming: - items = capture_items("transaction", "span") - - with mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, sentry_sdk.traces.start_span(name="anthropic"): - async with client.messages.stream( - max_tokens=1024, - messages=messages, - model="model", - system="You are a helpful assistant.", - ) as stream: - async for event in stream: - pass - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert len(spans) == 2 - - assert spans[1]["name"] == "anthropic" - (span, _) = spans - - assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - assert span["name"] == "chat model" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - - if send_default_pii and include_prompts: - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS in span["attributes"] - system_instructions = json.loads( - span["attributes"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS] - ) - assert system_instructions == [ - {"type": "text", "content": "You are a helpful assistant."} - ] + sentry_sdk.flush() + spans = [item.payload for item in items] + assert len(spans) == 1 - assert SPANDATA.GEN_AI_REQUEST_MESSAGES in span["attributes"] - stored_messages = json.loads( - span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - ) - assert len(stored_messages) == 1 - assert stored_messages[0]["role"] == "user" - assert stored_messages[0]["content"] == "Hello, Claude" - assert ( - span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi! I'm Claude!" - ) - else: - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in span["attributes"] - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] - - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 10 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 20 - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True - - elif stream_gen_ai_spans: - items = capture_items("transaction", "span") - - with mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, start_transaction(name="anthropic"): - async with client.messages.stream( - max_tokens=1024, - messages=messages, - model="model", - system="You are a helpful assistant.", - ) as stream: - async for event in stream: - pass - - (event,) = (item.payload for item in items if item.type == "transaction") - assert event["transaction"] == "anthropic" - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert len(spans) == 1 - (span,) = spans - - assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - assert span["name"] == "chat model" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - - if send_default_pii and include_prompts: - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS in span["attributes"] - system_instructions = json.loads( - span["attributes"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS] - ) - assert system_instructions == [ - {"type": "text", "content": "You are a helpful assistant."} - ] + (span,) = spans - assert SPANDATA.GEN_AI_REQUEST_MESSAGES in span["attributes"] - stored_messages = json.loads( - span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - ) - assert len(stored_messages) == 1 - assert stored_messages[0]["role"] == "user" - assert stored_messages[0]["content"] == "Hello, Claude" - assert ( - span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi! I'm Claude!" - ) - else: - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in span["attributes"] - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] - - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 10 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 20 - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True - else: - events = capture_events() - - with mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, start_transaction(name="anthropic"): - async with client.messages.stream( - max_tokens=1024, - messages=messages, - model="model", - system="You are a helpful assistant.", - ) as stream: - async for event in stream: - pass - - assert len(events) == 1 - (event,) = events - - assert event["type"] == "transaction" - assert event["transaction"] == "anthropic" - - assert len(event["spans"]) == 1 - (span,) = event["spans"] - - assert span["op"] == OP.GEN_AI_CHAT - assert span["description"] == "chat model" - assert span["data"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["data"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["data"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - - if send_default_pii and include_prompts: - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS in span["data"] - system_instructions = json.loads( - span["data"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS] - ) - assert system_instructions == [ - {"type": "text", "content": "You are a helpful assistant."} - ] + assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT + assert span["name"] == "chat model" + assert span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "anthropic" + assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - assert SPANDATA.GEN_AI_REQUEST_MESSAGES in span["data"] - stored_messages = json.loads(span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) - assert len(stored_messages) == 1 - assert stored_messages[0]["role"] == "user" - assert stored_messages[0]["content"] == "Hello, Claude" - assert span["data"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi! I'm Claude!" + if send_default_pii: + assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS in span["attributes"] + system_instructions = json.loads( + span["attributes"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS] + ) + assert system_instructions == [ + {"type": "text", "content": "You are a helpful assistant."} + ] - else: - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in span["data"] - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["data"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["data"] + assert SPANDATA.GEN_AI_REQUEST_MESSAGES in span["attributes"] + stored_messages = json.loads( + span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] + ) + assert len(stored_messages) == 1 + assert stored_messages[0]["role"] == "user" + assert stored_messages[0]["content"] == "Hello, Claude" + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi! I'm Claude!" + else: + assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in span["attributes"] + assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] + assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] - assert span["data"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["data"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 10 - assert span["data"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 20 - assert span["data"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True + assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 10 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 20 + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio @pytest.mark.parametrize( - "send_default_pii, include_prompts", - [ - (True, True), - (True, False), - (False, True), - (False, False), - ], + "send_default_pii", + [True, False], ) async def test_streaming_create_message_with_system_prompt_async( sentry_init, - capture_events, capture_items, send_default_pii, - include_prompts, get_model_response, async_iterator, server_side_event_chunks, - stream_gen_ai_spans, - span_streaming, ): """Test that system prompts are properly captured in streaming mode (async).""" client = AsyncAnthropic(api_key="z") @@ -7553,12 +4140,10 @@ async def test_streaming_create_message_with_system_prompt_async( ) sentry_init( - integrations=[AnthropicIntegration(include_prompts=include_prompts)], + integrations=[AnthropicIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) messages = [ @@ -7567,210 +4152,76 @@ async def test_streaming_create_message_with_system_prompt_async( "content": "Hello, Claude", } ] + items = capture_items("span") + + with mock.patch.object( + client._client, + "send", + return_value=response, + ): + message = await client.messages.create( + max_tokens=1024, + messages=messages, + model="model", + stream=True, + system="You are a helpful assistant.", + ) - if span_streaming: - items = capture_items("transaction", "span") - - with mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, sentry_sdk.traces.start_span(name="anthropic"): - message = await client.messages.create( - max_tokens=1024, - messages=messages, - model="model", - stream=True, - system="You are a helpful assistant.", - ) - - async for _ in message: - pass - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - - assert spans[1]["name"] == "anthropic" - assert len(spans) == 2 - (span, _) = spans - - assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - assert span["name"] == "chat model" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - - if send_default_pii and include_prompts: - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS in span["attributes"] - system_instructions = json.loads( - span["attributes"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS] - ) - assert system_instructions == [ - {"type": "text", "content": "You are a helpful assistant."} - ] - - assert SPANDATA.GEN_AI_REQUEST_MESSAGES in span["attributes"] - stored_messages = json.loads( - span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - ) - - assert len(stored_messages) == 1 - assert stored_messages[0]["role"] == "user" - assert stored_messages[0]["content"] == "Hello, Claude" - assert ( - span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi! I'm Claude!" - ) - - else: - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in span["attributes"] - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] - - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 10 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 20 - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True - - elif stream_gen_ai_spans: - items = capture_items("transaction", "span") - - with mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, start_transaction(name="anthropic"): - message = await client.messages.create( - max_tokens=1024, - messages=messages, - model="model", - stream=True, - system="You are a helpful assistant.", - ) - - async for _ in message: - pass - - (event,) = (item.payload for item in items if item.type == "transaction") - assert event["transaction"] == "anthropic" + async for _ in message: + pass - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert len(spans) == 1 - (span,) = spans + sentry_sdk.flush() + spans = [item.payload for item in items] - assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - assert span["name"] == "chat model" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" + assert len(spans) == 1 + (span,) = spans - if send_default_pii and include_prompts: - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS in span["attributes"] - system_instructions = json.loads( - span["attributes"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS] - ) - assert system_instructions == [ - {"type": "text", "content": "You are a helpful assistant."} - ] + assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT + assert span["name"] == "chat model" + assert span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "anthropic" + assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - assert SPANDATA.GEN_AI_REQUEST_MESSAGES in span["attributes"] - stored_messages = json.loads( - span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - ) + if send_default_pii: + assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS in span["attributes"] + system_instructions = json.loads( + span["attributes"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS] + ) + assert system_instructions == [ + {"type": "text", "content": "You are a helpful assistant."} + ] - assert len(stored_messages) == 1 - assert stored_messages[0]["role"] == "user" - assert stored_messages[0]["content"] == "Hello, Claude" - assert ( - span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi! I'm Claude!" - ) + assert SPANDATA.GEN_AI_REQUEST_MESSAGES in span["attributes"] + stored_messages = json.loads( + span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] + ) - else: - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in span["attributes"] - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] + assert len(stored_messages) == 1 + assert stored_messages[0]["role"] == "user" + assert stored_messages[0]["content"] == "Hello, Claude" + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi! I'm Claude!" - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 10 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 20 - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True else: - events = capture_events() - - with mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, start_transaction(name="anthropic"): - message = await client.messages.create( - max_tokens=1024, - messages=messages, - model="model", - stream=True, - system="You are a helpful assistant.", - ) - - async for _ in message: - pass - - assert len(events) == 1 - (event,) = events - - assert event["type"] == "transaction" - assert event["transaction"] == "anthropic" + assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in span["attributes"] + assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] + assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] - assert len(event["spans"]) == 1 - (span,) = event["spans"] + assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 10 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 20 + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True - assert span["op"] == OP.GEN_AI_CHAT - assert span["description"] == "chat model" - assert span["data"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["data"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["data"][SPANDATA.GEN_AI_REQUEST_MODEL] == "model" - if send_default_pii and include_prompts: - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS in span["data"] - system_instructions = json.loads( - span["data"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS] - ) - assert system_instructions == [ - {"type": "text", "content": "You are a helpful assistant."} - ] - assert SPANDATA.GEN_AI_REQUEST_MESSAGES in span["data"] - stored_messages = json.loads(span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) - assert len(stored_messages) == 1 - assert stored_messages[0]["role"] == "user" - assert stored_messages[0]["content"] == "Hello, Claude" - assert span["data"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hi! I'm Claude!" - - else: - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in span["data"] - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["data"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["data"] - - assert span["data"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["data"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 10 - assert span["data"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 20 - assert span["data"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_system_prompt_with_complex_structure( sentry_init, - capture_events, capture_items, - stream_gen_ai_spans, - span_streaming, ): """Test that complex system prompt structures (list of text blocks) are properly captured.""" sentry_init( - integrations=[AnthropicIntegration(include_prompts=True)], + integrations=[AnthropicIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = Anthropic(api_key="z") @@ -7788,111 +4239,36 @@ def test_system_prompt_with_complex_structure( "content": "Hello", } ] + items = capture_items("span") - if span_streaming: - items = capture_items("span") - - with sentry_sdk.traces.start_span(name="anthropic"): - response = client.messages.create( - max_tokens=1024, messages=messages, model="model", system=system_prompt - ) - - assert response == EXAMPLE_MESSAGE - - sentry_sdk.flush() - spans = [item.payload for item in items] - assert len(spans) == 2 - - assert spans[1]["name"] == "anthropic" - (span, _) = spans - - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS in span["attributes"] - system_instructions = json.loads( - span["attributes"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS] - ) - - # System content should be a list of text blocks - assert isinstance(system_instructions, list) - assert system_instructions == [ - {"type": "text", "content": "You are a helpful assistant."}, - {"type": "text", "content": "Be concise and clear."}, - ] - - assert SPANDATA.GEN_AI_REQUEST_MESSAGES in span["attributes"] - stored_messages = json.loads( - span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - ) - - elif stream_gen_ai_spans: - items = capture_items("span") - - with start_transaction(name="anthropic"): - response = client.messages.create( - max_tokens=1024, messages=messages, model="model", system=system_prompt - ) - - assert response == EXAMPLE_MESSAGE - - sentry_sdk.flush() - spans = [item.payload for item in items] - assert len(spans) == 1 - (span,) = spans - - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS in span["attributes"] - system_instructions = json.loads( - span["attributes"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS] - ) - - # System content should be a list of text blocks - assert isinstance(system_instructions, list) - assert system_instructions == [ - {"type": "text", "content": "You are a helpful assistant."}, - {"type": "text", "content": "Be concise and clear."}, - ] - - assert SPANDATA.GEN_AI_REQUEST_MESSAGES in span["attributes"] - stored_messages = json.loads( - span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - ) - else: - events = capture_events() - - with start_transaction(name="anthropic"): - response = client.messages.create( - max_tokens=1024, messages=messages, model="model", system=system_prompt - ) + response = client.messages.create( + max_tokens=1024, messages=messages, model="model", system=system_prompt + ) - assert response == EXAMPLE_MESSAGE + assert response == EXAMPLE_MESSAGE - assert len(events) == 1 - (event,) = events + sentry_sdk.flush() + spans = [item.payload for item in items] - assert len(event["spans"]) == 1 - (span,) = event["spans"] + (span,) = spans - assert span["data"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" - assert span["data"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" + assert span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "anthropic" + assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS in span["data"] - system_instructions = json.loads( - span["data"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS] - ) + assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS in span["attributes"] + system_instructions = json.loads( + span["attributes"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS] + ) - # System content should be a list of text blocks - assert isinstance(system_instructions, list) - assert system_instructions == [ - {"type": "text", "content": "You are a helpful assistant."}, - {"type": "text", "content": "Be concise and clear."}, - ] + # System content should be a list of text blocks + assert isinstance(system_instructions, list) + assert system_instructions == [ + {"type": "text", "content": "You are a helpful assistant."}, + {"type": "text", "content": "Be concise and clear."}, + ] - assert SPANDATA.GEN_AI_REQUEST_MESSAGES in span["data"] - stored_messages = json.loads(span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) + assert SPANDATA.GEN_AI_REQUEST_MESSAGES in span["attributes"] + stored_messages = json.loads(span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) assert len(stored_messages) == 1 assert stored_messages[0]["role"] == "user" @@ -8052,382 +4428,25 @@ def test_transform_content_part_text_block(): "text": "Hello, world!", } - # Shared transform_content_part returns None for text blocks - result = transform_content_part(content_block) - - assert result is None - - -def test_transform_message_content_string(): - """Test that string content is returned as-is.""" - result = transform_message_content("Hello, world!") - assert result == "Hello, world!" - - -def test_transform_message_content_list_anthropic(): - """Test that list content with Anthropic format is transformed correctly.""" - content = [ - {"type": "text", "text": "Hello!"}, - { - "type": "image", - "source": { - "type": "base64", - "media_type": "image/png", - "data": "base64data...", - }, - }, - ] - - result = transform_message_content(content) - - assert len(result) == 2 - # Text block stays as-is (transform returns None, keeps original) - assert result[0] == {"type": "text", "text": "Hello!"} - assert result[1] == { - "type": "blob", - "modality": "image", - "mime_type": "image/png", - "content": "base64data...", - } - - -# Integration tests for binary data in messages - - -def test_message_with_base64_image(sentry_init, capture_events): - """Test that messages with base64 images are properly captured.""" - sentry_init( - integrations=[AnthropicIntegration(include_prompts=True)], - disabled_integrations=[StdlibIntegration], - traces_sample_rate=1.0, - send_default_pii=True, - stream_gen_ai_spans=False, - ) - events = capture_events() - client = Anthropic(api_key="z") - client.messages._post = mock.Mock(return_value=EXAMPLE_MESSAGE) - - messages = [ - { - "role": "user", - "content": [ - {"type": "text", "text": "What's in this image?"}, - { - "type": "image", - "source": { - "type": "base64", - "media_type": "image/jpeg", - "data": "base64encodeddatahere...", - }, - }, - ], - } - ] - - with start_transaction(name="anthropic"): - client.messages.create(max_tokens=1024, messages=messages, model="model") - - assert len(events) == 1 - (event,) = events - (span,) = event["spans"] - - assert SPANDATA.GEN_AI_REQUEST_MESSAGES in span["data"] - stored_messages = json.loads(span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) - - assert len(stored_messages) == 1 - assert stored_messages[0]["role"] == "user" - content = stored_messages[0]["content"] - assert len(content) == 2 - assert content[0] == {"type": "text", "text": "What's in this image?"} - assert content[1] == { - "type": "blob", - "modality": "image", - "mime_type": "image/jpeg", - "content": BLOB_DATA_SUBSTITUTE, - } - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) -def test_message_with_url_image( - sentry_init, - capture_events, - capture_items, - stream_gen_ai_spans, - span_streaming, -): - """Test that messages with URL-referenced images are properly captured.""" - sentry_init( - integrations=[AnthropicIntegration(include_prompts=True)], - disabled_integrations=[StdlibIntegration], - traces_sample_rate=1.0, - send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", - ) - - client = Anthropic(api_key="z") - client.messages._post = mock.Mock(return_value=EXAMPLE_MESSAGE) - - messages = [ - { - "role": "user", - "content": [ - {"type": "text", "text": "Describe this image."}, - { - "type": "image", - "source": { - "type": "url", - "url": "https://example.com/photo.png", - }, - }, - ], - } - ] - - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with start_transaction(name="anthropic"): - client.messages.create(max_tokens=1024, messages=messages, model="model") - - sentry_sdk.flush() - spans = [item.payload for item in items] - (span,) = spans - - stored_messages = json.loads( - span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - ) - else: - events = capture_events() - - with start_transaction(name="anthropic"): - client.messages.create(max_tokens=1024, messages=messages, model="model") - - assert len(events) == 1 - (event,) = events - (span,) = event["spans"] - - stored_messages = json.loads(span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) - - content = stored_messages[0]["content"] - assert content[1] == { - "type": "uri", - "modality": "image", - "mime_type": "", - "uri": "https://example.com/photo.png", - } - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) -def test_message_with_file_image( - sentry_init, - capture_events, - capture_items, - stream_gen_ai_spans, - span_streaming, -): - """Test that messages with file_id-referenced images are properly captured.""" - sentry_init( - integrations=[AnthropicIntegration(include_prompts=True)], - disabled_integrations=[StdlibIntegration], - traces_sample_rate=1.0, - send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", - ) - - client = Anthropic(api_key="z") - client.messages._post = mock.Mock(return_value=EXAMPLE_MESSAGE) - - messages = [ - { - "role": "user", - "content": [ - {"type": "text", "text": "What do you see?"}, - { - "type": "image", - "source": { - "type": "file", - "file_id": "file_img_12345", - "media_type": "image/webp", - }, - }, - ], - } - ] - - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with start_transaction(name="anthropic"): - client.messages.create(max_tokens=1024, messages=messages, model="model") - - sentry_sdk.flush() - spans = [item.payload for item in items] - (span,) = spans - - stored_messages = json.loads( - span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - ) - else: - events = capture_events() - - with start_transaction(name="anthropic"): - client.messages.create(max_tokens=1024, messages=messages, model="model") - - assert len(events) == 1 - (event,) = events - (span,) = event["spans"] - - stored_messages = json.loads(span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) - - content = stored_messages[0]["content"] - assert content[1] == { - "type": "file", - "modality": "image", - "mime_type": "image/webp", - "file_id": "file_img_12345", - } - - -def test_message_with_base64_pdf(sentry_init, capture_events): - """Test that messages with base64-encoded PDF documents are properly captured.""" - sentry_init( - integrations=[AnthropicIntegration(include_prompts=True)], - disabled_integrations=[StdlibIntegration], - traces_sample_rate=1.0, - send_default_pii=True, - stream_gen_ai_spans=False, - ) - events = capture_events() - client = Anthropic(api_key="z") - client.messages._post = mock.Mock(return_value=EXAMPLE_MESSAGE) - - messages = [ - { - "role": "user", - "content": [ - {"type": "text", "text": "Summarize this document."}, - { - "type": "document", - "source": { - "type": "base64", - "media_type": "application/pdf", - "data": "JVBERi0xLjQKJeLj...base64pdfdata", - }, - }, - ], - } - ] - - with start_transaction(name="anthropic"): - client.messages.create(max_tokens=1024, messages=messages, model="model") - - assert len(events) == 1 - (event,) = events - (span,) = event["spans"] - - stored_messages = json.loads(span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) - content = stored_messages[0]["content"] - assert content[1] == { - "type": "blob", - "modality": "document", - "mime_type": "application/pdf", - "content": BLOB_DATA_SUBSTITUTE, - } - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) -def test_message_with_url_pdf( - sentry_init, - capture_events, - capture_items, - stream_gen_ai_spans, - span_streaming, -): - """Test that messages with URL-referenced PDF documents are properly captured.""" - sentry_init( - integrations=[AnthropicIntegration(include_prompts=True)], - disabled_integrations=[StdlibIntegration], - traces_sample_rate=1.0, - send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", - ) - - client = Anthropic(api_key="z") - client.messages._post = mock.Mock(return_value=EXAMPLE_MESSAGE) - - messages = [ - { - "role": "user", - "content": [ - {"type": "text", "text": "What is in this PDF?"}, - { - "type": "document", - "source": { - "type": "url", - "url": "https://example.com/report.pdf", - }, - }, - ], - } - ] - - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with start_transaction(name="anthropic"): - client.messages.create(max_tokens=1024, messages=messages, model="model") - - sentry_sdk.flush() - spans = [item.payload for item in items] - (span,) = spans - - stored_messages = json.loads( - span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - ) - else: - events = capture_events() - - with start_transaction(name="anthropic"): - client.messages.create(max_tokens=1024, messages=messages, model="model") + # Shared transform_content_part returns None for text blocks + result = transform_content_part(content_block) - assert len(events) == 1 - (event,) = events - (span,) = event["spans"] + assert result is None - stored_messages = json.loads(span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) - content = stored_messages[0]["content"] - assert content[1] == { - "type": "uri", - "modality": "document", - "mime_type": "", - "uri": "https://example.com/report.pdf", - } +# Integration tests for binary data in messages -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) -def test_message_with_file_document( +def test_message_with_url_image( sentry_init, - capture_events, capture_items, - stream_gen_ai_spans, - span_streaming, ): - """Test that messages with file_id-referenced documents are properly captured.""" + """Test that messages with URL-referenced images are properly captured.""" sentry_init( - integrations=[AnthropicIntegration(include_prompts=True)], + integrations=[AnthropicIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = Anthropic(api_key="z") @@ -8437,63 +4456,48 @@ def test_message_with_file_document( { "role": "user", "content": [ - {"type": "text", "text": "Analyze this document."}, + {"type": "text", "text": "Describe this image."}, { - "type": "document", + "type": "image", "source": { - "type": "file", - "file_id": "file_doc_67890", - "media_type": "application/pdf", + "type": "url", + "url": "https://example.com/photo.png", }, }, ], } ] + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with start_transaction(name="anthropic"): - client.messages.create(max_tokens=1024, messages=messages, model="model") - - sentry_sdk.flush() - spans = [item.payload for item in items] - (span,) = spans - - stored_messages = json.loads( - span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - ) - else: - events = capture_events() - - with start_transaction(name="anthropic"): - client.messages.create(max_tokens=1024, messages=messages, model="model") + client.messages.create(max_tokens=1024, messages=messages, model="model") - assert len(events) == 1 - (event,) = events - (span,) = event["spans"] + sentry_sdk.flush() + spans = [item.payload for item in items] + (span,) = spans - stored_messages = json.loads(span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) + stored_messages = json.loads(span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) content = stored_messages[0]["content"] assert content[1] == { - "type": "file", - "modality": "document", - "mime_type": "application/pdf", - "file_id": "file_doc_67890", + "type": "uri", + "modality": "image", + "mime_type": "", + "uri": "https://example.com/photo.png", } -def test_message_with_mixed_content(sentry_init, capture_events): - """Test that messages with mixed content (text, images, documents) are properly captured.""" +def test_message_with_file_image( + sentry_init, + capture_items, +): + """Test that messages with file_id-referenced images are properly captured.""" sentry_init( - integrations=[AnthropicIntegration(include_prompts=True)], + integrations=[AnthropicIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=False, ) - events = capture_events() + client = Anthropic(api_key="z") client.messages._post = mock.Mock(return_value=EXAMPLE_MESSAGE) @@ -8501,84 +4505,49 @@ def test_message_with_mixed_content(sentry_init, capture_events): { "role": "user", "content": [ - {"type": "text", "text": "Compare this image with the document."}, - { - "type": "image", - "source": { - "type": "base64", - "media_type": "image/png", - "data": "iVBORw0KGgo...base64imagedata", - }, - }, + {"type": "text", "text": "What do you see?"}, { "type": "image", "source": { - "type": "url", - "url": "https://example.com/comparison.jpg", - }, - }, - { - "type": "document", - "source": { - "type": "base64", - "media_type": "application/pdf", - "data": "JVBERi0xLjQK...base64pdfdata", + "type": "file", + "file_id": "file_img_12345", + "media_type": "image/webp", }, }, - {"type": "text", "text": "Please provide a detailed analysis."}, ], } ] + items = capture_items("span") - with start_transaction(name="anthropic"): - client.messages.create(max_tokens=1024, messages=messages, model="model") + client.messages.create(max_tokens=1024, messages=messages, model="model") - assert len(events) == 1 - (event,) = events - (span,) = event["spans"] + sentry_sdk.flush() + spans = [item.payload for item in items] + (span,) = spans - stored_messages = json.loads(span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) - content = stored_messages[0]["content"] + stored_messages = json.loads(span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) - assert len(content) == 5 - assert content[0] == { - "type": "text", - "text": "Compare this image with the document.", - } + content = stored_messages[0]["content"] assert content[1] == { - "type": "blob", - "modality": "image", - "mime_type": "image/png", - "content": BLOB_DATA_SUBSTITUTE, - } - assert content[2] == { - "type": "uri", + "type": "file", "modality": "image", - "mime_type": "", - "uri": "https://example.com/comparison.jpg", - } - assert content[3] == { - "type": "blob", - "modality": "document", - "mime_type": "application/pdf", - "content": BLOB_DATA_SUBSTITUTE, - } - assert content[4] == { - "type": "text", - "text": "Please provide a detailed analysis.", + "mime_type": "image/webp", + "file_id": "file_img_12345", } -def test_message_with_multiple_images_different_formats(sentry_init, capture_events): - """Test that messages with multiple images of different source types are handled.""" +def test_message_with_url_pdf( + sentry_init, + capture_items, +): + """Test that messages with URL-referenced PDF documents are properly captured.""" sentry_init( - integrations=[AnthropicIntegration(include_prompts=True)], + integrations=[AnthropicIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=False, ) - events = capture_events() + client = Anthropic(api_key="z") client.messages._post = mock.Mock(return_value=EXAMPLE_MESSAGE) @@ -8586,83 +4555,46 @@ def test_message_with_multiple_images_different_formats(sentry_init, capture_eve { "role": "user", "content": [ + {"type": "text", "text": "What is in this PDF?"}, { - "type": "image", - "source": { - "type": "base64", - "media_type": "image/jpeg", - "data": "base64data1...", - }, - }, - { - "type": "image", + "type": "document", "source": { "type": "url", - "url": "https://example.com/img2.gif", - }, - }, - { - "type": "image", - "source": { - "type": "file", - "file_id": "file_img_789", - "media_type": "image/webp", + "url": "https://example.com/report.pdf", }, }, - {"type": "text", "text": "Compare these three images."}, ], } ] + items = capture_items("span") - with start_transaction(name="anthropic"): - client.messages.create(max_tokens=1024, messages=messages, model="model") + client.messages.create(max_tokens=1024, messages=messages, model="model") - assert len(events) == 1 - (event,) = events - (span,) = event["spans"] + sentry_sdk.flush() + spans = [item.payload for item in items] + (span,) = spans - stored_messages = json.loads(span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) - content = stored_messages[0]["content"] + stored_messages = json.loads(span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) - assert len(content) == 4 - assert content[0] == { - "type": "blob", - "modality": "image", - "mime_type": "image/jpeg", - "content": BLOB_DATA_SUBSTITUTE, - } + content = stored_messages[0]["content"] assert content[1] == { "type": "uri", - "modality": "image", + "modality": "document", "mime_type": "", - "uri": "https://example.com/img2.gif", - } - assert content[2] == { - "type": "file", - "modality": "image", - "mime_type": "image/webp", - "file_id": "file_img_789", + "uri": "https://example.com/report.pdf", } - assert content[3] == {"type": "text", "text": "Compare these three images."} -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) -def test_binary_content_not_stored_when_pii_disabled( +def test_message_with_file_document( sentry_init, - capture_events, capture_items, - stream_gen_ai_spans, - span_streaming, ): - """Test that binary content is not stored when send_default_pii is False.""" + """Test that messages with file_id-referenced documents are properly captured.""" sentry_init( - integrations=[AnthropicIntegration(include_prompts=True)], + integrations=[AnthropicIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, - send_default_pii=False, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", + send_default_pii=True, ) client = Anthropic(api_key="z") @@ -8672,62 +4604,47 @@ def test_binary_content_not_stored_when_pii_disabled( { "role": "user", "content": [ - {"type": "text", "text": "What's in this image?"}, + {"type": "text", "text": "Analyze this document."}, { - "type": "image", + "type": "document", "source": { - "type": "base64", - "media_type": "image/jpeg", - "data": "base64encodeddatahere...", + "type": "file", + "file_id": "file_doc_67890", + "media_type": "application/pdf", }, }, ], } ] + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with start_transaction(name="anthropic"): - client.messages.create(max_tokens=1024, messages=messages, model="model") - - sentry_sdk.flush() - spans = [item.payload for item in items] - (span,) = spans - - # Messages should not be stored - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] - else: - events = capture_events() + client.messages.create(max_tokens=1024, messages=messages, model="model") - with start_transaction(name="anthropic"): - client.messages.create(max_tokens=1024, messages=messages, model="model") + sentry_sdk.flush() + spans = [item.payload for item in items] + (span,) = spans - assert len(events) == 1 - (event,) = events - (span,) = event["spans"] + stored_messages = json.loads(span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) - # Messages should not be stored - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["data"] + content = stored_messages[0]["content"] + assert content[1] == { + "type": "file", + "modality": "document", + "mime_type": "application/pdf", + "file_id": "file_doc_67890", + } -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) -def test_binary_content_not_stored_when_prompts_disabled( +def test_binary_content_not_stored_when_pii_disabled( sentry_init, - capture_events, capture_items, - stream_gen_ai_spans, - span_streaming, ): - """Test that binary content is not stored when include_prompts is False.""" + """Test that binary content is not stored when send_default_pii is False.""" sentry_init( - integrations=[AnthropicIntegration(include_prompts=False)], + integrations=[AnthropicIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, - send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", + send_default_pii=False, ) client = Anthropic(api_key="z") @@ -8749,49 +4666,27 @@ def test_binary_content_not_stored_when_prompts_disabled( ], } ] + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with start_transaction(name="anthropic"): - client.messages.create(max_tokens=1024, messages=messages, model="model") - - sentry_sdk.flush() - spans = [item.payload for item in items] - (span,) = spans - - # Messages should not be stored - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] - else: - events = capture_events() - - with start_transaction(name="anthropic"): - client.messages.create(max_tokens=1024, messages=messages, model="model") + client.messages.create(max_tokens=1024, messages=messages, model="model") - assert len(events) == 1 - (event,) = events - (span,) = event["spans"] + sentry_sdk.flush() + spans = [item.payload for item in items] + (span,) = spans - # Messages should not be stored - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["data"] + # Messages should not be stored + assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_cache_tokens_nonstreaming( sentry_init, - capture_events, capture_items, - stream_gen_ai_spans, - span_streaming, ): """Test cache read/write tokens are tracked for non-streaming responses.""" sentry_init( integrations=[AnthropicIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = Anthropic(api_key="z") @@ -8811,52 +4706,27 @@ def test_cache_tokens_nonstreaming( ), ) ) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with start_transaction(name="anthropic"): - client.messages.create( - max_tokens=1024, - messages=[{"role": "user", "content": "Hello"}], - model="claude-3-5-sonnet-20241022", - ) - - sentry_sdk.flush() - (span,) = (item.payload for item in items) - # input_tokens normalized: 100 + 80 (cache_read) + 20 (cache_write) = 200 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 200 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 50 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 250 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHED] == 80 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHE_WRITE] == 20 - else: - events = capture_events() - - with start_transaction(name="anthropic"): - client.messages.create( - max_tokens=1024, - messages=[{"role": "user", "content": "Hello"}], - model="claude-3-5-sonnet-20241022", - ) + client.messages.create( + max_tokens=1024, + messages=[{"role": "user", "content": "Hello"}], + model="claude-3-5-sonnet-20241022", + ) - (span,) = events[0]["spans"] - # input_tokens normalized: 100 + 80 (cache_read) + 20 (cache_write) = 200 - assert span["data"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 200 - assert span["data"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 50 - assert span["data"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 250 - assert span["data"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHED] == 80 - assert span["data"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHE_WRITE] == 20 + sentry_sdk.flush() + (span,) = (item.payload for item in items) + # input_tokens normalized: 100 + 80 (cache_read) + 20 (cache_write) = 200 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 200 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 50 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 250 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] == 80 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS] == 20 -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_input_tokens_include_cache_write_nonstreaming( sentry_init, - capture_events, capture_items, - stream_gen_ai_spans, - span_streaming, ): """ Test that gen_ai.usage.input_tokens includes cache_write tokens (non-streaming). @@ -8873,8 +4743,6 @@ def test_input_tokens_include_cache_write_nonstreaming( integrations=[AnthropicIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = Anthropic(api_key="z") @@ -8894,56 +4762,27 @@ def test_input_tokens_include_cache_write_nonstreaming( ), ) ) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with start_transaction(name="anthropic"): - client.messages.create( - max_tokens=1024, - messages=[{"role": "user", "content": "What is 3+3?"}], - model="claude-sonnet-4-20250514", - ) - - sentry_sdk.flush() - (span,) = (item.payload for item in items) - - # input_tokens should be total: 19 (non-cached) + 2846 (cache_write) = 2865 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 2865 - assert ( - span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 2879 - ) # 2865 + 14 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHED] == 0 - assert ( - span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHE_WRITE] == 2846 - ) - else: - events = capture_events() - - with start_transaction(name="anthropic"): - client.messages.create( - max_tokens=1024, - messages=[{"role": "user", "content": "What is 3+3?"}], - model="claude-sonnet-4-20250514", - ) + client.messages.create( + max_tokens=1024, + messages=[{"role": "user", "content": "What is 3+3?"}], + model="claude-sonnet-4-20250514", + ) - (span,) = events[0]["spans"] + sentry_sdk.flush() + (span,) = (item.payload for item in items) - # input_tokens should be total: 19 (non-cached) + 2846 (cache_write) = 2865 - assert span["data"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 2865 - assert span["data"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 2879 # 2865 + 14 - assert span["data"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHED] == 0 - assert span["data"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHE_WRITE] == 2846 + # input_tokens should be total: 19 (non-cached) + 2846 (cache_write) = 2865 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 2865 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 2879 # 2865 + 14 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] == 0 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS] == 2846 -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_input_tokens_include_cache_read_nonstreaming( sentry_init, - capture_events, capture_items, - stream_gen_ai_spans, - span_streaming, ): """ Test that gen_ai.usage.input_tokens includes cache_read tokens (non-streaming). @@ -8960,8 +4799,6 @@ def test_input_tokens_include_cache_read_nonstreaming( integrations=[AnthropicIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = Anthropic(api_key="z") @@ -8981,56 +4818,29 @@ def test_input_tokens_include_cache_read_nonstreaming( ), ) ) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with start_transaction(name="anthropic"): - client.messages.create( - max_tokens=1024, - messages=[{"role": "user", "content": "What is 5+5?"}], - model="claude-sonnet-4-20250514", - ) - - sentry_sdk.flush() - (span,) = [item.payload for item in items] - - # input_tokens should be total: 19 (non-cached) + 2846 (cache_read) = 2865 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 2865 - assert ( - span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 2879 - ) # 2865 + 14 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHED] == 2846 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHE_WRITE] == 0 - else: - events = capture_events() - - with start_transaction(name="anthropic"): - client.messages.create( - max_tokens=1024, - messages=[{"role": "user", "content": "What is 5+5?"}], - model="claude-sonnet-4-20250514", - ) + client.messages.create( + max_tokens=1024, + messages=[{"role": "user", "content": "What is 5+5?"}], + model="claude-sonnet-4-20250514", + ) - (span,) = events[0]["spans"] + sentry_sdk.flush() + (span,) = [item.payload for item in items] - # input_tokens should be total: 19 (non-cached) + 2846 (cache_read) = 2865 - assert span["data"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 2865 - assert span["data"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 2879 # 2865 + 14 - assert span["data"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHED] == 2846 - assert span["data"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHE_WRITE] == 0 + # input_tokens should be total: 19 (non-cached) + 2846 (cache_read) = 2865 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 2865 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 2879 # 2865 + 14 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] == 2846 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS] == 0 -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_input_tokens_include_cache_read_streaming( sentry_init, - capture_events, capture_items, get_model_response, server_side_event_chunks, - stream_gen_ai_spans, - span_streaming, ): """ Test that gen_ai.usage.input_tokens includes cache_read tokens (streaming). @@ -9071,71 +4881,37 @@ def test_input_tokens_include_cache_read_streaming( integrations=[AnthropicIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", - ) - - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, start_transaction(name="anthropic"): - for _ in client.messages.create( - max_tokens=1024, - messages=[{"role": "user", "content": "What is 5+5?"}], - model="claude-sonnet-4-20250514", - stream=True, - ): - pass - - sentry_sdk.flush() - (span,) = (item.payload for item in items) - - # input_tokens should be total: 19 + 2846 = test_stream_messages_input_tokens_include_cache_read_streaming - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 2865 - assert ( - span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 2879 - ) # 2865 + 14 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHED] == 2846 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHE_WRITE] == 0 - else: - events = capture_events() - - with mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, start_transaction(name="anthropic"): - for _ in client.messages.create( - max_tokens=1024, - messages=[{"role": "user", "content": "What is 5+5?"}], - model="claude-sonnet-4-20250514", - stream=True, - ): - pass + ) + items = capture_items("span") + + with mock.patch.object( + client._client, + "send", + return_value=response, + ): + for _ in client.messages.create( + max_tokens=1024, + messages=[{"role": "user", "content": "What is 5+5?"}], + model="claude-sonnet-4-20250514", + stream=True, + ): + pass - (span,) = events[0]["spans"] + sentry_sdk.flush() + (span,) = (item.payload for item in items) - # input_tokens should be total: 19 + 2846 = test_stream_messages_input_tokens_include_cache_read_streaming - assert span["data"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 2865 - assert span["data"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 2879 # 2865 + 14 - assert span["data"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHED] == 2846 - assert span["data"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHE_WRITE] == 0 + # input_tokens should be total: 19 + 2846 = test_stream_messages_input_tokens_include_cache_read_streaming + assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 2865 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 2879 # 2865 + 14 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] == 2846 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS] == 0 -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_stream_messages_input_tokens_include_cache_read_streaming( sentry_init, - capture_events, capture_items, get_model_response, server_side_event_chunks, - stream_gen_ai_spans, - span_streaming, ): """ Test that gen_ai.usage.input_tokens includes cache_read tokens (streaming). @@ -9175,67 +4951,34 @@ def test_stream_messages_input_tokens_include_cache_read_streaming( integrations=[AnthropicIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, start_transaction(name="anthropic"), client.messages.stream( - max_tokens=1024, - messages=[{"role": "user", "content": "What is 5+5?"}], - model="claude-sonnet-4-20250514", - ) as stream: - for event in stream: - pass - - sentry_sdk.flush() - (span,) = (item.payload for item in items) - - # input_tokens should be total: 19 + 2846 = 2865 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 2865 - assert ( - span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 2879 - ) # 2865 + 14 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHED] == 2846 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHE_WRITE] == 0 - else: - events = capture_events() - - with mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, start_transaction(name="anthropic"), client.messages.stream( - max_tokens=1024, - messages=[{"role": "user", "content": "What is 5+5?"}], - model="claude-sonnet-4-20250514", - ) as stream: - for event in stream: - pass + with mock.patch.object( + client._client, + "send", + return_value=response, + ), client.messages.stream( + max_tokens=1024, + messages=[{"role": "user", "content": "What is 5+5?"}], + model="claude-sonnet-4-20250514", + ) as stream: + for event in stream: + pass - (span,) = events[0]["spans"] + sentry_sdk.flush() + (span,) = (item.payload for item in items) - # input_tokens should be total: 19 + 2846 = 2865 - assert span["data"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 2865 - assert span["data"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 2879 # 2865 + 14 - assert span["data"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHED] == 2846 - assert span["data"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHE_WRITE] == 0 + # input_tokens should be total: 19 + 2846 = 2865 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 2865 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 2879 # 2865 + 14 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] == 2846 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS] == 0 -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_input_tokens_unchanged_without_caching( sentry_init, - capture_events, capture_items, - stream_gen_ai_spans, - span_streaming, ): """ Test that input_tokens is unchanged when there are no cached tokens. @@ -9247,8 +4990,6 @@ def test_input_tokens_unchanged_without_caching( integrations=[AnthropicIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = Anthropic(api_key="z") @@ -9266,48 +5007,26 @@ def test_input_tokens_unchanged_without_caching( ), ) ) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with start_transaction(name="anthropic"): - client.messages.create( - max_tokens=1024, - messages=[{"role": "user", "content": "What is 2+2?"}], - model="claude-sonnet-4-20250514", - ) - - sentry_sdk.flush() - (span,) = (item.payload for item in items) - - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 20 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 32 # 20 + 12 - else: - events = capture_events() - - with start_transaction(name="anthropic"): - client.messages.create( - max_tokens=1024, - messages=[{"role": "user", "content": "What is 2+2?"}], - model="claude-sonnet-4-20250514", - ) + client.messages.create( + max_tokens=1024, + messages=[{"role": "user", "content": "What is 2+2?"}], + model="claude-sonnet-4-20250514", + ) - (span,) = events[0]["spans"] + sentry_sdk.flush() + (span,) = (item.payload for item in items) - assert span["data"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 20 - assert span["data"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 32 # 20 + 12 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 20 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 32 # 20 + 12 -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_cache_tokens_streaming( sentry_init, - capture_events, capture_items, get_model_response, server_side_event_chunks, - stream_gen_ai_spans, - span_streaming, ): """Test cache tokens are tracked for streaming responses.""" client = Anthropic(api_key="z") @@ -9344,69 +5063,37 @@ def test_cache_tokens_streaming( integrations=[AnthropicIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", - ) - - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, start_transaction(name="anthropic"): - for _ in client.messages.create( - max_tokens=1024, - messages=[{"role": "user", "content": "Hello"}], - model="claude-3-5-sonnet-20241022", - stream=True, - ): - pass - - sentry_sdk.flush() - (span,) = (item.payload for item in items) - # input_tokens normalized: 100 + 80 (cache_read) + 20 (cache_write) = 200 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 200 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 10 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 210 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHED] == 80 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHE_WRITE] == 20 - else: - events = capture_events() - - with mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, start_transaction(name="anthropic"): - for _ in client.messages.create( - max_tokens=1024, - messages=[{"role": "user", "content": "Hello"}], - model="claude-3-5-sonnet-20241022", - stream=True, - ): - pass + ) + items = capture_items("span") + + with mock.patch.object( + client._client, + "send", + return_value=response, + ): + for _ in client.messages.create( + max_tokens=1024, + messages=[{"role": "user", "content": "Hello"}], + model="claude-3-5-sonnet-20241022", + stream=True, + ): + pass - (span,) = events[0]["spans"] - # input_tokens normalized: 100 + 80 (cache_read) + 20 (cache_write) = 200 - assert span["data"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 200 - assert span["data"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 10 - assert span["data"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 210 - assert span["data"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHED] == 80 - assert span["data"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHE_WRITE] == 20 + sentry_sdk.flush() + (span,) = (item.payload for item in items) + # input_tokens normalized: 100 + 80 (cache_read) + 20 (cache_write) = 200 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 200 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 10 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 210 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] == 80 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS] == 20 -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_stream_messages_cache_tokens( sentry_init, - capture_events, capture_items, get_model_response, server_side_event_chunks, - stream_gen_ai_spans, - span_streaming, ): """Test cache tokens are tracked for streaming responses.""" client = Anthropic(api_key="z") @@ -9443,52 +5130,26 @@ def test_stream_messages_cache_tokens( integrations=[AnthropicIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, start_transaction(name="anthropic"), client.messages.stream( - max_tokens=1024, - messages=[{"role": "user", "content": "Hello"}], - model="claude-3-5-sonnet-20241022", - ) as stream: - for event in stream: - pass - - sentry_sdk.flush() - (span,) = (item.payload for item in items) - # input_tokens normalized: 100 + 80 (cache_read) + 20 (cache_write) = 200 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 200 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 10 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 210 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHED] == 80 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHE_WRITE] == 20 - else: - events = capture_events() - - with mock.patch.object( - client._client, - "send", - return_value=response, - ) as _, start_transaction(name="anthropic"), client.messages.stream( - max_tokens=1024, - messages=[{"role": "user", "content": "Hello"}], - model="claude-3-5-sonnet-20241022", - ) as stream: - for event in stream: - pass - - (span,) = events[0]["spans"] - # input_tokens normalized: 100 + 80 (cache_read) + 20 (cache_write) = 200 - assert span["data"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 200 - assert span["data"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 10 - assert span["data"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 210 - assert span["data"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHED] == 80 - assert span["data"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHE_WRITE] == 20 + with mock.patch.object( + client._client, + "send", + return_value=response, + ), client.messages.stream( + max_tokens=1024, + messages=[{"role": "user", "content": "Hello"}], + model="claude-3-5-sonnet-20241022", + ) as stream: + for event in stream: + pass + + sentry_sdk.flush() + (span,) = (item.payload for item in items) + # input_tokens normalized: 100 + 80 (cache_read) + 20 (cache_write) = 200 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 200 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 10 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 210 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] == 80 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS] == 20 diff --git a/tests/integrations/ariadne/test_ariadne.py b/tests/integrations/ariadne/test_ariadne.py index 6f8b3b5199..e4914c5b2d 100644 --- a/tests/integrations/ariadne/test_ariadne.py +++ b/tests/integrations/ariadne/test_ariadne.py @@ -45,153 +45,9 @@ def resolve_name(obj, *_): return make_executable_schema(type_defs, query) -def test_capture_request_and_response_if_send_pii_is_on_async( - sentry_init, capture_events -): - sentry_init( - send_default_pii=True, - integrations=[ - AriadneIntegration(), - FastApiIntegration(), - StarletteIntegration(), - ], - ) - events = capture_events() - - schema = schema_factory() - - async_app = FastAPI() - async_app.mount("/graphql/", GraphQL(schema)) - - query = {"query": "query ErrorQuery {error}"} - client = TestClient(async_app) - client.post("/graphql", json=query) - - assert len(events) == 1 - - (event,) = events - assert event["exception"]["values"][0]["mechanism"]["type"] == "ariadne" - assert event["contexts"]["response"] == { - "data": { - "data": {"error": None}, - "errors": [ - { - "locations": [{"column": 19, "line": 1}], - "message": "resolver failed", - "path": ["error"], - } - ], - } - } - assert event["request"]["api_target"] == "graphql" - assert event["request"]["data"] == query - - -def test_capture_request_and_response_if_send_pii_is_on_sync( - sentry_init, capture_events -): - sentry_init( - send_default_pii=True, - integrations=[AriadneIntegration(), FlaskIntegration()], - ) - events = capture_events() - - schema = schema_factory() - - sync_app = Flask(__name__) - - @sync_app.route("/graphql", methods=["POST"]) - def graphql_server(): - data = request.get_json() - success, result = graphql_sync(schema, data) - return jsonify(result), 200 - - query = {"query": "query ErrorQuery {error}"} - client = sync_app.test_client() - client.post("/graphql", json=query) - - assert len(events) == 1 - - (event,) = events - assert event["exception"]["values"][0]["mechanism"]["type"] == "ariadne" - assert event["contexts"]["response"] == { - "data": { - "data": {"error": None}, - "errors": [ - { - "locations": [{"column": 19, "line": 1}], - "message": "resolver failed", - "path": ["error"], - } - ], - } - } - assert event["request"]["api_target"] == "graphql" - assert event["request"]["data"] == query - - -def test_do_not_capture_request_and_response_if_send_pii_is_off_async( - sentry_init, capture_events -): - sentry_init( - integrations=[ - AriadneIntegration(), - FastApiIntegration(), - StarletteIntegration(), - ], - ) - events = capture_events() - - schema = schema_factory() - - async_app = FastAPI() - async_app.mount("/graphql/", GraphQL(schema)) - - query = {"query": "query ErrorQuery {error}"} - client = TestClient(async_app) - client.post("/graphql", json=query) - - assert len(events) == 1 - - (event,) = events - assert event["exception"]["values"][0]["mechanism"]["type"] == "ariadne" - assert "data" not in event["request"] - assert "response" not in event["contexts"] - - -def test_do_not_capture_request_and_response_if_send_pii_is_off_sync( - sentry_init, capture_events -): - sentry_init( - integrations=[AriadneIntegration(), FlaskIntegration()], - ) - events = capture_events() - - schema = schema_factory() - - sync_app = Flask(__name__) - - @sync_app.route("/graphql", methods=["POST"]) - def graphql_server(): - data = request.get_json() - success, result = graphql_sync(schema, data) - return jsonify(result), 200 - - query = {"query": "query ErrorQuery {error}"} - client = sync_app.test_client() - client.post("/graphql", json=query) - - assert len(events) == 1 - - (event,) = events - assert event["exception"]["values"][0]["mechanism"]["type"] == "ariadne" - assert "data" not in event["request"] - assert "response" not in event["contexts"] - - def test_capture_validation_error(sentry_init, capture_events): sentry_init( - send_default_pii=True, + data_collection={}, integrations=[ AriadneIntegration(), FastApiIntegration(), @@ -234,6 +90,7 @@ def test_no_event_if_no_errors_async(sentry_init, capture_events): FastApiIntegration(), StarletteIntegration(), ], + data_collection={}, ) events = capture_events() @@ -255,6 +112,7 @@ def test_no_event_if_no_errors_async(sentry_init, capture_events): def test_no_event_if_no_errors_sync(sentry_init, capture_events): sentry_init( integrations=[AriadneIntegration(), FlaskIntegration()], + data_collection={}, ) events = capture_events() @@ -310,80 +168,58 @@ def graphql_server(): return make_client -def _init_all_integrations(sentry_init, **kwargs): - sentry_init( - integrations=[ - AriadneIntegration(), - FlaskIntegration(), - FastApiIntegration(), - StarletteIntegration(), - ], - **kwargs, - ) - - @pytest.mark.parametrize( - "init_kwargs,expect_query,expect_variables", + "data_collection,expect_query,expect_variables", [ pytest.param( - {"data_collection": {}}, + {}, True, True, id="data_collection_defaults", ), pytest.param( - {"data_collection": {"graphql": {"document": True, "variables": True}}}, + {"graphql": {"document": True, "variables": True}}, True, True, id="document_on_variables_on", ), pytest.param( - {"data_collection": {"graphql": {"document": False}}}, + {"graphql": {"document": False}}, False, True, id="document_off_variables_on", ), pytest.param( - {"data_collection": {"graphql": {"variables": False}}}, + {"graphql": {"variables": False}}, True, False, id="document_on_variables_off", ), pytest.param( - {"data_collection": {"graphql": {"document": False, "variables": False}}}, + {"graphql": {"document": False, "variables": False}}, None, None, id="document_off_variables_off", ), - pytest.param( - { - "send_default_pii": True, - "data_collection": {"graphql": {"document": False}}, - }, - False, - True, - id="data_collection_takes_precedence_over_send_default_pii_on", - ), - pytest.param( - { - "send_default_pii": False, - "data_collection": {"graphql": {"document": True}}, - }, - True, - True, - id="data_collection_takes_precedence_over_send_default_pii_off", - ), ], ) def test_request_data_collection( sentry_init, capture_events, graphql_client, - init_kwargs, + data_collection, expect_query, expect_variables, ): - _init_all_integrations(sentry_init, **init_kwargs) + sentry_init( + integrations=[ + AriadneIntegration(), + FlaskIntegration(), + FastApiIntegration(), + StarletteIntegration(), + ], + data_collection=data_collection, + ) events = capture_events() graphql_client().post("/graphql", json=ERROR_QUERY_WITH_VARIABLES) @@ -411,10 +247,15 @@ def test_request_data_collection_body_out_of_bounds_still_collects_variables( dropped but variables (which are not subject to the bounds check) are still collected. """ - _init_all_integrations( - sentry_init, - max_request_body_size="small", + sentry_init( + integrations=[ + AriadneIntegration(), + FlaskIntegration(), + FastApiIntegration(), + StarletteIntegration(), + ], data_collection={}, + max_request_body_size="small", ) events = capture_events() @@ -443,8 +284,16 @@ def test_request_data_collection_body_out_of_bounds_still_collects_variables( def test_response_data_collection( sentry_init, capture_events, graphql_client, http_bodies, expect_response ): - data_collection = {} if http_bodies is None else {"http_bodies": http_bodies} - _init_all_integrations(sentry_init, data_collection=data_collection) + sentry_init( + integrations=[ + AriadneIntegration(), + FlaskIntegration(), + FastApiIntegration(), + StarletteIntegration(), + ], + data_collection={} if http_bodies is None else {"http_bodies": http_bodies}, + ) + events = capture_events() graphql_client().post("/graphql", json={"query": "query ErrorQuery {error}"}) diff --git a/tests/integrations/arq/test_arq.py b/tests/integrations/arq/test_arq.py index 5601c6dea3..cdf1723390 100644 --- a/tests/integrations/arq/test_arq.py +++ b/tests/integrations/arq/test_arq.py @@ -10,7 +10,7 @@ from fakeredis.aioredis import FakeRedis import sentry_sdk -from sentry_sdk import get_client, start_transaction +from sentry_sdk import get_client from sentry_sdk.consts import SPANDATA from sentry_sdk.integrations.arq import ArqIntegration from tests.integrations.utils import DATA_COLLECTION_QUEUES_CASES @@ -44,7 +44,6 @@ def info(self, section): @pytest.fixture def init_arq(sentry_init): def inner( - span_streaming, cls_functions=None, cls_cron_jobs=None, kw_functions=None, @@ -64,8 +63,7 @@ def inner( sentry_init_kwargs = { "integrations": [ArqIntegration()], "traces_sample_rate": 1.0, - "send_default_pii": True, - "trace_lifecycle": "stream" if span_streaming else "static", + "data_collection": {}, } sentry_init_kwargs.update(init_kwargs or {}) sentry_init(**sentry_init_kwargs) @@ -94,7 +92,6 @@ class WorkerSettings: @pytest.fixture def init_arq_with_dict_settings(sentry_init): def inner( - span_streaming, cls_functions=None, cls_cron_jobs=None, kw_functions=None, @@ -114,8 +111,7 @@ def inner( sentry_init_kwargs = { "integrations": [ArqIntegration()], "traces_sample_rate": 1.0, - "send_default_pii": True, - "trace_lifecycle": "stream" if span_streaming else "static", + "data_collection": {}, } sentry_init_kwargs.update(init_kwargs or {}) sentry_init(**sentry_init_kwargs) @@ -147,7 +143,6 @@ def init_arq_with_kwarg_settings(sentry_init): """Test fixture that passes settings_cls as keyword argument only.""" def inner( - span_streaming, cls_functions=None, cls_cron_jobs=None, kw_functions=None, @@ -167,8 +162,7 @@ def inner( sentry_init_kwargs = { "integrations": [ArqIntegration()], "traces_sample_rate": 1.0, - "send_default_pii": True, - "trace_lifecycle": "stream" if span_streaming else "static", + "data_collection": {}, } sentry_init_kwargs.update(init_kwargs or {}) sentry_init(**sentry_init_kwargs) @@ -200,8 +194,10 @@ class WorkerSettings: "init_arq_settings", ["init_arq", "init_arq_with_dict_settings", "init_arq_with_kwarg_settings"], ) -@pytest.mark.parametrize("span_streaming", [True, False]) -async def test_job_result(init_arq_settings, request, span_streaming): +async def test_job_result( + init_arq_settings, + request, +): async def increase(ctx, num): return num + 1 @@ -209,7 +205,7 @@ async def increase(ctx, num): increase.__qualname__ = increase.__name__ - pool, worker = init_fixture_method(span_streaming, [increase]) + pool, worker = init_fixture_method([increase]) job = await pool.enqueue_job("increase", 3) @@ -227,13 +223,10 @@ async def increase(ctx, num): @pytest.mark.parametrize( "init_arq_settings", ["init_arq", "init_arq_with_dict_settings"] ) -@pytest.mark.parametrize("span_streaming", [True, False]) async def test_job_retry( - capture_events, capture_items, init_arq_settings, request, - span_streaming, ): async def retry_job(ctx): if ctx["job_try"] < 2: @@ -243,52 +236,32 @@ async def retry_job(ctx): retry_job.__qualname__ = retry_job.__name__ - pool, worker = init_fixture_method(span_streaming, [retry_job]) + pool, worker = init_fixture_method([retry_job]) job = await pool.enqueue_job("retry_job") + items = capture_items("span") - if span_streaming: - items = capture_items("span") - - await worker.run_job(job.job_id, timestamp_ms()) - - sentry_sdk.flush() - spans = [item.payload for item in items] - - # The retry re-enqueue happens without an active span, so no producer - # (queue.submit.arq) span is created for it; only the consumer segment - # is emitted. The consumer segment is preceded by the redis spans for - # the re-enqueue, so it lands at index 2. - assert spans[2]["attributes"]["sentry.op"] == "queue.task.arq" - assert spans[2]["status"] == "ok" - assert spans[2]["name"] == "retry_job" - - await worker.run_job(job.job_id, timestamp_ms()) + await worker.run_job(job.job_id, timestamp_ms()) - sentry_sdk.flush() - spans = [item.payload for item in items] + sentry_sdk.flush() + spans = [item.payload for item in items] - assert spans[5]["attributes"]["sentry.op"] == "queue.task.arq" - assert spans[5]["status"] == "ok" - assert spans[5]["name"] == "retry_job" - else: - events = capture_events() + # The retry re-enqueue happens without an active span, so no producer + # (queue.submit.arq) span is created for it; only the consumer segment + # is emitted. The consumer segment is preceded by the redis spans for + # the re-enqueue, so it lands at index 2. + assert spans[2]["attributes"]["sentry.op"] == "queue.task.arq" + assert spans[2]["status"] == "ok" + assert spans[2]["name"] == "retry_job" - await worker.run_job(job.job_id, timestamp_ms()) - - event = events.pop(0) - assert event["contexts"]["trace"]["status"] == "aborted" - assert event["transaction"] == "retry_job" - assert event["tags"]["arq_task_id"] == job.job_id - assert event["extra"]["arq-job"]["retry"] == 1 + await worker.run_job(job.job_id, timestamp_ms()) - await worker.run_job(job.job_id, timestamp_ms()) + sentry_sdk.flush() + spans = [item.payload for item in items] - event = events.pop(0) - assert event["contexts"]["trace"]["status"] == "ok" - assert event["transaction"] == "retry_job" - assert event["tags"]["arq_task_id"] == job.job_id - assert event["extra"]["arq-job"]["retry"] == 2 + assert spans[5]["attributes"]["sentry.op"] == "queue.task.arq" + assert spans[5]["status"] == "ok" + assert spans[5]["name"] == "retry_job" @pytest.mark.parametrize( @@ -299,15 +272,12 @@ async def retry_job(ctx): "init_arq_settings", ["init_arq", "init_arq_with_dict_settings"] ) @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) -async def test_job_transaction( - capture_events, +async def test_worker_jobs( capture_items, init_arq_settings, source, job_fails, request, - span_streaming, ): async def division(_, a, b=0): return a / b @@ -323,138 +293,56 @@ async def division(_, a, b=0): functions_key, cron_jobs_key = source pool, worker = init_fixture_method( - span_streaming, **{functions_key: [division], cron_jobs_key: [cron_job]} + **{functions_key: [division], cron_jobs_key: [cron_job]} ) job = await pool.enqueue_job("division", 1, b=int(not job_fails)) + items = capture_items("event", "span") - if span_streaming: - items = capture_items("event", "span") - - await worker.run_job(job.job_id, timestamp_ms()) - - loop = asyncio.get_event_loop() - task = loop.create_task(worker.async_run()) - await asyncio.sleep(1) - - task.cancel() - - await worker.close() - - events = [item.payload for item in items if item.type == "event"] - if job_fails: - error_func_event = events.pop(0) - error_cron_event = events.pop(0) - - assert ( - error_func_event["exception"]["values"][0]["type"] - == "ZeroDivisionError" - ) - assert ( - error_func_event["exception"]["values"][0]["mechanism"]["type"] == "arq" - ) - - func_extra = error_func_event["extra"]["arq-job"] - assert func_extra["task"] == "division" - - assert ( - error_cron_event["exception"]["values"][0]["type"] - == "ZeroDivisionError" - ) - assert ( - error_cron_event["exception"]["values"][0]["mechanism"]["type"] == "arq" - ) - - cron_extra = error_cron_event["extra"]["arq-job"] - assert cron_extra["task"] == "cron:division" - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - - task_spans = [ - span - for span in spans - if span["attributes"].get("sentry.op") == "queue.task.arq" - ] - - division_span = next(span for span in task_spans if span["name"] == "division") - assert division_span["attributes"]["sentry.segment.name.source"] == "task" - assert ( - division_span["attributes"][SPANDATA.MESSAGING_DESTINATION_NAME] - == worker.queue_name - ) - - assert any(span["name"] == "cron:division" for span in task_spans) - else: - events = capture_events() - - await worker.run_job(job.job_id, timestamp_ms()) - - loop = asyncio.get_event_loop() - task = loop.create_task(worker.async_run()) - await asyncio.sleep(1) - - task.cancel() - - await worker.close() - - if job_fails: - error_func_event = events.pop(0) - error_cron_event = events.pop(1) - - assert ( - error_func_event["exception"]["values"][0]["type"] - == "ZeroDivisionError" - ) - assert ( - error_func_event["exception"]["values"][0]["mechanism"]["type"] == "arq" - ) + await worker.run_job(job.job_id, timestamp_ms()) - func_extra = error_func_event["extra"]["arq-job"] - assert func_extra["task"] == "division" + loop = asyncio.get_event_loop() + task = loop.create_task(worker.async_run()) + await asyncio.sleep(1) - assert ( - error_cron_event["exception"]["values"][0]["type"] - == "ZeroDivisionError" - ) - assert ( - error_cron_event["exception"]["values"][0]["mechanism"]["type"] == "arq" - ) + task.cancel() - cron_extra = error_cron_event["extra"]["arq-job"] - assert cron_extra["task"] == "cron:division" + await worker.close() - [func_event, cron_event] = events + events = [item.payload for item in items if item.type == "event"] + if job_fails: + error_func_event = events.pop(0) + error_cron_event = events.pop(0) - assert func_event["type"] == "transaction" - assert func_event["transaction"] == "division" - assert func_event["transaction_info"] == {"source": "task"} - assert ( - func_event["contexts"]["trace"]["data"][SPANDATA.MESSAGING_DESTINATION_NAME] - == worker.queue_name - ) + assert error_func_event["exception"]["values"][0]["type"] == "ZeroDivisionError" + assert error_func_event["exception"]["values"][0]["mechanism"]["type"] == "arq" - assert "arq_task_id" in func_event["tags"] - assert "arq_task_retry" in func_event["tags"] + func_extra = error_func_event["extra"]["arq-job"] + assert func_extra["task"] == "division" - func_extra = func_event["extra"]["arq-job"] + assert error_cron_event["exception"]["values"][0]["type"] == "ZeroDivisionError" + assert error_cron_event["exception"]["values"][0]["mechanism"]["type"] == "arq" - assert func_extra["task"] == "division" - assert func_extra["kwargs"] == {"b": int(not job_fails)} - assert func_extra["retry"] == 1 + cron_extra = error_cron_event["extra"]["arq-job"] + assert cron_extra["task"] == "cron:division" - assert cron_event["type"] == "transaction" - assert cron_event["transaction"] == "cron:division" - assert cron_event["transaction_info"] == {"source": "task"} + sentry_sdk.flush() + spans = [item.payload for item in items if item.type == "span"] - assert "arq_task_id" in cron_event["tags"] - assert "arq_task_retry" in cron_event["tags"] + task_spans = [ + span + for span in spans + if span["attributes"].get("sentry.op") == "queue.task.arq" + ] - cron_extra = cron_event["extra"]["arq-job"] + division_span = next(span for span in task_spans if span["name"] == "division") + assert division_span["attributes"]["sentry.segment.name.source"] == "task" + assert ( + division_span["attributes"][SPANDATA.MESSAGING_DESTINATION_NAME] + == worker.queue_name + ) - assert cron_extra["task"] == "cron:division" - assert cron_extra["kwargs"] == {} - assert cron_extra["retry"] == 1 + assert any(span["name"] == "cron:division" for span in task_spans) @pytest.mark.parametrize( @@ -462,12 +350,9 @@ async def division(_, a, b=0): DATA_COLLECTION_QUEUES_CASES, ) @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) async def test_job_args_kwargs_data_collection( - capture_events, capture_items, init_arq, - span_streaming, init_kwargs, expected_args, expected_kwargs, @@ -478,22 +363,15 @@ async def division(_, a, b=1): division.__qualname__ = division.__name__ pool, worker = init_arq( - span_streaming, cls_functions=[division], init_kwargs=init_kwargs, ) job = await pool.enqueue_job("division", 1, b=0) - - if span_streaming: - items = capture_items("event") - else: - events = capture_events() + items = capture_items("event") await worker.run_job(job.job_id, timestamp_ms()) - - if span_streaming: - events = [item.payload for item in items] + events = [item.payload for item in items] (event,) = [event for event in events if "exception" in event] @@ -514,60 +392,41 @@ async def division(_, a, b=1): "init_arq_settings", ["init_arq", "init_arq_with_dict_settings"] ) @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) async def test_enqueue_job( - capture_events, capture_items, init_arq_settings, source, request, - span_streaming, ): async def dummy_job(_): pass init_fixture_method = request.getfixturevalue(init_arq_settings) - pool, _ = init_fixture_method(span_streaming, **{source: [dummy_job]}) - - if span_streaming: - items = capture_items("span") + pool, _ = init_fixture_method(**{source: [dummy_job]}) + items = capture_items("span") - with sentry_sdk.traces.start_span(name="custom parent") as span: - await pool.enqueue_job("dummy_job") + with sentry_sdk.start_span(name="custom parent") as span: + await pool.enqueue_job("dummy_job") - sentry_sdk.flush() - spans = [item.payload for item in items] + sentry_sdk.flush() + spans = [item.payload for item in items] - assert spans[2]["is_segment"] is True - assert spans[2]["trace_id"] == span.trace_id - assert spans[2]["span_id"] == span.span_id + assert spans[2]["is_segment"] is True + assert spans[2]["trace_id"] == span.trace_id + assert spans[2]["span_id"] == span.span_id - assert spans[1]["attributes"]["sentry.op"] == "queue.submit.arq" - assert spans[1]["name"] == "dummy_job" - else: - events = capture_events() - - with start_transaction() as transaction: - await pool.enqueue_job("dummy_job") - - (event,) = events - - assert event["contexts"]["trace"]["trace_id"] == transaction.trace_id - assert event["contexts"]["trace"]["span_id"] == transaction.span_id - - assert len(event["spans"]) - assert event["spans"][0]["op"] == "queue.submit.arq" - assert event["spans"][0]["description"] == "dummy_job" + assert spans[1]["attributes"]["sentry.op"] == "queue.submit.arq" + assert spans[1]["name"] == "dummy_job" @pytest.mark.asyncio @pytest.mark.parametrize( "init_arq_settings", ["init_arq", "init_arq_with_dict_settings"] ) -@pytest.mark.parametrize("span_streaming", [True, False]) async def test_execute_job_without_integration( - init_arq_settings, request, span_streaming + init_arq_settings, + request, ): async def dummy_job(_ctx): pass @@ -576,7 +435,7 @@ async def dummy_job(_ctx): dummy_job.__qualname__ = dummy_job.__name__ - pool, worker = init_fixture_method(span_streaming, [dummy_job]) + pool, worker = init_fixture_method([dummy_job]) # remove the integration to trigger the edge case get_client().integrations.pop("arq") @@ -592,54 +451,37 @@ async def dummy_job(_ctx): "init_arq_settings", ["init_arq", "init_arq_with_dict_settings"] ) @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) async def test_span_origin_producer( - capture_events, capture_items, init_arq_settings, source, request, - span_streaming, ): async def dummy_job(_): pass init_fixture_method = request.getfixturevalue(init_arq_settings) - pool, _ = init_fixture_method(span_streaming, **{source: [dummy_job]}) - - if span_streaming: - items = capture_items("span") + pool, _ = init_fixture_method(**{source: [dummy_job]}) + items = capture_items("span") - with sentry_sdk.traces.start_span(name="custom parent"): - await pool.enqueue_job("dummy_job") + with sentry_sdk.start_span(name="custom parent"): + await pool.enqueue_job("dummy_job") - sentry_sdk.flush() - spans = [item.payload for item in items] - assert spans[2]["attributes"]["sentry.origin"] == "manual" - assert spans[1]["attributes"]["sentry.origin"] == "auto.queue.arq" - else: - events = capture_events() - - with start_transaction(): - await pool.enqueue_job("dummy_job") - - (event,) = events - assert event["contexts"]["trace"]["origin"] == "manual" - assert event["spans"][0]["origin"] == "auto.queue.arq" + sentry_sdk.flush() + spans = [item.payload for item in items] + assert spans[2]["attributes"]["sentry.origin"] == "manual" + assert spans[1]["attributes"]["sentry.origin"] == "auto.queue.arq" @pytest.mark.asyncio @pytest.mark.parametrize( "init_arq_settings", ["init_arq", "init_arq_with_dict_settings"] ) -@pytest.mark.parametrize("span_streaming", [True, False]) async def test_span_origin_consumer( - capture_events, capture_items, init_arq_settings, request, - span_streaming, ): async def job(ctx): pass @@ -648,46 +490,29 @@ async def job(ctx): job.__qualname__ = job.__name__ - pool, worker = init_fixture_method(span_streaming, [job]) - - if span_streaming: - job = await pool.enqueue_job("job") - - items = capture_items("span") - - await worker.run_job(job.job_id, timestamp_ms()) - - sentry_sdk.flush() - spans = [item.payload for item in items] - - # No producer (queue.submit.arq) span is created for the re-enqueue - # triggered by the retry, since it happens without an active span, so - # the consumer segment lands at index 2. - assert spans[2]["attributes"]["sentry.op"] == "queue.task.arq" - assert spans[2]["attributes"]["sentry.origin"] == "auto.queue.arq" - assert spans[1]["attributes"]["sentry.origin"] == "auto.db.redis" - assert spans[0]["attributes"]["sentry.origin"] == "auto.db.redis" - else: - job = await pool.enqueue_job("job") + pool, worker = init_fixture_method([job]) + job = await pool.enqueue_job("job") - events = capture_events() + items = capture_items("span") - await worker.run_job(job.job_id, timestamp_ms()) + await worker.run_job(job.job_id, timestamp_ms()) - (event,) = events + sentry_sdk.flush() + spans = [item.payload for item in items] - assert event["contexts"]["trace"]["origin"] == "auto.queue.arq" - assert event["spans"][0]["origin"] == "auto.db.redis" - assert event["spans"][1]["origin"] == "auto.db.redis" + # No producer (queue.submit.arq) span is created for the re-enqueue + # triggered by the retry, since it happens without an active span, so + # the consumer segment lands at index 2. + assert spans[2]["attributes"]["sentry.op"] == "queue.task.arq" + assert spans[2]["attributes"]["sentry.origin"] == "auto.queue.arq" + assert spans[1]["attributes"]["sentry.origin"] == "auto.db.redis" + assert spans[0]["attributes"]["sentry.origin"] == "auto.db.redis" @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) async def test_job_concurrency( - capture_events, capture_items, init_arq, - span_streaming, ): """ 10 - division starts @@ -707,7 +532,7 @@ async def division(_): sleepy.__qualname__ = sleepy.__name__ division.__qualname__ = division.__name__ - pool, worker = init_arq(span_streaming, [sleepy, division]) + pool, worker = init_arq([sleepy, division]) await pool.enqueue_job( "division", _job_id="123", _defer_by=timedelta(milliseconds=10) @@ -715,35 +540,19 @@ async def division(_): await pool.enqueue_job( "sleepy", _job_id="456", _defer_by=timedelta(milliseconds=70) ) + items = capture_items("event") - if span_streaming: - items = capture_items("event") - - loop = asyncio.get_event_loop() - task = loop.create_task(worker.async_run()) - await asyncio.sleep(1) - - task.cancel() - - await worker.close() - - events = [item.payload for item in items] - exception_event = events[0] - assert exception_event["exception"]["values"][0]["type"] == "ZeroDivisionError" - assert exception_event["transaction"] == "division" - else: - events = capture_events() - - loop = asyncio.get_event_loop() - task = loop.create_task(worker.async_run()) - await asyncio.sleep(1) + loop = asyncio.get_event_loop() + task = loop.create_task(worker.async_run()) + await asyncio.sleep(1) - task.cancel() + task.cancel() - await worker.close() + await worker.close() - (exception_event,) = (event for event in events if "exception" in event) - assert exception_event["exception"]["values"][0]["type"] == "ZeroDivisionError" - assert exception_event["transaction"] == "division" + events = [item.payload for item in items] + exception_event = events[0] + assert exception_event["exception"]["values"][0]["type"] == "ZeroDivisionError" + assert exception_event["transaction"] == "division" assert exception_event["extra"]["arq-job"]["task"] == "division" diff --git a/tests/integrations/asgi/test_asgi.py b/tests/integrations/asgi/test_asgi.py index 2de17ab15a..64e67bef05 100644 --- a/tests/integrations/asgi/test_asgi.py +++ b/tests/integrations/asgi/test_asgi.py @@ -10,7 +10,7 @@ _get_ip, ) from sentry_sdk.integrations.asgi import SentryAsgiMiddleware, _looks_like_asgi3 -from sentry_sdk.tracing import TransactionSource +from sentry_sdk.traces import SegmentNameSource @pytest.fixture @@ -134,7 +134,7 @@ async def app(scope, receive, send): def asgi3_custom_transaction_app(): async def app(scope, receive, send): sentry_sdk.get_current_scope().set_transaction_name( - "foobar", source=TransactionSource.CUSTOM + "foobar", source=SegmentNameSource.CUSTOM ) await send( { @@ -171,104 +171,61 @@ def test_invalid_transaction_style(asgi3_app): "should_send_pii", [True, False], ) -@pytest.mark.parametrize( - "span_streaming", - [True, False], -) async def test_capture_transaction( sentry_init, asgi3_app, - capture_events, capture_items, - span_streaming, should_send_pii, ): sentry_init( send_default_pii=should_send_pii, traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) app = SentryAsgiMiddleware(asgi3_app) async with TestClient(app) as client: - if span_streaming: - items = capture_items("span") - else: - events = capture_events() + items = capture_items("span") await client.get("/some_url?somevalue=123") sentry_sdk.flush() - if span_streaming: - assert len(items) == 1 - span = items[0].payload + assert len(items) == 1 + span = items[0].payload + + assert span["is_segment"] is True + assert span["name"] == "/some_url" - assert span["is_segment"] is True - assert span["name"] == "/some_url" + assert span["attributes"]["sentry.segment.name.source"] == "url" + assert span["attributes"]["sentry.op"] == "http.server" - assert span["attributes"]["sentry.segment.name.source"] == "url" - assert span["attributes"]["sentry.op"] == "http.server" + assert span["attributes"]["network.protocol.name"] == "http" + assert span["attributes"]["http.request.method"] == "GET" + assert span["attributes"]["http.request.header.host"] == "localhost" + assert span["attributes"]["http.request.header.remote-addr"] == "127.0.0.1" + assert span["attributes"]["http.request.header.user-agent"] == "ASGI-Test-Client" - assert span["attributes"]["network.protocol.name"] == "http" - assert span["attributes"]["http.request.method"] == "GET" - assert span["attributes"]["http.request.header.host"] == "localhost" - assert span["attributes"]["http.request.header.remote-addr"] == "127.0.0.1" + if should_send_pii: assert ( - span["attributes"]["http.request.header.user-agent"] == "ASGI-Test-Client" + span["attributes"]["url.full"] == "http://localhost/some_url?somevalue=123" ) - - if should_send_pii: - assert ( - span["attributes"]["url.full"] - == "http://localhost/some_url?somevalue=123" - ) - assert span["attributes"]["url.path"] == "/some_url" - assert span["attributes"]["http.query"] == "somevalue=123" - - else: - (transaction_event,) = events - - assert transaction_event["type"] == "transaction" - assert transaction_event["transaction"] == "/some_url" - assert transaction_event["transaction_info"] == {"source": "url"} - assert transaction_event["contexts"]["trace"]["op"] == "http.server" - assert transaction_event["request"] == { - "headers": { - "host": "localhost", - "remote-addr": "127.0.0.1", - "user-agent": "ASGI-Test-Client", - }, - "method": "GET", - "query_string": "somevalue=123", - "url": "http://localhost/some_url", - } + assert span["attributes"]["url.path"] == "/some_url" + assert span["attributes"]["http.query"] == "somevalue=123" @pytest.mark.asyncio -@pytest.mark.parametrize( - "span_streaming", - [True, False], -) async def test_capture_transaction_with_error( sentry_init, asgi3_app_with_error, - capture_events, capture_items, - DictionaryContaining, # noqa: N803 - span_streaming, ): sentry_init( send_default_pii=True, traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) app = SentryAsgiMiddleware(asgi3_app_with_error) - if span_streaming: - items = capture_items("event", "span") - else: - events = capture_events() + items = capture_items("event", "span") with pytest.raises(ZeroDivisionError): async with TestClient(app) as client: @@ -276,15 +233,12 @@ async def test_capture_transaction_with_error( sentry_sdk.flush() - if span_streaming: - assert len(items) == 2 - assert items[0].type == "event" - assert items[1].type == "span" + assert len(items) == 2 + assert items[0].type == "event" + assert items[1].type == "span" - error_event = items[0].payload - span_item = items[1].payload - else: - (error_event, transaction_event) = events + error_event = items[0].payload + span_item = items[1].payload assert error_event["transaction"] == "/some_url" assert error_event["transaction_info"] == {"source": "url"} @@ -294,92 +248,53 @@ async def test_capture_transaction_with_error( assert error_event["exception"]["values"][0]["mechanism"]["handled"] is False assert error_event["exception"]["values"][0]["mechanism"]["type"] == "asgi" - if span_streaming: - assert span_item["trace_id"] == error_event["contexts"]["trace"]["trace_id"] - assert span_item["span_id"] == error_event["contexts"]["trace"]["span_id"] - assert span_item.get("parent_span_id") == error_event["contexts"]["trace"].get( - "parent_span_id" - ) - assert span_item["status"] == "error" - - else: - assert transaction_event["type"] == "transaction" - assert transaction_event["contexts"]["trace"] == DictionaryContaining( - error_event["contexts"]["trace"] - ) - assert transaction_event["contexts"]["trace"]["status"] == "internal_error" - assert transaction_event["transaction"] == error_event["transaction"] - assert transaction_event["request"] == error_event["request"] + assert span_item["trace_id"] == error_event["contexts"]["trace"]["trace_id"] + assert span_item["span_id"] == error_event["contexts"]["trace"]["span_id"] + assert span_item.get("parent_span_id") == error_event["contexts"]["trace"].get( + "parent_span_id" + ) + assert span_item["status"] == "error" @pytest.mark.asyncio -@pytest.mark.parametrize( - "span_streaming", - [True, False], -) async def test_has_trace_if_performance_enabled( sentry_init, asgi3_app_with_error_and_msg, - capture_events, capture_items, - span_streaming, ): sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) app = SentryAsgiMiddleware(asgi3_app_with_error_and_msg) with pytest.raises(ZeroDivisionError): async with TestClient(app) as client: - if span_streaming: - items = capture_items("event", "span") - else: - events = capture_events() + items = capture_items("event", "span") await client.get("/") sentry_sdk.flush() - if span_streaming: - msg_event, error_event, span = items - - assert msg_event.type == "event" - msg_event = msg_event.payload - assert msg_event["contexts"]["trace"] - assert "trace_id" in msg_event["contexts"]["trace"] - - assert error_event.type == "event" - error_event = error_event.payload - assert error_event["contexts"]["trace"] - assert "trace_id" in error_event["contexts"]["trace"] + msg_event, error_event, span = items - assert span.type == "span" - span = span.payload - assert span["trace_id"] is not None - - assert ( - error_event["contexts"]["trace"]["trace_id"] - == msg_event["contexts"]["trace"]["trace_id"] - == span["trace_id"] - ) - - else: - msg_event, error_event, transaction_event = events - - assert msg_event["contexts"]["trace"] - assert "trace_id" in msg_event["contexts"]["trace"] + assert msg_event.type == "event" + msg_event = msg_event.payload + assert msg_event["contexts"]["trace"] + assert "trace_id" in msg_event["contexts"]["trace"] - assert error_event["contexts"]["trace"] - assert "trace_id" in error_event["contexts"]["trace"] + assert error_event.type == "event" + error_event = error_event.payload + assert error_event["contexts"]["trace"] + assert "trace_id" in error_event["contexts"]["trace"] - assert transaction_event["contexts"]["trace"] - assert "trace_id" in transaction_event["contexts"]["trace"] + assert span.type == "span" + span = span.payload + assert span["trace_id"] is not None - assert ( - error_event["contexts"]["trace"]["trace_id"] - == transaction_event["contexts"]["trace"]["trace_id"] - == msg_event["contexts"]["trace"]["trace_id"] - ) + assert ( + error_event["contexts"]["trace"]["trace_id"] + == msg_event["contexts"]["trace"]["trace_id"] + == span["trace_id"] + ) @pytest.mark.asyncio @@ -405,21 +320,14 @@ async def test_has_trace_if_performance_disabled( assert "trace_id" in error_event["contexts"]["trace"] -@pytest.mark.parametrize( - "span_streaming", - [True, False], -) @pytest.mark.asyncio async def test_trace_from_headers_if_performance_enabled( sentry_init, asgi3_app_with_error_and_msg, - capture_events, capture_items, - span_streaming, ): sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) app = SentryAsgiMiddleware(asgi3_app_with_error_and_msg) @@ -428,50 +336,30 @@ async def test_trace_from_headers_if_performance_enabled( with pytest.raises(ZeroDivisionError): async with TestClient(app) as client: - if span_streaming: - items = capture_items("event", "span") - else: - events = capture_events() + items = capture_items("event", "span") await client.get("/", headers={"sentry-trace": sentry_trace_header}) sentry_sdk.flush() - if span_streaming: - msg_event, error_event, span = items - - assert msg_event.type == "event" - msg_event = msg_event.payload - assert msg_event["contexts"]["trace"] - assert "trace_id" in msg_event["contexts"]["trace"] - - assert error_event.type == "event" - error_event = error_event.payload - assert error_event["contexts"]["trace"] - assert "trace_id" in error_event["contexts"]["trace"] - - assert span.type == "span" - span = span.payload - assert span["trace_id"] is not None - - assert msg_event["contexts"]["trace"]["trace_id"] == trace_id - assert error_event["contexts"]["trace"]["trace_id"] == trace_id - assert span["trace_id"] == trace_id - - else: - msg_event, error_event, transaction_event = events + msg_event, error_event, span = items - assert msg_event["contexts"]["trace"] - assert "trace_id" in msg_event["contexts"]["trace"] + assert msg_event.type == "event" + msg_event = msg_event.payload + assert msg_event["contexts"]["trace"] + assert "trace_id" in msg_event["contexts"]["trace"] - assert error_event["contexts"]["trace"] - assert "trace_id" in error_event["contexts"]["trace"] + assert error_event.type == "event" + error_event = error_event.payload + assert error_event["contexts"]["trace"] + assert "trace_id" in error_event["contexts"]["trace"] - assert transaction_event["contexts"]["trace"] - assert "trace_id" in transaction_event["contexts"]["trace"] + assert span.type == "span" + span = span.payload + assert span["trace_id"] is not None - assert msg_event["contexts"]["trace"]["trace_id"] == trace_id - assert error_event["contexts"]["trace"]["trace_id"] == trace_id - assert transaction_event["contexts"]["trace"]["trace_id"] == trace_id + assert msg_event["contexts"]["trace"]["trace_id"] == trace_id + assert error_event["contexts"]["trace"]["trace_id"] == trace_id + assert span["trace_id"] == trace_id @pytest.mark.asyncio @@ -503,22 +391,15 @@ async def test_trace_from_headers_if_performance_disabled( @pytest.mark.asyncio -@pytest.mark.parametrize( - "span_streaming", - [True, False], -) async def test_websocket( sentry_init, asgi3_ws_app, - capture_events, capture_items, request, - span_streaming, ): sentry_init( send_default_pii=True, traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) asgi3_ws_app = SentryAsgiMiddleware(asgi3_ws_app) @@ -527,55 +408,40 @@ async def test_websocket( with pytest.raises(ValueError): client = TestClient(asgi3_ws_app) - if span_streaming: - items = capture_items("event", "span") - else: - events = capture_events() + items = capture_items("event", "span") async with client.websocket_connect(request_url) as ws: await ws.receive_text() sentry_sdk.flush() - if span_streaming: - msg_event, error_event, span = items - - assert msg_event.type == "event" - msg_event = msg_event.payload - assert msg_event["transaction"] == request_url - assert msg_event["transaction_info"] == {"source": "url"} - assert msg_event["message"] == "Some message to the world!" + msg_event, error_event, span = items - assert error_event.type == "event" - error_event = error_event.payload - (exc,) = error_event["exception"]["values"] - assert exc["type"] == "ValueError" - assert exc["value"] == "Oh no" + assert msg_event.type == "event" + msg_event = msg_event.payload + assert msg_event["transaction"] == request_url + assert msg_event["transaction_info"] == {"source": "url"} + assert msg_event["message"] == "Some message to the world!" - assert span.type == "span" - span = span.payload - assert span["name"] == request_url - assert span["attributes"]["sentry.segment.name.source"] == "url" - - else: - msg_event, error_event, transaction_event = events + assert error_event.type == "event" + error_event = error_event.payload + (exc,) = error_event["exception"]["values"] + assert exc["type"] == "ValueError" + assert exc["value"] == "Oh no" - assert msg_event["transaction"] == request_url - assert msg_event["transaction_info"] == {"source": "url"} - assert msg_event["message"] == "Some message to the world!" - - (exc,) = error_event["exception"]["values"] - assert exc["type"] == "ValueError" - assert exc["value"] == "Oh no" - - assert transaction_event["transaction"] == request_url - assert transaction_event["transaction_info"] == {"source": "url"} + assert span.type == "span" + span = span.payload + assert span["name"] == request_url + assert span["attributes"]["sentry.segment.name.source"] == "url" @pytest.mark.asyncio async def test_auto_session_tracking_with_aggregates( sentry_init, asgi3_app, capture_envelopes ): - sentry_init(send_default_pii=True, traces_sample_rate=1.0) + sentry_init( + send_default_pii=True, + traces_sample_rate=1.0, + ) app = SentryAsgiMiddleware(asgi3_app) scope = { @@ -598,12 +464,15 @@ async def test_auto_session_tracking_with_aggregates( for envelope in envelopes: count_item_types[envelope.items[0].type] += 1 - assert count_item_types["transaction"] == 3 + assert count_item_types["span"] == 3 assert count_item_types["event"] == 1 assert count_item_types["sessions"] == 1 assert len(envelopes) == 5 - session_aggregates = envelopes[-1].items[0].payload.json["aggregates"] + (session,) = [ + envelope for envelope in envelopes if envelope.items[0].type == "sessions" + ] + session_aggregates = session.items[0].payload.json["aggregates"] assert session_aggregates[0]["exited"] == 2 assert session_aggregates[0]["crashed"] == 1 assert len(session_aggregates) == 1 @@ -626,26 +495,19 @@ async def test_auto_session_tracking_with_aggregates( ), ], ) -@pytest.mark.parametrize( - "span_streaming", - [True, False], -) @pytest.mark.asyncio async def test_transaction_style( sentry_init, asgi3_app, - capture_events, capture_items, url, transaction_style, expected_transaction, expected_source, - span_streaming, ): sentry_init( send_default_pii=True, traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) app = SentryAsgiMiddleware(asgi3_app, transaction_style=transaction_style) @@ -656,26 +518,16 @@ async def test_transaction_style( } async with TestClient(app, scope=scope) as client: - if span_streaming: - items = capture_items("span") - else: - events = capture_events() + items = capture_items("span") await client.get(url) sentry_sdk.flush() - if span_streaming: - assert len(items) == 1 - span = items[0].payload - - assert span["name"] == expected_transaction - assert span["attributes"]["sentry.segment.name.source"] == expected_source - - else: - (transaction_event,) = events + assert len(items) == 1 + span = items[0].payload - assert transaction_event["transaction"] == expected_transaction - assert transaction_event["transaction_info"] == {"source": expected_source} + assert span["name"] == expected_transaction + assert span["attributes"]["sentry.segment.name.source"] == expected_source def mock_asgi2_app(): @@ -822,34 +674,6 @@ def test_get_headers(): } -@pytest.mark.asyncio -async def test_get_request_data_url_with_filtered_host( - sentry_init, capture_events, asgi3_app -): - # allowlist mode in data collection that does not allow "host" scrubs the host - # header value, but the reported URL must still resolve rather than embedding the - # substituted "[Filtered]" value. - sentry_init( - traces_sample_rate=1.0, - data_collection={ - "http_headers": {"request": {"mode": "allowlist", "terms": []}} - }, - ) - app = SentryAsgiMiddleware(asgi3_app) - - events = capture_events() - scope = {"server": ("example.com", 80), "scheme": "http"} - async with TestClient(app, scope=scope) as client: - await client.get("/foo", headers={"host": "example.com"}) - - sentry_sdk.flush() - - (transaction_event,) = events - - assert transaction_event["request"]["headers"]["host"] == "[Filtered]" - assert transaction_event["request"]["url"] == "http://example.com/foo" - - @pytest.mark.asyncio async def test_get_request_attributes_url_with_filtered_host( sentry_init, capture_items, asgi3_app @@ -860,7 +684,6 @@ async def test_get_request_attributes_url_with_filtered_host( sentry_init( send_default_pii=True, traces_sample_rate=1.0, - trace_lifecycle="stream", data_collection={ "http_headers": {"request": {"mode": "allowlist", "terms": []}} }, @@ -890,7 +713,6 @@ async def test_get_request_attributes_url_with_headers_off( sentry_init( send_default_pii=True, traces_sample_rate=1.0, - trace_lifecycle="stream", data_collection={"http_headers": {"request": {"mode": "off"}}}, ) app = SentryAsgiMiddleware(asgi3_app) @@ -918,151 +740,32 @@ def _http_scope(): @pytest.mark.asyncio @pytest.mark.parametrize( - "init_kwargs, expected_query_string", - [ - pytest.param( - {"send_default_pii": True}, - QUERY_STRING, - id="send_default_pii_true", - ), - pytest.param( - {"send_default_pii": False}, - QUERY_STRING, - id="send_default_pii_false", - ), - pytest.param( - {}, - QUERY_STRING, - id="defaults", - ), - pytest.param( - {"data_collection": {}}, - "token=%5BFiltered%5D&theme=dark&lang=en&session=%5BFiltered%5D", - id="data_collection_denylist_default", - ), - pytest.param( - { - "data_collection": { - "url_query_params": {"mode": "denylist", "terms": ["theme"]} - } - }, - "token=%5BFiltered%5D&theme=%5BFiltered%5D&lang=en&session=%5BFiltered%5D", - id="data_collection_denylist_custom_terms", - ), - pytest.param( - { - "data_collection": { - "url_query_params": {"mode": "allowlist", "terms": ["theme"]} - } - }, - "token=%5BFiltered%5D&theme=dark&lang=%5BFiltered%5D&session=%5BFiltered%5D", - id="data_collection_allowlist", - ), - pytest.param( - { - "data_collection": { - "url_query_params": {"mode": "allowlist", "terms": ["token"]} - } - }, - "token=%5BFiltered%5D&theme=%5BFiltered%5D&lang=%5BFiltered%5D&session=%5BFiltered%5D", - id="data_collection_allowlist_sensitive_term", - ), - pytest.param( - {"data_collection": {"url_query_params": {"mode": "off"}}}, - None, - id="data_collection_off", - ), - # data_collection wins over send_default_pii: filtering still applies. - pytest.param( - { - "send_default_pii": True, - "data_collection": {"url_query_params": {"mode": "off"}}, - }, - None, - id="data_collection_wins_over_send_default_pii", - ), - ], -) -async def test_get_request_data_query_string_data_collection( - sentry_init, capture_events, asgi3_app, init_kwargs, expected_query_string -): - sentry_init(traces_sample_rate=1.0, **init_kwargs) - app = SentryAsgiMiddleware(asgi3_app) - - events = capture_events() - async with TestClient(app, scope=_http_scope()) as client: - await client.get(f"/foo?{QUERY_STRING}", headers={"host": "example.com"}) - - sentry_sdk.flush() - - (transaction_event,) = events - request_data = transaction_event["request"] - - if expected_query_string is None: - assert "query_string" not in request_data - else: - assert request_data["query_string"] == expected_query_string - - -@pytest.mark.asyncio -async def test_get_request_data_query_string_empty_legacy_is_none( - sentry_init, capture_events, asgi3_app -): - # Legacy path: the query string is always set even when empty (``None``). - sentry_init(send_default_pii=True, traces_sample_rate=1.0) - app = SentryAsgiMiddleware(asgi3_app) - - events = capture_events() - async with TestClient(app, scope=_http_scope()) as client: - await client.get("/foo", headers={"host": "example.com"}) - - sentry_sdk.flush() - - (transaction_event,) = events - assert transaction_event["request"]["query_string"] is None - - -@pytest.mark.asyncio -async def test_get_request_data_empty_query_string_dropped_with_data_collection( - sentry_init, capture_events, asgi3_app -): - sentry_init(traces_sample_rate=1.0, data_collection={}) - app = SentryAsgiMiddleware(asgi3_app) - - events = capture_events() - async with TestClient(app, scope=_http_scope()) as client: - await client.get("/foo", headers={"host": "example.com"}) - - sentry_sdk.flush() - - (transaction_event,) = events - assert "query_string" not in transaction_event["request"] - - -@pytest.mark.asyncio -@pytest.mark.parametrize( - "init_kwargs, expected_query, expected_url_full", + "init_kwargs, request_url, expected_query, expected_url_full", [ pytest.param( {"send_default_pii": True}, + "/foo?" + QUERY_STRING, QUERY_STRING, "http://example.com/foo?" + QUERY_STRING, id="send_default_pii_true", ), pytest.param( {"send_default_pii": False}, + "/foo?" + QUERY_STRING, None, None, id="send_default_pii_false", ), pytest.param( {}, + "/foo?" + QUERY_STRING, None, None, id="defaults", ), pytest.param( {"data_collection": {}}, + "/foo?" + QUERY_STRING, "token=%5BFiltered%5D&theme=dark&lang=en&session=%5BFiltered%5D", "http://example.com/foo?token=%5BFiltered%5D&theme=dark&lang=en&session=%5BFiltered%5D", id="data_collection_denylist_default", @@ -1073,12 +776,14 @@ async def test_get_request_data_empty_query_string_dropped_with_data_collection( "url_query_params": {"mode": "allowlist", "terms": ["theme"]} } }, + "/foo?" + QUERY_STRING, "token=%5BFiltered%5D&theme=dark&lang=%5BFiltered%5D&session=%5BFiltered%5D", "http://example.com/foo?token=%5BFiltered%5D&theme=dark&lang=%5BFiltered%5D&session=%5BFiltered%5D", id="data_collection_allowlist", ), pytest.param( {"data_collection": {"url_query_params": {"mode": "off"}}}, + "/foo?" + QUERY_STRING, None, "http://example.com/foo", id="data_collection_off", @@ -1088,10 +793,18 @@ async def test_get_request_data_empty_query_string_dropped_with_data_collection( "send_default_pii": True, "data_collection": {"url_query_params": {"mode": "off"}}, }, + "/foo?" + QUERY_STRING, None, "http://example.com/foo", id="data_collection_wins_over_send_default_pii", ), + pytest.param( + {"_experiments": {"data_collection": {}}}, + "/foo", + None, + "http://example.com/foo", + id="empty_query_string", + ), ], ) async def test_get_request_attributes_query_data_collection( @@ -1099,19 +812,19 @@ async def test_get_request_attributes_query_data_collection( capture_items, asgi3_app, init_kwargs, + request_url, expected_query, expected_url_full, ): sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream", **init_kwargs, ) app = SentryAsgiMiddleware(asgi3_app) items = capture_items("span") async with TestClient(app, scope=_http_scope()) as client: - await client.get(f"/foo?{QUERY_STRING}", headers={"host": "example.com"}) + await client.get(request_url, headers={"host": "example.com"}) sentry_sdk.flush() @@ -1174,33 +887,6 @@ async def test_get_request_attributes_query_data_collection( ] -@pytest.mark.asyncio -@pytest.mark.parametrize("init_kwargs, has_client, expect_ip", USER_INFO_CASES) -async def test_get_request_data_env_user_info( - sentry_init, capture_events, asgi3_app, init_kwargs, has_client, expect_ip -): - sentry_init(traces_sample_rate=1.0, **init_kwargs) - app = SentryAsgiMiddleware(asgi3_app) - - scope = _http_scope() - if has_client: - scope["client"] = ("127.0.0.1", 60457) - - events = capture_events() - async with TestClient(app, scope=scope) as client: - await client.get("/foo", headers={"host": "example.com"}) - - sentry_sdk.flush() - - (transaction_event,) = events - request_data = transaction_event["request"] - - if expect_ip: - assert request_data["env"] == {"REMOTE_ADDR": "127.0.0.1"} - else: - assert "env" not in request_data - - @pytest.mark.asyncio @pytest.mark.parametrize("init_kwargs, has_client, expect_ip", USER_INFO_CASES) async def test_get_request_attributes_client_address_user_info( @@ -1208,7 +894,6 @@ async def test_get_request_attributes_client_address_user_info( ): sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream", **init_kwargs, ) app = SentryAsgiMiddleware(asgi3_app) @@ -1250,10 +935,6 @@ async def test_get_request_attributes_client_address_user_info( ), ], ) -@pytest.mark.parametrize( - "span_streaming", - [True, False], -) async def test_transaction_name( sentry_init, request_url, @@ -1261,49 +942,31 @@ async def test_transaction_name( expected_transaction_name, expected_transaction_source, asgi3_app, - capture_envelopes, capture_items, - span_streaming, ): """ Tests that the transaction name is something meaningful. """ sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") - else: - envelopes = capture_envelopes() + items = capture_items("span") app = SentryAsgiMiddleware(asgi3_app, transaction_style=transaction_style) async with TestClient(app) as client: await client.get(request_url) - if span_streaming: - sentry_sdk.flush() - - assert len(items) == 1 - span = items[0].payload - - assert span["name"] == expected_transaction_name - assert ( - span["attributes"]["sentry.segment.name.source"] - == expected_transaction_source - ) + sentry_sdk.flush() - else: - (transaction_envelope,) = envelopes - transaction_event = transaction_envelope.get_transaction_event() + assert len(items) == 1 + span = items[0].payload - assert transaction_event["transaction"] == expected_transaction_name - assert ( - transaction_event["transaction_info"]["source"] - == expected_transaction_source - ) + assert span["name"] == expected_transaction_name + assert ( + span["attributes"]["sentry.segment.name.source"] == expected_transaction_source + ) @pytest.mark.asyncio @@ -1324,10 +987,6 @@ async def test_transaction_name( ), ], ) -@pytest.mark.parametrize( - "span_streaming", - [True, False], -) async def test_transaction_name_in_traces_sampler( sentry_init, request_url, @@ -1335,7 +994,6 @@ async def test_transaction_name_in_traces_sampler( expected_transaction_name, expected_transaction_source, asgi3_app, - span_streaming, ): """ Tests that a custom traces_sampler has a meaningful transaction name. @@ -1354,7 +1012,6 @@ def dummy_traces_sampler(sampling_context): sentry_init( traces_sampler=dummy_traces_sampler, traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) app = SentryAsgiMiddleware(asgi3_app, transaction_style=transaction_style) @@ -1364,45 +1021,28 @@ def dummy_traces_sampler(sampling_context): @pytest.mark.asyncio -@pytest.mark.parametrize( - "span_streaming", - [True, False], -) async def test_custom_transaction_name( sentry_init, asgi3_custom_transaction_app, - capture_events, capture_items, - span_streaming, ): sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) app = SentryAsgiMiddleware(asgi3_custom_transaction_app) async with TestClient(app) as client: - if span_streaming: - items = capture_items("span") - else: - events = capture_events() + items = capture_items("span") await client.get("/test") sentry_sdk.flush() - if span_streaming: - assert len(items) == 1 - span = items[0].payload - - assert span["is_segment"] is True - assert span["name"] == "foobar" - assert span["attributes"]["sentry.segment.name.source"] == "custom" + assert len(items) == 1 + span = items[0].payload - else: - (transaction_event,) = events - assert transaction_event["type"] == "transaction" - assert transaction_event["transaction"] == "foobar" - assert transaction_event["transaction_info"] == {"source": "custom"} + assert span["is_segment"] is True + assert span["name"] == "foobar" + assert span["attributes"]["sentry.segment.name.source"] == "custom" @pytest.mark.asyncio @@ -1452,7 +1092,7 @@ async def app(scope, receive, send): await send({"type": "lifespan.shutdown.complete"}) return - with sentry_sdk.traces.start_span(name="child-span"): + with sentry_sdk.start_span(name="child-span"): pass await send( @@ -1466,7 +1106,6 @@ async def app(scope, receive, send): kwargs = dict(init_kwargs) sentry_init( - trace_lifecycle="stream", traces_sample_rate=1.0, **kwargs, ) diff --git a/tests/integrations/asyncio/test_asyncio.py b/tests/integrations/asyncio/test_asyncio.py index 53917ac6d4..f085fede6a 100644 --- a/tests/integrations/asyncio/test_asyncio.py +++ b/tests/integrations/asyncio/test_asyncio.py @@ -63,12 +63,9 @@ def get_sentry_task_factory(mock_get_running_loop): @minimum_python_38 @pytest.mark.asyncio(loop_scope="module") -@pytest.mark.parametrize("span_streaming", [True, False]) async def test_create_task( sentry_init, - capture_events, capture_items, - span_streaming, ): sentry_init( traces_sample_rate=1.0, @@ -76,92 +73,50 @@ async def test_create_task( integrations=[ AsyncioIntegration(), ], - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") - - with sentry_sdk.traces.start_span( - name="not so important", attributes={"sentry.op": "root"} - ): - foo_task = asyncio.create_task(foo()) - bar_task = asyncio.create_task(bar()) - - if hasattr(foo_task.get_coro(), "__name__"): - assert foo_task.get_coro().__name__ == "foo" - if hasattr(bar_task.get_coro(), "__name__"): - assert bar_task.get_coro().__name__ == "bar" - - tasks = [foo_task, bar_task] + items = capture_items("span") - await asyncio.wait(tasks, return_when=asyncio.FIRST_EXCEPTION) - - else: - events = capture_events() - - with sentry_sdk.start_transaction(name="test_transaction_for_create_task"): - with sentry_sdk.start_span(op="root", name="not so important"): - foo_task = asyncio.create_task(foo()) - bar_task = asyncio.create_task(bar()) + with sentry_sdk.start_span( + name="not so important", attributes={"sentry.op": "root"} + ): + foo_task = asyncio.create_task(foo()) + bar_task = asyncio.create_task(bar()) - if hasattr(foo_task.get_coro(), "__name__"): - assert foo_task.get_coro().__name__ == "foo" - if hasattr(bar_task.get_coro(), "__name__"): - assert bar_task.get_coro().__name__ == "bar" + if hasattr(foo_task.get_coro(), "__name__"): + assert foo_task.get_coro().__name__ == "foo" + if hasattr(bar_task.get_coro(), "__name__"): + assert bar_task.get_coro().__name__ == "bar" - tasks = [foo_task, bar_task] + tasks = [foo_task, bar_task] - await asyncio.wait(tasks, return_when=asyncio.FIRST_EXCEPTION) + await asyncio.wait(tasks, return_when=asyncio.FIRST_EXCEPTION) sentry_sdk.flush() - if span_streaming: - segment = items.pop().payload + segment = items.pop().payload - assert segment["is_segment"] is True - assert segment["name"] == "not so important" - assert segment["attributes"]["sentry.op"] == "root" + assert segment["is_segment"] is True + assert segment["name"] == "not so important" + assert segment["attributes"]["sentry.op"] == "root" - spans = [item.payload for item in items] - assert len(spans) == 2 + spans = [item.payload for item in items] + assert len(spans) == 2 - assert spans[0]["attributes"]["sentry.op"] == OP.FUNCTION - assert spans[0]["name"] == "foo" - assert spans[0]["parent_span_id"] == segment["span_id"] + assert spans[0]["attributes"]["sentry.op"] == OP.FUNCTION + assert spans[0]["name"] == "foo" + assert spans[0]["parent_span_id"] == segment["span_id"] - assert spans[1]["attributes"]["sentry.op"] == OP.FUNCTION - assert spans[1]["name"] == "bar" - assert spans[1]["parent_span_id"] == segment["span_id"] - else: - (transaction_event,) = events - - assert transaction_event["spans"][0]["op"] == "root" - assert transaction_event["spans"][0]["description"] == "not so important" - - assert transaction_event["spans"][1]["op"] == OP.FUNCTION - assert transaction_event["spans"][1]["description"] == "foo" - assert ( - transaction_event["spans"][1]["parent_span_id"] - == transaction_event["spans"][0]["span_id"] - ) - - assert transaction_event["spans"][2]["op"] == OP.FUNCTION - assert transaction_event["spans"][2]["description"] == "bar" - assert ( - transaction_event["spans"][2]["parent_span_id"] - == transaction_event["spans"][0]["span_id"] - ) + assert spans[1]["attributes"]["sentry.op"] == OP.FUNCTION + assert spans[1]["name"] == "bar" + assert spans[1]["parent_span_id"] == segment["span_id"] @minimum_python_38 @pytest.mark.asyncio(loop_scope="module") -@pytest.mark.parametrize("span_streaming", [True, False]) async def test_gather( sentry_init, - capture_events, capture_items, - span_streaming, ): sentry_init( traces_sample_rate=1.0, @@ -169,61 +124,32 @@ async def test_gather( integrations=[ AsyncioIntegration(), ], - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") + items = capture_items("span") - with sentry_sdk.traces.start_span( - name="not so important", attributes={"sentry.op": "root"} - ): - await asyncio.gather(foo(), bar(), return_exceptions=True) - - else: - events = capture_events() - - with sentry_sdk.start_transaction(name="test_transaction_for_gather"): - with sentry_sdk.start_span(op="root", name="not so important"): - await asyncio.gather(foo(), bar(), return_exceptions=True) + with sentry_sdk.start_span( + name="not so important", attributes={"sentry.op": "root"} + ): + await asyncio.gather(foo(), bar(), return_exceptions=True) sentry_sdk.flush() - if span_streaming: - segment = items.pop().payload - assert segment["is_segment"] is True - assert segment["name"] == "not so important" - assert segment["attributes"]["sentry.op"] == "root" + segment = items.pop().payload + assert segment["is_segment"] is True + assert segment["name"] == "not so important" + assert segment["attributes"]["sentry.op"] == "root" - spans = [item.payload for item in items] - assert len(spans) == 2 + spans = [item.payload for item in items] + assert len(spans) == 2 - assert spans[0]["attributes"]["sentry.op"] == OP.FUNCTION - assert spans[0]["name"] == "foo" - assert spans[0]["parent_span_id"] == segment["span_id"] + assert spans[0]["attributes"]["sentry.op"] == OP.FUNCTION + assert spans[0]["name"] == "foo" + assert spans[0]["parent_span_id"] == segment["span_id"] - assert spans[1]["attributes"]["sentry.op"] == OP.FUNCTION - assert spans[1]["name"] == "bar" - assert spans[1]["parent_span_id"] == segment["span_id"] - else: - (transaction_event,) = events - - assert transaction_event["spans"][0]["op"] == "root" - assert transaction_event["spans"][0]["description"] == "not so important" - - assert transaction_event["spans"][1]["op"] == OP.FUNCTION - assert transaction_event["spans"][1]["description"] == "foo" - assert ( - transaction_event["spans"][1]["parent_span_id"] - == transaction_event["spans"][0]["span_id"] - ) - - assert transaction_event["spans"][2]["op"] == OP.FUNCTION - assert transaction_event["spans"][2]["description"] == "bar" - assert ( - transaction_event["spans"][2]["parent_span_id"] - == transaction_event["spans"][0]["span_id"] - ) + assert spans[1]["attributes"]["sentry.op"] == OP.FUNCTION + assert spans[1]["name"] == "bar" + assert spans[1]["parent_span_id"] == segment["span_id"] @minimum_python_38 @@ -242,14 +168,14 @@ async def test_exception( events = capture_events() - with sentry_sdk.start_transaction(name="test_exception"): - with sentry_sdk.start_span(op="root", name="not so important"): + with sentry_sdk.start_span(name="test_exception", parent_span=None): + with sentry_sdk.start_span(name="not so important"): tasks = [asyncio.create_task(boom()), asyncio.create_task(bar())] await asyncio.wait(tasks, return_when=asyncio.FIRST_EXCEPTION) sentry_sdk.flush() - (error_event, _) = events + (error_event,) = events assert error_event["transaction"] == "test_exception" assert error_event["contexts"]["trace"]["op"] == "function" @@ -449,63 +375,40 @@ def test_sentry_task_factory_context_with_factory(mock_get_running_loop): @minimum_python_38 @pytest.mark.asyncio(loop_scope="module") -@pytest.mark.parametrize("span_streaming", [True, False]) async def test_span_origin( sentry_init, - capture_events, capture_items, - span_streaming, ): sentry_init( integrations=[AsyncioIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") + items = capture_items("span") - with sentry_sdk.traces.start_span(name="something"): - tasks = [ - asyncio.create_task(foo()), - ] - await asyncio.wait(tasks, return_when=asyncio.FIRST_EXCEPTION) - - else: - events = capture_events() - - with sentry_sdk.start_transaction(name="something"): - tasks = [ - asyncio.create_task(foo()), - ] - await asyncio.wait(tasks, return_when=asyncio.FIRST_EXCEPTION) + with sentry_sdk.start_span(name="something"): + tasks = [ + asyncio.create_task(foo()), + ] + await asyncio.wait(tasks, return_when=asyncio.FIRST_EXCEPTION) sentry_sdk.flush() - if span_streaming: - segment = items.pop().payload - assert segment["is_segment"] is True - assert segment["attributes"]["sentry.origin"] == "manual" + segment = items.pop().payload + assert segment["is_segment"] is True + assert segment["attributes"]["sentry.origin"] == "manual" - spans = [item.payload for item in items] - assert len(spans) == 1 - assert spans[0]["attributes"]["sentry.origin"] == "auto.function.asyncio" - else: - (event,) = events - - assert event["contexts"]["trace"]["origin"] == "manual" - assert event["spans"][0]["origin"] == "auto.function.asyncio" + spans = [item.payload for item in items] + assert len(spans) == 1 + assert spans[0]["attributes"]["sentry.origin"] == "auto.function.asyncio" @minimum_python_38 @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) async def test_task_spans_false( sentry_init, - capture_events, capture_items, uninstall_integration, - span_streaming, ): uninstall_integration("asyncio") @@ -514,43 +417,29 @@ async def test_task_spans_false( integrations=[ AsyncioIntegration(task_spans=False), ], - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") - - with sentry_sdk.traces.start_span(name="test_no_spans"): - tasks = [asyncio.create_task(foo()), asyncio.create_task(bar())] - await asyncio.wait(tasks, return_when=asyncio.FIRST_EXCEPTION) - - else: - events = capture_events() + items = capture_items("span") - with sentry_sdk.start_transaction(name="test_no_spans"): - tasks = [asyncio.create_task(foo()), asyncio.create_task(bar())] - await asyncio.wait(tasks, return_when=asyncio.FIRST_EXCEPTION) + with sentry_sdk.start_span(name="test_no_spans"): + tasks = [asyncio.create_task(foo()), asyncio.create_task(bar())] + await asyncio.wait(tasks, return_when=asyncio.FIRST_EXCEPTION) sentry_sdk.flush() - if span_streaming: - segment = items.pop().payload - assert segment["is_segment"] is True - assert segment["name"] == "test_no_spans" + segment = items.pop().payload + assert segment["is_segment"] is True + assert segment["name"] == "test_no_spans" - spans = [item.payload for item in items] - assert len(spans) == 0 - else: - (transaction_event,) = events - - assert not transaction_event["spans"] + spans = [item.payload for item in items] + assert len(spans) == 0 @minimum_python_38 @pytest.mark.asyncio async def test_enable_asyncio_integration_with_task_spans_false( sentry_init, - capture_events, + capture_items, uninstall_integration, ): """ @@ -567,81 +456,61 @@ async def test_enable_asyncio_integration_with_task_spans_false( assert "asyncio" in sentry_sdk.get_client().integrations assert sentry_sdk.get_client().integrations["asyncio"].task_spans is False - events = capture_events() + items = capture_items("span") - with sentry_sdk.start_transaction(name="test"): + with sentry_sdk.start_span(name="test"): await asyncio.create_task(foo()) sentry_sdk.flush() - (transaction,) = events - assert not transaction["spans"] + segment = items.pop().payload + assert segment["is_segment"] is True + + spans = [item.payload for item in items] + assert len(spans) == 0 @minimum_python_38 @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) async def test_delayed_enable_integration( - sentry_init, capture_events, capture_items, span_streaming + sentry_init, + capture_items, ): sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) assert "asyncio" not in sentry_sdk.get_client().integrations - if span_streaming: - items = capture_items("span") + items = capture_items("span") - with sentry_sdk.traces.start_span(name="test"): - await asyncio.create_task(foo()) - - sentry_sdk.flush() - - assert len(items) == 1 - assert items[0].payload.get("is_segment") is True - - items.clear() + with sentry_sdk.start_span(name="test"): + await asyncio.create_task(foo()) - else: - events = capture_events() + sentry_sdk.flush() - with sentry_sdk.start_transaction(name="test"): - await asyncio.create_task(foo()) + assert len(items) == 1 + assert items[0].payload.get("is_segment") is True - assert len(events) == 1 - (transaction,) = events - assert not transaction["spans"] + items.clear() enable_asyncio_integration() assert "asyncio" in sentry_sdk.get_client().integrations - if span_streaming: - items = capture_items("span") - - with sentry_sdk.traces.start_span(name="test"): - await asyncio.create_task(foo()) + items = capture_items("span") - sentry_sdk.flush() - - segment = items.pop().payload - assert segment["is_segment"] is True + with sentry_sdk.start_span(name="test"): + await asyncio.create_task(foo()) - spans = [item.payload for item in items] - assert len(spans) == 1 - assert spans[0]["attributes"]["sentry.origin"] == "auto.function.asyncio" - else: - events = capture_events() + sentry_sdk.flush() - with sentry_sdk.start_transaction(name="test"): - await asyncio.create_task(foo()) + segment = items.pop().payload + assert segment["is_segment"] is True - assert len(events) == 1 - (transaction,) = events - assert transaction["spans"] - assert transaction["spans"][0]["origin"] == "auto.function.asyncio" + spans = [item.payload for item in items] + assert len(spans) == 1 + assert spans[0]["attributes"]["sentry.origin"] == "auto.function.asyncio" @minimum_python_38 @@ -694,83 +563,59 @@ async def test_delayed_enable_enabled_integration(sentry_init, uninstall_integra @minimum_python_38 @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) async def test_delayed_enable_integration_after_disabling( - sentry_init, capture_events, capture_items, span_streaming + sentry_init, + capture_items, ): sentry_init( disabled_integrations=[AsyncioIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) assert "asyncio" not in sentry_sdk.get_client().integrations - if span_streaming: - items = capture_items("span") - - with sentry_sdk.traces.start_span(name="test"): - await asyncio.create_task(foo()) + items = capture_items("span") - sentry_sdk.flush() - - assert len(items) == 1 - assert items[0].payload.get("is_segment") is True - - items.clear() + with sentry_sdk.start_span(name="test"): + await asyncio.create_task(foo()) - else: - events = capture_events() + sentry_sdk.flush() - with sentry_sdk.start_transaction(name="test"): - await asyncio.create_task(foo()) + assert len(items) == 1 + assert items[0].payload.get("is_segment") is True - assert len(events) == 1 - (transaction,) = events - assert not transaction["spans"] + items.clear() enable_asyncio_integration() assert "asyncio" in sentry_sdk.get_client().integrations - if span_streaming: - items = capture_items("span") + items = capture_items("span") - with sentry_sdk.traces.start_span(name="test"): - await asyncio.create_task(foo()) - - sentry_sdk.flush() - - segment = items.pop().payload - assert segment["is_segment"] is True + with sentry_sdk.start_span(name="test"): + await asyncio.create_task(foo()) - spans = [item.payload for item in items] - assert len(spans) == 1 - assert spans[0]["attributes"]["sentry.origin"] == "auto.function.asyncio" - else: - events = capture_events() + sentry_sdk.flush() - with sentry_sdk.start_transaction(name="test"): - await asyncio.create_task(foo()) + segment = items.pop().payload + assert segment["is_segment"] is True - assert len(events) == 1 - (transaction,) = events - assert transaction["spans"] - assert transaction["spans"][0]["origin"] == "auto.function.asyncio" + spans = [item.payload for item in items] + assert len(spans) == 1 + assert spans[0]["attributes"]["sentry.origin"] == "auto.function.asyncio" @minimum_python_39 @pytest.mark.asyncio(loop_scope="module") -@pytest.mark.parametrize("span_streaming", [True, False]) async def test_internal_tasks_not_wrapped( - sentry_init, capture_events, capture_items, span_streaming + sentry_init, + capture_items, ): from sentry_sdk.utils import mark_sentry_task_internal sentry_init( integrations=[AsyncioIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) async def user_task(): @@ -781,64 +626,31 @@ async def internal_task(): await asyncio.sleep(0.01) return "internal_result" - if span_streaming: - items = capture_items("span") - - with sentry_sdk.traces.start_span(name="test_streamed_span"): - user_task_obj = asyncio.create_task(user_task()) - - with mark_sentry_task_internal(): - internal_task_obj = asyncio.create_task(internal_task()) + items = capture_items("span") - user_result = await user_task_obj - internal_result = await internal_task_obj + with sentry_sdk.start_span(name="test_streamed_span"): + user_task_obj = asyncio.create_task(user_task()) - else: - events = capture_events() + with mark_sentry_task_internal(): + internal_task_obj = asyncio.create_task(internal_task()) - with sentry_sdk.start_transaction(name="test_transaction"): - user_task_obj = asyncio.create_task(user_task()) - - with mark_sentry_task_internal(): - internal_task_obj = asyncio.create_task(internal_task()) - - user_result = await user_task_obj - internal_result = await internal_task_obj + user_result = await user_task_obj + internal_result = await internal_task_obj assert user_result == "user_result" assert internal_result == "internal_result" sentry_sdk.flush() - if span_streaming: - assert len(items) == 2 - - segment = items.pop().payload - assert segment["is_segment"] is True - assert segment["name"] == "test_streamed_span" - - spans = [item.payload for item in items] - assert len(spans) == 1 - assert spans[0]["name"].endswith("user_task") - else: - assert len(events) == 1 - transaction = events[0] - - user_spans = [] - internal_spans = [] - - for span in transaction.get("spans", []): - if "user_task" in span.get("description", ""): - user_spans.append(span) - elif "internal_task" in span.get("description", ""): - internal_spans.append(span) - - assert len(user_spans) > 0, ( - f"User task should have been traced. All spans: {[s.get('description') for s in transaction.get('spans', [])]}" - ) - assert len(internal_spans) == 0, ( - f"Internal task should NOT have been traced. All spans: {[s.get('description') for s in transaction.get('spans', [])]}" - ) + assert len(items) == 2 + + segment = items.pop().payload + assert segment["is_segment"] is True + assert segment["name"] == "test_streamed_span" + + spans = [item.payload for item in items] + assert len(spans) == 1 + assert spans[0]["name"].endswith("user_task") @minimum_python_38 diff --git a/tests/integrations/asyncpg/test_asyncpg.py b/tests/integrations/asyncpg/test_asyncpg.py index 1991b9af05..83c49c66ac 100644 --- a/tests/integrations/asyncpg/test_asyncpg.py +++ b/tests/integrations/asyncpg/test_asyncpg.py @@ -12,6 +12,7 @@ import datetime import os from contextlib import contextmanager +from datetime import timezone from unittest import mock import asyncpg @@ -20,7 +21,7 @@ from asyncpg import Connection, connect import sentry_sdk -from sentry_sdk import capture_message, start_transaction +from sentry_sdk import capture_message from sentry_sdk.consts import OP, SPANDATA from sentry_sdk.integrations.asyncpg import AsyncPGIntegration from sentry_sdk.tracing_utils import record_sql_queries @@ -44,21 +45,6 @@ def _get_db_name(): PG_USER, PG_PASSWORD, PG_HOST, PG_NAME ) CRUMBS_CONNECT = { - "category": "query", - "data": ApproxDict( - { - "db.name": PG_NAME, - "db.system": "postgresql", - "db.user": PG_USER, - "db.driver.name": "asyncpg", - "server.address": PG_HOST, - "server.port": PG_PORT, - } - ), - "message": "connect", - "type": "default", -} -CRUMBS_CONNECT_STREAMING = { "category": "query", "data": ApproxDict( { @@ -110,22 +96,18 @@ async def _clean_pg(): @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) async def test_connect( - sentry_init, capture_events, capture_items, span_streaming + sentry_init, + capture_items, ) -> None: sentry_init( integrations=[AsyncPGIntegration()], - trace_lifecycle="stream" if span_streaming else "static", _experiments={ "record_sql_params": True, }, ) - if span_streaming: - items = capture_items("event") - else: - events = capture_events() + items = capture_items("event") conn: Connection = await connect(PG_CONNECTION_URI) @@ -133,37 +115,28 @@ async def test_connect( capture_message("hi") - if span_streaming: - event = items[0].payload - else: - (event,) = events + event = items[0].payload for crumb in event["breadcrumbs"]["values"]: del crumb["timestamp"] - expected_crumbs_connect = ( - CRUMBS_CONNECT_STREAMING if span_streaming else CRUMBS_CONNECT - ) + expected_crumbs_connect = CRUMBS_CONNECT assert event["breadcrumbs"]["values"] == [expected_crumbs_connect] @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) async def test_execute( - sentry_init, capture_events, capture_items, span_streaming + sentry_init, + capture_items, ) -> None: sentry_init( integrations=[AsyncPGIntegration()], - trace_lifecycle="stream" if span_streaming else "static", _experiments={ "record_sql_params": True, }, ) - if span_streaming: - items = capture_items("event") - else: - events = capture_events() + items = capture_items("event") conn: Connection = await connect(PG_CONNECTION_URI) @@ -188,17 +161,12 @@ async def test_execute( capture_message("hi") - if span_streaming: - event = items[0].payload - else: - (event,) = events + event = items[0].payload for crumb in event["breadcrumbs"]["values"]: del crumb["timestamp"] - expected_crumbs_connect = ( - CRUMBS_CONNECT_STREAMING if span_streaming else CRUMBS_CONNECT - ) + expected_crumbs_connect = CRUMBS_CONNECT assert event["breadcrumbs"]["values"] == [ expected_crumbs_connect, { @@ -229,22 +197,18 @@ async def test_execute( @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) async def test_execute_many( - sentry_init, capture_events, capture_items, span_streaming + sentry_init, + capture_items, ) -> None: sentry_init( integrations=[AsyncPGIntegration()], - trace_lifecycle="stream" if span_streaming else "static", _experiments={ "record_sql_params": True, }, ) - if span_streaming: - items = capture_items("event") - else: - events = capture_events() + items = capture_items("event") conn: Connection = await connect(PG_CONNECTION_URI) @@ -260,19 +224,13 @@ async def test_execute_many( capture_message("hi") - if span_streaming: - event = items[0].payload - else: - (event,) = events + event = items[0].payload for crumb in event["breadcrumbs"]["values"]: del crumb["timestamp"] - expected_crumbs_connect = ( - CRUMBS_CONNECT_STREAMING if span_streaming else CRUMBS_CONNECT - ) assert event["breadcrumbs"]["values"] == [ - expected_crumbs_connect, + CRUMBS_CONNECT, { "category": "query", "data": {"db.executemany": True}, @@ -346,7 +304,7 @@ async def test_cursor(sentry_init, capture_events) -> None: async for record in conn.cursor( "SELECT * FROM users WHERE dob > $1", datetime.date(1970, 1, 1) ): - print(record) + pass await conn.close() @@ -400,11 +358,9 @@ async def test_cursor_manual(sentry_init, capture_events) -> None: cur = await conn.cursor( "SELECT * FROM users WHERE dob > $1", datetime.date(1970, 1, 1) ) - record = await cur.fetchrow() - print(record) + await cur.fetchrow() while await cur.forward(1): - record = await cur.fetchrow() - print(record) + await cur.fetchrow() await conn.close() @@ -460,8 +416,8 @@ async def test_prepared_stmt(sentry_init, capture_events) -> None: stmt = await conn.prepare("SELECT * FROM users WHERE name = $1") - print(await stmt.fetchval("Bob")) - print(await stmt.fetchval("Alice")) + await stmt.fetchval("Bob") + await stmt.fetchval("Alice") await conn.close() @@ -555,60 +511,41 @@ async def test_connection_pool(sentry_init, capture_events) -> None: @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) async def test_query_source_disabled( - sentry_init, capture_events, capture_items, span_streaming + sentry_init, + capture_items, ): - sentry_options = { - "integrations": [AsyncPGIntegration()], - "traces_sample_rate": 1.0, - "enable_db_query_source": False, - "db_query_source_threshold_ms": 0, - "trace_lifecycle": "stream" if span_streaming else "static", - } - - sentry_init(**sentry_options) - - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="test_segment"): - conn: Connection = await connect(PG_CONNECTION_URI) - - await conn.execute( - "INSERT INTO users(name, password, dob) VALUES ('Alice', 'secret', '1990-12-25')", - ) - - await conn.close() - sentry_sdk.flush() + sentry_init( + integrations=[AsyncPGIntegration()], + traces_sample_rate=1.0, + enable_db_query_source=False, + db_query_source_threshold_ms=0, + ) - spans = [item.payload for item in items] + items = capture_items("span") + with sentry_sdk.start_span(name="test_segment"): + conn: Connection = await connect(PG_CONNECTION_URI) - assert len(spans) == 3 + await conn.execute( + "INSERT INTO users(name, password, dob) VALUES ('Alice', 'secret', '1990-12-25')", + ) - connect_span = spans[0] - insert_span = spans[1] - segment = spans[2] + await conn.close() - assert segment["name"] == "test_segment" - assert insert_span["name"].startswith("INSERT INTO") - assert connect_span["name"] == "connect" - data = insert_span.get("attributes", {}) - else: - events = capture_events() + sentry_sdk.flush() - with start_transaction(name="test_transaction", sampled=True): - conn: Connection = await connect(PG_CONNECTION_URI) + spans = [item.payload for item in items] - await conn.execute( - "INSERT INTO users(name, password, dob) VALUES ('Alice', 'secret', '1990-12-25')", - ) + assert len(spans) == 3 - await conn.close() + connect_span = spans[0] + insert_span = spans[1] + segment = spans[2] - (event,) = events - span = event["spans"][-1] - assert span["description"].startswith("INSERT INTO") - data = span.get("data", {}) + assert segment["name"] == "test_segment" + assert insert_span["name"].startswith("INSERT INTO") + assert connect_span["name"] == "connect" + data = insert_span.get("attributes", {}) assert SPANDATA.CODE_LINENO not in data assert SPANDATA.CODE_NAMESPACE not in data @@ -618,148 +555,82 @@ async def test_query_source_disabled( @pytest.mark.asyncio @pytest.mark.parametrize("enable_db_query_source", [None, True]) -@pytest.mark.parametrize("span_streaming", [True, False]) async def test_query_source_enabled( - sentry_init, capture_events, capture_items, enable_db_query_source, span_streaming + sentry_init, + capture_items, + enable_db_query_source, ): sentry_options = { "integrations": [AsyncPGIntegration()], "traces_sample_rate": 1.0, "db_query_source_threshold_ms": 0, - "trace_lifecycle": "stream" if span_streaming else "static", } if enable_db_query_source is not None: sentry_options["enable_db_query_source"] = enable_db_query_source sentry_init(**sentry_options) - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="test_segment"): - conn: Connection = await connect(PG_CONNECTION_URI) - - await conn.execute( - "INSERT INTO users(name, password, dob) VALUES ('Alice', 'secret', '1990-12-25')", - ) - - await conn.close() - sentry_sdk.flush() - - spans = [item.payload for item in items] + items = capture_items("span") + with sentry_sdk.start_span(name="test_segment"): + conn: Connection = await connect(PG_CONNECTION_URI) - assert len(spans) == 3 + await conn.execute( + "INSERT INTO users(name, password, dob) VALUES ('Alice', 'secret', '1990-12-25')", + ) - connect_span = spans[0] - insert_span = spans[1] - segment = spans[2] + await conn.close() - assert segment["name"] == "test_segment" - assert insert_span["name"].startswith("INSERT INTO") - assert connect_span["name"] == "connect" - data = insert_span.get("attributes", {}) - else: - events = capture_events() + sentry_sdk.flush() - with start_transaction(name="test_transaction", sampled=True): - conn: Connection = await connect(PG_CONNECTION_URI) + spans = [item.payload for item in items] - await conn.execute( - "INSERT INTO users(name, password, dob) VALUES ('Alice', 'secret', '1990-12-25')", - ) + assert len(spans) == 3 - await conn.close() + connect_span = spans[0] + insert_span = spans[1] + segment = spans[2] - (event,) = events - span = event["spans"][-1] - assert span["description"].startswith("INSERT INTO") - data = span.get("data", {}) + assert segment["name"] == "test_segment" + assert insert_span["name"].startswith("INSERT INTO") + assert connect_span["name"] == "connect" - lineno_key = "code.line.number" if span_streaming else SPANDATA.CODE_LINENO - filepath_key = "code.file.path" if span_streaming else SPANDATA.CODE_FILEPATH - - assert lineno_key in data - assert filepath_key in data - assert SPANDATA.CODE_NAMESPACE in data - assert SPANDATA.CODE_FUNCTION in data + _assert_query_source(insert_span, "test_query_source_enabled") @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) -async def test_query_source(sentry_init, capture_events, capture_items, span_streaming): +async def test_query_source(sentry_init, capture_items): sentry_init( integrations=[AsyncPGIntegration()], traces_sample_rate=1.0, enable_db_query_source=True, db_query_source_threshold_ms=0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="test_segment"): - conn: Connection = await connect(PG_CONNECTION_URI) - - await conn.execute( - "INSERT INTO users(name, password, dob) VALUES ('Alice', 'secret', '1990-12-25')", - ) - - await conn.close() - sentry_sdk.flush() - - spans = [item.payload for item in items] - - assert len(spans) == 3 - - connect_span = spans[0] - insert_span = spans[1] - segment = spans[2] - - assert segment["name"] == "test_segment" - assert insert_span["name"].startswith("INSERT INTO") - assert connect_span["name"] == "connect" - data = insert_span.get("attributes", {}) - else: - events = capture_events() - - with start_transaction(name="test_transaction", sampled=True): - conn: Connection = await connect(PG_CONNECTION_URI) - - await conn.execute( - "INSERT INTO users(name, password, dob) VALUES ('Alice', 'secret', '1990-12-25')", - ) + items = capture_items("span") + with sentry_sdk.start_span(name="test_segment"): + conn: Connection = await connect(PG_CONNECTION_URI) - await conn.close() + await conn.execute( + "INSERT INTO users(name, password, dob) VALUES ('Alice', 'secret', '1990-12-25')", + ) - (event,) = events - span = event["spans"][-1] - assert span["description"].startswith("INSERT INTO") - data = span.get("data", {}) + await conn.close() - lineno_key = "code.line.number" if span_streaming else SPANDATA.CODE_LINENO - filepath_key = "code.file.path" if span_streaming else SPANDATA.CODE_FILEPATH + sentry_sdk.flush() - assert lineno_key in data - assert filepath_key in data - assert SPANDATA.CODE_NAMESPACE in data - assert SPANDATA.CODE_FUNCTION in data + spans = [item.payload for item in items] - assert type(data.get(lineno_key)) == int - assert data.get(lineno_key) > 0 - assert ( - data.get(SPANDATA.CODE_NAMESPACE) == "tests.integrations.asyncpg.test_asyncpg" - ) - assert data.get(filepath_key).endswith("tests/integrations/asyncpg/test_asyncpg.py") + assert len(spans) == 3 - is_relative_path = data.get(filepath_key)[0] != os.sep - assert is_relative_path + _, insert_span, _ = spans - assert data.get(SPANDATA.CODE_FUNCTION) == "test_query_source" + _assert_query_source(insert_span, "test_query_source") @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) async def test_query_source_with_module_in_search_path( - sentry_init, capture_events, capture_items, span_streaming + sentry_init, + capture_items, ): """ Test that query source is relative to the path of the module it ran in @@ -769,156 +640,88 @@ async def test_query_source_with_module_in_search_path( traces_sample_rate=1.0, enable_db_query_source=True, db_query_source_threshold_ms=0, - trace_lifecycle="stream" if span_streaming else "static", ) from asyncpg_helpers.helpers import execute_query_in_connection - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="test_segment"): - conn: Connection = await connect(PG_CONNECTION_URI) - - await execute_query_in_connection( - "INSERT INTO users(name, password, dob) VALUES ('Alice', 'secret', '1990-12-25')", - conn, - ) - - await conn.close() - sentry_sdk.flush() - - spans = [item.payload for item in items] - - assert len(spans) == 3 - - connect_span = spans[0] - insert_span = spans[1] - segment = spans[2] - - assert segment["name"] == "test_segment" - assert insert_span["name"].startswith("INSERT INTO") - assert connect_span["name"] == "connect" - data = insert_span.get("attributes", {}) - else: - events = capture_events() + items = capture_items("span") + with sentry_sdk.start_span(name="test_segment"): + conn: Connection = await connect(PG_CONNECTION_URI) - with start_transaction(name="test_transaction", sampled=True): - conn: Connection = await connect(PG_CONNECTION_URI) + await execute_query_in_connection( + "INSERT INTO users(name, password, dob) VALUES ('Alice', 'secret', '1990-12-25')", + conn, + ) - await execute_query_in_connection( - "INSERT INTO users(name, password, dob) VALUES ('Alice', 'secret', '1990-12-25')", - conn, - ) + await conn.close() + sentry_sdk.flush() - await conn.close() + spans = [item.payload for item in items] - (event,) = events + assert len(spans) == 3 - span = event["spans"][-1] - assert span["description"].startswith("INSERT INTO") - data = span.get("data", {}) + connect_span = spans[0] + insert_span = spans[1] + segment = spans[2] - lineno_key = "code.line.number" if span_streaming else SPANDATA.CODE_LINENO - filepath_key = "code.file.path" if span_streaming else SPANDATA.CODE_FILEPATH + assert segment["name"] == "test_segment" + assert insert_span["name"].startswith("INSERT INTO") + assert connect_span["name"] == "connect" + data = insert_span.get("attributes", {}) - assert lineno_key in data - assert filepath_key in data + assert "code.line.number" in data + assert "code.file.path" in data assert SPANDATA.CODE_NAMESPACE in data assert SPANDATA.CODE_FUNCTION in data - assert type(data.get(lineno_key)) == int - assert data.get(lineno_key) > 0 - assert data.get(filepath_key) == "asyncpg_helpers/helpers.py" + assert type(data.get("code.line.number")) == int + assert data.get("code.line.number") > 0 + assert data.get("code.file.path") == "asyncpg_helpers/helpers.py" assert data.get(SPANDATA.CODE_NAMESPACE) == "asyncpg_helpers.helpers" - is_relative_path = data.get(filepath_key)[0] != os.sep + is_relative_path = data.get("code.file.path")[0] != os.sep assert is_relative_path assert data.get(SPANDATA.CODE_FUNCTION) == "execute_query_in_connection" @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) async def test_no_query_source_if_duration_too_short( - sentry_init, capture_events, capture_items, span_streaming + sentry_init, + capture_items, ): sentry_init( integrations=[AsyncPGIntegration()], traces_sample_rate=1.0, enable_db_query_source=True, - db_query_source_threshold_ms=100, - trace_lifecycle="stream" if span_streaming else "static", + db_query_source_threshold_ms=100000, ) - if span_streaming: - items = capture_items("span") - - @contextmanager - def fake_record_sql_queries_streaming(*args, **kwargs): - with record_sql_queries(*args, **kwargs) as span: - pass - span._start_timestamp = datetime.datetime(2024, 1, 1, microsecond=0) - if span_streaming: - span._end_timestamp = datetime.datetime(2024, 1, 1, microsecond=99999) - else: - span._timestamp = datetime.datetime(2024, 1, 1, microsecond=99999) - yield span - - with sentry_sdk.traces.start_span(name="test_segment"): - conn: Connection = await connect(PG_CONNECTION_URI) - - with mock.patch( - "sentry_sdk.integrations.asyncpg.record_sql_queries", - fake_record_sql_queries_streaming, - ): - await conn.execute( - "INSERT INTO users(name, password, dob) VALUES ('Alice', 'secret', '1990-12-25')", - ) - - await conn.close() - sentry_sdk.flush() - - spans = [item.payload for item in items] - - assert len(spans) == 3 + items = capture_items("span") - connect_span = spans[0] - insert_span = spans[1] - segment = spans[2] + with sentry_sdk.start_span(name="test_segment"): + conn: Connection = await connect(PG_CONNECTION_URI) - assert segment["name"] == "test_segment" - assert insert_span["name"].startswith("INSERT INTO") - assert connect_span["name"] == "connect" - data = insert_span.get("attributes", {}) - else: - events = capture_events() + await conn.execute( + "INSERT INTO users(name, password, dob) VALUES ('Alice', 'secret', '1990-12-25')", + ) - with start_transaction(name="test_transaction", sampled=True): - conn: Connection = await connect(PG_CONNECTION_URI) + await conn.close() - @contextmanager - def fake_record_sql_queries(*args, **kwargs): - with record_sql_queries(*args, **kwargs) as span: - pass - span.start_timestamp = datetime.datetime(2024, 1, 1, microsecond=0) - span.timestamp = datetime.datetime(2024, 1, 1, microsecond=99999) - yield span + sentry_sdk.flush() - with mock.patch( - "sentry_sdk.integrations.asyncpg.record_sql_queries", - fake_record_sql_queries, - ): - await conn.execute( - "INSERT INTO users(name, password, dob) VALUES ('Alice', 'secret', '1990-12-25')", - ) + spans = [item.payload for item in items] - await conn.close() + assert len(spans) == 3 - (event,) = events + connect_span = spans[0] + insert_span = spans[1] + segment = spans[2] - span = event["spans"][-1] - assert span["description"].startswith("INSERT INTO") - data = span.get("data", {}) + assert segment["name"] == "test_segment" + assert insert_span["name"].startswith("INSERT INTO") + assert connect_span["name"] == "connect" + data = insert_span.get("attributes", {}) assert SPANDATA.CODE_LINENO not in data assert SPANDATA.CODE_NAMESPACE not in data @@ -927,7 +730,7 @@ def fake_record_sql_queries(*args, **kwargs): @pytest.mark.asyncio -async def test_query_source_if_duration_over_threshold(sentry_init, capture_events): +async def test_query_source_if_duration_over_threshold(sentry_init, capture_items): sentry_init( integrations=[AsyncPGIntegration()], traces_sample_rate=1.0, @@ -935,18 +738,18 @@ async def test_query_source_if_duration_over_threshold(sentry_init, capture_even db_query_source_threshold_ms=100, ) - events = capture_events() + items = capture_items() - with start_transaction(name="test_transaction", sampled=True): + with sentry_sdk.start_span(name="test_segment"): conn: Connection = await connect(PG_CONNECTION_URI) @contextmanager def fake_record_sql_queries(*args, **kwargs): with record_sql_queries(*args, **kwargs) as span: - pass - span.start_timestamp = datetime.datetime(2024, 1, 1, microsecond=0) - span.timestamp = datetime.datetime(2024, 1, 1, microsecond=100001) - yield span + span._start_timestamp = datetime.datetime( + 2024, 1, 1, microsecond=0, tzinfo=timezone.utc + ) + yield span with mock.patch( "sentry_sdk.integrations.asyncpg.record_sql_queries", @@ -958,181 +761,71 @@ def fake_record_sql_queries(*args, **kwargs): await conn.close() - (event,) = events - - span = event["spans"][-1] - assert span["description"].startswith("INSERT INTO") + sentry_sdk.flush() - data = span.get("data", {}) + spans = [item.payload for item in items] - assert SPANDATA.CODE_LINENO in data - assert SPANDATA.CODE_NAMESPACE in data - assert SPANDATA.CODE_FILEPATH in data - assert SPANDATA.CODE_FUNCTION in data + assert len(spans) == 3 - assert type(data.get(SPANDATA.CODE_LINENO)) == int - assert data.get(SPANDATA.CODE_LINENO) > 0 - assert ( - data.get(SPANDATA.CODE_NAMESPACE) == "tests.integrations.asyncpg.test_asyncpg" - ) - assert data.get(SPANDATA.CODE_FILEPATH).endswith( - "tests/integrations/asyncpg/test_asyncpg.py" - ) + connect_span = spans[0] + insert_span = spans[1] + segment = spans[2] - is_relative_path = data.get(SPANDATA.CODE_FILEPATH)[0] != os.sep - assert is_relative_path + assert segment["name"] == "test_segment" + assert insert_span["name"].startswith("INSERT INTO") + assert connect_span["name"] == "connect" - assert ( - data.get(SPANDATA.CODE_FUNCTION) - == "test_query_source_if_duration_over_threshold" - ) + _assert_query_source(insert_span, "test_query_source_if_duration_over_threshold") @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) -async def test_span_origin(sentry_init, capture_events, capture_items, span_streaming): +async def test_span_origin(sentry_init, capture_items): sentry_init( integrations=[AsyncPGIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="test_segment"): - conn: Connection = await connect(PG_CONNECTION_URI) - - await conn.execute("SELECT 1") - await conn.fetchrow("SELECT 2") - await conn.close() - sentry_sdk.flush() - - spans = [item.payload for item in items] - - assert len(spans) == 4 - - connect_span = spans[0] - select1_span = spans[1] - select2_span = spans[2] - segment = spans[3] - - assert segment["name"] == "test_segment" - assert connect_span["name"] == "connect" - assert select1_span["name"] == "SELECT 1" - assert select2_span["name"] == "SELECT 2" + items = capture_items("span") + with sentry_sdk.start_span(name="test_segment"): + conn: Connection = await connect(PG_CONNECTION_URI) - assert segment["attributes"]["sentry.origin"] == "manual" - assert connect_span["attributes"]["sentry.origin"] == "auto.db.asyncpg" - assert select1_span["attributes"]["sentry.origin"] == "auto.db.asyncpg" - assert select2_span["attributes"]["sentry.origin"] == "auto.db.asyncpg" - else: - events = capture_events() + await conn.execute("SELECT 1") + await conn.fetchrow("SELECT 2") + await conn.close() + sentry_sdk.flush() - with start_transaction(name="test_transaction"): - conn: Connection = await connect(PG_CONNECTION_URI) + spans = [item.payload for item in items] - await conn.execute("SELECT 1") - await conn.fetchrow("SELECT 2") - await conn.close() + assert len(spans) == 4 - (event,) = events + connect_span = spans[0] + select1_span = spans[1] + select2_span = spans[2] + segment = spans[3] - assert event["contexts"]["trace"]["origin"] == "manual" + assert segment["name"] == "test_segment" + assert connect_span["name"] == "connect" + assert select1_span["name"] == "SELECT 1" + assert select2_span["name"] == "SELECT 2" - for span in event["spans"]: - assert span["origin"] == "auto.db.asyncpg" + assert segment["attributes"]["sentry.origin"] == "manual" + assert connect_span["attributes"]["sentry.origin"] == "auto.db.asyncpg" + assert select1_span["attributes"]["sentry.origin"] == "auto.db.asyncpg" + assert select2_span["attributes"]["sentry.origin"] == "auto.db.asyncpg" @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) async def test_multiline_query_description_normalized( - sentry_init, capture_events, capture_items, span_streaming -): - sentry_init( - integrations=[AsyncPGIntegration()], - traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", - ) - - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="test_segment"): - conn: Connection = await connect(PG_CONNECTION_URI) - await conn.execute( - """ - SELECT - id, - name - FROM - users - WHERE - name = 'Alice' - """ - ) - await conn.close() - sentry_sdk.flush() - - spans = [item.payload for item in items] - - assert len(spans) == 3 - - connect_span = spans[0] - select_span = spans[1] - segment = spans[2] - - assert segment["name"] == "test_segment" - assert connect_span["name"] == "connect" - assert select_span["name"] == "SELECT id, name FROM users WHERE name = 'Alice'" - else: - events = capture_events() - - with start_transaction(name="test_transaction"): - conn: Connection = await connect(PG_CONNECTION_URI) - await conn.execute( - """ - SELECT - id, - name - FROM - users - WHERE - name = 'Alice' - """ - ) - await conn.close() - - (event,) = events - - spans = [ - s - for s in event["spans"] - if s["op"] == "db" and "SELECT" in s.get("description", "") - ] - assert len(spans) == 1 - assert ( - spans[0]["description"] == "SELECT id, name FROM users WHERE name = 'Alice'" - ) - - -@pytest.mark.asyncio -async def test_before_send_transaction_sees_normalized_description( - sentry_init, capture_events + sentry_init, + capture_items, ): - def before_send_transaction(event, hint): - for span in event.get("spans", []): - desc = span.get("description", "") - if "SELECT id, name FROM users" in desc: - span["description"] = "filtered" - return event - sentry_init( integrations=[AsyncPGIntegration()], traces_sample_rate=1.0, - before_send_transaction=before_send_transaction, ) - events = capture_events() - with start_transaction(name="test_transaction"): + items = capture_items("span") + with sentry_sdk.start_span(name="test_segment"): conn: Connection = await connect(PG_CONNECTION_URI) await conn.execute( """ @@ -1141,213 +834,161 @@ def before_send_transaction(event, hint): name FROM users + WHERE + name = 'Alice' """ ) await conn.close() - (event,) = events - spans = [ - s - for s in event["spans"] - if s["op"] == "db" and "filtered" in s.get("description", "") - ] + sentry_sdk.flush() + + spans = [item.payload for item in items] - assert len(spans) == 1 - assert spans[0]["description"] == "filtered" + assert len(spans) == 3 + connect_span = spans[0] + select_span = spans[1] + segment = spans[2] -def _assert_query_source(span, span_streaming, expected_function): - if span_streaming: - data = span.get("attributes", {}) - lineno_key = "code.line.number" - filepath_key = "code.file.path" - else: - data = span.get("data", {}) - lineno_key = SPANDATA.CODE_LINENO - filepath_key = SPANDATA.CODE_FILEPATH + assert segment["name"] == "test_segment" + assert connect_span["name"] == "connect" + assert select_span["name"] == "SELECT id, name FROM users WHERE name = 'Alice'" - assert lineno_key in data - assert filepath_key in data + +def _assert_query_source(span, expected_function): + data = span.get("attributes", {}) + + assert "code.line.number" in data + assert "code.file.path" in data assert SPANDATA.CODE_NAMESPACE in data assert SPANDATA.CODE_FUNCTION in data - assert type(data.get(lineno_key)) == int - assert data.get(lineno_key) > 0 + assert type(data.get("code.line.number")) == int + assert data.get("code.line.number") > 0 assert data[SPANDATA.CODE_NAMESPACE] == "tests.integrations.asyncpg.test_asyncpg" - assert data.get(filepath_key).endswith("tests/integrations/asyncpg/test_asyncpg.py") - assert data.get(filepath_key)[0] != os.sep + assert data.get("code.file.path").endswith( + "tests/integrations/asyncpg/test_asyncpg.py" + ) + assert data.get("code.file.path")[0] != os.sep assert data[SPANDATA.CODE_FUNCTION] == expected_function @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) async def test_query_source_execute( - sentry_init, capture_events, capture_items, span_streaming + sentry_init, + capture_items, ): sentry_init( integrations=[AsyncPGIntegration()], traces_sample_rate=1.0, enable_db_query_source=True, db_query_source_threshold_ms=0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="test_segment"): - conn: Connection = await connect(PG_CONNECTION_URI) - await conn.execute( - "INSERT INTO users(name, password, dob) VALUES($1, $2, $3)", - "Alice", - "pw", - datetime.date(1990, 12, 25), - ) - await conn.close() - sentry_sdk.flush() - - spans = [item.payload for item in items] - assert len(spans) == 3 - - connect_span = spans[0] - query_span = spans[1] - segment = spans[2] - - assert connect_span["name"] == "connect" - assert query_span["name"].startswith("INSERT INTO") - assert segment["name"] == "test_segment" - assert segment["is_segment"] is True - else: - events = capture_events() - with start_transaction(name="test_transaction", sampled=True): - conn: Connection = await connect(PG_CONNECTION_URI) - await conn.execute( - "INSERT INTO users(name, password, dob) VALUES($1, $2, $3)", - "Alice", - "pw", - datetime.date(1990, 12, 25), - ) - await conn.close() + items = capture_items("span") + with sentry_sdk.start_span(name="test_segment"): + conn: Connection = await connect(PG_CONNECTION_URI) + await conn.execute( + "INSERT INTO users(name, password, dob) VALUES($1, $2, $3)", + "Alice", + "pw", + datetime.date(1990, 12, 25), + ) + await conn.close() + sentry_sdk.flush() + + spans = [item.payload for item in items] + assert len(spans) == 3 - (event,) = events - spans = event["spans"] - assert len(spans) == 2 - assert spans[0]["description"] == "connect" - assert spans[1]["description"].startswith("INSERT INTO") - query_span = spans[1] + connect_span = spans[0] + query_span = spans[1] + segment = spans[2] - _assert_query_source(query_span, span_streaming, "test_query_source_execute") + assert connect_span["name"] == "connect" + assert query_span["name"].startswith("INSERT INTO") + assert segment["name"] == "test_segment" + assert segment["is_segment"] is True + + _assert_query_source(query_span, "test_query_source_execute") @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) async def test_query_source_executemany( - sentry_init, capture_events, capture_items, span_streaming + sentry_init, + capture_items, ): sentry_init( integrations=[AsyncPGIntegration()], traces_sample_rate=1.0, enable_db_query_source=True, db_query_source_threshold_ms=0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="test_segment"): - conn: Connection = await connect(PG_CONNECTION_URI) - await conn.executemany( - "INSERT INTO users(name, password, dob) VALUES($1, $2, $3)", - [("Bob", "secret_pw", datetime.date(1984, 3, 1))], - ) - await conn.close() - sentry_sdk.flush() - - spans = [item.payload for item in items] - assert len(spans) == 3 - - connect_span = spans[0] - query_span = spans[1] - segment = spans[2] - - assert connect_span["name"] == "connect" - assert query_span["name"].startswith("INSERT INTO") - assert segment["name"] == "test_segment" - else: - events = capture_events() - with start_transaction(name="test_transaction", sampled=True): - conn: Connection = await connect(PG_CONNECTION_URI) - await conn.executemany( - "INSERT INTO users(name, password, dob) VALUES($1, $2, $3)", - [("Bob", "secret_pw", datetime.date(1984, 3, 1))], - ) - await conn.close() + items = capture_items("span") + with sentry_sdk.start_span(name="test_segment"): + conn: Connection = await connect(PG_CONNECTION_URI) + await conn.executemany( + "INSERT INTO users(name, password, dob) VALUES($1, $2, $3)", + [("Bob", "secret_pw", datetime.date(1984, 3, 1))], + ) + await conn.close() + sentry_sdk.flush() - (event,) = events - spans = event["spans"] - assert len(spans) == 2 - assert spans[0]["description"] == "connect" - assert spans[1]["description"].startswith("INSERT INTO") - query_span = spans[1] + spans = [item.payload for item in items] + assert len(spans) == 3 - _assert_query_source(query_span, span_streaming, "test_query_source_executemany") + connect_span = spans[0] + query_span = spans[1] + segment = spans[2] + + assert connect_span["name"] == "connect" + assert query_span["name"].startswith("INSERT INTO") + assert segment["name"] == "test_segment" + + _assert_query_source(query_span, "test_query_source_executemany") @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) async def test_query_source_prepare( - sentry_init, capture_events, capture_items, span_streaming + sentry_init, + capture_items, ): sentry_init( integrations=[AsyncPGIntegration()], traces_sample_rate=1.0, enable_db_query_source=True, db_query_source_threshold_ms=0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="test_segment"): - conn: Connection = await connect(PG_CONNECTION_URI) - await conn.prepare("SELECT * FROM users WHERE name = $1") - await conn.close() - sentry_sdk.flush() - - spans = [item.payload for item in items] - assert len(spans) == 3 - connect_span = spans[0] - query_span = spans[1] - segment = spans[2] - - assert connect_span["name"] == "connect" - assert query_span["name"] == "SELECT * FROM users WHERE name = $1" - assert segment["name"] == "test_segment" - - assert ( - query_span["attributes"][SPANDATA.DB_QUERY_TEXT] - == "SELECT * FROM users WHERE name = $1" - ) - else: - events = capture_events() - with start_transaction(name="test_transaction", sampled=True): - conn: Connection = await connect(PG_CONNECTION_URI) - await conn.prepare("SELECT * FROM users WHERE name = $1") - await conn.close() + items = capture_items("span") + with sentry_sdk.start_span(name="test_segment"): + conn: Connection = await connect(PG_CONNECTION_URI) + await conn.prepare("SELECT * FROM users WHERE name = $1") + await conn.close() + sentry_sdk.flush() + + spans = [item.payload for item in items] + assert len(spans) == 3 + connect_span = spans[0] + query_span = spans[1] + segment = spans[2] + + assert connect_span["name"] == "connect" + assert query_span["name"] == "SELECT * FROM users WHERE name = $1" + assert segment["name"] == "test_segment" - (event,) = events - spans = event["spans"] - assert len(spans) == 2 - assert spans[0]["description"] == "connect" - assert spans[1]["description"] == "SELECT * FROM users WHERE name = $1" - query_span = spans[1] + assert ( + query_span["attributes"][SPANDATA.DB_QUERY_TEXT] + == "SELECT * FROM users WHERE name = $1" + ) - _assert_query_source(query_span, span_streaming, "test_query_source_prepare") + _assert_query_source(query_span, "test_query_source_prepare") @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) async def test_cursor_iteration_creates_db_cursor_iter_spans( - sentry_init, capture_events, capture_items, span_streaming + sentry_init, + capture_items, ) -> None: """ Regression test for https://github.com/getsentry/sentry-python/issues/6576 @@ -1364,196 +1005,113 @@ async def test_cursor_iteration_creates_db_cursor_iter_spans( sentry_init( integrations=[AsyncPGIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") - - with sentry_sdk.traces.start_span(name="test_segment"): - conn: Connection = await connect(PG_CONNECTION_URI) - - await conn.executemany( - "INSERT INTO users(name, password, dob) VALUES($1, $2, $3)", - [(f"user-{i}", "pw", datetime.date(1990, 1, 1)) for i in range(20)], - ) - - async with conn.transaction(): - async for _record in conn.cursor("SELECT * FROM users", prefetch=5): - pass - - await conn.close() + items = capture_items("span") - sentry_sdk.flush() - - cursor_iter_spans = [ - item.payload - for item in items - if item.payload.get("name") == "SELECT * FROM users" - ] - - assert len(cursor_iter_spans) == 5 - for span in cursor_iter_spans: - assert span["attributes"]["sentry.op"] == OP.DB_CURSOR_ITERATOR - assert span["attributes"][SPANDATA.DB_QUERY_TEXT] == "SELECT * FROM users" - else: - events = capture_events() - - with start_transaction(name="test_transaction", sampled=True): - conn: Connection = await connect(PG_CONNECTION_URI) + with sentry_sdk.start_span(name="test_segment"): + conn: Connection = await connect(PG_CONNECTION_URI) - await conn.executemany( - "INSERT INTO users(name, password, dob) VALUES($1, $2, $3)", - [(f"user-{i}", "pw", datetime.date(1990, 1, 1)) for i in range(20)], - ) + await conn.executemany( + "INSERT INTO users(name, password, dob) VALUES($1, $2, $3)", + [(f"user-{i}", "pw", datetime.date(1990, 1, 1)) for i in range(20)], + ) - async with conn.transaction(): - async for _record in conn.cursor("SELECT * FROM users", prefetch=5): - pass + async with conn.transaction(): + async for _record in conn.cursor("SELECT * FROM users", prefetch=5): + pass - await conn.close() + await conn.close() - (event,) = events + sentry_sdk.flush() - cursor_iter_spans = [ - s for s in event["spans"] if s.get("description") == "SELECT * FROM users" - ] + cursor_iter_spans = [ + item.payload + for item in items + if item.payload.get("name") == "SELECT * FROM users" + ] - assert len(cursor_iter_spans) == 5 - for span in cursor_iter_spans: - assert span["op"] == OP.DB_CURSOR_ITERATOR + assert len(cursor_iter_spans) == 5 + for span in cursor_iter_spans: + assert span["attributes"]["sentry.op"] == OP.DB_CURSOR_ITERATOR + assert span["attributes"][SPANDATA.DB_QUERY_TEXT] == "SELECT * FROM users" @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) async def test_cursor_fetch_methods_create_spans( - sentry_init, capture_events, capture_items, span_streaming + sentry_init, + capture_items, ) -> None: sentry_init( integrations=[AsyncPGIntegration()], traces_sample_rate=1.0, enable_db_query_source=True, db_query_source_threshold_ms=0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items() - - with sentry_sdk.traces.start_span(name="test_segment"): - conn: Connection = await connect(PG_CONNECTION_URI) - - await conn.executemany( - "INSERT INTO users(name, password, dob) VALUES($1, $2, $3)", - [ - ("Bob", "secret_pw", datetime.date(1984, 3, 1)), - ("Alice", "pw", datetime.date(1990, 12, 25)), - ], - ) - - async with conn.transaction(): - cur = await conn.cursor( - "SELECT * FROM users WHERE dob > $1", datetime.date(1970, 1, 1) - ) - # These exercise the `_exec` patch - await cur.fetchrow() - await cur.fetchrow() - - await conn.close() - - sentry_sdk.flush() - - spans = [item.payload for item in items] + items = capture_items() - assert len(spans) == 7 - - connect_span = spans[0] - executemany_span = spans[1] - begin_span = spans[2] - fetchrow_span_1 = spans[3] - fetchrow_span_2 = spans[4] - commit_span = spans[5] - _segment_span = spans[6] + with sentry_sdk.start_span(name="test_segment"): + conn: Connection = await connect(PG_CONNECTION_URI) - assert connect_span["name"] == "connect" - assert ( - executemany_span["name"] - == "INSERT INTO users(name, password, dob) VALUES($1, $2, $3)" - ) - assert begin_span["name"] == "BEGIN;" - assert fetchrow_span_1["name"] == "SELECT * FROM users WHERE dob > $1" - assert fetchrow_span_2["name"] == "SELECT * FROM users WHERE dob > $1" - assert commit_span["name"] == "COMMIT;" - - assert ( - fetchrow_span_1["attributes"][SPANDATA.DB_QUERY_TEXT] - == "SELECT * FROM users WHERE dob > $1" - ) - assert ( - fetchrow_span_2["attributes"][SPANDATA.DB_QUERY_TEXT] - == "SELECT * FROM users WHERE dob > $1" + await conn.executemany( + "INSERT INTO users(name, password, dob) VALUES($1, $2, $3)", + [ + ("Bob", "secret_pw", datetime.date(1984, 3, 1)), + ("Alice", "pw", datetime.date(1990, 12, 25)), + ], ) - for span in (fetchrow_span_1, fetchrow_span_2): - assert span["attributes"][SPANDATA.DB_SYSTEM_NAME] == "postgresql" - assert span["attributes"][SPANDATA.DB_DRIVER_NAME] == "asyncpg" - assert span["attributes"]["sentry.op"] == OP.DB_CURSOR_FETCH - assert span["attributes"]["sentry.origin"] == "auto.db.asyncpg" - - else: - events = capture_events() + async with conn.transaction(): + cur = await conn.cursor( + "SELECT * FROM users WHERE dob > $1", datetime.date(1970, 1, 1) + ) + # These exercise the `_exec` patch + await cur.fetchrow() + await cur.fetchrow() - with start_transaction(name="test_transaction"): - conn: Connection = await connect(PG_CONNECTION_URI) + await conn.close() - await conn.executemany( - "INSERT INTO users(name, password, dob) VALUES($1, $2, $3)", - [ - ("Bob", "secret_pw", datetime.date(1984, 3, 1)), - ("Alice", "pw", datetime.date(1990, 12, 25)), - ], - ) + sentry_sdk.flush() - async with conn.transaction(): - cur = await conn.cursor( - "SELECT * FROM users WHERE dob > $1", datetime.date(1970, 1, 1) - ) - # These exercise the `_exec` patch - await cur.fetchrow() - await cur.fetchrow() + spans = [item.payload for item in items] - await conn.close() + assert len(spans) == 7 - (event,) = events + connect_span = spans[0] + executemany_span = spans[1] + begin_span = spans[2] + fetchrow_span_1 = spans[3] + fetchrow_span_2 = spans[4] + commit_span = spans[5] + _segment_span = spans[6] - assert len(event["spans"]) == 6 + assert connect_span["name"] == "connect" + assert ( + executemany_span["name"] + == "INSERT INTO users(name, password, dob) VALUES($1, $2, $3)" + ) + assert begin_span["name"] == "BEGIN;" + assert fetchrow_span_1["name"] == "SELECT * FROM users WHERE dob > $1" + assert fetchrow_span_2["name"] == "SELECT * FROM users WHERE dob > $1" + assert commit_span["name"] == "COMMIT;" - connect_span = event["spans"][0] - executemany_span = event["spans"][1] - begin_span = event["spans"][2] - fetchrow_span_1 = event["spans"][3] - fetchrow_span_2 = event["spans"][4] - commit_span = event["spans"][5] + assert ( + fetchrow_span_1["attributes"][SPANDATA.DB_QUERY_TEXT] + == "SELECT * FROM users WHERE dob > $1" + ) + assert ( + fetchrow_span_2["attributes"][SPANDATA.DB_QUERY_TEXT] + == "SELECT * FROM users WHERE dob > $1" + ) - assert connect_span["description"] == "connect" - assert ( - executemany_span["description"] - == "INSERT INTO users(name, password, dob) VALUES($1, $2, $3)" - ) - assert begin_span["description"] == "BEGIN;" - assert fetchrow_span_1["description"] == "SELECT * FROM users WHERE dob > $1" - assert fetchrow_span_2["description"] == "SELECT * FROM users WHERE dob > $1" - assert commit_span["description"] == "COMMIT;" - - for span in (fetchrow_span_1, fetchrow_span_2): - assert span["data"]["db.cursor"] is not None - assert span["data"]["db.system"] == "postgresql" - assert span["data"]["db.driver.name"] == "asyncpg" - assert span["op"] == OP.DB_CURSOR_FETCH - assert span["origin"] == "auto.db.asyncpg" + for span in (fetchrow_span_1, fetchrow_span_2): + assert span["attributes"][SPANDATA.DB_SYSTEM_NAME] == "postgresql" + assert span["attributes"][SPANDATA.DB_DRIVER_NAME] == "asyncpg" + assert span["attributes"]["sentry.op"] == OP.DB_CURSOR_FETCH + assert span["attributes"]["sentry.origin"] == "auto.db.asyncpg" _assert_query_source( span, - span_streaming, "test_cursor_fetch_methods_create_spans", ) diff --git a/tests/integrations/aws_lambda/lambda_functions_with_embedded_sdk/BasicOkSendDefaultPii/.gitignore b/tests/integrations/aws_lambda/lambda_functions_with_embedded_sdk/BasicOkSendDefaultPii/.gitignore deleted file mode 100644 index 1c56884372..0000000000 --- a/tests/integrations/aws_lambda/lambda_functions_with_embedded_sdk/BasicOkSendDefaultPii/.gitignore +++ /dev/null @@ -1,11 +0,0 @@ -# Need to add some ignore rules in this directory, because the unit tests will add the Sentry SDK and its dependencies -# into this directory to create a Lambda function package that contains everything needed to instrument a Lambda function using Sentry. - -# Ignore everything -* - -# But not index.py -!index.py - -# And not .gitignore itself -!.gitignore diff --git a/tests/integrations/aws_lambda/lambda_functions_with_embedded_sdk/BasicOkSendDefaultPii/.lock b/tests/integrations/aws_lambda/lambda_functions_with_embedded_sdk/BasicOkSendDefaultPii/.lock deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tests/integrations/aws_lambda/lambda_functions_with_embedded_sdk/BasicOkSendDefaultPii/index.py b/tests/integrations/aws_lambda/lambda_functions_with_embedded_sdk/BasicOkSendDefaultPii/index.py deleted file mode 100644 index 502a6ae3ee..0000000000 --- a/tests/integrations/aws_lambda/lambda_functions_with_embedded_sdk/BasicOkSendDefaultPii/index.py +++ /dev/null @@ -1,15 +0,0 @@ -import os - -import sentry_sdk -from sentry_sdk.integrations.aws_lambda import AwsLambdaIntegration - -sentry_sdk.init( - dsn=os.environ.get("SENTRY_DSN"), - traces_sample_rate=1.0, - send_default_pii=True, - integrations=[AwsLambdaIntegration()], -) - - -def handler(event, context): - return {"event": event} diff --git a/tests/integrations/aws_lambda/lambda_functions_with_embedded_sdk/BasicOkSpanStreaming/index.py b/tests/integrations/aws_lambda/lambda_functions_with_embedded_sdk/BasicOkSpanStreaming/index.py index 29fdb83aec..3a2cfeec85 100644 --- a/tests/integrations/aws_lambda/lambda_functions_with_embedded_sdk/BasicOkSpanStreaming/index.py +++ b/tests/integrations/aws_lambda/lambda_functions_with_embedded_sdk/BasicOkSpanStreaming/index.py @@ -5,9 +5,9 @@ sentry_sdk.init( dsn=os.environ.get("SENTRY_DSN"), + data_collection={}, traces_sample_rate=1.0, integrations=[AwsLambdaIntegration()], - trace_lifecycle="stream", ) diff --git a/tests/integrations/aws_lambda/lambda_functions_with_embedded_sdk/BasicOkSpanStreamingDataCollection/index.py b/tests/integrations/aws_lambda/lambda_functions_with_embedded_sdk/BasicOkSpanStreamingDataCollection/index.py index add84cc9c2..b24dec6e95 100644 --- a/tests/integrations/aws_lambda/lambda_functions_with_embedded_sdk/BasicOkSpanStreamingDataCollection/index.py +++ b/tests/integrations/aws_lambda/lambda_functions_with_embedded_sdk/BasicOkSpanStreamingDataCollection/index.py @@ -7,7 +7,6 @@ dsn=os.environ.get("SENTRY_DSN"), traces_sample_rate=1.0, integrations=[AwsLambdaIntegration()], - trace_lifecycle="stream", data_collection={ "url_query_params": { "mode": "denylist", diff --git a/tests/integrations/aws_lambda/lambda_functions_with_embedded_sdk/BasicOkSpanStreamingDataCollectionUserInfoOff/index.py b/tests/integrations/aws_lambda/lambda_functions_with_embedded_sdk/BasicOkSpanStreamingDataCollectionUserInfoOff/index.py index ef00b0fce4..4cfe3abbeb 100644 --- a/tests/integrations/aws_lambda/lambda_functions_with_embedded_sdk/BasicOkSpanStreamingDataCollectionUserInfoOff/index.py +++ b/tests/integrations/aws_lambda/lambda_functions_with_embedded_sdk/BasicOkSpanStreamingDataCollectionUserInfoOff/index.py @@ -7,7 +7,6 @@ dsn=os.environ.get("SENTRY_DSN"), traces_sample_rate=1.0, integrations=[AwsLambdaIntegration()], - trace_lifecycle="stream", data_collection={ "user_info": False, }, diff --git a/tests/integrations/aws_lambda/lambda_functions_with_embedded_sdk/BasicOkSpanStreamingDataCollectionUserInfoOn/index.py b/tests/integrations/aws_lambda/lambda_functions_with_embedded_sdk/BasicOkSpanStreamingDataCollectionUserInfoOn/index.py index 4cec57ed71..bcb0d66575 100644 --- a/tests/integrations/aws_lambda/lambda_functions_with_embedded_sdk/BasicOkSpanStreamingDataCollectionUserInfoOn/index.py +++ b/tests/integrations/aws_lambda/lambda_functions_with_embedded_sdk/BasicOkSpanStreamingDataCollectionUserInfoOn/index.py @@ -7,7 +7,6 @@ dsn=os.environ.get("SENTRY_DSN"), traces_sample_rate=1.0, integrations=[AwsLambdaIntegration()], - trace_lifecycle="stream", data_collection={ "user_info": True, }, diff --git a/tests/integrations/aws_lambda/lambda_functions_with_embedded_sdk/BasicOkSpanStreamingPii/.gitignore b/tests/integrations/aws_lambda/lambda_functions_with_embedded_sdk/BasicOkSpanStreamingPii/.gitignore deleted file mode 100644 index 1c56884372..0000000000 --- a/tests/integrations/aws_lambda/lambda_functions_with_embedded_sdk/BasicOkSpanStreamingPii/.gitignore +++ /dev/null @@ -1,11 +0,0 @@ -# Need to add some ignore rules in this directory, because the unit tests will add the Sentry SDK and its dependencies -# into this directory to create a Lambda function package that contains everything needed to instrument a Lambda function using Sentry. - -# Ignore everything -* - -# But not index.py -!index.py - -# And not .gitignore itself -!.gitignore diff --git a/tests/integrations/aws_lambda/lambda_functions_with_embedded_sdk/BasicOkSpanStreamingPii/index.py b/tests/integrations/aws_lambda/lambda_functions_with_embedded_sdk/BasicOkSpanStreamingPii/index.py deleted file mode 100644 index ae997c8dfb..0000000000 --- a/tests/integrations/aws_lambda/lambda_functions_with_embedded_sdk/BasicOkSpanStreamingPii/index.py +++ /dev/null @@ -1,16 +0,0 @@ -import os - -import sentry_sdk -from sentry_sdk.integrations.aws_lambda import AwsLambdaIntegration - -sentry_sdk.init( - dsn=os.environ.get("SENTRY_DSN"), - traces_sample_rate=1.0, - send_default_pii=True, - integrations=[AwsLambdaIntegration()], - trace_lifecycle="stream", -) - - -def handler(event, context): - return {"event": event} diff --git a/tests/integrations/aws_lambda/lambda_functions_with_embedded_sdk/RaiseErrorPerformanceDisabled/index.py b/tests/integrations/aws_lambda/lambda_functions_with_embedded_sdk/RaiseErrorPerformanceDisabled/index.py index 7669fb8aaf..707234b95c 100644 --- a/tests/integrations/aws_lambda/lambda_functions_with_embedded_sdk/RaiseErrorPerformanceDisabled/index.py +++ b/tests/integrations/aws_lambda/lambda_functions_with_embedded_sdk/RaiseErrorPerformanceDisabled/index.py @@ -5,6 +5,7 @@ sentry_sdk.init( dsn=os.environ.get("SENTRY_DSN"), + data_collection={}, traces_sample_rate=None, # this is the default, just added for clarity integrations=[AwsLambdaIntegration()], ) diff --git a/tests/integrations/aws_lambda/lambda_functions_with_embedded_sdk/RaiseErrorPerformanceEnabled/index.py b/tests/integrations/aws_lambda/lambda_functions_with_embedded_sdk/RaiseErrorPerformanceEnabled/index.py index 9503f04966..e7dd016973 100644 --- a/tests/integrations/aws_lambda/lambda_functions_with_embedded_sdk/RaiseErrorPerformanceEnabled/index.py +++ b/tests/integrations/aws_lambda/lambda_functions_with_embedded_sdk/RaiseErrorPerformanceEnabled/index.py @@ -5,6 +5,7 @@ sentry_sdk.init( dsn=os.environ.get("SENTRY_DSN"), + data_collection={}, traces_sample_rate=1.0, integrations=[AwsLambdaIntegration()], ) diff --git a/tests/integrations/aws_lambda/lambda_functions_with_embedded_sdk/RaiseErrorSpanStreaming/index.py b/tests/integrations/aws_lambda/lambda_functions_with_embedded_sdk/RaiseErrorSpanStreaming/index.py index 589265cbbe..e7dd016973 100644 --- a/tests/integrations/aws_lambda/lambda_functions_with_embedded_sdk/RaiseErrorSpanStreaming/index.py +++ b/tests/integrations/aws_lambda/lambda_functions_with_embedded_sdk/RaiseErrorSpanStreaming/index.py @@ -5,9 +5,9 @@ sentry_sdk.init( dsn=os.environ.get("SENTRY_DSN"), + data_collection={}, traces_sample_rate=1.0, integrations=[AwsLambdaIntegration()], - trace_lifecycle="stream", ) diff --git a/tests/integrations/aws_lambda/lambda_functions_with_embedded_sdk/TimeoutErrorScopeModified/index.py b/tests/integrations/aws_lambda/lambda_functions_with_embedded_sdk/TimeoutErrorScopeModified/index.py index 109245b90d..52fb73e47d 100644 --- a/tests/integrations/aws_lambda/lambda_functions_with_embedded_sdk/TimeoutErrorScopeModified/index.py +++ b/tests/integrations/aws_lambda/lambda_functions_with_embedded_sdk/TimeoutErrorScopeModified/index.py @@ -6,6 +6,7 @@ sentry_sdk.init( dsn=os.environ.get("SENTRY_DSN"), + data_collection={}, traces_sample_rate=1.0, integrations=[AwsLambdaIntegration(timeout_warning=True)], ) diff --git a/tests/integrations/aws_lambda/lambda_functions_with_embedded_sdk/TracesSampler/index.py b/tests/integrations/aws_lambda/lambda_functions_with_embedded_sdk/TracesSampler/index.py index 3e4d9b3c36..36ff898561 100644 --- a/tests/integrations/aws_lambda/lambda_functions_with_embedded_sdk/TracesSampler/index.py +++ b/tests/integrations/aws_lambda/lambda_functions_with_embedded_sdk/TracesSampler/index.py @@ -30,6 +30,7 @@ def trace_sampler(sampling_context): sentry_sdk.init( dsn=os.environ.get("SENTRY_DSN"), + data_collection={}, traces_sample_rate=1.0, traces_sampler=trace_sampler, integrations=[AwsLambdaIntegration()], diff --git a/tests/integrations/aws_lambda/test_aws_lambda.py b/tests/integrations/aws_lambda/test_aws_lambda.py index 0bf1cd3670..45aa6a8f20 100644 --- a/tests/integrations/aws_lambda/test_aws_lambda.py +++ b/tests/integrations/aws_lambda/test_aws_lambda.py @@ -2,7 +2,6 @@ import subprocess import tempfile import time -from unittest import mock import boto3 import docker @@ -107,98 +106,23 @@ def lambda_client(): ) -def test_basic_no_exception(lambda_client, test_environment): - lambda_client.invoke( - FunctionName="BasicOk", - Payload=json.dumps({}), - ) - envelopes = test_environment["server"].envelopes - - (transaction_event,) = envelopes - - assert transaction_event["type"] == "transaction" - assert transaction_event["transaction"] == "BasicOk" - assert transaction_event["sdk"]["name"] == "sentry.python.aws_lambda" - assert transaction_event["tags"] == {"aws_region": "us-east-1"} - - assert transaction_event["extra"]["cloudwatch logs"] == { - "log_group": mock.ANY, - "log_stream": mock.ANY, - "url": mock.ANY, - } - assert transaction_event["extra"]["lambda"] == { - "aws_request_id": mock.ANY, - "execution_duration_in_millis": mock.ANY, - "function_name": "BasicOk", - "function_version": "$LATEST", - "invoked_function_arn": "arn:aws:lambda:us-east-1:012345678912:function:BasicOk", - "remaining_time_in_millis": mock.ANY, - } - assert transaction_event["contexts"]["trace"] == { - "op": "function.aws", - "description": mock.ANY, - "span_id": mock.ANY, - "parent_span_id": mock.ANY, - "trace_id": mock.ANY, - "origin": "auto.function.aws_lambda", - "data": mock.ANY, - } - - -def test_basic_exception(lambda_client, test_environment): - lambda_client.invoke( - FunctionName="BasicException", - Payload=json.dumps({}), - ) - envelopes = test_environment["server"].envelopes - - # The second envelope we ignore. - # It is the transaction that we test in test_basic_no_exception. - (error_event, _) = envelopes - - assert error_event["level"] == "error" - assert error_event["exception"]["values"][0]["type"] == "RuntimeError" - assert error_event["exception"]["values"][0]["value"] == "Oh!" - assert error_event["sdk"]["name"] == "sentry.python.aws_lambda" - - assert error_event["tags"] == {"aws_region": "us-east-1"} - assert error_event["extra"]["cloudwatch logs"] == { - "log_group": mock.ANY, - "log_stream": mock.ANY, - "url": mock.ANY, - } - assert error_event["extra"]["lambda"] == { - "aws_request_id": mock.ANY, - "execution_duration_in_millis": mock.ANY, - "function_name": "BasicException", - "function_version": "$LATEST", - "invoked_function_arn": "arn:aws:lambda:us-east-1:012345678912:function:BasicException", - "remaining_time_in_millis": mock.ANY, - } - assert error_event["contexts"]["trace"] == { - "op": "function.aws", - "description": mock.ANY, - "span_id": mock.ANY, - "parent_span_id": mock.ANY, - "trace_id": mock.ANY, - "origin": "auto.function.aws_lambda", - "data": mock.ANY, - } - - def test_init_error(lambda_client, test_environment): lambda_client.invoke( FunctionName="InitError", Payload=json.dumps({}), ) envelopes = test_environment["server"].envelopes + span_items = test_environment["server"].span_items - (error_event, transaction_event) = envelopes + (error_event,) = envelopes assert ( error_event["exception"]["values"][0]["value"] == "name 'func' is not defined" ) - assert transaction_event["transaction"] == "InitError" + + segment_spans = [s for s in span_items if s.get("is_segment")] + assert len(segment_spans) == 1 + assert segment_spans[0]["name"] == "InitError" def test_timeout_error_scope_modified(lambda_client, test_environment): @@ -218,9 +142,7 @@ def test_timeout_error_scope_modified(lambda_client, test_environment): (exception,) = error_event["exception"]["values"] assert not exception["mechanism"]["handled"] assert exception["type"] == "ServerlessTimeoutWarning" - assert exception["value"].startswith( - "WARNING : Function is expected to get timed out. Configured timeout duration =" - ) + assert exception["value"] == "WARNING: Function is about to time out." assert exception["mechanism"]["type"] == "threading" assert error_event["tags"]["custom_tag"] == "custom_value" @@ -297,13 +219,9 @@ def test_non_dict_event( Payload=aws_event, ) envelopes = test_environment["server"].envelopes + span_items = test_environment["server"].span_items - (error_event, transaction_event) = envelopes - - assert transaction_event["type"] == "transaction" - assert transaction_event["transaction"] == "BasicException" - assert transaction_event["sdk"]["name"] == "sentry.python.aws_lambda" - assert transaction_event["contexts"]["trace"]["status"] == "internal_error" + (error_event,) = envelopes assert error_event["level"] == "error" assert error_event["transaction"] == "BasicException" @@ -325,16 +243,14 @@ def test_non_dict_event( request_data = {"url": "awslambda:///BasicException"} assert error_event["request"] == request_data - assert transaction_event["request"] == request_data - if batch_size > 1: - assert error_event["tags"]["batch_size"] == batch_size - assert error_event["tags"]["batch_request"] is True - assert transaction_event["tags"]["batch_size"] == batch_size - assert transaction_event["tags"]["batch_request"] is True + segment_spans = [s for s in span_items if s.get("is_segment")] + assert len(segment_spans) == 1 + assert segment_spans[0]["name"] == "BasicException" + assert segment_spans[0]["status"] == "error" -def test_request_data_with_send_default_pii_false(lambda_client, test_environment): +def test_request_data_with_default_data_collection(lambda_client, test_environment): payload = b""" { "resource": "/asd", @@ -367,88 +283,14 @@ def test_request_data_with_send_default_pii_false(lambda_client, test_environmen FunctionName="BasicOk", Payload=payload, ) - envelopes = test_environment["server"].envelopes - - (transaction_event,) = envelopes - - assert transaction_event["request"] == { - "headers": { - "Host": "iwsz2c7uwi.execute-api.us-east-1.amazonaws.com", - "User-Agent": "custom", - # X-Forwarded-Proto is not sensitive and passes through. - "X-Forwarded-Proto": "https", - # With send_default_pii=False, _filter_headers substitutes the - # SENSITIVE_HEADERS (Authorization, Cookie); the EventScrubber - # also scrubs them. Both end up as "[Filtered]". - "Authorization": "[Filtered]", - "Cookie": "[Filtered]", - }, - "method": "GET", - "query_string": {"bonkers": "true"}, - "url": "https://iwsz2c7uwi.execute-api.us-east-1.amazonaws.com/asd", - } - - -def test_request_data_with_send_default_pii_true(lambda_client, test_environment): - payload = b""" - { - "resource": "/asd", - "path": "/asd", - "httpMethod": "GET", - "headers": { - "Host": "iwsz2c7uwi.execute-api.us-east-1.amazonaws.com", - "User-Agent": "custom", - "X-Forwarded-Proto": "https", - "Authorization": "Bearer secret-token", - "Cookie": "sessionid=secret" - }, - "queryStringParameters": { - "bonkers": "true" - }, - "pathParameters": null, - "stageVariables": null, - "requestContext": { - "identity": { - "sourceIp": "213.47.147.207", - "userArn": "42" - } - }, - "body": null, - "isBase64Encoded": false - } - """ - - lambda_client.invoke( - FunctionName="BasicOkSendDefaultPii", - Payload=payload, - ) - envelopes = test_environment["server"].envelopes - - (transaction_event,) = envelopes + span_items = test_environment["server"].span_items - assert transaction_event["request"] == { - "headers": { - "Host": "iwsz2c7uwi.execute-api.us-east-1.amazonaws.com", - "User-Agent": "custom", - "X-Forwarded-Proto": "https", - # With send_default_pii=True (and no data_collection config), - # _filter_headers passes headers through untouched. Authorization - # and Cookie are still scrubbed to "[Filtered]" by the always-on - # EventScrubber (DEFAULT_DENYLIST), independent of PII settings. - "Authorization": "[Filtered]", - "Cookie": "[Filtered]", - }, - "method": "GET", - "query_string": {"bonkers": "true"}, - "url": "https://iwsz2c7uwi.execute-api.us-east-1.amazonaws.com/asd", - "data": None, - } + segment_spans = [s for s in span_items if s.get("is_segment")] + assert len(segment_spans) == 1 + attrs = segment_spans[0]["attributes"] - # Legacy send_default_pii=True attaches the user identity. - assert transaction_event["user"] == { - "id": "42", - "ip_address": "213.47.147.207", - } + assert _get_span_attr(attrs, "http.request.method") == "GET" + assert _get_span_attr(attrs, "url.query") == "bonkers=true" USER_INFO_PAYLOAD = b""" @@ -483,26 +325,13 @@ def test_user_info_with_data_collection_user_info_on(lambda_client, test_environ FunctionName="BasicOkDataCollectionUserInfoOn", Payload=USER_INFO_PAYLOAD, ) - envelopes = test_environment["server"].envelopes - - (transaction_event,) = envelopes - - assert transaction_event["user"] == { - "id": "42", - "ip_address": "213.47.147.207", - } - - -def test_user_info_with_data_collection_user_info_off(lambda_client, test_environment): - lambda_client.invoke( - FunctionName="BasicOkDataCollectionUserInfoOff", - Payload=USER_INFO_PAYLOAD, - ) - envelopes = test_environment["server"].envelopes + span_items = test_environment["server"].span_items - (transaction_event,) = envelopes + segment_spans = [s for s in span_items if s.get("is_segment")] + assert len(segment_spans) == 1 + attrs = segment_spans[0]["attributes"] - assert "user" not in transaction_event + assert _get_span_attr(attrs, "user.id") == "42" def test_request_data_with_data_collection_allowlist(lambda_client, test_environment): @@ -539,29 +368,25 @@ def test_request_data_with_data_collection_allowlist(lambda_client, test_environ FunctionName="BasicOkDataCollectionAllowlist", Payload=payload, ) - envelopes = test_environment["server"].envelopes + span_items = test_environment["server"].span_items - (transaction_event,) = envelopes + segment_spans = [s for s in span_items if s.get("is_segment")] + assert len(segment_spans) == 1 + attrs = segment_spans[0]["attributes"] - assert transaction_event["request"] == { - "headers": { - # Allowlisted, non-sensitive headers pass through. - "User-Agent": "custom", - "X-Allow-Me": "yes", - # Not allowlisted -> substituted. - "Host": "[Filtered]", - "X-Forwarded-Proto": "[Filtered]", - # Allowlisted but sensitive -> still filtered; an allowlist entry - # cannot override the built-in sensitive denylist. - "Authorization": "[Filtered]", - # Not allowlisted, and cookies are always substituted. - "Cookie": "[Filtered]", - }, - "method": "GET", - "query_string": {"bonkers": "true"}, - "url": "https://iwsz2c7uwi.execute-api.us-east-1.amazonaws.com/asd", - "data": '{"toy": "tennisball"}', - } + assert _get_span_attr(attrs, "http.request.method") == "GET" + # Allowlisted, non-sensitive headers pass through. + assert _get_span_attr(attrs, "http.request.header.user-agent") == "custom" + assert _get_span_attr(attrs, "http.request.header.x-allow-me") == "yes" + # Not allowlisted -> filtered. + assert _get_span_attr(attrs, "http.request.header.host") == "[Filtered]" + assert ( + _get_span_attr(attrs, "http.request.header.x-forwarded-proto") == "[Filtered]" + ) + # Allowlisted but sensitive -> still filtered. + assert _get_span_attr(attrs, "http.request.header.authorization") == "[Filtered]" + # Not allowlisted, and cookies are always filtered. + assert _get_span_attr(attrs, "http.request.header.cookie") == "[Filtered]" def test_request_data_with_data_collection_denylist(lambda_client, test_environment): @@ -598,28 +423,28 @@ def test_request_data_with_data_collection_denylist(lambda_client, test_environm FunctionName="BasicOkDataCollectionDenylist", Payload=payload, ) - envelopes = test_environment["server"].envelopes + span_items = test_environment["server"].span_items - (transaction_event,) = envelopes + segment_spans = [s for s in span_items if s.get("is_segment")] + assert len(segment_spans) == 1 + attrs = segment_spans[0]["attributes"] - assert transaction_event["request"] == { - "headers": { - # Not denied by any term -> pass through. - "Host": "iwsz2c7uwi.execute-api.us-east-1.amazonaws.com", - "X-Custom": "keep-me", - # Denied by custom terms. - "User-Agent": "[Filtered]", - "X-Forwarded-Proto": "[Filtered]", - # Denied by the built-in sensitive denylist. - "Authorization": "[Filtered]", - # Cookies are always substituted. - "Cookie": "[Filtered]", - }, - "method": "GET", - "query_string": {"bonkers": "true"}, - "url": "https://iwsz2c7uwi.execute-api.us-east-1.amazonaws.com/asd", - "data": '{"toy": "tennisball"}', - } + assert _get_span_attr(attrs, "http.request.method") == "GET" + # Not denied by any term -> pass through. + assert ( + _get_span_attr(attrs, "http.request.header.host") + == "iwsz2c7uwi.execute-api.us-east-1.amazonaws.com" + ) + assert _get_span_attr(attrs, "http.request.header.x-custom") == "keep-me" + # Denied by custom terms. + assert _get_span_attr(attrs, "http.request.header.user-agent") == "[Filtered]" + assert ( + _get_span_attr(attrs, "http.request.header.x-forwarded-proto") == "[Filtered]" + ) + # Denied by the built-in sensitive denylist. + assert _get_span_attr(attrs, "http.request.header.authorization") == "[Filtered]" + # Cookies are always filtered. + assert _get_span_attr(attrs, "http.request.header.cookie") == "[Filtered]" def test_request_data_with_data_collection_off(lambda_client, test_environment): @@ -655,66 +480,16 @@ def test_request_data_with_data_collection_off(lambda_client, test_environment): FunctionName="BasicOkDataCollectionOff", Payload=payload, ) - envelopes = test_environment["server"].envelopes - - (transaction_event,) = envelopes - - assert transaction_event["request"] == { - # With request headers collection turned off, no headers are collected. - "headers": {}, - "method": "GET", - "query_string": {"bonkers": "true"}, - "url": "https://iwsz2c7uwi.execute-api.us-east-1.amazonaws.com/asd", - "data": '{"toy": "tennisball"}', - } - - -def test_url_query_params_with_data_collection_denylist( - lambda_client, test_environment -): - payload = b""" - { - "resource": "/asd", - "path": "/asd", - "httpMethod": "GET", - "headers": { - "Host": "iwsz2c7uwi.execute-api.us-east-1.amazonaws.com", - "X-Forwarded-Proto": "https" - }, - "queryStringParameters": { - "page": "2", - "tracking": "campaign", - "token": "secret-token" - }, - "pathParameters": null, - "stageVariables": null, - "requestContext": { - "identity": { - "sourceIp": "213.47.147.207", - "userArn": "42" - } - }, - "body": null, - "isBase64Encoded": false - } - """ - - lambda_client.invoke( - FunctionName="BasicOkDataCollectionUrlQueryDenylist", - Payload=payload, - ) - envelopes = test_environment["server"].envelopes + span_items = test_environment["server"].span_items - (transaction_event,) = envelopes + segment_spans = [s for s in span_items if s.get("is_segment")] + assert len(segment_spans) == 1 + attrs = segment_spans[0]["attributes"] - assert transaction_event["request"]["query_string"] == { - # Not denied by any term -> pass through. - "page": "2", - # Denied by custom terms. - "tracking": "[Filtered]", - # Denied by the built-in sensitive denylist. - "token": "[Filtered]", - } + assert _get_span_attr(attrs, "http.request.method") == "GET" + # With request headers collection turned off, no header attributes are collected. + header_attrs = [k for k in attrs if k.startswith("http.request.header.")] + assert header_attrs == [] def test_url_query_params_with_data_collection_allowlist( @@ -751,19 +526,19 @@ def test_url_query_params_with_data_collection_allowlist( FunctionName="BasicOkDataCollectionUrlQueryAllowlist", Payload=payload, ) - envelopes = test_environment["server"].envelopes + span_items = test_environment["server"].span_items - (transaction_event,) = envelopes + segment_spans = [s for s in span_items if s.get("is_segment")] + assert len(segment_spans) == 1 + attrs = segment_spans[0]["attributes"] - assert transaction_event["request"]["query_string"] == { - # Allowlisted, non-sensitive -> pass through. - "page": "2", - # Not allowlisted -> substituted. - "tracking": "[Filtered]", - # Allowlisted but sensitive -> still filtered; an allowlist entry - # cannot override the built-in sensitive denylist. - "token": "[Filtered]", - } + # Allowlisted, non-sensitive -> pass through. + # Not allowlisted -> substituted. + # Allowlisted but sensitive -> still filtered. + assert ( + _get_span_attr(attrs, "url.query") + == "page=2&tracking=%5BFiltered%5D&token=%5BFiltered%5D" + ) def test_url_query_params_with_data_collection_off(lambda_client, test_environment): @@ -797,41 +572,14 @@ def test_url_query_params_with_data_collection_off(lambda_client, test_environme FunctionName="BasicOkDataCollectionUrlQueryOff", Payload=payload, ) - envelopes = test_environment["server"].envelopes + span_items = test_environment["server"].span_items - (transaction_event,) = envelopes + segment_spans = [s for s in span_items if s.get("is_segment")] + assert len(segment_spans) == 1 + attrs = segment_spans[0]["attributes"] # With url_query_params collection turned off, no query string is collected. - assert "query_string" not in transaction_event["request"] - - -def test_trace_continuation(lambda_client, test_environment): - trace_id = "471a43a4192642f0b136d5159a501701" - parent_span_id = "6e8f22c393e68f19" - parent_sampled = 1 - sentry_trace_header = "{}-{}-{}".format(trace_id, parent_span_id, parent_sampled) - - # We simulate here AWS Api Gateway's behavior of passing HTTP headers - # as the `headers` dict in the event passed to the Lambda function. - payload = { - "headers": { - "sentry-trace": sentry_trace_header, - } - } - - lambda_client.invoke( - FunctionName="BasicException", - Payload=json.dumps(payload), - ) - envelopes = test_environment["server"].envelopes - - (error_event, transaction_event) = envelopes - - assert ( - error_event["contexts"]["trace"]["trace_id"] - == transaction_event["contexts"]["trace"]["trace_id"] - == "471a43a4192642f0b136d5159a501701" - ) + assert "url.query" not in attrs @pytest.mark.parametrize( @@ -858,7 +606,7 @@ def test_headers(lambda_client, test_environment, payload): ) envelopes = test_environment["server"].envelopes - (error_event, _) = envelopes + (error_event,) = envelopes assert error_event["level"] == "error" assert error_event["exception"]["values"][0]["type"] == "RuntimeError" @@ -870,12 +618,13 @@ def test_span_origin(lambda_client, test_environment): FunctionName="BasicOk", Payload=json.dumps({}), ) - envelopes = test_environment["server"].envelopes - - (transaction_event,) = envelopes + span_items = test_environment["server"].span_items + segment_spans = [s for s in span_items if s.get("is_segment")] + assert len(segment_spans) == 1 assert ( - transaction_event["contexts"]["trace"]["origin"] == "auto.function.aws_lambda" + _get_span_attr(segment_spans[0]["attributes"], "sentry.origin") + == "auto.function.aws_lambda" ) @@ -910,22 +659,18 @@ def test_error_has_new_trace_context( Payload=json.dumps({}), ) envelopes = test_environment["server"].envelopes + span_items = test_environment["server"].span_items - if lambda_function_name == "RaiseErrorPerformanceEnabled": - (error_event, transaction_event) = envelopes - else: - (error_event,) = envelopes - transaction_event = None + (error_event,) = envelopes assert "trace" in error_event["contexts"] assert "trace_id" in error_event["contexts"]["trace"] - if transaction_event: - assert "trace" in transaction_event["contexts"] - assert "trace_id" in transaction_event["contexts"]["trace"] + if lambda_function_name == "RaiseErrorPerformanceEnabled": + segment_spans = [s for s in span_items if s.get("is_segment")] + assert len(segment_spans) == 1 assert ( - error_event["contexts"]["trace"]["trace_id"] - == transaction_event["contexts"]["trace"]["trace_id"] + error_event["contexts"]["trace"]["trace_id"] == segment_spans[0]["trace_id"] ) @@ -937,7 +682,7 @@ def _get_span_attr(attrs, key): return val -def test_span_streaming_no_error(lambda_client, test_environment): +def test_no_error(lambda_client, test_environment): lambda_client.invoke( FunctionName="BasicOkSpanStreaming", Payload=json.dumps({}), @@ -979,7 +724,7 @@ def test_span_streaming_no_error(lambda_client, test_environment): assert _get_span_attr(attrs, "messaging.batch.message_count") == 1 -def test_span_streaming_error(lambda_client, test_environment): +def test_error(lambda_client, test_environment): lambda_client.invoke( FunctionName="RaiseErrorSpanStreaming", Payload=json.dumps({}), @@ -1029,7 +774,7 @@ def test_span_streaming_error(lambda_client, test_environment): assert _get_span_attr(attrs, "messaging.batch.message_count") == 1 -def test_span_streaming_trace_continuation(lambda_client, test_environment): +def test_trace_continuation(lambda_client, test_environment): trace_id = "471a43a4192642f0b136d5159a501701" parent_span_id = "6e8f22c393e68f19" parent_sampled = 1 @@ -1069,7 +814,7 @@ def test_span_streaming_trace_continuation(lambda_client, test_environment): assert "faas.invocation_id" in attrs -def test_span_streaming_request_attributes(lambda_client, test_environment): +def test_request_attributes(lambda_client, test_environment): payload = { "headers": { "Content-Type": "application/json", @@ -1081,7 +826,7 @@ def test_span_streaming_request_attributes(lambda_client, test_environment): } lambda_client.invoke( - FunctionName="BasicOkSpanStreamingPii", + FunctionName="BasicOkSpanStreamingDataCollection", Payload=json.dumps(payload), ) span_items = test_environment["server"].span_items @@ -1100,21 +845,19 @@ def test_span_streaming_request_attributes(lambda_client, test_environment): _get_span_attr(attrs, "http.request.header.content-type") == "application/json" ) assert _get_span_attr(attrs, "http.request.header.accept") == "text/html" - assert _get_span_attr(attrs, "faas.name") == "BasicOkSpanStreamingPii" + assert _get_span_attr(attrs, "faas.name") == "BasicOkSpanStreamingDataCollection" assert _get_span_attr(attrs, "cloud.provider") == "aws" assert _get_span_attr(attrs, "cloud.platform") == "aws_lambda" assert _get_span_attr(attrs, "cloud.region") == "us-east-1" assert _get_span_attr(attrs, "faas.version") == "$LATEST" assert "faas.invocation_id" in attrs assert _get_span_attr(attrs, "aws.log.group.names") == [ - "aws/lambda/BasicOkSpanStreamingPii" + "aws/lambda/BasicOkSpanStreamingDataCollection" ] assert _get_span_attr(attrs, "aws.log.stream.names") == ["$LATEST"] -def test_span_streaming_url_query_params_with_data_collection( - lambda_client, test_environment -): +def test_url_query_params_with_data_collection(lambda_client, test_environment): payload = { "httpMethod": "GET", "queryStringParameters": { @@ -1144,67 +887,7 @@ def test_span_streaming_url_query_params_with_data_collection( ) -def test_span_streaming_user_info_with_send_default_pii( - lambda_client, test_environment -): - payload = b""" - { - "resource": "/asd", - "path": "/asd", - "httpMethod": "GET", - "headers": { - "Host": "iwsz2c7uwi.execute-api.us-east-1.amazonaws.com", - "User-Agent": "custom", - "X-Forwarded-Proto": "https" - }, - "queryStringParameters": { - "bonkers": "true" - }, - "pathParameters": null, - "stageVariables": null, - "requestContext": { - "identity": { - "sourceIp": "213.47.147.207", - "userArn": "42" - } - }, - "body": null, - "isBase64Encoded": false - } - """ - - lambda_client.invoke( - FunctionName="BasicOkSpanStreamingPii", - Payload=payload, - ) - span_items = test_environment["server"].span_items - - segment_spans = [s for s in span_items if s.get("is_segment")] - assert len(segment_spans) == 1 - attrs = segment_spans[0]["attributes"] - - assert _get_span_attr(attrs, "user.id") == "42" - - -def test_span_streaming_user_info_with_data_collection_user_info_on( - lambda_client, test_environment -): - lambda_client.invoke( - FunctionName="BasicOkSpanStreamingDataCollectionUserInfoOn", - Payload=USER_INFO_PAYLOAD, - ) - span_items = test_environment["server"].span_items - - segment_spans = [s for s in span_items if s.get("is_segment")] - assert len(segment_spans) == 1 - attrs = segment_spans[0]["attributes"] - - assert _get_span_attr(attrs, "user.id") == "42" - - -def test_span_streaming_user_info_with_data_collection_user_info_off( - lambda_client, test_environment -): +def test_user_info_with_data_collection_user_info_off(lambda_client, test_environment): lambda_client.invoke( FunctionName="BasicOkSpanStreamingDataCollectionUserInfoOff", Payload=USER_INFO_PAYLOAD, @@ -1243,12 +926,9 @@ def test_error_has_existing_trace_context( Payload=json.dumps(payload), ) envelopes = test_environment["server"].envelopes + span_items = test_environment["server"].span_items - if lambda_function_name == "RaiseErrorPerformanceEnabled": - (error_event, transaction_event) = envelopes - else: - (error_event,) = envelopes - transaction_event = None + (error_event,) = envelopes assert "trace" in error_event["contexts"] assert "trace_id" in error_event["contexts"]["trace"] @@ -1257,10 +937,7 @@ def test_error_has_existing_trace_context( == "471a43a4192642f0b136d5159a501701" ) - if transaction_event: - assert "trace" in transaction_event["contexts"] - assert "trace_id" in transaction_event["contexts"]["trace"] - assert ( - transaction_event["contexts"]["trace"]["trace_id"] - == "471a43a4192642f0b136d5159a501701" - ) + if lambda_function_name == "RaiseErrorPerformanceEnabled": + segment_spans = [s for s in span_items if s.get("is_segment")] + assert len(segment_spans) == 1 + assert segment_spans[0]["trace_id"] == "471a43a4192642f0b136d5159a501701" diff --git a/tests/integrations/boto3/test_aws_http_connection.py b/tests/integrations/boto3/test_aws_http_connection.py index 684f89d385..4aacf2d2d6 100644 --- a/tests/integrations/boto3/test_aws_http_connection.py +++ b/tests/integrations/boto3/test_aws_http_connection.py @@ -45,25 +45,19 @@ def _request(server, headers, path="/"): connection.close() -@pytest.mark.parametrize("span_streaming", [False, True]) def test_aws_http_connection_adds_missing_unsigned_propagation_headers( - sentry_init, local_http_server, span_streaming + sentry_init, + local_http_server, ): """Add missing unsigned `sentry-trace` and `baggage`.""" sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", default_integrations=False, integrations=[StdlibIntegration()], ) server, requests = local_http_server - - if span_streaming: - with sentry_sdk.traces.start_span(name="test"): # type: ignore[attr-defined] - _request(server, []) - else: - with sentry_sdk.start_transaction(name="test", sampled=True): - _request(server, []) + with sentry_sdk.start_span(name="test"): # type: ignore[attr-defined] + _request(server, []) headers: HTTPMessage = requests[0] @@ -78,37 +72,25 @@ def test_aws_http_connection_adds_missing_unsigned_propagation_headers( assert len(sentry_trace_headers) == 1 -@pytest.mark.parametrize("span_streaming", [False, True]) def test_aws_http_connection_appends_baggage_but_preserves_sentry_trace( - sentry_init, local_http_server, span_streaming + sentry_init, + local_http_server, ): """Append unsigned `baggage`; leave existing `sentry-trace` as-is.""" sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", default_integrations=False, integrations=[StdlibIntegration()], ) server, requests = local_http_server - - if span_streaming: - with sentry_sdk.traces.start_span(name="test"): # type: ignore[attr-defined] - _request( - server, - [ - ("baggage", "vendor=value"), - ("sentry-trace", "existing-trace"), - ], - ) - else: - with sentry_sdk.start_transaction(name="test", sampled=True): - _request( - server, - [ - ("baggage", "vendor=value"), - ("sentry-trace", "existing-trace"), - ], - ) + with sentry_sdk.start_span(name="test"): # type: ignore[attr-defined] + _request( + server, + [ + ("baggage", "vendor=value"), + ("sentry-trace", "existing-trace"), + ], + ) headers: HTTPMessage = requests[0] @@ -123,14 +105,13 @@ def test_aws_http_connection_appends_baggage_but_preserves_sentry_trace( assert headers.get_all("sentry-trace") == ["existing-trace"] -@pytest.mark.parametrize("span_streaming", [False, True]) def test_aws_http_connection_preserves_signed_propagation_headers( - sentry_init, local_http_server, span_streaming + sentry_init, + local_http_server, ): """Leave signed `sentry-trace` and `baggage` as-is.""" sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", default_integrations=False, integrations=[StdlibIntegration()], ) @@ -143,27 +124,15 @@ def test_aws_http_connection_preserves_signed_propagation_headers( "SignedHeaders=baggage;host;sentry-trace, " "Signature=sixtyseven" ) - - if span_streaming: - with sentry_sdk.traces.start_span(name="test"): # type: ignore[attr-defined] - _request( - server, - [ - ("baggage", "vendor=value"), - ("sentry-trace", "existing-trace"), - ("Authorization", authorization), - ], - ) - else: - with sentry_sdk.start_transaction(name="test", sampled=True): - _request( - server, - [ - ("baggage", "vendor=value"), - ("sentry-trace", "existing-trace"), - ("Authorization", authorization), - ], - ) + with sentry_sdk.start_span(name="test"): # type: ignore[attr-defined] + _request( + server, + [ + ("baggage", "vendor=value"), + ("sentry-trace", "existing-trace"), + ("Authorization", authorization), + ], + ) headers: HTTPMessage = requests[0] @@ -180,14 +149,13 @@ def test_aws_http_connection_preserves_signed_propagation_headers( } -@pytest.mark.parametrize("span_streaming", [False, True]) def test_aws_http_connection_preserves_query_signed_baggage( - sentry_init, local_http_server, span_streaming + sentry_init, + local_http_server, ): """Leave query-signed `baggage` as-is; add unsigned `sentry-trace`.""" sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", default_integrations=False, integrations=[StdlibIntegration()], ) @@ -202,21 +170,12 @@ def test_aws_http_connection_preserves_query_signed_baggage( "&X-Amz-SignedHeaders=baggage%3Bhost" "&X-Amz-Signature=sixtyseven" ) - - if span_streaming: - with sentry_sdk.traces.start_span(name="test"): # type: ignore[attr-defined] - _request( - server, - [("baggage", "vendor=value")], - path=path, - ) - else: - with sentry_sdk.start_transaction(name="test", sampled=True): - _request( - server, - [("baggage", "vendor=value")], - path=path, - ) + with sentry_sdk.start_span(name="test"): # type: ignore[attr-defined] + _request( + server, + [("baggage", "vendor=value")], + path=path, + ) headers: HTTPMessage = requests[0] # query-signed `baggage`: leave as-is. diff --git a/tests/integrations/boto3/test_s3.py b/tests/integrations/boto3/test_s3.py index 888e44ee4c..e7c57126d9 100644 --- a/tests/integrations/boto3/test_s3.py +++ b/tests/integrations/boto3/test_s3.py @@ -17,12 +17,9 @@ ) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_basic( sentry_init, - capture_events, capture_items, - span_streaming, ): sentry_init( traces_sample_rate=1.0, @@ -30,342 +27,202 @@ def test_basic( # disabled because session.resource() or s3.Bucket() result in a subprocess span for a # shell that runs "uname -p 2> /dev/null" on Python 3.7 with boto3 version 1.12.49. default_integrations=False, - trace_lifecycle="stream" if span_streaming else "static", ) s3 = session.resource("s3") bucket = s3.Bucket("bucket") + items = capture_items("span") - if span_streaming: - items = capture_items("span") + with sentry_sdk.start_span(name="custom parent") as span, MockResponse( + s3.meta.client, 200, {}, read_fixture("s3_list.xml") + ): + objects = [obj for obj in bucket.objects.all()] + assert len(objects) == 2 + assert objects[0].key == "foo.txt" + assert objects[1].key == "bar.txt" + span.end() - with sentry_sdk.traces.start_span(name="custom parent") as span, MockResponse( - s3.meta.client, 200, {}, read_fixture("s3_list.xml") - ): - objects = [obj for obj in bucket.objects.all()] - assert len(objects) == 2 - assert objects[0].key == "foo.txt" - assert objects[1].key == "bar.txt" - span.end() + sentry_sdk.flush() + spans = [item.payload for item in items] + assert len(spans) == 2 + span = spans[0] + assert span["attributes"]["sentry.op"] == "http.client" + assert span["name"] == "aws.s3.ListObjects" - sentry_sdk.flush() - spans = [item.payload for item in items] - assert len(spans) == 2 - span = spans[0] - assert span["attributes"]["sentry.op"] == "http.client" - assert span["name"] == "aws.s3.ListObjects" - else: - events = capture_events() - with sentry_sdk.start_transaction() as transaction, MockResponse( - s3.meta.client, 200, {}, read_fixture("s3_list.xml") - ): - items = [obj for obj in bucket.objects.all()] - assert len(items) == 2 - assert items[0].key == "foo.txt" - assert items[1].key == "bar.txt" - transaction.finish() - - (event,) = events - assert event["type"] == "transaction" - assert len(event["spans"]) == 1 - (span,) = event["spans"] - assert span["op"] == "http.client" - assert span["description"] == "aws.s3.ListObjects" - - -@pytest.mark.parametrize("send_default_pii", [True, False]) -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_streaming( - sentry_init, - capture_events, - capture_items, - span_streaming, - send_default_pii, -): +def test_streaming(sentry_init, capture_events, capture_items): sentry_init( traces_sample_rate=1.0, integrations=[Boto3Integration()], - send_default_pii=send_default_pii, - trace_lifecycle="stream" if span_streaming else "static", + data_collection={}, ) s3 = session.resource("s3") obj = s3.Bucket("bucket").Object("foo.pdf") - if span_streaming: - items = capture_items("span") - - with sentry_sdk.traces.start_span(name="custom parent") as span, MockResponse( - s3.meta.client, 200, {}, b"hello" - ): - body = obj.get()["Body"] - assert body.read(1) == b"h" - assert body.read(2) == b"el" - assert body.read(3) == b"lo" - assert body.read(1) == b"" - span.end() - - sentry_sdk.flush() - spans = [item.payload for item in items] - assert len(spans) == 3 - - span1 = spans[0] - assert span1["attributes"]["sentry.op"] == "http.client" - assert span1["name"] == "aws.s3.GetObject" - - expected_attrs = { - "http.request.method": "GET", - "rpc.method": "S3/GetObject", - "sentry.environment": "production", - "sentry.op": "http.client", - "sentry.origin": "auto.http.boto3", - "sentry.release": mock.ANY, - "sentry.sdk.name": "sentry.python", - "sentry.sdk.version": mock.ANY, - "sentry.segment.id": mock.ANY, - "sentry.segment.name": "custom parent", - "server.address": mock.ANY, - "thread.id": mock.ANY, - "thread.name": mock.ANY, - } - if send_default_pii: - expected_attrs["url.full"] = "https://bucket.s3.amazonaws.com/foo.pdf" - assert span1["attributes"] == ApproxDict(expected_attrs) - - assert "url.fragment" not in span1["attributes"] - assert "url.query" not in span1["attributes"] - if not send_default_pii: - assert "url.full" not in span1["attributes"] - - span2 = spans[1] - assert span2["attributes"]["sentry.op"] == "http.client.stream" - assert span2["name"] == "aws.s3.GetObject" - assert span2["parent_span_id"] == span1["span_id"] - else: - events = capture_events() + items = capture_items("span") - with sentry_sdk.start_transaction() as transaction, MockResponse( - s3.meta.client, 200, {}, b"hello" - ): - body = obj.get()["Body"] - assert body.read(1) == b"h" - assert body.read(2) == b"el" - assert body.read(3) == b"lo" - assert body.read(1) == b"" - transaction.finish() - - (event,) = events - assert event["type"] == "transaction" - assert len(event["spans"]) == 2 - - span1 = event["spans"][0] - assert span1["op"] == "http.client" - assert span1["description"] == "aws.s3.GetObject" - assert span1["data"] == ApproxDict( - { - "http.method": "GET", - "aws.request.url": "https://bucket.s3.amazonaws.com/foo.pdf", - "http.fragment": "", - "http.query": "", - } - ) + with sentry_sdk.start_span(name="custom parent") as span, MockResponse( + s3.meta.client, 200, {}, b"hello" + ): + body = obj.get()["Body"] + assert body.read(1) == b"h" + assert body.read(2) == b"el" + assert body.read(3) == b"lo" + assert body.read(1) == b"" + span.end() - span2 = event["spans"][1] - assert span2["op"] == "http.client.stream" - assert span2["description"] == "aws.s3.GetObject" - assert span2["parent_span_id"] == span1["span_id"] + sentry_sdk.flush() + spans = [item.payload for item in items] + assert len(spans) == 3 + + span1 = spans[0] + assert span1["attributes"]["sentry.op"] == "http.client" + assert span1["name"] == "aws.s3.GetObject" + + expected_attrs = { + "http.request.method": "GET", + "rpc.method": "S3/GetObject", + "sentry.environment": "production", + "sentry.op": "http.client", + "sentry.origin": "auto.http.boto3", + "sentry.release": mock.ANY, + "sentry.sdk.name": "sentry.python", + "sentry.sdk.version": mock.ANY, + "sentry.segment.id": mock.ANY, + "sentry.segment.name": "custom parent", + "server.address": mock.ANY, + "thread.id": mock.ANY, + "thread.name": mock.ANY, + } + expected_attrs["url.full"] = "https://bucket.s3.amazonaws.com/foo.pdf" + assert span1["attributes"] == ApproxDict(expected_attrs) + + assert "url.fragment" not in span1["attributes"] + assert "url.query" not in span1["attributes"] + span2 = spans[1] + assert span2["attributes"]["sentry.op"] == "http.client.stream" + assert span2["name"] == "aws.s3.GetObject" + assert span2["parent_span_id"] == span1["span_id"] -@pytest.mark.parametrize("span_streaming", [True, False]) def test_streaming_close( sentry_init, capture_events, capture_items, - span_streaming, ): sentry_init( traces_sample_rate=1.0, integrations=[Boto3Integration()], - trace_lifecycle="stream" if span_streaming else "static", ) s3 = session.resource("s3") obj = s3.Bucket("bucket").Object("foo.pdf") - if span_streaming: - items = capture_items("span") - - with sentry_sdk.traces.start_span(name="custom parent") as span, MockResponse( - s3.meta.client, 200, {}, b"hello" - ): - body = obj.get()["Body"] - assert body.read(1) == b"h" - body.close() # close partially-read stream - span.end() - - sentry_sdk.flush() - spans = [item.payload for item in items] - assert len(spans) == 3 - span1 = spans[0] - assert span1["attributes"]["sentry.op"] == "http.client" - span2 = spans[1] - assert span2["attributes"]["sentry.op"] == "http.client.stream" - else: - events = capture_events() + items = capture_items("span") - with sentry_sdk.start_transaction() as transaction, MockResponse( - s3.meta.client, 200, {}, b"hello" - ): - body = obj.get()["Body"] - assert body.read(1) == b"h" - body.close() # close partially-read stream - transaction.finish() + with sentry_sdk.start_span(name="custom parent") as span, MockResponse( + s3.meta.client, 200, {}, b"hello" + ): + body = obj.get()["Body"] + assert body.read(1) == b"h" + body.close() # close partially-read stream + span.end() - (event,) = events - assert event["type"] == "transaction" - assert len(event["spans"]) == 2 - span1 = event["spans"][0] - assert span1["op"] == "http.client" - span2 = event["spans"][1] - assert span2["op"] == "http.client.stream" + sentry_sdk.flush() + spans = [item.payload for item in items] + assert len(spans) == 3 + span1 = spans[0] + assert span1["attributes"]["sentry.op"] == "http.client" + span2 = spans[1] + assert span2["attributes"]["sentry.op"] == "http.client.stream" @pytest.mark.tests_internal_exceptions -@pytest.mark.parametrize("span_streaming", [True, False]) def test_omit_url_data_if_parsing_fails( sentry_init, capture_events, capture_items, - span_streaming, ): sentry_init( traces_sample_rate=1.0, integrations=[Boto3Integration()], - send_default_pii=True, - trace_lifecycle="stream" if span_streaming else "static", + data_collection={}, ) s3 = session.resource("s3") bucket = s3.Bucket("bucket") - if span_streaming: - items = capture_items("span") + items = capture_items("span") - with mock.patch( - "sentry_sdk.integrations.boto3.parse_url", - side_effect=ValueError, + with mock.patch( + "sentry_sdk.integrations.boto3.parse_url", + side_effect=ValueError, + ): + with sentry_sdk.start_span(name="custom parent") as span, MockResponse( + s3.meta.client, 200, {}, read_fixture("s3_list.xml") ): - with sentry_sdk.traces.start_span( - name="custom parent" - ) as span, MockResponse( - s3.meta.client, 200, {}, read_fixture("s3_list.xml") - ): - objects = [obj for obj in bucket.objects.all()] - assert len(objects) == 2 - assert objects[0].key == "foo.txt" - assert objects[1].key == "bar.txt" - span.end() - - sentry_sdk.flush() - spans = [item.payload for item in items] - assert spans[0]["attributes"] == ApproxDict( - { - "http.request.method": "GET", - "rpc.method": "S3/ListObjects", - "sentry.environment": "production", - "sentry.op": "http.client", - "sentry.origin": "auto.http.boto3", - "sentry.release": mock.ANY, - "sentry.sdk.name": "sentry.python", - "sentry.sdk.version": mock.ANY, - "sentry.segment.id": mock.ANY, - "sentry.segment.name": "custom parent", - "server.address": mock.ANY, - "thread.id": mock.ANY, - "thread.name": mock.ANY, - } - ) - - assert "url.full" not in spans[0]["attributes"] - assert "url.fragment" not in spans[0]["attributes"] - assert "url.query" not in spans[0]["attributes"] - else: - events = capture_events() + objects = [obj for obj in bucket.objects.all()] + assert len(objects) == 2 + assert objects[0].key == "foo.txt" + assert objects[1].key == "bar.txt" + span.end() + + sentry_sdk.flush() + spans = [item.payload for item in items] + assert spans[0]["attributes"] == ApproxDict( + { + "http.request.method": "GET", + "rpc.method": "S3/ListObjects", + "sentry.environment": "production", + "sentry.op": "http.client", + "sentry.origin": "auto.http.boto3", + "sentry.release": mock.ANY, + "sentry.sdk.name": "sentry.python", + "sentry.sdk.version": mock.ANY, + "sentry.segment.id": mock.ANY, + "sentry.segment.name": "custom parent", + "server.address": mock.ANY, + "thread.id": mock.ANY, + "thread.name": mock.ANY, + } + ) + + assert "url.full" not in spans[0]["attributes"] + assert "url.fragment" not in spans[0]["attributes"] + assert "url.query" not in spans[0]["attributes"] + - with mock.patch( - "sentry_sdk.integrations.boto3.parse_url", - side_effect=ValueError, - ): - with sentry_sdk.start_transaction() as transaction, MockResponse( - s3.meta.client, 200, {}, read_fixture("s3_list.xml") - ): - items = [obj for obj in bucket.objects.all()] - assert len(items) == 2 - assert items[0].key == "foo.txt" - assert items[1].key == "bar.txt" - transaction.finish() - - (event,) = events - assert event["spans"][0]["data"] == ApproxDict( - { - "http.method": "GET", - # no url data - } - ) - - assert "aws.request.url" not in event["spans"][0]["data"] - assert "http.fragment" not in event["spans"][0]["data"] - assert "http.query" not in event["spans"][0]["data"] - - -@pytest.mark.parametrize("span_streaming", [True, False]) def test_span_origin( sentry_init, - capture_events, capture_items, - span_streaming, ): sentry_init( traces_sample_rate=1.0, integrations=[Boto3Integration()], - trace_lifecycle="stream" if span_streaming else "static", ) s3 = session.resource("s3") bucket = s3.Bucket("bucket") + items = capture_items("span") - if span_streaming: - items = capture_items("span") - - with sentry_sdk.traces.start_span(name="custom parent"), MockResponse( - s3.meta.client, 200, {}, read_fixture("s3_list.xml") - ): - _ = [obj for obj in bucket.objects.all()] - - sentry_sdk.flush() - spans = [item.payload for item in items] - - assert spans[1]["attributes"]["sentry.origin"] == "manual" - assert spans[0]["attributes"]["sentry.origin"] == "auto.http.boto3" - else: - events = capture_events() - - with sentry_sdk.start_transaction(), MockResponse( - s3.meta.client, 200, {}, read_fixture("s3_list.xml") - ): - _ = [obj for obj in bucket.objects.all()] + with sentry_sdk.start_span(name="custom parent"), MockResponse( + s3.meta.client, 200, {}, read_fixture("s3_list.xml") + ): + _ = [obj for obj in bucket.objects.all()] - (event,) = events + sentry_sdk.flush() + spans = [item.payload for item in items] - assert event["contexts"]["trace"]["origin"] == "manual" - assert event["spans"][0]["origin"] == "auto.http.boto3" + assert spans[1]["attributes"]["sentry.origin"] == "manual" + assert spans[0]["attributes"]["sentry.origin"] == "auto.http.boto3" def test_breadcrumb(sentry_init, capture_events): sentry_init( integrations=[Boto3Integration()], default_integrations=False, + data_collection={}, ) s3 = session.resource("s3") @@ -373,7 +230,9 @@ def test_breadcrumb(sentry_init, capture_events): events = capture_events() - with MockResponse(s3.meta.client, 200, {}, read_fixture("s3_list.xml")): + with sentry_sdk.start_span(name="custom parent"), MockResponse( + s3.meta.client, 200, {}, read_fixture("s3_list.xml") + ): _ = [obj for obj in bucket.objects.all()] capture_message("Testing!") @@ -382,60 +241,15 @@ def test_breadcrumb(sentry_init, capture_events): (crumb,) = event["breadcrumbs"]["values"] assert crumb["type"] == "http" assert crumb["category"] == "httplib" + assert crumb["data"] == ApproxDict( { - "aws.request.url": mock.ANY, - SPANDATA.HTTP_METHOD: "GET", - SPANDATA.HTTP_QUERY: mock.ANY, - SPANDATA.HTTP_FRAGMENT: "", + SPANDATA.URL_FULL: mock.ANY, + SPANDATA.HTTP_REQUEST_METHOD: "GET", + SPANDATA.URL_QUERY: mock.ANY, } ) - - -@pytest.mark.parametrize("send_default_pii", [True, False]) -def test_breadcrumb_span_streaming(sentry_init, capture_events, send_default_pii): - sentry_init( - integrations=[Boto3Integration()], - default_integrations=False, - trace_lifecycle="stream", - send_default_pii=send_default_pii, - ) - - s3 = session.resource("s3") - bucket = s3.Bucket("bucket") - - events = capture_events() - - with sentry_sdk.traces.start_span(name="custom parent"), MockResponse( - s3.meta.client, 200, {}, read_fixture("s3_list.xml") - ): - _ = [obj for obj in bucket.objects.all()] - - capture_message("Testing!") - - (event,) = events - (crumb,) = event["breadcrumbs"]["values"] - assert crumb["type"] == "http" - assert crumb["category"] == "httplib" - - if send_default_pii: - assert crumb["data"] == ApproxDict( - { - SPANDATA.URL_FULL: mock.ANY, - SPANDATA.HTTP_REQUEST_METHOD: "GET", - SPANDATA.URL_QUERY: mock.ANY, - } - ) - assert SPANDATA.URL_FRAGMENT not in crumb["data"] - else: - assert crumb["data"] == ApproxDict( - { - SPANDATA.HTTP_REQUEST_METHOD: "GET", - } - ) - assert SPANDATA.URL_FULL not in crumb["data"] - assert SPANDATA.URL_QUERY not in crumb["data"] - assert SPANDATA.URL_FRAGMENT not in crumb["data"] + assert SPANDATA.URL_FRAGMENT not in crumb["data"] BUCKET_URL = "https://bucket.s3.amazonaws.com/" @@ -444,19 +258,9 @@ def test_breadcrumb_span_streaming(sentry_init, capture_events, send_default_pii # means the URL is recorded without a query string. # Structure of the parameters is "init_kwargs, expected_query" URL_QUERY_PARAMS = [ - pytest.param( - {"send_default_pii": True}, - "list-type=2&prefix=foo&continuation-token=abc&encoding-type=url", - id="send_default_pii_true", - ), - pytest.param( - {"send_default_pii": False}, - None, - id="send_default_pii_false", - ), pytest.param( {}, - None, + "list-type=2&prefix=foo&continuation-token=%5BFiltered%5D&encoding-type=url", id="defaults", ), pytest.param( @@ -499,26 +303,17 @@ def test_breadcrumb_span_streaming(sentry_init, capture_events, send_default_pii "", id="data_collection_off", ), - pytest.param( - { - "send_default_pii": True, - "data_collection": {"url_query_params": {"mode": "off"}}, - }, - "", - id="data_collection_wins_over_send_default_pii", - ), ] @pytest.mark.parametrize("init_kwargs, expected_query", URL_QUERY_PARAMS) -def test_url_query_data_collection_span_streaming( +def test_url_query_data_collection( sentry_init, capture_items, init_kwargs, expected_query ): sentry_init( traces_sample_rate=1.0, integrations=[Boto3Integration()], default_integrations=False, - trace_lifecycle="stream", **init_kwargs, ) @@ -526,7 +321,7 @@ def test_url_query_data_collection_span_streaming( items = capture_items("span") - with sentry_sdk.traces.start_span(name="custom parent"), MockResponse( + with sentry_sdk.start_span(name="custom parent"), MockResponse( client, 200, {}, read_fixture("s3_list.xml") ): client.list_objects_v2(Bucket="bucket", Prefix="foo", ContinuationToken="abc") @@ -559,7 +354,6 @@ def test_url_query_data_collection_breadcrumb( sentry_init( integrations=[Boto3Integration()], default_integrations=False, - trace_lifecycle="stream", **init_kwargs, ) @@ -567,7 +361,7 @@ def test_url_query_data_collection_breadcrumb( events = capture_events() - with sentry_sdk.traces.start_span(name="custom parent"), MockResponse( + with sentry_sdk.start_span(name="custom parent"), MockResponse( client, 200, {}, read_fixture("s3_list.xml") ): client.list_objects_v2(Bucket="bucket", Prefix="foo", ContinuationToken="abc") diff --git a/tests/integrations/boto3/test_trace_propagation.py b/tests/integrations/boto3/test_trace_propagation.py index 85d6544c63..b9485ebf53 100644 --- a/tests/integrations/boto3/test_trace_propagation.py +++ b/tests/integrations/boto3/test_trace_propagation.py @@ -3,7 +3,6 @@ from urllib.parse import parse_qs, urlparse import boto3 -import pytest from botocore.config import Config import sentry_sdk @@ -35,11 +34,11 @@ def _start_server(): return server, thread -@pytest.mark.parametrize("span_streaming", [False, True]) -def test_botocore_merges_propagation_before_sigv4_signing(sentry_init, span_streaming): +def test_botocore_merges_propagation_before_sigv4_signing( + sentry_init, +): sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", default_integrations=False, integrations=[Boto3Integration(), StdlibIntegration()], ) @@ -76,21 +75,13 @@ def capture_headers_after_instrumentation(request, **kwargs): client.meta.events.register_last( "before-sign", capture_headers_after_instrumentation ) - - if span_streaming: - with sentry_sdk.traces.start_span( # type: ignore[attr-defined] - name="incoming" - ): - response = client.head_object( - Bucket="example-bucket", - Key="example-key", - ) - else: - with sentry_sdk.start_transaction(name="incoming", sampled=True): - response = client.head_object( - Bucket="example-bucket", - Key="example-key", - ) + with sentry_sdk.start_span( # type: ignore[attr-defined] + name="incoming" + ): + response = client.head_object( + Bucket="example-bucket", + Key="example-key", + ) assert response["ResponseMetadata"]["HTTPStatusCode"] == 200 headers = _AwsRequestHandler.requests[-1] @@ -127,14 +118,12 @@ def capture_headers_after_instrumentation(request, **kwargs): thread.join() -@pytest.mark.parametrize("span_streaming", [False, True]) def test_botocore_without_boto3_integration_preserves_signed_baggage( - sentry_init, span_streaming + sentry_init, ): """Leave signed `baggage` as-is; add unsigned `sentry-trace`.""" sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", default_integrations=False, integrations=[StdlibIntegration()], ) @@ -154,21 +143,13 @@ def _inject_signed_baggage(request, **kwargs): # inject `baggage` before SigV4; stdlib-only path cannot change signed fields. client.meta.events.register("before-sign", _inject_signed_baggage) - - if span_streaming: - with sentry_sdk.traces.start_span( # type: ignore[attr-defined] - name="incoming" - ): - response = client.head_object( - Bucket="example-bucket", - Key="example-key", - ) - else: - with sentry_sdk.start_transaction(name="incoming", sampled=True): - response = client.head_object( - Bucket="example-bucket", - Key="example-key", - ) + with sentry_sdk.start_span( # type: ignore[attr-defined] + name="incoming" + ): + response = client.head_object( + Bucket="example-bucket", + Key="example-key", + ) assert response["ResponseMetadata"]["HTTPStatusCode"] == 200 headers = _AwsRequestHandler.requests[-1] diff --git a/tests/integrations/bottle/test_bottle.py b/tests/integrations/bottle/test_bottle.py index 7f8ad7fa3f..6acaeaa99e 100644 --- a/tests/integrations/bottle/test_bottle.py +++ b/tests/integrations/bottle/test_bottle.py @@ -60,69 +60,6 @@ def test_has_context(sentry_init, app, capture_events, get_client): assert event["request"]["url"] == "http://localhost/message" -@pytest.mark.parametrize( - "url,transaction_style,expected_transaction,expected_source", - [ - ("/message", "endpoint", "hi", "component"), - ("/message", "url", "/message", "route"), - ("/message/123456", "url", "/message/", "route"), - ("/message-named-route", "endpoint", "hi", "component"), - ], -) -def test_transaction_style( - sentry_init, - url, - transaction_style, - expected_transaction, - expected_source, - capture_events, - get_client, -): - sentry_init(integrations=[BottleIntegration(transaction_style=transaction_style)]) - events = capture_events() - - client = get_client() - response = client.get(url) - assert response[1] == "200 OK" - - (event,) = events - # We use endswith() because in Python 2.7 it is "test_bottle.hi" - # and in later Pythons "test_bottle.app..hi" - assert event["transaction"].endswith(expected_transaction) - assert event["transaction_info"] == {"source": expected_source} - - -@pytest.mark.parametrize("debug", (True, False), ids=["debug", "nodebug"]) -@pytest.mark.parametrize("catchall", (True, False), ids=["catchall", "nocatchall"]) -def test_errors( - sentry_init, capture_exceptions, capture_events, app, debug, catchall, get_client -): - sentry_init(integrations=[BottleIntegration()]) - - app.catchall = catchall - set_debug(mode=debug) - - exceptions = capture_exceptions() - events = capture_events() - - @app.route("/") - def index(): - 1 / 0 - - client = get_client() - try: - client.get("/") - except ZeroDivisionError: - pass - - (exc,) = exceptions - assert isinstance(exc, ZeroDivisionError) - - (event,) = events - assert event["exception"]["values"][0]["mechanism"]["type"] == "bottle" - assert event["exception"]["values"][0]["mechanism"]["handled"] is False - - @pytest.mark.parametrize("max_value_length", [1024, None]) def test_large_json_request( sentry_init, capture_events, app, get_client, max_value_length @@ -497,121 +434,33 @@ def here(): assert not events -@pytest.mark.parametrize("span_streaming", [True, False]) def test_span_origin( sentry_init, get_client, capture_events, capture_items, - span_streaming, ): sentry_init( integrations=[BottleIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") - else: - events = capture_events() + items = capture_items("span") client = get_client() client.get("/message") - if span_streaming: - sentry_sdk.flush() - spans = [item.payload for item in items] - segment = spans[-1] - assert segment["is_segment"] is True - assert segment["attributes"]["sentry.origin"] == "auto.http.bottle" - else: - (_, event) = events - assert event["contexts"]["trace"]["origin"] == "auto.http.bottle" - - -@pytest.mark.parametrize("raise_error", [True, False]) -@pytest.mark.parametrize( - ("integration_kwargs", "status_code", "should_capture"), - ( - ({}, None, False), - ({}, 400, False), - ({}, 451, False), # Highest 4xx status code - ({}, 500, True), - ({}, 511, True), # Highest 5xx status code - ({"failed_request_status_codes": set()}, 500, False), - ({"failed_request_status_codes": set()}, 511, False), - ({"failed_request_status_codes": {404, *range(500, 600)}}, 404, True), - ({"failed_request_status_codes": {404, *range(500, 600)}}, 500, True), - ({"failed_request_status_codes": {404, *range(500, 600)}}, 400, False), - ), -) -def test_failed_request_status_codes( - sentry_init, - capture_events, - integration_kwargs, - status_code, - should_capture, - raise_error, -): - sentry_init(integrations=[BottleIntegration(**integration_kwargs)]) - events = capture_events() - - app = Bottle() - - @app.route("/") - def handle(): - if status_code is not None: - response = HTTPResponse(status=status_code) - if raise_error: - raise response - else: - return response - return "OK" - - client = Client(app, Response) - response = client.get("/") - - expected_status = 200 if status_code is None else status_code - assert response.status_code == expected_status - - if should_capture: - (event,) = events - assert event["exception"]["values"][0]["type"] == "HTTPResponse" - else: - assert not events - - -def test_failed_request_status_codes_non_http_exception(sentry_init, capture_events): - """ - If an exception, which is not an instance of HTTPResponse, is raised, it should be captured, even if - failed_request_status_codes is empty. - """ - sentry_init(integrations=[BottleIntegration(failed_request_status_codes=set())]) - events = capture_events() - - app = Bottle() - - @app.route("/") - def handle(): - 1 / 0 - - client = Client(app, Response) - - try: - client.get("/") - except ZeroDivisionError: - pass - - (event,) = events - assert event["exception"]["values"][0]["type"] == "ZeroDivisionError" + sentry_sdk.flush() + spans = [item.payload for item in items] + segment = spans[-1] + assert segment["is_segment"] is True + assert segment["attributes"]["sentry.origin"] == "auto.http.bottle" -def test_span_streaming_basic(sentry_init, capture_items): +def test_basic(sentry_init, capture_items): sentry_init( integrations=[BottleIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", ) items = capture_items("span") @@ -651,7 +500,7 @@ def hi(): ("/message-named-route", "endpoint", "hi", "component"), ], ) -def test_span_streaming_transaction_style( +def test_transaction_style( sentry_init, capture_items, url, @@ -662,7 +511,6 @@ def test_span_streaming_transaction_style( sentry_init( integrations=[BottleIntegration(transaction_style=transaction_style)], traces_sample_rate=1.0, - trace_lifecycle="stream", ) items = capture_items("span") @@ -703,7 +551,6 @@ def test_http_route( sentry_init( integrations=[BottleIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", ) items = capture_items("span") @@ -722,15 +569,19 @@ def hi_with_id(message_id): assert segment["attributes"][SPANDATA.HTTP_ROUTE] == "/message/" -def test_span_streaming_with_error(sentry_init, capture_items): +@pytest.mark.parametrize("debug", (True, False), ids=["debug", "nodebug"]) +@pytest.mark.parametrize("catchall", (True, False), ids=["catchall", "nocatchall"]) +def test_errors(sentry_init, capture_items, debug, catchall): sentry_init( integrations=[BottleIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", ) - items = capture_items("event", "span") app = Bottle() + app.catchall = catchall + set_debug(mode=debug) + + items = capture_items("event", "span") @app.route("/error") def error(): @@ -778,7 +629,7 @@ def error(): (500, "error"), ], ) -def test_span_streaming_http_error_status( +def test_http_error_status( sentry_init, capture_items, status_code, @@ -787,7 +638,6 @@ def test_span_streaming_http_error_status( sentry_init( integrations=[BottleIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", ) items = capture_items("span") @@ -824,7 +674,7 @@ def handle(): ({"failed_request_status_codes": {404, *range(500, 600)}}, 400, False), ), ) -def test_span_streaming_failed_request_status_codes( +def test_failed_request_status_codes( sentry_init, capture_items, integration_kwargs, @@ -835,7 +685,6 @@ def test_span_streaming_failed_request_status_codes( sentry_init( integrations=[BottleIntegration(**integration_kwargs)], traces_sample_rate=1.0, - trace_lifecycle="stream", ) items = capture_items("event", "span") @@ -869,6 +718,31 @@ def handle(): assert len(events) == 0 +def test_failed_request_status_codes_non_http_exception(sentry_init, capture_events): + """ + If an exception, which is not an instance of HTTPResponse, is raised, it should be captured, even if + failed_request_status_codes is empty. + """ + sentry_init(integrations=[BottleIntegration(failed_request_status_codes=set())]) + events = capture_events() + + app = Bottle() + + @app.route("/") + def handle(): + 1 / 0 + + client = Client(app, Response) + + try: + client.get("/") + except ZeroDivisionError: + pass + + (event,) = events + assert event["exception"]["values"][0]["type"] == "ZeroDivisionError" + + @pytest.mark.parametrize( "data_collection, expect_body", [ @@ -950,31 +824,32 @@ def index(): assert "data" not in event.get("_meta", {}).get("request", {}) -def test_transaction_request_body_data_collection( - sentry_init, capture_events, app, get_client -): - sentry_init( - integrations=[BottleIntegration()], - traces_sample_rate=1.0, - data_collection={"http_bodies": []}, - ) +def test_error_event_has_transaction_name(sentry_init, capture_events): + """ + Error events captured during request handling should have the correct + transaction name set by the event processor, even though the inline + set_transaction_name call happens after the handler returns. + """ + sentry_init(integrations=[BottleIntegration(transaction_style="url")]) + events = capture_events() - data = {"username": "sentry-user", "age": "26"} + app = Bottle() - @app.route("/", method="POST") - def index(): - capture_message("hi") - return "ok" + @app.route("/error/") + def error_handler(error_id): + 1 / 0 - events = capture_events() + client = Client(app) - client = get_client() - response = client.post("/", content_type="application/json", data=json.dumps(data)) - assert response[1] == "200 OK" + try: + client.get("/error/123") + except ZeroDivisionError: + pass - event, transaction_event = events - assert "data" not in event["request"] - assert "data" not in transaction_event["request"] + (event,) = events + assert event["exception"]["values"][0]["type"] == "ZeroDivisionError" + assert event["transaction"] == "/error/" + assert event["transaction_info"] == {"source": "route"} def test_oversized_request_body_not_annotated_data_collection( diff --git a/tests/integrations/celery/integration_tests/test_celery_beat_cron_monitoring.py b/tests/integrations/celery/integration_tests/test_celery_beat_cron_monitoring.py index bd81199826..53d7bf2913 100644 --- a/tests/integrations/celery/integration_tests/test_celery_beat_cron_monitoring.py +++ b/tests/integrations/celery/integration_tests/test_celery_beat_cron_monitoring.py @@ -1,5 +1,4 @@ import os -import sys import pytest from celery.contrib.testing.worker import start_worker @@ -53,7 +52,6 @@ def inner(propagate_traces=True, monitor_beat_tasks=False, **kwargs): return inner -@pytest.mark.skipif(sys.version_info < (3, 7), reason="Requires Python 3.7+") @pytest.mark.forked def test_explanation(celery_init, capture_envelopes): """ @@ -92,7 +90,6 @@ def test_task(): assert len(envelopes) >= 0 -@pytest.mark.skipif(sys.version_info < (3, 7), reason="Requires Python 3.7+") @pytest.mark.forked def test_beat_task_crons_success(celery_init, capture_envelopes): app = celery_init( @@ -125,7 +122,6 @@ def test_task(): assert check_in["status"] == "ok" -@pytest.mark.skipif(sys.version_info < (3, 7), reason="Requires Python 3.7+") @pytest.mark.forked def test_beat_task_crons_error(celery_init, capture_envelopes): app = celery_init( diff --git a/tests/integrations/celery/test_celery.py b/tests/integrations/celery/test_celery.py index 56c7e9b781..b55186f71a 100644 --- a/tests/integrations/celery/test_celery.py +++ b/tests/integrations/celery/test_celery.py @@ -8,15 +8,11 @@ from celery.bin import worker import sentry_sdk -import sentry_sdk.traces -from sentry_sdk import get_current_span, start_transaction from sentry_sdk.integrations.celery import ( CeleryIntegration, _wrap_task_run, ) from sentry_sdk.integrations.celery.beat import _get_headers -from sentry_sdk.utils import SENSITIVE_DATA_SUBSTITUTE -from tests.conftest import ApproxDict @pytest.fixture @@ -121,20 +117,14 @@ def celery_invocation(request): return request.param -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("send_default_pii", [True, False]) def test_simple_with_performance( - capture_events, capture_items, init_celery, celery_invocation, - span_streaming, - send_default_pii, ): celery = init_celery( traces_sample_rate=1.0, - send_default_pii=send_default_pii, - trace_lifecycle="stream" if span_streaming else "static", + data_collection={}, ) @celery.task(name="dummy_task") @@ -142,43 +132,24 @@ def dummy_task(x, y): foo = 42 # noqa return x / y - if span_streaming: - items = capture_items("event", "span") + items = capture_items("event", "span") - with sentry_sdk.traces.start_span(name="span") as span: - celery_invocation(dummy_task, 1, 2) - _, expected_context = celery_invocation(dummy_task, 1, 0) + with sentry_sdk.start_span(name="span") as span: + celery_invocation(dummy_task, 1, 2) + _, expected_context = celery_invocation(dummy_task, 1, 0) - sentry_sdk.flush() - - error_event = next(item.payload for item in items if item.type == "event") - - assert error_event["contexts"]["trace"]["trace_id"] == span.trace_id - assert error_event["contexts"]["trace"]["span_id"] != span.span_id - else: - events = capture_events() - - with start_transaction(op="unit test transaction") as transaction: - celery_invocation(dummy_task, 1, 2) - _, expected_context = celery_invocation(dummy_task, 1, 0) + sentry_sdk.flush() - (_, error_event, _, _) = events + error_event = next(item.payload for item in items if item.type == "event") - assert error_event["contexts"]["trace"]["trace_id"] == transaction.trace_id - assert error_event["contexts"]["trace"]["span_id"] != transaction.span_id + assert error_event["contexts"]["trace"]["trace_id"] == span.trace_id + assert error_event["contexts"]["trace"]["span_id"] != span.span_id assert error_event["transaction"] == "dummy_task" assert "celery_task_id" in error_event["tags"] - if send_default_pii: - assert error_event["extra"]["celery-job"] == dict( - task_name="dummy_task", **expected_context - ) - else: - assert error_event["extra"]["celery-job"] == { - "task_name": "dummy_task", - "args": SENSITIVE_DATA_SUBSTITUTE, - "kwargs": SENSITIVE_DATA_SUBSTITUTE, - } + assert error_event["extra"]["celery-job"] == dict( + task_name="dummy_task", **expected_context + ) (exception,) = error_event["exception"]["values"] assert exception["type"] == "ZeroDivisionError" @@ -186,11 +157,11 @@ def dummy_task(x, y): assert exception["stacktrace"]["frames"][0]["vars"]["foo"] == "42" -@pytest.mark.parametrize("send_default_pii", [True, False]) -def test_simple_without_performance( - capture_events, init_celery, celery_invocation, send_default_pii -): - celery = init_celery(traces_sample_rate=None, send_default_pii=send_default_pii) +def test_simple_without_performance(capture_events, init_celery, celery_invocation): + celery = init_celery( + traces_sample_rate=None, + data_collection={}, + ) events = capture_events() @celery.task(name="dummy_task") @@ -215,16 +186,9 @@ def dummy_task(x, y): ) assert error_event["transaction"] == "dummy_task" assert "celery_task_id" in error_event["tags"] - if send_default_pii: - assert error_event["extra"]["celery-job"] == dict( - task_name="dummy_task", **expected_context - ) - else: - assert error_event["extra"]["celery-job"] == { - "task_name": "dummy_task", - "args": SENSITIVE_DATA_SUBSTITUTE, - "kwargs": SENSITIVE_DATA_SUBSTITUTE, - } + assert error_event["extra"]["celery-job"] == dict( + task_name="dummy_task", **expected_context + ) (exception,) = error_event["exception"]["values"] assert exception["type"] == "ZeroDivisionError" @@ -233,50 +197,26 @@ def dummy_task(x, y): @pytest.mark.parametrize( - "init_kwargs,expected_args,expected_kwargs", + "data_collection,expected_args,expected_kwargs", [ pytest.param( - {"data_collection": {}}, + {}, "included", "included", id="data_collection_default", ), pytest.param( - {"data_collection": {"queues": True}}, + {"queues": True}, "included", "included", id="data_collection_queues_on", ), pytest.param( - {"data_collection": {"queues": False}}, + {"queues": False}, None, None, id="data_collection_queues_off", ), - pytest.param( - {"send_default_pii": False}, - SENSITIVE_DATA_SUBSTITUTE, - SENSITIVE_DATA_SUBSTITUTE, - id="no_pii", - ), - pytest.param( - { - "data_collection": {"queues": False}, - "send_default_pii": False, - }, - None, - None, - id="data_collection_queues_off_with_no_pii", - ), - pytest.param( - { - "data_collection": {"queues": True}, - "send_default_pii": False, - }, - "included", - "included", - id="data_collection_queues_on_with_no_pii", - ), ], ) @pytest.mark.parametrize( @@ -286,24 +226,17 @@ def dummy_task(x, y): pytest.param("keyword", [], {"x": 1, "y": 0}, id="keyword_args"), ], ) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_task_args_kwargs_data_collection( - capture_events, capture_items, init_celery, - span_streaming, invocation_style, task_args, task_kwargs, - init_kwargs, + data_collection, expected_args, expected_kwargs, ): - init_dict = {"send_default_pii": True, **init_kwargs} - celery = init_celery( - trace_lifecycle="stream" if span_streaming else "static", - **init_dict, - ) + celery = init_celery(data_collection=data_collection) @celery.task(name="dummy_task") def dummy_task(x, y): @@ -314,15 +247,10 @@ def dummy_task(x, y): else: invoke = lambda: dummy_task.apply_async(kwargs=dict(x=1, y=0)) - if span_streaming: - items = capture_items("event") - invoke() - sentry_sdk.flush() - (error_event,) = (item.payload for item in items) - else: - events = capture_events() - invoke() - (error_event,) = events + items = capture_items("event") + invoke() + sentry_sdk.flush() + (error_event,) = (item.payload for item in items) celery_job = error_event["extra"]["celery-job"] @@ -332,24 +260,18 @@ def dummy_task(x, y): elif expected_args == "included": assert celery_job["args"] == task_args assert celery_job["kwargs"] == task_kwargs - else: - assert celery_job["args"] == SENSITIVE_DATA_SUBSTITUTE - assert celery_job["kwargs"] == SENSITIVE_DATA_SUBSTITUTE -@pytest.mark.parametrize("span_streaming", [True, False]) @pytest.mark.parametrize("task_fails", [True, False], ids=["error", "success"]) def test_transaction_events( - capture_events, capture_items, init_celery, celery_invocation, task_fails, - span_streaming, ): celery = init_celery( traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", + data_collection={}, ) @celery.task(name="dummy_task") @@ -360,100 +282,44 @@ def dummy_task(x, y): celery_invocation(dummy_task, 1, 1) sentry_sdk.flush() - if span_streaming: - items = capture_items("event", "span") - - with sentry_sdk.traces.start_span(name="submission") as span: - celery_invocation(dummy_task, 1, 0 if task_fails else 1) - - sentry_sdk.flush() - - if task_fails: - error_event = items.pop(0).payload - assert error_event["contexts"]["trace"]["trace_id"] == span.trace_id - assert error_event["exception"]["values"][0]["type"] == "ZeroDivisionError" + items = capture_items("event", "span") - process_span, execution_span, submit_span, submission_span = [ - item.payload for item in items - ] + with sentry_sdk.start_span(name="submission") as span: + celery_invocation(dummy_task, 1, 0 if task_fails else 1) - assert execution_span["name"] == "dummy_task" - assert execution_span["is_segment"] is True - assert execution_span["attributes"]["sentry.segment.name.source"] == "task" - assert execution_span["trace_id"] == span.trace_id - if task_fails: - assert execution_span["status"] == "error" - else: - assert execution_span["status"] == "ok" - - assert process_span["name"] == "dummy_task" - assert process_span["trace_id"] == span.trace_id - assert process_span["attributes"]["sentry.op"] == "queue.process" - assert process_span["parent_span_id"] == execution_span["span_id"] + sentry_sdk.flush() - assert submission_span["name"] == "submission" - assert submission_span["is_segment"] is True + if task_fails: + error_event = items.pop(0).payload + assert error_event["contexts"]["trace"]["trace_id"] == span.trace_id + assert error_event["exception"]["values"][0]["type"] == "ZeroDivisionError" - assert submit_span["name"] == "dummy_task" - assert submit_span["attributes"]["sentry.op"] == "queue.submit.celery" - assert submit_span["attributes"]["sentry.origin"] == "auto.queue.celery" - assert ( - submit_span["parent_span_id"] == submission_span["span_id"] == span.span_id - ) - assert submit_span["trace_id"] == span.trace_id + process_span, execution_span, submit_span, submission_span = [ + item.payload for item in items + ] + assert execution_span["name"] == "dummy_task" + assert execution_span["is_segment"] is True + assert execution_span["attributes"]["sentry.segment.name.source"] == "task" + assert execution_span["trace_id"] == span.trace_id + if task_fails: + assert execution_span["status"] == "error" else: - events = capture_events() - - with start_transaction(name="submission") as transaction: - celery_invocation(dummy_task, 1, 0 if task_fails else 1) - - if task_fails: - error_event = events.pop(0) - assert error_event["contexts"]["trace"]["trace_id"] == transaction.trace_id - assert error_event["exception"]["values"][0]["type"] == "ZeroDivisionError" + assert execution_span["status"] == "ok" - execution_event, submission_event = events - assert execution_event["transaction"] == "dummy_task" - assert execution_event["transaction_info"] == {"source": "task"} + assert process_span["name"] == "dummy_task" + assert process_span["trace_id"] == span.trace_id + assert process_span["attributes"]["sentry.op"] == "queue.process" + assert process_span["parent_span_id"] == execution_span["span_id"] - assert submission_event["transaction"] == "submission" - assert submission_event["transaction_info"] == {"source": "custom"} + assert submission_span["name"] == "submission" + assert submission_span["is_segment"] is True - assert execution_event["type"] == submission_event["type"] == "transaction" - assert execution_event["contexts"]["trace"]["trace_id"] == transaction.trace_id - assert submission_event["contexts"]["trace"]["trace_id"] == transaction.trace_id - - if task_fails: - assert execution_event["contexts"]["trace"]["status"] == "internal_error" - else: - assert execution_event["contexts"]["trace"]["status"] == "ok" - - assert len(execution_event["spans"]) == 1 - assert ( - execution_event["spans"][0].items() - >= { - "trace_id": str(transaction.trace_id), - "same_process_as_parent": True, - "op": "queue.process", - "description": "dummy_task", - "data": ApproxDict(), - }.items() - ) - assert submission_event["spans"] == [ - { - "data": ApproxDict(), - "description": "dummy_task", - "op": "queue.submit.celery", - "origin": "auto.queue.celery", - "parent_span_id": submission_event["contexts"]["trace"]["span_id"], - "same_process_as_parent": True, - "span_id": submission_event["spans"][0]["span_id"], - "start_timestamp": submission_event["spans"][0]["start_timestamp"], - "timestamp": submission_event["spans"][0]["timestamp"], - "trace_id": str(transaction.trace_id), - } - ] + assert submit_span["name"] == "dummy_task" + assert submit_span["attributes"]["sentry.op"] == "queue.submit.celery" + assert submit_span["attributes"]["sentry.origin"] == "auto.queue.celery" + assert submit_span["parent_span_id"] == submission_span["span_id"] == span.span_id + assert submit_span["trace_id"] == span.trace_id def test_no_double_patching(celery): @@ -487,18 +353,18 @@ def dummy_task(): def test_simple_no_propagation(capture_events, init_celery): - celery = init_celery(propagate_traces=False) + celery = init_celery(propagate_traces=False, data_collection={}) events = capture_events() @celery.task(name="dummy_task") def dummy_task(): 1 / 0 - with start_transaction() as transaction: + with sentry_sdk.start_span(name="segment") as segment: dummy_task.delay() (event,) = events - assert event["contexts"]["trace"]["trace_id"] != transaction.trace_id + assert event["contexts"]["trace"]["trace_id"] != segment.trace_id assert event["transaction"] == "dummy_task" (exception,) = event["exception"]["values"] assert exception["type"] == "ZeroDivisionError" @@ -553,61 +419,6 @@ def dummy_task(self): assert e["type"] == "ZeroDivisionError" -@pytest.mark.skip( - reason="This test is hanging when running test with `tox --parallel auto`. TODO: Figure out why and fix it!" -) -@pytest.mark.forked -def test_redis_backend_trace_propagation(init_celery, capture_events_forksafe): - celery = init_celery(traces_sample_rate=1.0, backend="redis") - - events = capture_events_forksafe() - - runs = [] - - @celery.task(name="dummy_task", bind=True) - def dummy_task(self): - runs.append(1) - 1 / 0 - - with start_transaction(name="submit_celery"): - # Curious: Cannot use delay() here or py2.7-celery-4.2 crashes - res = dummy_task.apply_async() - - with pytest.raises(Exception): # noqa: B017 - # Celery 4.1 raises a gibberish exception - res.wait() - - # if this is nonempty, the worker never really forked - assert not runs - - submit_transaction = events.read_event() - assert submit_transaction["type"] == "transaction" - assert submit_transaction["transaction"] == "submit_celery" - - assert len(submit_transaction["spans"]), ( - 4 - ) # Because redis integration was auto enabled - span = submit_transaction["spans"][0] - assert span["op"] == "queue.submit.celery" - assert span["description"] == "dummy_task" - - event = events.read_event() - (exception,) = event["exception"]["values"] - assert exception["type"] == "ZeroDivisionError" - - transaction = events.read_event() - assert ( - transaction["contexts"]["trace"]["trace_id"] - == event["contexts"]["trace"]["trace_id"] - == submit_transaction["contexts"]["trace"]["trace_id"] - ) - - events.read_flush() - - # if this is nonempty, the worker never really forked - assert not runs - - @pytest.mark.forked @pytest.mark.parametrize("newrelic_order", ["sentry_first", "sentry_last"]) def test_newrelic_interference(init_celery, newrelic_order, celery_invocation): @@ -648,18 +459,13 @@ def dummy_task(self, x, y): assert celery_invocation(dummy_task, 1, 1)[0].wait() == 1 -@pytest.mark.parametrize("span_streaming", [True, False]) def test_traces_sampler_gets_task_info_in_sampling_context( - span_streaming, init_celery, celery_invocation, DictionaryContaining, # noqa:N803 ): traces_sampler = mock.Mock(return_value=1.0) - celery = init_celery( - traces_sampler=traces_sampler, - trace_lifecycle="stream" if span_streaming else "static", - ) + celery = init_celery(traces_sampler=traces_sampler, data_collection={}) @celery.task(name="dog_walk") def walk_dogs(x, y): @@ -678,7 +484,9 @@ def walk_dogs(x, y): ) -def test_abstract_task(capture_events, celery, celery_invocation): +def test_abstract_task(init_celery, capture_events, celery, celery_invocation): + init_celery() + events = capture_events() class AbstractTask(celery.Task): @@ -694,7 +502,7 @@ def __call__(self, *args, **kwargs): def dummy_task(x, y): return x / y - with start_transaction(): + with sentry_sdk.start_span(name="task"): celery_invocation(dummy_task, 1, 0) assert not events @@ -729,7 +537,7 @@ def dummy_task(self, x, y): def test_baggage_propagation(init_celery): - celery = init_celery(traces_sample_rate=1.0, release="abcdef") + celery = init_celery(traces_sample_rate=1.0, release="abcdef", data_collection={}) @celery.task(name="dummy_task", bind=True) def dummy_task(self, x, y): @@ -737,7 +545,7 @@ def dummy_task(self, x, y): # patch random.randrange to return a predictable sample_rand value with mock.patch("sentry_sdk.tracing_utils.Random.randrange", return_value=500000): - with start_transaction() as transaction: + with sentry_sdk.start_span(name="segment") as segment: result = dummy_task.apply_async( args=(1, 0), headers={"baggage": "custom=value"}, @@ -746,18 +554,18 @@ def dummy_task(self, x, y): assert sorted(result["baggage"].split(",")) == sorted( [ "sentry-release=abcdef", - "sentry-trace_id={}".format(transaction.trace_id), + "sentry-trace_id={}".format(segment.trace_id), "sentry-environment=production", "sentry-sample_rand=0.500000", "sentry-sample_rate=1.0", "sentry-sampled=true", "custom=value", + "sentry-transaction=segment", ] ) -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_sentry_propagate_traces_override(span_streaming, init_celery): +def test_sentry_propagate_traces_override(init_celery): """ Test if the `sentry-propagate-traces` header given to `apply_async` overrides the `propagate_traces` parameter in the integration constructor. @@ -766,55 +574,35 @@ def test_sentry_propagate_traces_override(span_streaming, init_celery): propagate_traces=True, traces_sample_rate=1.0, release="abcdef", - trace_lifecycle="stream" if span_streaming else "static", + data_collection={}, ) @celery.task(name="dummy_task", bind=True) def dummy_task(self, message): - trace_id = ( - sentry_sdk.traces.get_current_span().trace_id - if span_streaming - else get_current_span().trace_id - ) + trace_id = sentry_sdk.get_current_span().trace_id return trace_id - if span_streaming: - with sentry_sdk.traces.start_span(name="parent") as span: - parent_trace_id = span.trace_id + with sentry_sdk.start_span(name="parent") as span: + parent_trace_id = span.trace_id - # should propagate trace - task_trace_id = dummy_task.apply_async( - args=("some message",), - ).get() - assert parent_trace_id == task_trace_id + # should propagate trace + task_trace_id = dummy_task.apply_async( + args=("some message",), + ).get() + assert parent_trace_id == task_trace_id - # should NOT propagate trace - task_trace_id = dummy_task.apply_async( - args=("another message",), - headers={"sentry-propagate-traces": False}, - ).get() - assert parent_trace_id != task_trace_id - else: - with start_transaction() as transaction: - transaction_trace_id = transaction.trace_id - - # should propagate trace - task_trace_id = dummy_task.apply_async( - args=("some message",), - ).get() - assert transaction_trace_id == task_trace_id - - # should NOT propagate trace - task_trace_id = dummy_task.apply_async( - args=("another message",), - headers={"sentry-propagate-traces": False}, - ).get() - assert transaction_trace_id != task_trace_id + # should NOT propagate trace + task_trace_id = dummy_task.apply_async( + args=("another message",), + headers={"sentry-propagate-traces": False}, + ).get() + assert parent_trace_id != task_trace_id def test_apply_async_manually_span(sentry_init): sentry_init( integrations=[CeleryIntegration()], + data_collection={}, ) def dummy_function(*args, **kwargs): @@ -827,7 +615,7 @@ def dummy_function(*args, **kwargs): def test_apply_async_no_args(init_celery): - celery = init_celery() + celery = init_celery(data_collection={}) @celery.task def example_task(): @@ -841,47 +629,37 @@ def example_task(): assert result.get() == "success" -@pytest.mark.parametrize("span_streaming", [True, False]) @pytest.mark.parametrize("routing_key", ("celery", "custom")) @mock.patch("celery.app.task.Task.request") def test_messaging_destination_name_default_exchange( mock_request, routing_key, - span_streaming, init_celery, - capture_events, capture_items, ): celery_app = init_celery( traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", + data_collection={}, ) mock_request.delivery_info = {"routing_key": routing_key, "exchange": ""} @celery_app.task() def task(): ... - if span_streaming: - items = capture_items("span") - task.apply_async() - sentry_sdk.flush() - process_span, _execution_span = items - assert ( - process_span.payload["attributes"]["messaging.destination.name"] - == routing_key - ) - else: - events = capture_events() - task.apply_async() - (event,) = events - (span,) = event["spans"] - assert span["data"]["messaging.destination.name"] == routing_key + items = capture_items("span") + task.apply_async() + + sentry_sdk.flush() + + process_span, _execution_span = items + assert ( + process_span.payload["attributes"]["messaging.destination.name"] == routing_key + ) -@pytest.mark.parametrize("span_streaming", [True, False]) @mock.patch("celery.app.task.Task.request") def test_messaging_destination_name_nondefault_exchange( - mock_request, span_streaming, init_celery, capture_events, capture_items + mock_request, init_celery, capture_items ): """ Currently, we only capture the routing key as the messaging.destination.name when @@ -891,112 +669,88 @@ def test_messaging_destination_name_nondefault_exchange( """ celery_app = init_celery( traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", + data_collection={}, ) mock_request.delivery_info = {"routing_key": "celery", "exchange": "custom"} @celery_app.task() def task(): ... - if span_streaming: - items = capture_items("span") - task.apply_async() - sentry_sdk.flush() - process_span, _execution_span = items - assert "messaging.destination.name" not in process_span.payload["attributes"] - else: - events = capture_events() - task.apply_async() - (event,) = events - (span,) = event["spans"] - assert "messaging.destination.name" not in span["data"] + items = capture_items("span") + + task.apply_async() + + sentry_sdk.flush() + + process_span, _execution_span = items + assert "messaging.destination.name" not in process_span.payload["attributes"] -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_messaging_id(span_streaming, init_celery, capture_events, capture_items): +def test_messaging_id(init_celery, capture_items): celery = init_celery( traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", + data_collection={}, ) @celery.task def example_task(): ... - if span_streaming: - items = capture_items("span") - example_task.apply_async() - sentry_sdk.flush() - process_span, _execution_span = items - assert "messaging.message.id" in process_span.payload["attributes"] - else: - events = capture_events() - example_task.apply_async() - (event,) = events - (span,) = event["spans"] - assert "messaging.message.id" in span["data"] + items = capture_items("span") + + example_task.apply_async() + + sentry_sdk.flush() + + process_span, _execution_span = items + assert "messaging.message.id" in process_span.payload["attributes"] -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_retry_count_zero(span_streaming, init_celery, capture_events, capture_items): +def test_retry_count_zero(init_celery, capture_items): celery = init_celery( traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", + data_collection={}, ) @celery.task() def task(): ... - if span_streaming: - items = capture_items("span") - task.apply_async() - sentry_sdk.flush() - process_span, _execution_span = items - assert process_span.payload["attributes"]["messaging.message.retry.count"] == 0 - else: - events = capture_events() - task.apply_async() - (event,) = events - (span,) = event["spans"] - assert span["data"]["messaging.message.retry.count"] == 0 + items = capture_items("span") + + task.apply_async() + + sentry_sdk.flush() + + process_span, _execution_span = items + assert process_span.payload["attributes"]["messaging.message.retry.count"] == 0 -@pytest.mark.parametrize("span_streaming", [True, False]) @mock.patch("celery.app.task.Task.request") -def test_retry_count_nonzero( - mock_request, span_streaming, init_celery, capture_events, capture_items -): +def test_retry_count_nonzero(mock_request, init_celery, capture_items): mock_request.retries = 3 celery = init_celery( traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", + data_collection={}, ) @celery.task() def task(): ... - if span_streaming: - items = capture_items("span") - task.apply_async() - sentry_sdk.flush() - process_span, _execution_span = items - assert process_span.payload["attributes"]["messaging.message.retry.count"] == 3 - else: - events = capture_events() - task.apply_async() - (event,) = events - (span,) = event["spans"] - assert span["data"]["messaging.message.retry.count"] == 3 + items = capture_items("span") + + task.apply_async() + + sentry_sdk.flush() + + process_span, _execution_span = items + assert process_span.payload["attributes"]["messaging.message.retry.count"] == 3 -@pytest.mark.parametrize("span_streaming", [True, False]) @pytest.mark.parametrize("system", ("redis", "amqp")) -def test_messaging_system( - system, span_streaming, init_celery, capture_events, capture_items -): +def test_messaging_system(system, init_celery, capture_items): celery = init_celery( traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", + data_collection={}, ) # Does not need to be a real URL, since we use always eager @@ -1005,25 +759,18 @@ def test_messaging_system( @celery.task() def task(): ... - if span_streaming: - items = capture_items("span") - task.apply_async() - sentry_sdk.flush() - process_span, _execution_span = items - assert process_span.payload["attributes"]["messaging.system"] == system - else: - events = capture_events() - task.apply_async() - (event,) = events - (span,) = event["spans"] - assert span["data"]["messaging.system"] == system + items = capture_items("span") + + task.apply_async() + + sentry_sdk.flush() + + process_span, _execution_span = items + assert process_span.payload["attributes"]["messaging.system"] == system -@pytest.mark.parametrize("span_streaming", [True, False]) @pytest.mark.parametrize("system", ("amqp", "redis")) -def test_producer_span_data( - system, span_streaming, monkeypatch, sentry_init, capture_events, capture_items -): +def test_producer_span_data(system, monkeypatch, sentry_init, capture_items): old_publish = kombu.messaging.Producer._publish def publish(*args, **kwargs): @@ -1034,111 +781,75 @@ def publish(*args, **kwargs): sentry_init( integrations=[CeleryIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", + data_collection={}, ) celery = Celery(__name__, broker=f"{system}://example.com") # noqa: E231 @celery.task() def task(): ... - if span_streaming: - items = capture_items("span") - - with sentry_sdk.traces.start_span(name="producer test"): - task.apply_async() - - sentry_sdk.flush() + items = capture_items("span") - span_items = [item.payload for item in items] - publish_span = next( - s for s in span_items if s["attributes"].get("sentry.op") == "queue.publish" - ) - - assert publish_span["attributes"]["messaging.system"] == system - assert publish_span["attributes"]["messaging.destination.name"] == "celery" - assert "messaging.message.id" in publish_span["attributes"] - assert publish_span["attributes"]["messaging.message.retry.count"] == 0 - else: - events = capture_events() + with sentry_sdk.start_span(name="producer test"): + task.apply_async() - with start_transaction(): - task.apply_async() + sentry_sdk.flush() - (event,) = events - span = next(span for span in event["spans"] if span["op"] == "queue.publish") + span_items = [item.payload for item in items] + publish_span = next( + s for s in span_items if s["attributes"].get("sentry.op") == "queue.publish" + ) - assert span["data"]["messaging.system"] == system - assert span["data"]["messaging.destination.name"] == "celery" - assert "messaging.message.id" in span["data"] - assert span["data"]["messaging.message.retry.count"] == 0 + assert publish_span["attributes"]["messaging.system"] == system + assert publish_span["attributes"]["messaging.destination.name"] == "celery" + assert "messaging.message.id" in publish_span["attributes"] + assert publish_span["attributes"]["messaging.message.retry.count"] == 0 monkeypatch.setattr(kombu.messaging.Producer, "_publish", old_publish) -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_receive_latency(span_streaming, init_celery, capture_events, capture_items): +def test_receive_latency(init_celery, capture_items): celery = init_celery( traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", + data_collection={}, ) @celery.task() def task(): ... - if span_streaming: - items = capture_items("span") - task.apply_async() - sentry_sdk.flush() - process_span, _execution_span = items - assert "messaging.message.receive.latency" in process_span.payload["attributes"] - assert ( - process_span.payload["attributes"]["messaging.message.receive.latency"] > 0 - ) - else: - events = capture_events() - task.apply_async() - (event,) = events - (span,) = event["spans"] - assert "messaging.message.receive.latency" in span["data"] - assert span["data"]["messaging.message.receive.latency"] > 0 + items = capture_items("span") + task.apply_async() -@pytest.mark.parametrize("span_streaming", [True, False]) -def tests_span_origin_consumer( - span_streaming, init_celery, capture_events, capture_items -): + sentry_sdk.flush() + + process_span, _execution_span = items + assert "messaging.message.receive.latency" in process_span.payload["attributes"] + assert process_span.payload["attributes"]["messaging.message.receive.latency"] > 0 + + +def tests_span_origin_consumer(init_celery, capture_items): celery = init_celery( traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", + data_collection={}, ) celery.conf.broker_url = "redis://example.com" # noqa: E231 @celery.task() def task(): ... - if span_streaming: - items = capture_items("span") - task.apply_async() - sentry_sdk.flush() - process_span, execution_span = items - assert ( - execution_span.payload["attributes"]["sentry.origin"] == "auto.queue.celery" - ) - assert ( - process_span.payload["attributes"]["sentry.origin"] == "auto.queue.celery" - ) - else: - events = capture_events() - task.apply_async() - (event,) = events - assert event["contexts"]["trace"]["origin"] == "auto.queue.celery" - assert event["spans"][0]["origin"] == "auto.queue.celery" + items = capture_items("span") + task.apply_async() -@pytest.mark.parametrize("span_streaming", [True, False]) -def tests_span_origin_producer( - span_streaming, monkeypatch, sentry_init, capture_events, capture_items -): + sentry_sdk.flush() + + process_span, execution_span = items + assert execution_span.payload["attributes"]["sentry.origin"] == "auto.queue.celery" + assert process_span.payload["attributes"]["sentry.origin"] == "auto.queue.celery" + + +def tests_span_origin_producer(monkeypatch, sentry_init, capture_items): old_publish = kombu.messaging.Producer._publish def publish(*args, **kwargs): @@ -1149,74 +860,50 @@ def publish(*args, **kwargs): sentry_init( integrations=[CeleryIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", + data_collection={}, ) celery = Celery(__name__, broker="redis://example.com") # noqa: E231 @celery.task() def task(): ... - if span_streaming: - items = capture_items("span") - - with sentry_sdk.traces.start_span(name="custom parent"): - task.apply_async() - - sentry_sdk.flush() + items = capture_items("span") - parent = items.pop(-1).payload - assert parent["name"] == "custom parent" - assert parent["attributes"]["sentry.origin"] == "manual" - - for item in items: - assert item.payload["attributes"]["sentry.origin"] == "auto.queue.celery" - else: - events = capture_events() - - with start_transaction(name="custom_transaction"): - task.apply_async() + with sentry_sdk.start_span(name="custom parent"): + task.apply_async() - (event,) = events + sentry_sdk.flush() - assert event["contexts"]["trace"]["origin"] == "manual" + parent = items.pop(-1).payload + assert parent["name"] == "custom parent" + assert parent["attributes"]["sentry.origin"] == "manual" - for span in event["spans"]: - assert span["origin"] == "auto.queue.celery" + for item in items: + assert item.payload["attributes"]["sentry.origin"] == "auto.queue.celery" monkeypatch.setattr(kombu.messaging.Producer, "_publish", old_publish) -@pytest.mark.parametrize("span_streaming", [True, False]) @pytest.mark.forked @mock.patch("celery.Celery.send_task") def test_send_task_wrapped( patched_send_task, - span_streaming, sentry_init, - capture_events, capture_items, reset_integrations, ): sentry_init( integrations=[CeleryIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", + data_collection={}, ) celery = Celery(__name__, broker="redis://example.com") # noqa: E231 - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="custom parent") as outer_span: - celery.send_task( - "very_creative_task_name", args=(1, 2), kwargs={"foo": "bar"} - ) - sentry_sdk.flush() - else: - events = capture_events() - with sentry_sdk.start_transaction(name="custom_transaction"): - celery.send_task( - "very_creative_task_name", args=(1, 2), kwargs={"foo": "bar"} - ) + items = capture_items("span") + with sentry_sdk.start_span(name="custom parent") as outer_span: + celery.send_task("very_creative_task_name", args=(1, 2), kwargs={"foo": "bar"}) + + sentry_sdk.flush() (call,) = patched_send_task.call_args_list # We should have exactly one call (args, kwargs) = call @@ -1240,32 +927,18 @@ def test_send_task_wrapped( == kwargs["headers"]["headers"]["sentry-trace"] ) - if span_streaming: - submit_span, outer = [item.payload for item in items] + submit_span, outer = [item.payload for item in items] - assert outer["name"] == "custom parent" - assert outer["is_segment"] is True + assert outer["name"] == "custom parent" + assert outer["is_segment"] is True - assert submit_span["name"] == "very_creative_task_name" - assert submit_span["attributes"]["sentry.op"] == "queue.submit.celery" - assert submit_span["trace_id"] == outer_span.trace_id - assert ( - submit_span["trace_id"] == kwargs["headers"]["sentry-trace"].split("-")[0] - ) - - else: - (event,) = events - assert event["type"] == "transaction" - assert event["transaction"] == "custom_transaction" + assert submit_span["name"] == "very_creative_task_name" + assert submit_span["attributes"]["sentry.op"] == "queue.submit.celery" + assert submit_span["trace_id"] == outer_span.trace_id + assert submit_span["trace_id"] == kwargs["headers"]["sentry-trace"].split("-")[0] - (span,) = event["spans"] - assert span["description"] == "very_creative_task_name" - assert span["op"] == "queue.submit.celery" - assert span["trace_id"] == kwargs["headers"]["sentry-trace"].split("-")[0] - -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_user_custom_headers_accessible_in_task(span_streaming, init_celery): +def test_user_custom_headers_accessible_in_task(init_celery): """ Regression test for https://github.com/getsentry/sentry-python/issues/5566 @@ -1274,7 +947,7 @@ def test_user_custom_headers_accessible_in_task(span_streaming, init_celery): """ celery = init_celery( traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", + data_collection={}, ) @celery.task(name="custom_headers_task", bind=True) @@ -1287,12 +960,8 @@ def custom_headers_task(self): "tenant_id": "tenant-42", } - if span_streaming: - with sentry_sdk.traces.start_span(name="test"): - result = custom_headers_task.apply_async(headers=custom_headers) - else: - with start_transaction(name="test"): - result = custom_headers_task.apply_async(headers=custom_headers) + with sentry_sdk.start_span(name="test"): + result = custom_headers_task.apply_async(headers=custom_headers) received_headers = result.get() for key, value in custom_headers.items(): diff --git a/tests/integrations/celery/test_update_celery_task_headers.py b/tests/integrations/celery/test_update_celery_task_headers.py index 18f2f96bbf..97d3f6def5 100644 --- a/tests/integrations/celery/test_update_celery_task_headers.py +++ b/tests/integrations/celery/test_update_celery_task_headers.py @@ -69,42 +69,42 @@ def test_monitor_beat_tasks_with_headers(monitor_beat_tasks): assert "sentry-monitor-start-timestamp-s" not in outgoing_headers["headers"] -def test_span_with_transaction(sentry_init): - sentry_init(traces_sample_rate=1.0) +def test_span_with_segment(sentry_init): + sentry_init(traces_sample_rate=1.0, data_collection={}) headers = {} monitor_beat_tasks = False - with sentry_sdk.start_transaction(name="test_transaction") as transaction: - with sentry_sdk.start_span(op="test_span") as span: + with sentry_sdk.start_span(name="test_segment") as segment: + with sentry_sdk.start_span(name="test_span") as span: outgoing_headers = _update_celery_task_headers( headers, span, monitor_beat_tasks ) - assert outgoing_headers["sentry-trace"] == span.to_traceparent() - assert outgoing_headers["headers"]["sentry-trace"] == span.to_traceparent() - assert outgoing_headers["baggage"] == transaction.get_baggage().serialize() + assert outgoing_headers["sentry-trace"] == span._to_traceparent() + assert outgoing_headers["headers"]["sentry-trace"] == span._to_traceparent() + assert outgoing_headers["baggage"] == segment._get_baggage().serialize() assert ( outgoing_headers["headers"]["baggage"] - == transaction.get_baggage().serialize() + == segment._get_baggage().serialize() ) -def test_span_with_transaction_custom_headers(sentry_init): - sentry_init(traces_sample_rate=1.0) +def test_span_with_segment_custom_headers(sentry_init): + sentry_init(traces_sample_rate=1.0, data_collection={}) headers = { "baggage": BAGGAGE_VALUE, "sentry-trace": SENTRY_TRACE_VALUE, } - with sentry_sdk.start_transaction(name="test_transaction") as transaction: - with sentry_sdk.start_span(op="test_span") as span: + with sentry_sdk.start_span(name="test_segment") as segment: + with sentry_sdk.start_span(name="test_span") as span: outgoing_headers = _update_celery_task_headers(headers, span, False) - assert outgoing_headers["sentry-trace"] == span.to_traceparent() - assert outgoing_headers["headers"]["sentry-trace"] == span.to_traceparent() + assert outgoing_headers["sentry-trace"] == span._to_traceparent() + assert outgoing_headers["headers"]["sentry-trace"] == span._to_traceparent() incoming_baggage = Baggage.from_incoming_header(headers["baggage"]) - combined_baggage = copy(transaction.get_baggage()) + combined_baggage = copy(segment._get_baggage()) combined_baggage.sentry_items.update(incoming_baggage.sentry_items) combined_baggage.third_party_items = ",".join( [ @@ -133,7 +133,7 @@ def test_celery_trace_propagation_default(sentry_init, monitor_beat_tasks): The Celery integration has its own mechanism to propagate traces: https://docs.sentry.io/platforms/python/integrations/celery/#distributed-traces """ - sentry_init() + sentry_init(data_collection={}) headers = {} span = None @@ -169,43 +169,7 @@ def test_celery_trace_propagation_traces_sample_rate( The Celery integration has its own mechanism to propagate traces: https://docs.sentry.io/platforms/python/integrations/celery/#distributed-traces """ - sentry_init(traces_sample_rate=traces_sample_rate) - - headers = {} - span = None - - scope = sentry_sdk.get_isolation_scope() - - outgoing_headers = _update_celery_task_headers(headers, span, monitor_beat_tasks) - - assert outgoing_headers["sentry-trace"] == scope.get_traceparent() - assert outgoing_headers["headers"]["sentry-trace"] == scope.get_traceparent() - assert outgoing_headers["baggage"] == scope.get_baggage().serialize() - assert outgoing_headers["headers"]["baggage"] == scope.get_baggage().serialize() - - if monitor_beat_tasks: - assert "sentry-monitor-start-timestamp-s" in outgoing_headers - assert "sentry-monitor-start-timestamp-s" in outgoing_headers["headers"] - else: - assert "sentry-monitor-start-timestamp-s" not in outgoing_headers - assert "sentry-monitor-start-timestamp-s" not in outgoing_headers["headers"] - - -@pytest.mark.parametrize( - "enable_tracing,monitor_beat_tasks", - list(itertools.product([None, True, False], [True, False])), -) -def test_celery_trace_propagation_enable_tracing( - sentry_init, enable_tracing, monitor_beat_tasks -): - """ - The celery integration does not check the traces_sample_rate. - By default traces_sample_rate is None which means "do not propagate traces". - But the celery integration does not check this value. - The Celery integration has its own mechanism to propagate traces: - https://docs.sentry.io/platforms/python/integrations/celery/#distributed-traces - """ - sentry_init(enable_tracing=enable_tracing) + sentry_init(traces_sample_rate=traces_sample_rate, data_collection={}) headers = {} span = None diff --git a/tests/integrations/chalice/test_chalice.py b/tests/integrations/chalice/test_chalice.py index 69f023efd4..0ffe31a2b8 100644 --- a/tests/integrations/chalice/test_chalice.py +++ b/tests/integrations/chalice/test_chalice.py @@ -41,7 +41,10 @@ def _generate_lambda_context(self): @pytest.fixture def app(sentry_init): - sentry_init(integrations=[ChaliceIntegration()]) + sentry_init( + integrations=[ChaliceIntegration()], + traces_sample_rate=1.0, + ) app = Chalice(app_name="sentry_chalice") @app.route("/boom") @@ -175,39 +178,13 @@ def test_transaction( assert event["transaction_info"] == {"source": expected_source} -def _make_span_streaming_app(sentry_init): - sentry_init( - integrations=[ChaliceIntegration()], - traces_sample_rate=1.0, - trace_lifecycle="stream", - ) - app = Chalice(app_name="sentry_chalice") - - @app.route("/message") - def hi(): - capture_message("hi") - return {"status": "ok"} - - @app.route("/boom") - def boom(): - raise Exception("boom goes the dynamite!") - - LocalGateway._generate_lambda_context = _generate_lambda_context - - return app - - -def test_span_streaming_existing_span( - sentry_init, - capture_items, -): +def test_existing_span(sentry_init, capture_items, app): """When a segment already exists (e.g. created by the AWS Lambda integration), Chalice decorates it instead of creating a duplicate.""" - app = _make_span_streaming_app(sentry_init) client = RequestHandler(app) items = capture_items("span") - with sentry_sdk.traces.start_span( + with sentry_sdk.start_span( name="lambda_segment", parent_span=None, attributes={ @@ -232,15 +209,15 @@ def test_span_streaming_existing_span( assert span["status"] == "ok" -def test_span_streaming_existing_span_error( +def test_existing_span_error( sentry_init, capture_items, + app, ): - app = _make_span_streaming_app(sentry_init) client = RequestHandler(app) items = capture_items("event", "span") - with sentry_sdk.traces.start_span( + with sentry_sdk.start_span( name="lambda_segment", parent_span=None, attributes={"sentry.origin": "auto.function.aws_lambda"}, diff --git a/tests/integrations/clickhouse_driver/test_clickhouse_driver.py b/tests/integrations/clickhouse_driver/test_clickhouse_driver.py index d333f2a6c9..5ddf9b1ab0 100644 --- a/tests/integrations/clickhouse_driver/test_clickhouse_driver.py +++ b/tests/integrations/clickhouse_driver/test_clickhouse_driver.py @@ -5,14 +5,11 @@ ``` """ -from unittest import mock - import clickhouse_driver -import pytest from clickhouse_driver import Client, connect import sentry_sdk -from sentry_sdk import capture_message, start_transaction +from sentry_sdk import capture_message from sentry_sdk.integrations.clickhouse_driver import ClickhouseDriverIntegration from tests.conftest import ApproxDict @@ -21,13 +18,10 @@ EXPECT_PARAMS_IN_SELECT = False -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_clickhouse_client_breadcrumbs( - sentry_init, capture_events, span_streaming -) -> None: +def test_clickhouse_client_breadcrumbs(sentry_init, capture_events) -> None: sentry_init( integrations=[ClickhouseDriverIntegration()], - trace_lifecycle="stream" if span_streaming else "static", + data_collection={}, _experiments={"record_sql_params": True}, ) events = capture_events() @@ -113,9 +107,6 @@ def test_clickhouse_client_breadcrumbs( }, ] - if not EXPECT_PARAMS_IN_SELECT: - expected_breadcrumbs[-1]["data"].pop("db.params", None) - for crumb in expected_breadcrumbs: crumb["data"] = ApproxDict(crumb["data"]) @@ -131,13 +122,12 @@ def test_clickhouse_client_breadcrumbs( assert actual_query_breadcrumbs == expected_breadcrumbs -def test_clickhouse_client_breadcrumbs_span_streaming( +def test_clickhouse_client_breadcrumbs_with_data_collection( sentry_init, capture_events ) -> None: sentry_init( integrations=[ClickhouseDriverIntegration()], - trace_lifecycle="stream", - _experiments={"record_sql_params": True}, + data_collection={"database_query_data": True}, ) events = capture_events() @@ -164,6 +154,7 @@ def test_clickhouse_client_breadcrumbs_span_streaming( "db.user": "default", "server.address": "localhost", "server.port": 9000, + "db.result": [], }, "message": "DROP TABLE IF EXISTS test", "type": "default", @@ -177,6 +168,7 @@ def test_clickhouse_client_breadcrumbs_span_streaming( "db.user": "default", "server.address": "localhost", "server.port": 9000, + "db.result": [], }, "message": "CREATE TABLE test (x Int32) ENGINE = Memory", "type": "default", @@ -216,6 +208,7 @@ def test_clickhouse_client_breadcrumbs_span_streaming( "db.user": "default", "server.address": "localhost", "server.port": 9000, + "db.result": [[370]], }, "message": "SELECT sum(x) FROM test WHERE x > 150", "type": "default", @@ -228,20 +221,15 @@ def test_clickhouse_client_breadcrumbs_span_streaming( for crumb in event["breadcrumbs"]["values"]: crumb.pop("timestamp", None) - actual_query_breadcrumbs = [ - breadcrumb - for breadcrumb in event["breadcrumbs"]["values"] - if breadcrumb["category"] == "query" - ] - - assert actual_query_breadcrumbs == expected_breadcrumbs + assert event["breadcrumbs"]["values"] == expected_breadcrumbs -def test_clickhouse_client_breadcrumbs_with_pii(sentry_init, capture_events) -> None: +def test_clickhouse_client_breadcrumbs_with_data_collection_disabled( + sentry_init, capture_events +) -> None: sentry_init( integrations=[ClickhouseDriverIntegration()], - send_default_pii=True, - _experiments={"record_sql_params": True}, + data_collection={"database_query_data": False}, ) events = capture_events() @@ -263,11 +251,11 @@ def test_clickhouse_client_breadcrumbs_with_pii(sentry_init, capture_events) -> "category": "query", "data": { "db.system": "clickhouse", + "db.driver.name": "clickhouse-driver", "db.name": "", "db.user": "default", "server.address": "localhost", "server.port": 9000, - "db.result": [], }, "message": "DROP TABLE IF EXISTS test", "type": "default", @@ -276,11 +264,11 @@ def test_clickhouse_client_breadcrumbs_with_pii(sentry_init, capture_events) -> "category": "query", "data": { "db.system": "clickhouse", + "db.driver.name": "clickhouse-driver", "db.name": "", "db.user": "default", "server.address": "localhost", "server.port": 9000, - "db.result": [], }, "message": "CREATE TABLE test (x Int32) ENGINE = Memory", "type": "default", @@ -289,11 +277,11 @@ def test_clickhouse_client_breadcrumbs_with_pii(sentry_init, capture_events) -> "category": "query", "data": { "db.system": "clickhouse", + "db.driver.name": "clickhouse-driver", "db.name": "", "db.user": "default", "server.address": "localhost", "server.port": 9000, - "db.params": [{"x": 100}], }, "message": "INSERT INTO test (x) VALUES", "type": "default", @@ -302,11 +290,11 @@ def test_clickhouse_client_breadcrumbs_with_pii(sentry_init, capture_events) -> "category": "query", "data": { "db.system": "clickhouse", + "db.driver.name": "clickhouse-driver", "db.name": "", "db.user": "default", "server.address": "localhost", "server.port": 9000, - "db.params": [[170], [200]], }, "message": "INSERT INTO test (x) VALUES", "type": "default", @@ -315,21 +303,17 @@ def test_clickhouse_client_breadcrumbs_with_pii(sentry_init, capture_events) -> "category": "query", "data": { "db.system": "clickhouse", + "db.driver.name": "clickhouse-driver", "db.name": "", "db.user": "default", "server.address": "localhost", "server.port": 9000, - "db.result": [[370]], - "db.params": {"minv": 150}, }, "message": "SELECT sum(x) FROM test WHERE x > 150", "type": "default", }, ] - if not EXPECT_PARAMS_IN_SELECT: - expected_breadcrumbs[-1]["data"].pop("db.params", None) - for crumb in expected_breadcrumbs: crumb["data"] = ApproxDict(crumb["data"]) @@ -339,14 +323,12 @@ def test_clickhouse_client_breadcrumbs_with_pii(sentry_init, capture_events) -> assert event["breadcrumbs"]["values"] == expected_breadcrumbs -def test_clickhouse_client_breadcrumbs_with_pii_span_streaming( +def test_clickhouse_client_breadcrumbs_with_data_collection_default( sentry_init, capture_events ) -> None: sentry_init( integrations=[ClickhouseDriverIntegration()], - send_default_pii=True, - trace_lifecycle="stream", - _experiments={"record_sql_params": True}, + data_collection={}, ) events = capture_events() @@ -443,7 +425,38 @@ def test_clickhouse_client_breadcrumbs_with_pii_span_streaming( assert event["breadcrumbs"]["values"] == expected_breadcrumbs -def test_clickhouse_client_breadcrumbs_with_data_collection( +def test_clickhouse_client_with_data_collection(sentry_init, capture_items) -> None: + sentry_init( + integrations=[ClickhouseDriverIntegration()], + traces_sample_rate=1.0, + data_collection={"database_query_data": True}, + ) + items = capture_items("span") + + with sentry_sdk.start_span(name="custom parent"): + client = Client("localhost") + client.execute("DROP TABLE IF EXISTS test") + client.execute("CREATE TABLE test (x Int32) ENGINE = Memory") + client.execute("INSERT INTO test (x) VALUES", [{"x": 100}]) + client.execute("INSERT INTO test (x) VALUES", ((i,) for i in range(3))) + + res = client.execute("SELECT sum(x) FROM test WHERE x > %(minv)i", {"minv": 2}) + assert res[0][0] == 100 + + sentry_sdk.flush() + + spans = [item.payload for item in items] + assert len(spans) > 1 # sanity check that db spans were actually streamed + + for span in spans: + attribute_keys = { + attribute["name"] if isinstance(attribute, dict) else attribute + for attribute in span.get("attributes", {}) + } + assert "db.result" not in attribute_keys + + +def test_clickhouse_client_send_data_generator_with_data_collection( sentry_init, capture_events ) -> None: sentry_init( @@ -455,114 +468,206 @@ def test_clickhouse_client_breadcrumbs_with_data_collection( client = Client("localhost") client.execute("DROP TABLE IF EXISTS test") client.execute("CREATE TABLE test (x Int32) ENGINE = Memory") - client.execute("INSERT INTO test (x) VALUES", [{"x": 100}]) - client.execute("INSERT INTO test (x) VALUES", [[170], [200]]) + client.execute("INSERT INTO test (x) VALUES", ((i,) for i in range(3))) - res = client.execute("SELECT sum(x) FROM test WHERE x > %(minv)i", {"minv": 150}) - assert res[0][0] == 370 + res = client.execute("SELECT sum(x) FROM test") + assert res[0][0] == 3 capture_message("hi") (event,) = events - expected_breadcrumbs = [ + (insert_breadcrumb,) = [ + crumb + for crumb in event["breadcrumbs"]["values"] + if crumb["message"] == "INSERT INTO test (x) VALUES" + ] + + assert "db.params" not in insert_breadcrumb["data"] + + +def test_clickhouse_client_send_data_generator_with_data_collection_disabled( + sentry_init, capture_events +) -> None: + sentry_init( + integrations=[ClickhouseDriverIntegration()], + data_collection={"database_query_data": False}, + ) + events = capture_events() + + client = Client("localhost") + client.execute("DROP TABLE IF EXISTS test") + client.execute("CREATE TABLE test (x Int32) ENGINE = Memory") + client.execute("INSERT INTO test (x) VALUES", ((i,) for i in range(3))) + + res = client.execute("SELECT sum(x) FROM test") + assert res[0][0] == 3 + + capture_message("hi") + + (event,) = events + + (insert_breadcrumb,) = [ + crumb + for crumb in event["breadcrumbs"]["values"] + if crumb["message"] == "INSERT INTO test (x) VALUES" + ] + + assert "db.params" not in insert_breadcrumb["data"] + + +def test_clickhouse_client_spans( + sentry_init, + capture_items, +): + sentry_init( + integrations=[ClickhouseDriverIntegration()], + _experiments={ + "record_sql_params": True, + }, + traces_sample_rate=1.0, + data_collection={}, + ) + items = capture_items("span") + + trace_id = None + span_id = None + + with sentry_sdk.start_span(name="custom parent") as span: + trace_id = span.trace_id + span_id = span.span_id + + client = Client("localhost") + client.execute("DROP TABLE IF EXISTS test") + client.execute("CREATE TABLE test (x Int32) ENGINE = Memory") + client.execute("INSERT INTO test (x) VALUES", [{"x": 100}]) + client.execute("INSERT INTO test (x) VALUES", [[170], [200]]) + + res = client.execute( + "SELECT sum(x) FROM test WHERE x > %(minv)i", {"minv": 150} + ) + assert res[0][0] == 370 + + sentry_sdk.flush() + spans = [item.payload for item in items] + + expected_spans = [ { - "category": "query", - "data": { - "db.system": "clickhouse", - "db.name": "", + "name": "DROP TABLE IF EXISTS test", + "attributes": { + "db.system.name": "clickhouse", + "db.driver.name": "clickhouse-driver", + "db.namespace": "", "db.user": "default", + "sentry.op": "db", + "db.query.text": "DROP TABLE IF EXISTS test", + "sentry.origin": "auto.db.clickhouse_driver", "server.address": "localhost", "server.port": 9000, - "db.result": [], }, - "message": "DROP TABLE IF EXISTS test", - "type": "default", + "trace_id": trace_id, + "parent_span_id": span_id, }, { - "category": "query", - "data": { - "db.system": "clickhouse", - "db.name": "", + "name": "CREATE TABLE test (x Int32) ENGINE = Memory", + "attributes": { + "db.system.name": "clickhouse", + "db.driver.name": "clickhouse-driver", + "db.namespace": "", "db.user": "default", + "sentry.op": "db", + "db.query.text": "CREATE TABLE test (x Int32) ENGINE = Memory", + "sentry.origin": "auto.db.clickhouse_driver", "server.address": "localhost", "server.port": 9000, - "db.result": [], }, - "message": "CREATE TABLE test (x Int32) ENGINE = Memory", - "type": "default", + "trace_id": trace_id, + "parent_span_id": span_id, }, { - "category": "query", - "data": { - "db.system": "clickhouse", - "db.name": "", + "name": "INSERT INTO test (x) VALUES", + "attributes": { + "db.system.name": "clickhouse", + "db.driver.name": "clickhouse-driver", + "db.namespace": "", "db.user": "default", + "sentry.op": "db", + "db.query.text": "INSERT INTO test (x) VALUES", + "sentry.origin": "auto.db.clickhouse_driver", "server.address": "localhost", "server.port": 9000, - "db.params": [{"x": 100}], }, - "message": "INSERT INTO test (x) VALUES", - "type": "default", + "trace_id": trace_id, + "parent_span_id": span_id, }, { - "category": "query", - "data": { - "db.system": "clickhouse", - "db.name": "", + "name": "INSERT INTO test (x) VALUES", + "attributes": { + "db.system.name": "clickhouse", + "db.driver.name": "clickhouse-driver", + "db.namespace": "", "db.user": "default", + "sentry.op": "db", + "db.query.text": "INSERT INTO test (x) VALUES", + "sentry.origin": "auto.db.clickhouse_driver", "server.address": "localhost", "server.port": 9000, - "db.params": [[170], [200]], }, - "message": "INSERT INTO test (x) VALUES", - "type": "default", + "trace_id": trace_id, + "parent_span_id": span_id, }, { - "category": "query", - "data": { - "db.system": "clickhouse", - "db.name": "", + "name": "SELECT sum(x) FROM test WHERE x > 150", + "attributes": { + "db.system.name": "clickhouse", + "db.driver.name": "clickhouse-driver", + "db.namespace": "", "db.user": "default", + "sentry.op": "db", + "db.query.text": "SELECT sum(x) FROM test WHERE x > 150", + "sentry.origin": "auto.db.clickhouse_driver", "server.address": "localhost", "server.port": 9000, - "db.result": [[370]], - "db.params": {"minv": 150}, }, - "message": "SELECT sum(x) FROM test WHERE x > 150", - "type": "default", + "trace_id": trace_id, + "parent_span_id": span_id, + }, + { + "name": "custom parent", + "attributes": [], + "trace_id": trace_id, }, ] - if not EXPECT_PARAMS_IN_SELECT: - expected_breadcrumbs[-1]["data"].pop("db.params", None) - - for crumb in expected_breadcrumbs: - crumb["data"] = ApproxDict(crumb["data"]) + for span in expected_spans: + span["attributes"] = ApproxDict(span["attributes"]) - for crumb in event["breadcrumbs"]["values"]: - crumb.pop("timestamp", None) + for span in spans: + span.pop("span_id", None) + span.pop("start_timestamp", None) + span.pop("end_timestamp", None) + span.pop("is_segment", None) + span.pop("status", None) - assert event["breadcrumbs"]["values"] == expected_breadcrumbs + assert spans == expected_spans -def test_clickhouse_client_breadcrumbs_with_data_collection_span_streaming( - sentry_init, capture_events -) -> None: +def test_clickhouse_dbapi_breadcrumbs(sentry_init, capture_events) -> None: sentry_init( integrations=[ClickhouseDriverIntegration()], - trace_lifecycle="stream", - data_collection={"database_query_data": True}, + data_collection={}, ) events = capture_events() - client = Client("localhost") - client.execute("DROP TABLE IF EXISTS test") - client.execute("CREATE TABLE test (x Int32) ENGINE = Memory") - client.execute("INSERT INTO test (x) VALUES", [{"x": 100}]) - client.execute("INSERT INTO test (x) VALUES", [[170], [200]]) + conn = connect("clickhouse://localhost") + cursor = conn.cursor() + cursor.execute("DROP TABLE IF EXISTS test") + cursor.execute("CREATE TABLE test (x Int32) ENGINE = Memory") + cursor.executemany("INSERT INTO test (x) VALUES", [{"x": 100}]) + cursor.executemany("INSERT INTO test (x) VALUES", [[170], [200]]) + cursor.execute("SELECT sum(x) FROM test WHERE x > %(minv)i", {"minv": 150}) + res = cursor.fetchall() - res = client.execute("SELECT sum(x) FROM test WHERE x > %(minv)i", {"minv": 150}) assert res[0][0] == 370 capture_message("hi") @@ -579,7 +684,6 @@ def test_clickhouse_client_breadcrumbs_with_data_collection_span_streaming( "db.user": "default", "server.address": "localhost", "server.port": 9000, - "db.result": [], }, "message": "DROP TABLE IF EXISTS test", "type": "default", @@ -593,7 +697,6 @@ def test_clickhouse_client_breadcrumbs_with_data_collection_span_streaming( "db.user": "default", "server.address": "localhost", "server.port": 9000, - "db.result": [], }, "message": "CREATE TABLE test (x Int32) ENGINE = Memory", "type": "default", @@ -633,7 +736,6 @@ def test_clickhouse_client_breadcrumbs_with_data_collection_span_streaming( "db.user": "default", "server.address": "localhost", "server.port": 9000, - "db.result": [[370]], }, "message": "SELECT sum(x) FROM test WHERE x > 150", "type": "default", @@ -649,2271 +751,155 @@ def test_clickhouse_client_breadcrumbs_with_data_collection_span_streaming( assert event["breadcrumbs"]["values"] == expected_breadcrumbs -def test_clickhouse_client_breadcrumbs_with_data_collection_disabled( - sentry_init, capture_events -) -> None: +def test_clickhouse_dbapi_spans( + sentry_init, + capture_items, + capture_envelopes, +): sentry_init( integrations=[ClickhouseDriverIntegration()], - data_collection={"database_query_data": False}, + _experiments={ + "record_sql_params": True, + }, + traces_sample_rate=1.0, + data_collection={}, ) - events = capture_events() + items = capture_items("span") - client = Client("localhost") - client.execute("DROP TABLE IF EXISTS test") - client.execute("CREATE TABLE test (x Int32) ENGINE = Memory") - client.execute("INSERT INTO test (x) VALUES", [{"x": 100}]) - client.execute("INSERT INTO test (x) VALUES", [[170], [200]]) + trace_id = None + span_id = None - res = client.execute("SELECT sum(x) FROM test WHERE x > %(minv)i", {"minv": 150}) - assert res[0][0] == 370 + with sentry_sdk.start_span(name="custom parent") as span: + trace_id = span.trace_id + span_id = span.span_id - capture_message("hi") + conn = connect("clickhouse://localhost") + cursor = conn.cursor() + cursor.execute("DROP TABLE IF EXISTS test") + cursor.execute("CREATE TABLE test (x Int32) ENGINE = Memory") + cursor.executemany("INSERT INTO test (x) VALUES", [{"x": 100}]) + cursor.executemany("INSERT INTO test (x) VALUES", [[170], [200]]) + cursor.execute("SELECT sum(x) FROM test WHERE x > %(minv)i", {"minv": 150}) - (event,) = events + sentry_sdk.flush() + spans = [item.payload for item in items] - expected_breadcrumbs = [ + expected_spans = [ { - "category": "query", - "data": { - "db.system": "clickhouse", - "db.name": "", + "name": "DROP TABLE IF EXISTS test", + "attributes": { + "db.system.name": "clickhouse", + "db.driver.name": "clickhouse-driver", + "db.namespace": "", "db.user": "default", + "db.query.text": "DROP TABLE IF EXISTS test", + "sentry.op": "db", + "sentry.origin": "auto.db.clickhouse_driver", "server.address": "localhost", "server.port": 9000, }, - "message": "DROP TABLE IF EXISTS test", - "type": "default", + "trace_id": trace_id, + "parent_span_id": span_id, }, { - "category": "query", - "data": { - "db.system": "clickhouse", - "db.name": "", + "name": "CREATE TABLE test (x Int32) ENGINE = Memory", + "attributes": { + "db.system.name": "clickhouse", + "db.driver.name": "clickhouse-driver", + "db.namespace": "", "db.user": "default", + "db.query.text": "CREATE TABLE test (x Int32) ENGINE = Memory", + "sentry.op": "db", + "sentry.origin": "auto.db.clickhouse_driver", "server.address": "localhost", "server.port": 9000, }, - "message": "CREATE TABLE test (x Int32) ENGINE = Memory", - "type": "default", + "trace_id": trace_id, + "parent_span_id": span_id, }, { - "category": "query", - "data": { - "db.system": "clickhouse", - "db.name": "", + "name": "INSERT INTO test (x) VALUES", + "attributes": { + "db.system.name": "clickhouse", + "db.driver.name": "clickhouse-driver", + "db.namespace": "", "db.user": "default", + "db.query.text": "INSERT INTO test (x) VALUES", + "sentry.op": "db", + "sentry.origin": "auto.db.clickhouse_driver", "server.address": "localhost", "server.port": 9000, }, - "message": "INSERT INTO test (x) VALUES", - "type": "default", - }, - { - "category": "query", - "data": { - "db.system": "clickhouse", - "db.name": "", - "db.user": "default", - "server.address": "localhost", - "server.port": 9000, - }, - "message": "INSERT INTO test (x) VALUES", - "type": "default", - }, - { - "category": "query", - "data": { - "db.system": "clickhouse", - "db.name": "", - "db.user": "default", - "server.address": "localhost", - "server.port": 9000, - }, - "message": "SELECT sum(x) FROM test WHERE x > 150", - "type": "default", - }, - ] - - for crumb in expected_breadcrumbs: - crumb["data"] = ApproxDict(crumb["data"]) - - for crumb in event["breadcrumbs"]["values"]: - crumb.pop("timestamp", None) - - assert event["breadcrumbs"]["values"] == expected_breadcrumbs - - # ApproxDict is subset matching, so explicitly assert params/result absence - for crumb in event["breadcrumbs"]["values"]: - assert "db.params" not in crumb["data"] - assert "db.result" not in crumb["data"] - - -def test_clickhouse_client_breadcrumbs_with_data_collection_disabled_span_streaming( - sentry_init, capture_events -) -> None: - sentry_init( - integrations=[ClickhouseDriverIntegration()], - trace_lifecycle="stream", - data_collection={"database_query_data": False}, - ) - events = capture_events() - - client = Client("localhost") - client.execute("DROP TABLE IF EXISTS test") - client.execute("CREATE TABLE test (x Int32) ENGINE = Memory") - client.execute("INSERT INTO test (x) VALUES", [{"x": 100}]) - client.execute("INSERT INTO test (x) VALUES", [[170], [200]]) - - res = client.execute("SELECT sum(x) FROM test WHERE x > %(minv)i", {"minv": 150}) - assert res[0][0] == 370 - - capture_message("hi") - - (event,) = events - - expected_breadcrumbs = [ - { - "category": "query", - "data": { - "db.system": "clickhouse", - "db.driver.name": "clickhouse-driver", - "db.name": "", - "db.user": "default", - "server.address": "localhost", - "server.port": 9000, - }, - "message": "DROP TABLE IF EXISTS test", - "type": "default", - }, - { - "category": "query", - "data": { - "db.system": "clickhouse", - "db.driver.name": "clickhouse-driver", - "db.name": "", - "db.user": "default", - "server.address": "localhost", - "server.port": 9000, - }, - "message": "CREATE TABLE test (x Int32) ENGINE = Memory", - "type": "default", - }, - { - "category": "query", - "data": { - "db.system": "clickhouse", - "db.driver.name": "clickhouse-driver", - "db.name": "", - "db.user": "default", - "server.address": "localhost", - "server.port": 9000, - }, - "message": "INSERT INTO test (x) VALUES", - "type": "default", - }, - { - "category": "query", - "data": { - "db.system": "clickhouse", - "db.driver.name": "clickhouse-driver", - "db.name": "", - "db.user": "default", - "server.address": "localhost", - "server.port": 9000, - }, - "message": "INSERT INTO test (x) VALUES", - "type": "default", - }, - { - "category": "query", - "data": { - "db.system": "clickhouse", - "db.driver.name": "clickhouse-driver", - "db.name": "", - "db.user": "default", - "server.address": "localhost", - "server.port": 9000, - }, - "message": "SELECT sum(x) FROM test WHERE x > 150", - "type": "default", - }, - ] - - for crumb in expected_breadcrumbs: - crumb["data"] = ApproxDict(crumb["data"]) - - for crumb in event["breadcrumbs"]["values"]: - crumb.pop("timestamp", None) - - assert event["breadcrumbs"]["values"] == expected_breadcrumbs - - -def test_clickhouse_client_breadcrumbs_data_collection_overrides_pii( - sentry_init, capture_events -) -> None: - sentry_init( - integrations=[ClickhouseDriverIntegration()], - send_default_pii=True, - data_collection={"database_query_data": False}, - ) - events = capture_events() - - client = Client("localhost") - client.execute("DROP TABLE IF EXISTS test") - client.execute("CREATE TABLE test (x Int32) ENGINE = Memory") - client.execute("INSERT INTO test (x) VALUES", [{"x": 100}]) - client.execute("INSERT INTO test (x) VALUES", [[170], [200]]) - - res = client.execute("SELECT sum(x) FROM test WHERE x > %(minv)i", {"minv": 150}) - assert res[0][0] == 370 - - capture_message("hi") - - (event,) = events - - expected_breadcrumbs = [ - { - "category": "query", - "data": { - "db.system": "clickhouse", - "db.name": "", - "db.user": "default", - "server.address": "localhost", - "server.port": 9000, - }, - "message": "DROP TABLE IF EXISTS test", - "type": "default", - }, - { - "category": "query", - "data": { - "db.system": "clickhouse", - "db.name": "", - "db.user": "default", - "server.address": "localhost", - "server.port": 9000, - }, - "message": "CREATE TABLE test (x Int32) ENGINE = Memory", - "type": "default", - }, - { - "category": "query", - "data": { - "db.system": "clickhouse", - "db.name": "", - "db.user": "default", - "server.address": "localhost", - "server.port": 9000, - }, - "message": "INSERT INTO test (x) VALUES", - "type": "default", - }, - { - "category": "query", - "data": { - "db.system": "clickhouse", - "db.name": "", - "db.user": "default", - "server.address": "localhost", - "server.port": 9000, - }, - "message": "INSERT INTO test (x) VALUES", - "type": "default", - }, - { - "category": "query", - "data": { - "db.system": "clickhouse", - "db.name": "", - "db.user": "default", - "server.address": "localhost", - "server.port": 9000, - }, - "message": "SELECT sum(x) FROM test WHERE x > 150", - "type": "default", - }, - ] - - for crumb in expected_breadcrumbs: - crumb["data"] = ApproxDict(crumb["data"]) - - for crumb in event["breadcrumbs"]["values"]: - crumb.pop("timestamp", None) - - assert event["breadcrumbs"]["values"] == expected_breadcrumbs - - # ApproxDict is subset matching, so explicitly assert params/result absence - for crumb in event["breadcrumbs"]["values"]: - assert "db.params" not in crumb["data"] - assert "db.result" not in crumb["data"] - - -def test_clickhouse_client_breadcrumbs_data_collection_overrides_pii_span_streaming( - sentry_init, capture_events -) -> None: - sentry_init( - integrations=[ClickhouseDriverIntegration()], - send_default_pii=True, - trace_lifecycle="stream", - data_collection={"database_query_data": False}, - ) - events = capture_events() - - client = Client("localhost") - client.execute("DROP TABLE IF EXISTS test") - client.execute("CREATE TABLE test (x Int32) ENGINE = Memory") - client.execute("INSERT INTO test (x) VALUES", [{"x": 100}]) - client.execute("INSERT INTO test (x) VALUES", [[170], [200]]) - - res = client.execute("SELECT sum(x) FROM test WHERE x > %(minv)i", {"minv": 150}) - assert res[0][0] == 370 - - capture_message("hi") - - (event,) = events - - expected_breadcrumbs = [ - { - "category": "query", - "data": { - "db.system": "clickhouse", - "db.driver.name": "clickhouse-driver", - "db.name": "", - "db.user": "default", - "server.address": "localhost", - "server.port": 9000, - }, - "message": "DROP TABLE IF EXISTS test", - "type": "default", - }, - { - "category": "query", - "data": { - "db.system": "clickhouse", - "db.driver.name": "clickhouse-driver", - "db.name": "", - "db.user": "default", - "server.address": "localhost", - "server.port": 9000, - }, - "message": "CREATE TABLE test (x Int32) ENGINE = Memory", - "type": "default", - }, - { - "category": "query", - "data": { - "db.system": "clickhouse", - "db.driver.name": "clickhouse-driver", - "db.name": "", - "db.user": "default", - "server.address": "localhost", - "server.port": 9000, - }, - "message": "INSERT INTO test (x) VALUES", - "type": "default", - }, - { - "category": "query", - "data": { - "db.system": "clickhouse", - "db.driver.name": "clickhouse-driver", - "db.name": "", - "db.user": "default", - "server.address": "localhost", - "server.port": 9000, - }, - "message": "INSERT INTO test (x) VALUES", - "type": "default", - }, - { - "category": "query", - "data": { - "db.system": "clickhouse", - "db.driver.name": "clickhouse-driver", - "db.name": "", - "db.user": "default", - "server.address": "localhost", - "server.port": 9000, - }, - "message": "SELECT sum(x) FROM test WHERE x > 150", - "type": "default", - }, - ] - - for crumb in expected_breadcrumbs: - crumb["data"] = ApproxDict(crumb["data"]) - - for crumb in event["breadcrumbs"]["values"]: - crumb.pop("timestamp", None) - - assert event["breadcrumbs"]["values"] == expected_breadcrumbs - - -def test_clickhouse_client_breadcrumbs_with_data_collection_default( - sentry_init, capture_events -) -> None: - sentry_init( - integrations=[ClickhouseDriverIntegration()], - data_collection={}, - ) - events = capture_events() - - client = Client("localhost") - client.execute("DROP TABLE IF EXISTS test") - client.execute("CREATE TABLE test (x Int32) ENGINE = Memory") - client.execute("INSERT INTO test (x) VALUES", [{"x": 100}]) - client.execute("INSERT INTO test (x) VALUES", [[170], [200]]) - - res = client.execute("SELECT sum(x) FROM test WHERE x > %(minv)i", {"minv": 150}) - assert res[0][0] == 370 - - capture_message("hi") - - (event,) = events - - expected_breadcrumbs = [ - { - "category": "query", - "data": { - "db.system": "clickhouse", - "db.name": "", - "db.user": "default", - "server.address": "localhost", - "server.port": 9000, - "db.result": [], - }, - "message": "DROP TABLE IF EXISTS test", - "type": "default", - }, - { - "category": "query", - "data": { - "db.system": "clickhouse", - "db.name": "", - "db.user": "default", - "server.address": "localhost", - "server.port": 9000, - "db.result": [], - }, - "message": "CREATE TABLE test (x Int32) ENGINE = Memory", - "type": "default", - }, - { - "category": "query", - "data": { - "db.system": "clickhouse", - "db.name": "", - "db.user": "default", - "server.address": "localhost", - "server.port": 9000, - "db.params": [{"x": 100}], - }, - "message": "INSERT INTO test (x) VALUES", - "type": "default", - }, - { - "category": "query", - "data": { - "db.system": "clickhouse", - "db.name": "", - "db.user": "default", - "server.address": "localhost", - "server.port": 9000, - "db.params": [[170], [200]], - }, - "message": "INSERT INTO test (x) VALUES", - "type": "default", - }, - { - "category": "query", - "data": { - "db.system": "clickhouse", - "db.name": "", - "db.user": "default", - "server.address": "localhost", - "server.port": 9000, - "db.result": [[370]], - "db.params": {"minv": 150}, - }, - "message": "SELECT sum(x) FROM test WHERE x > 150", - "type": "default", - }, - ] - - if not EXPECT_PARAMS_IN_SELECT: - expected_breadcrumbs[-1]["data"].pop("db.params", None) - - for crumb in expected_breadcrumbs: - crumb["data"] = ApproxDict(crumb["data"]) - - for crumb in event["breadcrumbs"]["values"]: - crumb.pop("timestamp", None) - - assert event["breadcrumbs"]["values"] == expected_breadcrumbs - - -def test_clickhouse_client_breadcrumbs_with_data_collection_default_span_streaming( - sentry_init, capture_events -) -> None: - sentry_init( - integrations=[ClickhouseDriverIntegration()], - trace_lifecycle="stream", - data_collection={}, - ) - events = capture_events() - - client = Client("localhost") - client.execute("DROP TABLE IF EXISTS test") - client.execute("CREATE TABLE test (x Int32) ENGINE = Memory") - client.execute("INSERT INTO test (x) VALUES", [{"x": 100}]) - client.execute("INSERT INTO test (x) VALUES", [[170], [200]]) - - res = client.execute("SELECT sum(x) FROM test WHERE x > %(minv)i", {"minv": 150}) - assert res[0][0] == 370 - - capture_message("hi") - - (event,) = events - - expected_breadcrumbs = [ - { - "category": "query", - "data": { - "db.system": "clickhouse", - "db.driver.name": "clickhouse-driver", - "db.name": "", - "db.user": "default", - "server.address": "localhost", - "server.port": 9000, - "db.result": [], - }, - "message": "DROP TABLE IF EXISTS test", - "type": "default", - }, - { - "category": "query", - "data": { - "db.system": "clickhouse", - "db.driver.name": "clickhouse-driver", - "db.name": "", - "db.user": "default", - "server.address": "localhost", - "server.port": 9000, - "db.result": [], - }, - "message": "CREATE TABLE test (x Int32) ENGINE = Memory", - "type": "default", - }, - { - "category": "query", - "data": { - "db.system": "clickhouse", - "db.driver.name": "clickhouse-driver", - "db.name": "", - "db.user": "default", - "server.address": "localhost", - "server.port": 9000, - }, - "message": "INSERT INTO test (x) VALUES", - "type": "default", - }, - { - "category": "query", - "data": { - "db.system": "clickhouse", - "db.driver.name": "clickhouse-driver", - "db.name": "", - "db.user": "default", - "server.address": "localhost", - "server.port": 9000, - }, - "message": "INSERT INTO test (x) VALUES", - "type": "default", - }, - { - "category": "query", - "data": { - "db.system": "clickhouse", - "db.driver.name": "clickhouse-driver", - "db.name": "", - "db.user": "default", - "server.address": "localhost", - "server.port": 9000, - "db.result": [[370]], - }, - "message": "SELECT sum(x) FROM test WHERE x > 150", - "type": "default", - }, - ] - - for crumb in expected_breadcrumbs: - crumb["data"] = ApproxDict(crumb["data"]) - - for crumb in event["breadcrumbs"]["values"]: - crumb.pop("timestamp", None) - - assert event["breadcrumbs"]["values"] == expected_breadcrumbs - - -def test_clickhouse_client_span_streaming_with_data_collection( - sentry_init, capture_items -) -> None: - # Streamed spans never carry db.params/db.result, regardless of the - # data_collection configuration - sentry_init( - integrations=[ClickhouseDriverIntegration()], - traces_sample_rate=1.0, - trace_lifecycle="stream", - data_collection={"database_query_data": True}, - ) - items = capture_items("span") - - with sentry_sdk.traces.start_span(name="custom parent"): - client = Client("localhost") - client.execute("DROP TABLE IF EXISTS test") - client.execute("CREATE TABLE test (x Int32) ENGINE = Memory") - client.execute("INSERT INTO test (x) VALUES", [{"x": 100}]) - client.execute("INSERT INTO test (x) VALUES", ((i,) for i in range(3))) - - res = client.execute("SELECT sum(x) FROM test WHERE x > %(minv)i", {"minv": 2}) - assert res[0][0] == 100 - - sentry_sdk.flush() - - spans = [item.payload for item in items] - assert len(spans) > 1 # sanity check that db spans were actually streamed - - for span in spans: - attribute_keys = { - attribute["name"] if isinstance(attribute, dict) else attribute - for attribute in span.get("attributes", {}) - } - assert "db.params" not in attribute_keys - assert "db.result" not in attribute_keys - - -def test_clickhouse_client_send_data_generator_with_data_collection( - sentry_init, capture_events -) -> None: - sentry_init( - integrations=[ClickhouseDriverIntegration()], - data_collection={"database_query_data": True}, - ) - events = capture_events() - - client = Client("localhost") - client.execute("DROP TABLE IF EXISTS test") - client.execute("CREATE TABLE test (x Int32) ENGINE = Memory") - client.execute("INSERT INTO test (x) VALUES", ((i,) for i in range(3))) - - res = client.execute("SELECT sum(x) FROM test") - assert res[0][0] == 3 - - capture_message("hi") - - (event,) = events - - (insert_breadcrumb,) = [ - crumb - for crumb in event["breadcrumbs"]["values"] - if crumb["message"] == "INSERT INTO test (x) VALUES" - ] - - assert insert_breadcrumb["data"]["db.params"] == [[0], [1], [2]] - - -def test_clickhouse_client_send_data_generator_with_data_collection_disabled( - sentry_init, capture_events -) -> None: - sentry_init( - integrations=[ClickhouseDriverIntegration()], - data_collection={"database_query_data": False}, - ) - events = capture_events() - - client = Client("localhost") - client.execute("DROP TABLE IF EXISTS test") - client.execute("CREATE TABLE test (x Int32) ENGINE = Memory") - client.execute("INSERT INTO test (x) VALUES", ((i,) for i in range(3))) - - res = client.execute("SELECT sum(x) FROM test") - assert res[0][0] == 3 - - capture_message("hi") - - (event,) = events - - (insert_breadcrumb,) = [ - crumb - for crumb in event["breadcrumbs"]["values"] - if crumb["message"] == "INSERT INTO test (x) VALUES" - ] - - assert "db.params" not in insert_breadcrumb["data"] - - -def test_clickhouse_client_send_data_generator_span_streaming_with_data_collection( - sentry_init, capture_events -) -> None: - sentry_init( - integrations=[ClickhouseDriverIntegration()], - trace_lifecycle="stream", - data_collection={"database_query_data": True}, - ) - events = capture_events() - - client = Client("localhost") - client.execute("DROP TABLE IF EXISTS test") - client.execute("CREATE TABLE test (x Int32) ENGINE = Memory") - client.execute("INSERT INTO test (x) VALUES", ((i,) for i in range(3))) - - res = client.execute("SELECT sum(x) FROM test") - assert res[0][0] == 3 - - capture_message("hi") - - (event,) = events - - (insert_breadcrumb,) = [ - crumb - for crumb in event["breadcrumbs"]["values"] - if crumb["message"] == "INSERT INTO test (x) VALUES" - ] - - assert "db.params" not in insert_breadcrumb["data"] - - -def test_clickhouse_client_send_data_generator_span_streaming_with_data_collection_disabled( - sentry_init, capture_events -) -> None: - sentry_init( - integrations=[ClickhouseDriverIntegration()], - trace_lifecycle="stream", - data_collection={"database_query_data": False}, - ) - events = capture_events() - - client = Client("localhost") - client.execute("DROP TABLE IF EXISTS test") - client.execute("CREATE TABLE test (x Int32) ENGINE = Memory") - client.execute("INSERT INTO test (x) VALUES", ((i,) for i in range(3))) - - res = client.execute("SELECT sum(x) FROM test") - assert res[0][0] == 3 - - capture_message("hi") - - (event,) = events - - (insert_breadcrumb,) = [ - crumb - for crumb in event["breadcrumbs"]["values"] - if crumb["message"] == "INSERT INTO test (x) VALUES" - ] - - assert "db.params" not in insert_breadcrumb["data"] - - -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_clickhouse_client_spans( - sentry_init, - capture_events, - capture_items, - span_streaming, -): - sentry_init( - integrations=[ClickhouseDriverIntegration()], - trace_lifecycle="stream" if span_streaming else "static", - _experiments={ - "record_sql_params": True, - }, - traces_sample_rate=1.0, - ) - if span_streaming: - items = capture_items("span") - - trace_id = None - span_id = None - - with sentry_sdk.traces.start_span(name="custom parent") as span: - trace_id = span.trace_id - span_id = span.span_id - - client = Client("localhost") - client.execute("DROP TABLE IF EXISTS test") - client.execute("CREATE TABLE test (x Int32) ENGINE = Memory") - client.execute("INSERT INTO test (x) VALUES", [{"x": 100}]) - client.execute("INSERT INTO test (x) VALUES", [[170], [200]]) - - res = client.execute( - "SELECT sum(x) FROM test WHERE x > %(minv)i", {"minv": 150} - ) - assert res[0][0] == 370 - - sentry_sdk.flush() - spans = [item.payload for item in items] - - expected_spans = [ - { - "name": "DROP TABLE IF EXISTS test", - "attributes": { - "db.system.name": "clickhouse", - "db.driver.name": "clickhouse-driver", - "db.namespace": "", - "db.user": "default", - "sentry.op": "db", - "db.query.text": "DROP TABLE IF EXISTS test", - "sentry.origin": "auto.db.clickhouse_driver", - "server.address": "localhost", - "server.port": 9000, - }, - "trace_id": trace_id, - "parent_span_id": span_id, - }, - { - "name": "CREATE TABLE test (x Int32) ENGINE = Memory", - "attributes": { - "db.system.name": "clickhouse", - "db.driver.name": "clickhouse-driver", - "db.namespace": "", - "db.user": "default", - "sentry.op": "db", - "db.query.text": "CREATE TABLE test (x Int32) ENGINE = Memory", - "sentry.origin": "auto.db.clickhouse_driver", - "server.address": "localhost", - "server.port": 9000, - }, - "trace_id": trace_id, - "parent_span_id": span_id, - }, - { - "name": "INSERT INTO test (x) VALUES", - "attributes": { - "db.system.name": "clickhouse", - "db.driver.name": "clickhouse-driver", - "db.namespace": "", - "db.user": "default", - "sentry.op": "db", - "db.query.text": "INSERT INTO test (x) VALUES", - "sentry.origin": "auto.db.clickhouse_driver", - "server.address": "localhost", - "server.port": 9000, - }, - "trace_id": trace_id, - "parent_span_id": span_id, - }, - { - "name": "INSERT INTO test (x) VALUES", - "attributes": { - "db.system.name": "clickhouse", - "db.driver.name": "clickhouse-driver", - "db.namespace": "", - "db.user": "default", - "sentry.op": "db", - "db.query.text": "INSERT INTO test (x) VALUES", - "sentry.origin": "auto.db.clickhouse_driver", - "server.address": "localhost", - "server.port": 9000, - }, - "trace_id": trace_id, - "parent_span_id": span_id, - }, - { - "name": "SELECT sum(x) FROM test WHERE x > 150", - "attributes": { - "db.system.name": "clickhouse", - "db.driver.name": "clickhouse-driver", - "db.namespace": "", - "db.user": "default", - "sentry.op": "db", - "db.query.text": "SELECT sum(x) FROM test WHERE x > 150", - "sentry.origin": "auto.db.clickhouse_driver", - "server.address": "localhost", - "server.port": 9000, - }, - "trace_id": trace_id, - "parent_span_id": span_id, - }, - { - "name": "custom parent", - "attributes": [], - "trace_id": trace_id, - }, - ] - - for span in expected_spans: - span["attributes"] = ApproxDict(span["attributes"]) - - for span in spans: - span.pop("span_id", None) - span.pop("start_timestamp", None) - span.pop("end_timestamp", None) - span.pop("is_segment", None) - span.pop("status", None) - - assert spans == expected_spans - else: - events = capture_events() - - transaction_trace_id = None - transaction_span_id = None - - with start_transaction(name="test_clickhouse_transaction") as transaction: - transaction_trace_id = transaction.trace_id - transaction_span_id = transaction.span_id - - client = Client("localhost") - client.execute("DROP TABLE IF EXISTS test") - client.execute("CREATE TABLE test (x Int32) ENGINE = Memory") - client.execute("INSERT INTO test (x) VALUES", [{"x": 100}]) - client.execute("INSERT INTO test (x) VALUES", [[170], [200]]) - - res = client.execute( - "SELECT sum(x) FROM test WHERE x > %(minv)i", {"minv": 150} - ) - assert res[0][0] == 370 - - (event,) = events - - expected_spans = [ - { - "op": "db", - "origin": "auto.db.clickhouse_driver", - "description": "DROP TABLE IF EXISTS test", - "data": { - "db.system": "clickhouse", - "db.driver.name": "clickhouse-driver", - "db.name": "", - "db.user": "default", - "server.address": "localhost", - "server.port": 9000, - }, - "same_process_as_parent": True, - "trace_id": transaction_trace_id, - "parent_span_id": transaction_span_id, - }, - { - "op": "db", - "origin": "auto.db.clickhouse_driver", - "description": "CREATE TABLE test (x Int32) ENGINE = Memory", - "data": { - "db.system": "clickhouse", - "db.driver.name": "clickhouse-driver", - "db.name": "", - "db.user": "default", - "server.address": "localhost", - "server.port": 9000, - }, - "same_process_as_parent": True, - "trace_id": transaction_trace_id, - "parent_span_id": transaction_span_id, - }, - { - "op": "db", - "origin": "auto.db.clickhouse_driver", - "description": "INSERT INTO test (x) VALUES", - "data": { - "db.system": "clickhouse", - "db.driver.name": "clickhouse-driver", - "db.name": "", - "db.user": "default", - "server.address": "localhost", - "server.port": 9000, - }, - "same_process_as_parent": True, - "trace_id": transaction_trace_id, - "parent_span_id": transaction_span_id, - }, - { - "op": "db", - "origin": "auto.db.clickhouse_driver", - "description": "INSERT INTO test (x) VALUES", - "data": { - "db.system": "clickhouse", - "db.driver.name": "clickhouse-driver", - "db.name": "", - "db.user": "default", - "server.address": "localhost", - "server.port": 9000, - }, - "same_process_as_parent": True, - "trace_id": transaction_trace_id, - "parent_span_id": transaction_span_id, - }, - { - "op": "db", - "origin": "auto.db.clickhouse_driver", - "description": "SELECT sum(x) FROM test WHERE x > 150", - "data": { - "db.system": "clickhouse", - "db.driver.name": "clickhouse-driver", - "db.name": "", - "db.user": "default", - "server.address": "localhost", - "server.port": 9000, - }, - "same_process_as_parent": True, - "trace_id": transaction_trace_id, - "parent_span_id": transaction_span_id, - }, - ] - - if not EXPECT_PARAMS_IN_SELECT: - expected_spans[-1]["data"].pop("db.params", None) - - for span in expected_spans: - span["data"] = ApproxDict(span["data"]) - - for span in event["spans"]: - span.pop("span_id", None) - span.pop("start_timestamp", None) - span.pop("timestamp", None) - - assert event["spans"] == expected_spans - - -def test_clickhouse_spans_with_generator(sentry_init, capture_events): - sentry_init( - integrations=[ClickhouseDriverIntegration()], - send_default_pii=True, - traces_sample_rate=1.0, - ) - events = capture_events() - - # Use a generator to test that the integration obtains values from the generator, - # without consuming the generator. - values = ({"x": i} for i in range(3)) - - with start_transaction(name="test_clickhouse_transaction"): - client = Client("localhost") - client.execute("DROP TABLE IF EXISTS test") - client.execute("CREATE TABLE test (x Int32) ENGINE = Memory") - client.execute("INSERT INTO test (x) VALUES", values) - res = client.execute("SELECT x FROM test") - - # Verify that the integration did not consume the generator - assert res == [(0,), (1,), (2,)] - - (event,) = events - spans = event["spans"] - - [span] = [ - span for span in spans if span["description"] == "INSERT INTO test (x) VALUES" - ] - - assert span["data"]["db.params"] == [{"x": 0}, {"x": 1}, {"x": 2}] - - -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_clickhouse_client_spans_with_pii( - sentry_init, - capture_events, - capture_items, - capture_envelopes, - span_streaming, -): - sentry_init( - integrations=[ClickhouseDriverIntegration()], - trace_lifecycle="stream" if span_streaming else "static", - _experiments={ - "record_sql_params": True, - }, - traces_sample_rate=1.0, - send_default_pii=True, - ) - if span_streaming: - items = capture_items("span") - - trace_id = None - span_id = None - - with sentry_sdk.traces.start_span(name="custom parent") as span: - trace_id = span.trace_id - span_id = span.span_id - - client = Client("localhost") - client.execute("DROP TABLE IF EXISTS test") - client.execute("CREATE TABLE test (x Int32) ENGINE = Memory") - client.execute("INSERT INTO test (x) VALUES", [{"x": 100}]) - client.execute("INSERT INTO test (x) VALUES", [[170], [200]]) - - res = client.execute( - "SELECT sum(x) FROM test WHERE x > %(minv)i", {"minv": 150} - ) - assert res[0][0] == 370 - - sentry_sdk.flush() - spans = [item.payload for item in items] - - expected_spans = [ - { - "name": "DROP TABLE IF EXISTS test", - "attributes": { - "db.system.name": "clickhouse", - "db.namespace": "", - "db.user": "default", - "db.query.text": "DROP TABLE IF EXISTS test", - "server.address": "localhost", - "server.port": 9000, - "thread.id": mock.ANY, - "thread.name": mock.ANY, - }, - "trace_id": trace_id, - "parent_span_id": span_id, - }, - { - "name": "CREATE TABLE test (x Int32) ENGINE = Memory", - "attributes": { - "db.system.name": "clickhouse", - "db.namespace": "", - "db.user": "default", - "db.query.text": "CREATE TABLE test (x Int32) ENGINE = Memory", - "server.address": "localhost", - "server.port": 9000, - "thread.id": mock.ANY, - "thread.name": mock.ANY, - }, - "trace_id": trace_id, - "parent_span_id": span_id, - }, - { - "name": "INSERT INTO test (x) VALUES", - "attributes": { - "db.system.name": "clickhouse", - "db.namespace": "", - "db.user": "default", - "db.query.text": "INSERT INTO test (x) VALUES", - "server.address": "localhost", - "server.port": 9000, - "thread.id": mock.ANY, - "thread.name": mock.ANY, - }, - "trace_id": trace_id, - "parent_span_id": span_id, - }, - { - "name": "INSERT INTO test (x) VALUES", - "attributes": { - "db.system.name": "clickhouse", - "db.namespace": "", - "db.user": "default", - "db.query.text": "INSERT INTO test (x) VALUES", - "server.address": "localhost", - "server.port": 9000, - }, - "trace_id": trace_id, - "parent_span_id": span_id, - }, - { - "name": "SELECT sum(x) FROM test WHERE x > 150", - "attributes": { - "db.system.name": "clickhouse", - "db.namespace": "", - "db.user": "default", - "db.query.text": "SELECT sum(x) FROM test WHERE x > 150", - "server.address": "localhost", - "server.port": 9000, - }, - "trace_id": trace_id, - "parent_span_id": span_id, - }, - { - "name": "custom parent", - "attributes": [], - "trace_id": trace_id, - }, - ] - - for span in expected_spans: - span["attributes"] = ApproxDict(span["attributes"]) - - for span in spans: - span.pop("span_id", None) - span.pop("start_timestamp", None) - span.pop("end_timestamp", None) - span.pop("is_segment", None) - span.pop("status", None) - - assert spans == expected_spans - else: - events = capture_events() - - transaction_trace_id = None - transaction_span_id = None - - with start_transaction(name="test_clickhouse_transaction") as transaction: - transaction_trace_id = transaction.trace_id - transaction_span_id = transaction.span_id - - client = Client("localhost") - client.execute("DROP TABLE IF EXISTS test") - client.execute("CREATE TABLE test (x Int32) ENGINE = Memory") - client.execute("INSERT INTO test (x) VALUES", [{"x": 100}]) - client.execute("INSERT INTO test (x) VALUES", [[170], [200]]) - - res = client.execute( - "SELECT sum(x) FROM test WHERE x > %(minv)i", {"minv": 150} - ) - assert res[0][0] == 370 - - (event,) = events - - expected_spans = [ - { - "op": "db", - "origin": "auto.db.clickhouse_driver", - "description": "DROP TABLE IF EXISTS test", - "data": { - "db.system": "clickhouse", - "db.name": "", - "db.user": "default", - "server.address": "localhost", - "server.port": 9000, - "db.result": [], - }, - "same_process_as_parent": True, - "trace_id": transaction_trace_id, - "parent_span_id": transaction_span_id, - }, - { - "op": "db", - "origin": "auto.db.clickhouse_driver", - "description": "CREATE TABLE test (x Int32) ENGINE = Memory", - "data": { - "db.system": "clickhouse", - "db.name": "", - "db.user": "default", - "server.address": "localhost", - "server.port": 9000, - "db.result": [], - }, - "same_process_as_parent": True, - "trace_id": transaction_trace_id, - "parent_span_id": transaction_span_id, - }, - { - "op": "db", - "origin": "auto.db.clickhouse_driver", - "description": "INSERT INTO test (x) VALUES", - "data": { - "db.system": "clickhouse", - "db.name": "", - "db.user": "default", - "server.address": "localhost", - "server.port": 9000, - "db.params": [{"x": 100}], - }, - "same_process_as_parent": True, - "trace_id": transaction_trace_id, - "parent_span_id": transaction_span_id, - }, - { - "op": "db", - "origin": "auto.db.clickhouse_driver", - "description": "INSERT INTO test (x) VALUES", - "data": { - "db.system": "clickhouse", - "db.name": "", - "db.user": "default", - "server.address": "localhost", - "server.port": 9000, - "db.params": [[170], [200]], - }, - "same_process_as_parent": True, - "trace_id": transaction_trace_id, - "parent_span_id": transaction_span_id, - }, - { - "op": "db", - "origin": "auto.db.clickhouse_driver", - "description": "SELECT sum(x) FROM test WHERE x > 150", - "data": { - "db.system": "clickhouse", - "db.name": "", - "db.user": "default", - "server.address": "localhost", - "server.port": 9000, - "db.params": {"minv": 150}, - "db.result": [[370]], - }, - "same_process_as_parent": True, - "trace_id": transaction_trace_id, - "parent_span_id": transaction_span_id, - }, - ] - - if not EXPECT_PARAMS_IN_SELECT: - expected_spans[-1]["data"].pop("db.params", None) - - for span in expected_spans: - span["data"] = ApproxDict(span["data"]) - - for span in event["spans"]: - span.pop("span_id", None) - span.pop("start_timestamp", None) - span.pop("timestamp", None) - - assert event["spans"] == expected_spans - - -def test_clickhouse_dbapi_breadcrumbs(sentry_init, capture_events) -> None: - sentry_init( - integrations=[ClickhouseDriverIntegration()], - ) - events = capture_events() - - conn = connect("clickhouse://localhost") - cursor = conn.cursor() - cursor.execute("DROP TABLE IF EXISTS test") - cursor.execute("CREATE TABLE test (x Int32) ENGINE = Memory") - cursor.executemany("INSERT INTO test (x) VALUES", [{"x": 100}]) - cursor.executemany("INSERT INTO test (x) VALUES", [[170], [200]]) - cursor.execute("SELECT sum(x) FROM test WHERE x > %(minv)i", {"minv": 150}) - res = cursor.fetchall() - - assert res[0][0] == 370 - - capture_message("hi") - - (event,) = events - - expected_breadcrumbs = [ - { - "category": "query", - "data": { - "db.system": "clickhouse", - "db.driver.name": "clickhouse-driver", - "db.name": "", - "db.user": "default", - "server.address": "localhost", - "server.port": 9000, - }, - "message": "DROP TABLE IF EXISTS test", - "type": "default", - }, - { - "category": "query", - "data": { - "db.system": "clickhouse", - "db.driver.name": "clickhouse-driver", - "db.name": "", - "db.user": "default", - "server.address": "localhost", - "server.port": 9000, - }, - "message": "CREATE TABLE test (x Int32) ENGINE = Memory", - "type": "default", - }, - { - "category": "query", - "data": { - "db.system": "clickhouse", - "db.driver.name": "clickhouse-driver", - "db.name": "", - "db.user": "default", - "server.address": "localhost", - "server.port": 9000, - }, - "message": "INSERT INTO test (x) VALUES", - "type": "default", - }, - { - "category": "query", - "data": { - "db.system": "clickhouse", - "db.driver.name": "clickhouse-driver", - "db.name": "", - "db.user": "default", - "server.address": "localhost", - "server.port": 9000, - }, - "message": "INSERT INTO test (x) VALUES", - "type": "default", - }, - { - "category": "query", - "data": { - "db.system": "clickhouse", - "db.driver.name": "clickhouse-driver", - "db.name": "", - "db.user": "default", - "server.address": "localhost", - "server.port": 9000, - }, - "message": "SELECT sum(x) FROM test WHERE x > 150", - "type": "default", - }, - ] - - if not EXPECT_PARAMS_IN_SELECT: - expected_breadcrumbs[-1]["data"].pop("db.params", None) - - for crumb in expected_breadcrumbs: - crumb["data"] = ApproxDict(crumb["data"]) - - for crumb in event["breadcrumbs"]["values"]: - crumb.pop("timestamp", None) - - assert event["breadcrumbs"]["values"] == expected_breadcrumbs - - -def test_clickhouse_dbapi_breadcrumbs_span_streaming( - sentry_init, capture_events -) -> None: - sentry_init( - integrations=[ClickhouseDriverIntegration()], - trace_lifecycle="stream", - ) - events = capture_events() - - conn = connect("clickhouse://localhost") - cursor = conn.cursor() - cursor.execute("DROP TABLE IF EXISTS test") - cursor.execute("CREATE TABLE test (x Int32) ENGINE = Memory") - cursor.executemany("INSERT INTO test (x) VALUES", [{"x": 100}]) - cursor.executemany("INSERT INTO test (x) VALUES", [[170], [200]]) - cursor.execute("SELECT sum(x) FROM test WHERE x > %(minv)i", {"minv": 150}) - res = cursor.fetchall() - - assert res[0][0] == 370 - - capture_message("hi") - - (event,) = events - - expected_breadcrumbs = [ - { - "category": "query", - "data": { - "db.system": "clickhouse", - "db.driver.name": "clickhouse-driver", - "db.name": "", - "db.user": "default", - "server.address": "localhost", - "server.port": 9000, - }, - "message": "DROP TABLE IF EXISTS test", - "type": "default", - }, - { - "category": "query", - "data": { - "db.system": "clickhouse", - "db.driver.name": "clickhouse-driver", - "db.name": "", - "db.user": "default", - "server.address": "localhost", - "server.port": 9000, - }, - "message": "CREATE TABLE test (x Int32) ENGINE = Memory", - "type": "default", - }, - { - "category": "query", - "data": { - "db.system": "clickhouse", - "db.driver.name": "clickhouse-driver", - "db.name": "", - "db.user": "default", - "server.address": "localhost", - "server.port": 9000, - }, - "message": "INSERT INTO test (x) VALUES", - "type": "default", - }, - { - "category": "query", - "data": { - "db.system": "clickhouse", - "db.driver.name": "clickhouse-driver", - "db.name": "", - "db.user": "default", - "server.address": "localhost", - "server.port": 9000, - }, - "message": "INSERT INTO test (x) VALUES", - "type": "default", - }, - { - "category": "query", - "data": { - "db.system": "clickhouse", - "db.driver.name": "clickhouse-driver", - "db.name": "", - "db.user": "default", - "server.address": "localhost", - "server.port": 9000, - }, - "message": "SELECT sum(x) FROM test WHERE x > 150", - "type": "default", - }, - ] - - for crumb in expected_breadcrumbs: - crumb["data"] = ApproxDict(crumb["data"]) - - for crumb in event["breadcrumbs"]["values"]: - crumb.pop("timestamp", None) - - assert event["breadcrumbs"]["values"] == expected_breadcrumbs - - -def test_clickhouse_dbapi_breadcrumbs_with_pii(sentry_init, capture_events) -> None: - sentry_init( - integrations=[ClickhouseDriverIntegration()], - send_default_pii=True, - ) - events = capture_events() - - conn = connect("clickhouse://localhost") - cursor = conn.cursor() - cursor.execute("DROP TABLE IF EXISTS test") - cursor.execute("CREATE TABLE test (x Int32) ENGINE = Memory") - cursor.executemany("INSERT INTO test (x) VALUES", [{"x": 100}]) - cursor.executemany("INSERT INTO test (x) VALUES", [[170], [200]]) - cursor.execute("SELECT sum(x) FROM test WHERE x > %(minv)i", {"minv": 150}) - res = cursor.fetchall() - - assert res[0][0] == 370 - - capture_message("hi") - - (event,) = events - - expected_breadcrumbs = [ - { - "category": "query", - "data": { - "db.system": "clickhouse", - "db.name": "", - "db.user": "default", - "server.address": "localhost", - "server.port": 9000, - "db.result": [[], []], - }, - "message": "DROP TABLE IF EXISTS test", - "type": "default", - }, - { - "category": "query", - "data": { - "db.system": "clickhouse", - "db.name": "", - "db.user": "default", - "server.address": "localhost", - "server.port": 9000, - "db.result": [[], []], - }, - "message": "CREATE TABLE test (x Int32) ENGINE = Memory", - "type": "default", - }, - { - "category": "query", - "data": { - "db.system": "clickhouse", - "db.name": "", - "db.user": "default", - "server.address": "localhost", - "server.port": 9000, - "db.params": [{"x": 100}], - }, - "message": "INSERT INTO test (x) VALUES", - "type": "default", - }, - { - "category": "query", - "data": { - "db.system": "clickhouse", - "db.name": "", - "db.user": "default", - "server.address": "localhost", - "server.port": 9000, - "db.params": [[170], [200]], - }, - "message": "INSERT INTO test (x) VALUES", - "type": "default", - }, - { - "category": "query", - "data": { - "db.system": "clickhouse", - "db.name": "", - "db.user": "default", - "server.address": "localhost", - "server.port": 9000, - "db.params": {"minv": 150}, - "db.result": [[["370"]], [["'sum(x)'", "'Int64'"]]], - }, - "message": "SELECT sum(x) FROM test WHERE x > 150", - "type": "default", - }, - ] - - if not EXPECT_PARAMS_IN_SELECT: - expected_breadcrumbs[-1]["data"].pop("db.params", None) - - for crumb in expected_breadcrumbs: - crumb["data"] = ApproxDict(crumb["data"]) - - for crumb in event["breadcrumbs"]["values"]: - crumb.pop("timestamp", None) - - assert event["breadcrumbs"]["values"] == expected_breadcrumbs - - -def test_clickhouse_dbapi_breadcrumbs_with_pii_span_streaming( - sentry_init, capture_events -) -> None: - sentry_init( - integrations=[ClickhouseDriverIntegration()], - send_default_pii=True, - trace_lifecycle="stream", - ) - events = capture_events() - - conn = connect("clickhouse://localhost") - cursor = conn.cursor() - cursor.execute("DROP TABLE IF EXISTS test") - cursor.execute("CREATE TABLE test (x Int32) ENGINE = Memory") - cursor.executemany("INSERT INTO test (x) VALUES", [{"x": 100}]) - cursor.executemany("INSERT INTO test (x) VALUES", [[170], [200]]) - cursor.execute("SELECT sum(x) FROM test WHERE x > %(minv)i", {"minv": 150}) - res = cursor.fetchall() - - assert res[0][0] == 370 - - capture_message("hi") - - (event,) = events - - expected_breadcrumbs = [ - { - "category": "query", - "data": { - "db.system": "clickhouse", - "db.driver.name": "clickhouse-driver", - "db.name": "", - "db.user": "default", - "server.address": "localhost", - "server.port": 9000, - "db.result": [[], []], - }, - "message": "DROP TABLE IF EXISTS test", - "type": "default", - }, - { - "category": "query", - "data": { - "db.system": "clickhouse", - "db.driver.name": "clickhouse-driver", - "db.name": "", - "db.user": "default", - "server.address": "localhost", - "server.port": 9000, - "db.result": [[], []], - }, - "message": "CREATE TABLE test (x Int32) ENGINE = Memory", - "type": "default", + "trace_id": trace_id, + "parent_span_id": span_id, }, { - "category": "query", - "data": { - "db.system": "clickhouse", + "name": "INSERT INTO test (x) VALUES", + "attributes": { + "db.system.name": "clickhouse", "db.driver.name": "clickhouse-driver", - "db.name": "", + "db.namespace": "", "db.user": "default", + "db.query.text": "INSERT INTO test (x) VALUES", + "sentry.op": "db", + "sentry.origin": "auto.db.clickhouse_driver", "server.address": "localhost", "server.port": 9000, }, - "message": "INSERT INTO test (x) VALUES", - "type": "default", + "trace_id": trace_id, + "parent_span_id": span_id, }, { - "category": "query", - "data": { - "db.system": "clickhouse", + "name": "SELECT sum(x) FROM test WHERE x > 150", + "attributes": { + "db.system.name": "clickhouse", "db.driver.name": "clickhouse-driver", - "db.name": "", + "db.namespace": "", "db.user": "default", + "db.query.text": "SELECT sum(x) FROM test WHERE x > 150", + "sentry.op": "db", + "sentry.origin": "auto.db.clickhouse_driver", "server.address": "localhost", "server.port": 9000, }, - "message": "INSERT INTO test (x) VALUES", - "type": "default", + "trace_id": trace_id, + "parent_span_id": span_id, }, { - "category": "query", - "data": { - "db.system": "clickhouse", - "db.driver.name": "clickhouse-driver", - "db.name": "", - "db.user": "default", - "server.address": "localhost", - "server.port": 9000, - "db.result": [[["370"]], [["'sum(x)'", "'Int64'"]]], - }, - "message": "SELECT sum(x) FROM test WHERE x > 150", - "type": "default", + "name": "custom parent", + "attributes": [], + "trace_id": trace_id, }, ] - for crumb in expected_breadcrumbs: - crumb["data"] = ApproxDict(crumb["data"]) - - for crumb in event["breadcrumbs"]["values"]: - crumb.pop("timestamp", None) - - assert event["breadcrumbs"]["values"] == expected_breadcrumbs - - -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_clickhouse_dbapi_spans( - sentry_init, - capture_events, - capture_items, - capture_envelopes, - span_streaming, -): - sentry_init( - integrations=[ClickhouseDriverIntegration()], - trace_lifecycle="stream" if span_streaming else "static", - _experiments={ - "record_sql_params": True, - }, - traces_sample_rate=1.0, - ) - if span_streaming: - items = capture_items("span") - - trace_id = None - span_id = None - - with sentry_sdk.traces.start_span(name="custom parent") as span: - trace_id = span.trace_id - span_id = span.span_id - - conn = connect("clickhouse://localhost") - cursor = conn.cursor() - cursor.execute("DROP TABLE IF EXISTS test") - cursor.execute("CREATE TABLE test (x Int32) ENGINE = Memory") - cursor.executemany("INSERT INTO test (x) VALUES", [{"x": 100}]) - cursor.executemany("INSERT INTO test (x) VALUES", [[170], [200]]) - cursor.execute("SELECT sum(x) FROM test WHERE x > %(minv)i", {"minv": 150}) - res = cursor.fetchall() - - sentry_sdk.flush() - spans = [item.payload for item in items] - - expected_spans = [ - { - "name": "DROP TABLE IF EXISTS test", - "attributes": { - "db.system.name": "clickhouse", - "db.driver.name": "clickhouse-driver", - "db.namespace": "", - "db.user": "default", - "db.query.text": "DROP TABLE IF EXISTS test", - "sentry.op": "db", - "sentry.origin": "auto.db.clickhouse_driver", - "server.address": "localhost", - "server.port": 9000, - }, - "trace_id": trace_id, - "parent_span_id": span_id, - }, - { - "name": "CREATE TABLE test (x Int32) ENGINE = Memory", - "attributes": { - "db.system.name": "clickhouse", - "db.driver.name": "clickhouse-driver", - "db.namespace": "", - "db.user": "default", - "db.query.text": "CREATE TABLE test (x Int32) ENGINE = Memory", - "sentry.op": "db", - "sentry.origin": "auto.db.clickhouse_driver", - "server.address": "localhost", - "server.port": 9000, - }, - "trace_id": trace_id, - "parent_span_id": span_id, - }, - { - "name": "INSERT INTO test (x) VALUES", - "attributes": { - "db.system.name": "clickhouse", - "db.driver.name": "clickhouse-driver", - "db.namespace": "", - "db.user": "default", - "db.query.text": "INSERT INTO test (x) VALUES", - "sentry.op": "db", - "sentry.origin": "auto.db.clickhouse_driver", - "server.address": "localhost", - "server.port": 9000, - }, - "trace_id": trace_id, - "parent_span_id": span_id, - }, - { - "name": "INSERT INTO test (x) VALUES", - "attributes": { - "db.system.name": "clickhouse", - "db.driver.name": "clickhouse-driver", - "db.namespace": "", - "db.user": "default", - "db.query.text": "INSERT INTO test (x) VALUES", - "sentry.op": "db", - "sentry.origin": "auto.db.clickhouse_driver", - "server.address": "localhost", - "server.port": 9000, - }, - "trace_id": trace_id, - "parent_span_id": span_id, - }, - { - "name": "SELECT sum(x) FROM test WHERE x > 150", - "attributes": { - "db.system.name": "clickhouse", - "db.driver.name": "clickhouse-driver", - "db.namespace": "", - "db.user": "default", - "db.query.text": "SELECT sum(x) FROM test WHERE x > 150", - "sentry.op": "db", - "sentry.origin": "auto.db.clickhouse_driver", - "server.address": "localhost", - "server.port": 9000, - }, - "trace_id": trace_id, - "parent_span_id": span_id, - }, - { - "name": "custom parent", - "attributes": [], - "trace_id": trace_id, - }, - ] - - for span in expected_spans: - span["attributes"] = ApproxDict(span["attributes"]) - - for span in spans: - span.pop("span_id", None) - span.pop("start_timestamp", None) - span.pop("end_timestamp", None) - span.pop("is_segment", None) - span.pop("status", None) - - assert spans == expected_spans - else: - events = capture_events() - - transaction_trace_id = None - transaction_span_id = None - - with start_transaction(name="test_clickhouse_transaction") as transaction: - transaction_trace_id = transaction.trace_id - transaction_span_id = transaction.span_id - - conn = connect("clickhouse://localhost") - cursor = conn.cursor() - cursor.execute("DROP TABLE IF EXISTS test") - cursor.execute("CREATE TABLE test (x Int32) ENGINE = Memory") - cursor.executemany("INSERT INTO test (x) VALUES", [{"x": 100}]) - cursor.executemany("INSERT INTO test (x) VALUES", [[170], [200]]) - cursor.execute("SELECT sum(x) FROM test WHERE x > %(minv)i", {"minv": 150}) - res = cursor.fetchall() - - assert res[0][0] == 370 - - (event,) = events - - expected_spans = [ - { - "op": "db", - "origin": "auto.db.clickhouse_driver", - "description": "DROP TABLE IF EXISTS test", - "data": { - "db.system": "clickhouse", - "db.driver.name": "clickhouse-driver", - "db.name": "", - "db.user": "default", - "server.address": "localhost", - "server.port": 9000, - }, - "same_process_as_parent": True, - "trace_id": transaction_trace_id, - "parent_span_id": transaction_span_id, - }, - { - "op": "db", - "origin": "auto.db.clickhouse_driver", - "description": "CREATE TABLE test (x Int32) ENGINE = Memory", - "data": { - "db.system": "clickhouse", - "db.driver.name": "clickhouse-driver", - "db.name": "", - "db.user": "default", - "server.address": "localhost", - "server.port": 9000, - }, - "same_process_as_parent": True, - "trace_id": transaction_trace_id, - "parent_span_id": transaction_span_id, - }, - { - "op": "db", - "origin": "auto.db.clickhouse_driver", - "description": "INSERT INTO test (x) VALUES", - "data": { - "db.system": "clickhouse", - "db.driver.name": "clickhouse-driver", - "db.name": "", - "db.user": "default", - "server.address": "localhost", - "server.port": 9000, - }, - "same_process_as_parent": True, - "trace_id": transaction_trace_id, - "parent_span_id": transaction_span_id, - }, - { - "op": "db", - "origin": "auto.db.clickhouse_driver", - "description": "INSERT INTO test (x) VALUES", - "data": { - "db.system": "clickhouse", - "db.driver.name": "clickhouse-driver", - "db.name": "", - "db.user": "default", - "server.address": "localhost", - "server.port": 9000, - }, - "same_process_as_parent": True, - "trace_id": transaction_trace_id, - "parent_span_id": transaction_span_id, - }, - { - "op": "db", - "origin": "auto.db.clickhouse_driver", - "description": "SELECT sum(x) FROM test WHERE x > 150", - "data": { - "db.system": "clickhouse", - "db.driver.name": "clickhouse-driver", - "db.name": "", - "db.user": "default", - "server.address": "localhost", - "server.port": 9000, - }, - "same_process_as_parent": True, - "trace_id": transaction_trace_id, - "parent_span_id": transaction_span_id, - }, - ] - - if not EXPECT_PARAMS_IN_SELECT: - expected_spans[-1]["data"].pop("db.params", None) - - for span in expected_spans: - span["data"] = ApproxDict(span["data"]) - - for span in event["spans"]: - span.pop("span_id", None) - span.pop("start_timestamp", None) - span.pop("timestamp", None) - - assert event["spans"] == expected_spans - - -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_clickhouse_dbapi_spans_with_pii( - sentry_init, - capture_events, - capture_items, - capture_envelopes, - span_streaming, -): - sentry_init( - integrations=[ClickhouseDriverIntegration()], - trace_lifecycle="stream" if span_streaming else "static", - _experiments={ - "record_sql_params": True, - }, - traces_sample_rate=1.0, - send_default_pii=True, - ) - if span_streaming: - items = capture_items("span") - - trace_id = None - span_id = None - - with sentry_sdk.traces.start_span(name="custom parent") as span: - trace_id = span.trace_id - span_id = span.span_id + for span in expected_spans: + span["attributes"] = ApproxDict(span["attributes"]) - conn = connect("clickhouse://localhost") - cursor = conn.cursor() - cursor.execute("DROP TABLE IF EXISTS test") - cursor.execute("CREATE TABLE test (x Int32) ENGINE = Memory") - cursor.executemany("INSERT INTO test (x) VALUES", [{"x": 100}]) - cursor.executemany("INSERT INTO test (x) VALUES", [[170], [200]]) - cursor.execute("SELECT sum(x) FROM test WHERE x > %(minv)i", {"minv": 150}) - res = cursor.fetchall() - - assert res[0][0] == 370 - - sentry_sdk.flush() - spans = [item.payload for item in items] - - expected_spans = [ - { - "name": "DROP TABLE IF EXISTS test", - "attributes": { - "db.system.name": "clickhouse", - "db.namespace": "", - "db.user": "default", - "db.query.text": "DROP TABLE IF EXISTS test", - "sentry.op": "db", - "sentry.origin": "auto.db.clickhouse_driver", - "server.address": "localhost", - "server.port": 9000, - }, - "trace_id": trace_id, - "parent_span_id": span_id, - }, - { - "name": "CREATE TABLE test (x Int32) ENGINE = Memory", - "attributes": { - "db.system.name": "clickhouse", - "db.namespace": "", - "db.user": "default", - "db.query.text": "CREATE TABLE test (x Int32) ENGINE = Memory", - "sentry.op": "db", - "sentry.origin": "auto.db.clickhouse_driver", - "server.address": "localhost", - "server.port": 9000, - }, - "trace_id": trace_id, - "parent_span_id": span_id, - }, - { - "name": "INSERT INTO test (x) VALUES", - "attributes": { - "db.system.name": "clickhouse", - "db.namespace": "", - "db.user": "default", - "db.query.text": "INSERT INTO test (x) VALUES", - "sentry.op": "db", - "sentry.origin": "auto.db.clickhouse_driver", - "server.address": "localhost", - "server.port": 9000, - }, - "trace_id": trace_id, - "parent_span_id": span_id, - }, - { - "name": "INSERT INTO test (x) VALUES", - "attributes": { - "db.system.name": "clickhouse", - "db.namespace": "", - "db.user": "default", - "db.query.text": "INSERT INTO test (x) VALUES", - "sentry.op": "db", - "sentry.origin": "auto.db.clickhouse_driver", - "server.address": "localhost", - "server.port": 9000, - }, - "trace_id": trace_id, - "parent_span_id": span_id, - }, - { - "name": "SELECT sum(x) FROM test WHERE x > 150", - "attributes": { - "db.system.name": "clickhouse", - "db.namespace": "", - "db.user": "default", - "db.query.text": "SELECT sum(x) FROM test WHERE x > 150", - "sentry.op": "db", - "sentry.origin": "auto.db.clickhouse_driver", - "server.address": "localhost", - "server.port": 9000, - }, - "trace_id": trace_id, - "parent_span_id": span_id, - }, - { - "name": "custom parent", - "attributes": [], - "trace_id": trace_id, - }, - ] - - for span in expected_spans: - span["attributes"] = ApproxDict(span["attributes"]) - - for span in spans: - span.pop("span_id", None) - span.pop("start_timestamp", None) - span.pop("end_timestamp", None) - span.pop("is_segment", None) - span.pop("status", None) - - assert spans == expected_spans - else: - events = capture_events() - - transaction_trace_id = None - transaction_span_id = None - - with start_transaction(name="test_clickhouse_transaction") as transaction: - transaction_trace_id = transaction.trace_id - transaction_span_id = transaction.span_id - - conn = connect("clickhouse://localhost") - cursor = conn.cursor() - cursor.execute("DROP TABLE IF EXISTS test") - cursor.execute("CREATE TABLE test (x Int32) ENGINE = Memory") - cursor.executemany("INSERT INTO test (x) VALUES", [{"x": 100}]) - cursor.executemany("INSERT INTO test (x) VALUES", [[170], [200]]) - cursor.execute("SELECT sum(x) FROM test WHERE x > %(minv)i", {"minv": 150}) - res = cursor.fetchall() - - assert res[0][0] == 370 - - (event,) = events - - expected_spans = [ - { - "op": "db", - "origin": "auto.db.clickhouse_driver", - "description": "DROP TABLE IF EXISTS test", - "data": { - "db.system": "clickhouse", - "db.name": "", - "db.user": "default", - "server.address": "localhost", - "server.port": 9000, - "db.result": [[], []], - }, - "same_process_as_parent": True, - "trace_id": transaction_trace_id, - "parent_span_id": transaction_span_id, - }, - { - "op": "db", - "origin": "auto.db.clickhouse_driver", - "description": "CREATE TABLE test (x Int32) ENGINE = Memory", - "data": { - "db.system": "clickhouse", - "db.name": "", - "db.user": "default", - "server.address": "localhost", - "server.port": 9000, - "db.result": [[], []], - }, - "same_process_as_parent": True, - "trace_id": transaction_trace_id, - "parent_span_id": transaction_span_id, - }, - { - "op": "db", - "origin": "auto.db.clickhouse_driver", - "description": "INSERT INTO test (x) VALUES", - "data": { - "db.system": "clickhouse", - "db.name": "", - "db.user": "default", - "server.address": "localhost", - "server.port": 9000, - "db.params": [{"x": 100}], - }, - "same_process_as_parent": True, - "trace_id": transaction_trace_id, - "parent_span_id": transaction_span_id, - }, - { - "op": "db", - "origin": "auto.db.clickhouse_driver", - "description": "INSERT INTO test (x) VALUES", - "data": { - "db.system": "clickhouse", - "db.name": "", - "db.user": "default", - "server.address": "localhost", - "server.port": 9000, - "db.params": [[170], [200]], - }, - "same_process_as_parent": True, - "trace_id": transaction_trace_id, - "parent_span_id": transaction_span_id, - }, - { - "op": "db", - "origin": "auto.db.clickhouse_driver", - "description": "SELECT sum(x) FROM test WHERE x > 150", - "data": { - "db.system": "clickhouse", - "db.name": "", - "db.user": "default", - "server.address": "localhost", - "server.port": 9000, - "db.params": {"minv": 150}, - "db.result": [[[370]], [["sum(x)", "Int64"]]], - }, - "same_process_as_parent": True, - "trace_id": transaction_trace_id, - "parent_span_id": transaction_span_id, - }, - ] - - if not EXPECT_PARAMS_IN_SELECT: - expected_spans[-1]["data"].pop("db.params", None) - - for span in expected_spans: - span["data"] = ApproxDict(span["data"]) - - for span in event["spans"]: - span.pop("span_id", None) - span.pop("start_timestamp", None) - span.pop("timestamp", None) + for span in spans: + span.pop("span_id", None) + span.pop("start_timestamp", None) + span.pop("end_timestamp", None) + span.pop("is_segment", None) + span.pop("status", None) - assert event["spans"] == expected_spans + assert spans == expected_spans -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_span_origin( - sentry_init, - capture_events, - capture_items, - capture_envelopes, - span_streaming, -): +def test_span_origin(sentry_init, capture_items, capture_envelopes): sentry_init( integrations=[ClickhouseDriverIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", + data_collection={}, ) - if span_streaming: - items = capture_items("span") - - with sentry_sdk.traces.start_span(name="custom parent"): - conn = connect("clickhouse://localhost") - cursor = conn.cursor() - cursor.execute("SELECT 1") - - sentry_sdk.flush() - spans = [item.payload for item in items] - - assert spans[1]["attributes"]["sentry.origin"] == "manual" - assert spans[0]["attributes"]["sentry.origin"] == "auto.db.clickhouse_driver" - else: - events = capture_events() + items = capture_items("span") - with start_transaction(name="test_clickhouse_transaction"): - conn = connect("clickhouse://localhost") - cursor = conn.cursor() - cursor.execute("SELECT 1") + with sentry_sdk.start_span(name="custom parent"): + conn = connect("clickhouse://localhost") + cursor = conn.cursor() + cursor.execute("SELECT 1") - (event,) = events + sentry_sdk.flush() + spans = [item.payload for item in items] - assert event["contexts"]["trace"]["origin"] == "manual" - assert event["spans"][0]["origin"] == "auto.db.clickhouse_driver" + assert spans[1]["attributes"]["sentry.origin"] == "manual" + assert spans[0]["attributes"]["sentry.origin"] == "auto.db.clickhouse_driver" diff --git a/tests/integrations/cohere/test_cohere.py b/tests/integrations/cohere/test_cohere.py index 9cb9fac75d..941dcc3145 100644 --- a/tests/integrations/cohere/test_cohere.py +++ b/tests/integrations/cohere/test_cohere.py @@ -7,29 +7,23 @@ from httpx import Client as HTTPXClient import sentry_sdk -from sentry_sdk import start_transaction from sentry_sdk.consts import SPANDATA from sentry_sdk.integrations.cohere import CohereIntegration -@pytest.mark.parametrize("span_streaming", [True, False]) @pytest.mark.parametrize( - "send_default_pii, include_prompts", - [(True, True), (True, False), (False, True), (False, False)], + "send_default_pii", + [True, False], ) def test_nonstreaming_chat( sentry_init, - capture_events, capture_items, send_default_pii, - include_prompts, - span_streaming, ): sentry_init( - integrations=[CohereIntegration(include_prompts=include_prompts)], + integrations=[CohereIntegration()], traces_sample_rate=1.0, send_default_pii=send_default_pii, - trace_lifecycle="stream" if span_streaming else "static", ) client = Client(api_key="z") @@ -47,99 +41,56 @@ def test_nonstreaming_chat( }, ) ) + items = capture_items("span") + + response = client.chat( + model="some-model", + chat_history=[ChatMessage(role="SYSTEM", message="some context")], + message="hello", + ).text + + assert response == "the model response" + sentry_sdk.flush() + + assert len(items) == 1 + span = items[0].payload + + assert span["attributes"]["sentry.op"] == "ai.chat_completions.create.cohere" + assert span["attributes"][SPANDATA.AI_MODEL_ID] == "some-model" - if span_streaming: - items = capture_items("span") - - with start_transaction(name="cohere tx"): - response = client.chat( - model="some-model", - chat_history=[ChatMessage(role="SYSTEM", message="some context")], - message="hello", - ).text - - assert response == "the model response" - sentry_sdk.flush() - - assert len(items) == 1 - span = items[0].payload - - assert span["attributes"]["sentry.op"] == "ai.chat_completions.create.cohere" - assert span["attributes"][SPANDATA.AI_MODEL_ID] == "some-model" - - if send_default_pii and include_prompts: - assert ( - '{"role": "system", "content": "some context"}' - in span["attributes"][SPANDATA.AI_INPUT_MESSAGES] - ) - assert ( - '{"role": "user", "content": "hello"}' - in span["attributes"][SPANDATA.AI_INPUT_MESSAGES] - ) - assert "the model response" in span["attributes"][SPANDATA.AI_RESPONSES] - else: - assert SPANDATA.AI_INPUT_MESSAGES not in span["attributes"] - assert SPANDATA.AI_RESPONSES not in span["attributes"] - - assert span["attributes"]["gen_ai.usage.output_tokens"] == 10 - assert span["attributes"]["gen_ai.usage.input_tokens"] == 20 - assert span["attributes"]["gen_ai.usage.total_tokens"] == 30 + if send_default_pii: + assert ( + '{"role": "system", "content": "some context"}' + in span["attributes"][SPANDATA.AI_INPUT_MESSAGES] + ) + assert ( + '{"role": "user", "content": "hello"}' + in span["attributes"][SPANDATA.AI_INPUT_MESSAGES] + ) + assert "the model response" in span["attributes"][SPANDATA.AI_RESPONSES] else: - events = capture_events() - - with start_transaction(name="cohere tx"): - response = client.chat( - model="some-model", - chat_history=[ChatMessage(role="SYSTEM", message="some context")], - message="hello", - ).text - - assert response == "the model response" - tx = events[0] - assert tx["type"] == "transaction" - assert len(tx["spans"]) == 1 - span = tx["spans"][0] - assert span["op"] == "ai.chat_completions.create.cohere" - assert span["data"][SPANDATA.AI_MODEL_ID] == "some-model" - - if send_default_pii and include_prompts: - assert ( - '{"role": "system", "content": "some context"}' - in span["data"][SPANDATA.AI_INPUT_MESSAGES] - ) - assert ( - '{"role": "user", "content": "hello"}' - in span["data"][SPANDATA.AI_INPUT_MESSAGES] - ) - assert "the model response" in span["data"][SPANDATA.AI_RESPONSES] - else: - assert SPANDATA.AI_INPUT_MESSAGES not in span["data"] - assert SPANDATA.AI_RESPONSES not in span["data"] - - assert span["data"]["gen_ai.usage.output_tokens"] == 10 - assert span["data"]["gen_ai.usage.input_tokens"] == 20 - assert span["data"]["gen_ai.usage.total_tokens"] == 30 + assert SPANDATA.AI_INPUT_MESSAGES not in span["attributes"] + assert SPANDATA.AI_RESPONSES not in span["attributes"] + + assert span["attributes"]["gen_ai.usage.output_tokens"] == 10 + assert span["attributes"]["gen_ai.usage.input_tokens"] == 20 + assert span["attributes"]["gen_ai.usage.total_tokens"] == 30 # noinspection PyTypeChecker -@pytest.mark.parametrize("span_streaming", [True, False]) @pytest.mark.parametrize( - "send_default_pii, include_prompts", - [(True, True), (True, False), (False, True), (False, False)], + "send_default_pii", + [True, False], ) def test_streaming_chat( sentry_init, - capture_events, capture_items, send_default_pii, - include_prompts, - span_streaming, ): sentry_init( - integrations=[CohereIntegration(include_prompts=include_prompts)], + integrations=[CohereIntegration()], traces_sample_rate=1.0, send_default_pii=send_default_pii, - trace_lifecycle="stream" if span_streaming else "static", ) client = Client(api_key="z") @@ -169,148 +120,72 @@ def test_streaming_chat( ), ) ) + items = capture_items("span") - if span_streaming: - items = capture_items("span") - - with start_transaction(name="cohere tx"): - responses = list( - client.chat_stream( - model="some-model", - chat_history=[ChatMessage(role="SYSTEM", message="some context")], - message="hello", - ) - ) - response_string = responses[-1].response.text - - assert response_string == "the model response" - sentry_sdk.flush() - - assert len(items) == 1 - span = items[0].payload - - assert span["attributes"]["sentry.op"] == "ai.chat_completions.create.cohere" - assert span["attributes"][SPANDATA.AI_MODEL_ID] == "some-model" - - if send_default_pii and include_prompts: - assert ( - '{"role": "system", "content": "some context"}' - in span["attributes"][SPANDATA.AI_INPUT_MESSAGES] - ) - assert ( - '{"role": "user", "content": "hello"}' - in span["attributes"][SPANDATA.AI_INPUT_MESSAGES] - ) - assert "the model response" in span["attributes"][SPANDATA.AI_RESPONSES] - else: - assert SPANDATA.AI_INPUT_MESSAGES not in span["attributes"] - assert SPANDATA.AI_RESPONSES not in span["attributes"] - - assert span["attributes"]["gen_ai.usage.output_tokens"] == 10 - assert span["attributes"]["gen_ai.usage.input_tokens"] == 20 - assert span["attributes"]["gen_ai.usage.total_tokens"] == 30 - else: - events = capture_events() - - with start_transaction(name="cohere tx"): - responses = list( - client.chat_stream( - model="some-model", - chat_history=[ChatMessage(role="SYSTEM", message="some context")], - message="hello", - ) - ) - response_string = responses[-1].response.text - - assert response_string == "the model response" - tx = events[0] - assert tx["type"] == "transaction" - assert len(tx["spans"]) == 1 - span = tx["spans"][0] - assert span["op"] == "ai.chat_completions.create.cohere" - assert span["data"][SPANDATA.AI_MODEL_ID] == "some-model" - - if send_default_pii and include_prompts: - assert ( - '{"role": "system", "content": "some context"}' - in span["data"][SPANDATA.AI_INPUT_MESSAGES] - ) - assert ( - '{"role": "user", "content": "hello"}' - in span["data"][SPANDATA.AI_INPUT_MESSAGES] - ) - assert "the model response" in span["data"][SPANDATA.AI_RESPONSES] - else: - assert SPANDATA.AI_INPUT_MESSAGES not in span["data"] - assert SPANDATA.AI_RESPONSES not in span["data"] - - assert span["data"]["gen_ai.usage.output_tokens"] == 10 - assert span["data"]["gen_ai.usage.input_tokens"] == 20 - assert span["data"]["gen_ai.usage.total_tokens"] == 30 - - -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_bad_chat(sentry_init, capture_events, capture_items, span_streaming): - sentry_init( - integrations=[CohereIntegration()], - traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", + responses = list( + client.chat_stream( + model="some-model", + chat_history=[ChatMessage(role="SYSTEM", message="some context")], + message="hello", + ) ) + response_string = responses[-1].response.text - if span_streaming: - items = capture_items("event", "span") + assert response_string == "the model response" + sentry_sdk.flush() - client = Client(api_key="z") - HTTPXClient.request = mock.Mock( - side_effect=httpx.HTTPError("API rate limit reached") - ) - with pytest.raises(httpx.HTTPError): - client.chat(model="some-model", message="hello") + assert len(items) == 1 + span = items[0].payload - (event,) = (item.payload for item in items if item.type == "event") - assert event["level"] == "error" + assert span["attributes"]["sentry.op"] == "ai.chat_completions.create.cohere" + assert span["attributes"][SPANDATA.AI_MODEL_ID] == "some-model" - sentry_sdk.flush() - (span,) = (item.payload for item in items if item.type == "span") - assert span["status"] == "error" + if send_default_pii: + assert ( + '{"role": "system", "content": "some context"}' + in span["attributes"][SPANDATA.AI_INPUT_MESSAGES] + ) + assert ( + '{"role": "user", "content": "hello"}' + in span["attributes"][SPANDATA.AI_INPUT_MESSAGES] + ) + assert "the model response" in span["attributes"][SPANDATA.AI_RESPONSES] else: - events = capture_events() + assert SPANDATA.AI_INPUT_MESSAGES not in span["attributes"] + assert SPANDATA.AI_RESPONSES not in span["attributes"] - client = Client(api_key="z") - HTTPXClient.request = mock.Mock( - side_effect=httpx.HTTPError("API rate limit reached") - ) - with pytest.raises(httpx.HTTPError): - client.chat(model="some-model", message="hello") + assert span["attributes"]["gen_ai.usage.output_tokens"] == 10 + assert span["attributes"]["gen_ai.usage.input_tokens"] == 20 + assert span["attributes"]["gen_ai.usage.total_tokens"] == 30 - (event, transaction) = events - assert event["level"] == "error" - assert transaction["contexts"]["trace"]["status"] == "internal_error" +def test_bad_chat(sentry_init, capture_items): + sentry_init( + integrations=[CohereIntegration()], + traces_sample_rate=1.0, + ) -def test_span_status_error(sentry_init, capture_events): - sentry_init(integrations=[CohereIntegration()], traces_sample_rate=1.0) - events = capture_events() + items = capture_items("event", "span") - with start_transaction(name="test"): - client = Client(api_key="z") - HTTPXClient.request = mock.Mock( - side_effect=httpx.HTTPError("API rate limit reached") - ) - with pytest.raises(httpx.HTTPError): - client.chat(model="some-model", message="hello") + client = Client(api_key="z") + HTTPXClient.request = mock.Mock( + side_effect=httpx.HTTPError("API rate limit reached") + ) + with pytest.raises(httpx.HTTPError): + client.chat(model="some-model", message="hello") - (error, transaction) = events - assert error["level"] == "error" - assert transaction["spans"][0]["status"] == "internal_error" - assert transaction["spans"][0]["tags"]["status"] == "internal_error" + (event,) = (item.payload for item in items if item.type == "event") + assert event["level"] == "error" + sentry_sdk.flush() + (span,) = (item.payload for item in items if item.type == "span") + assert span["status"] == "error" -def test_span_status_error_streaming(sentry_init, capture_events, capture_items): + +def test_span_status_error(sentry_init, capture_items): sentry_init( integrations=[CohereIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", ) items = capture_items("span") @@ -318,9 +193,8 @@ def test_span_status_error_streaming(sentry_init, capture_events, capture_items) HTTPXClient.request = mock.Mock( side_effect=httpx.HTTPError("API rate limit reached") ) - with start_transaction(name="test"): - with pytest.raises(httpx.HTTPError): - client.chat(model="some-model", message="hello") + with pytest.raises(httpx.HTTPError): + client.chat(model="some-model", message="hello") sentry_sdk.flush() @@ -329,24 +203,19 @@ def test_span_status_error_streaming(sentry_init, capture_events, capture_items) assert span["status"] == "error" -@pytest.mark.parametrize("span_streaming", [True, False]) @pytest.mark.parametrize( - "send_default_pii, include_prompts", - [(True, True), (True, False), (False, True), (False, False)], + "send_default_pii", + [True, False], ) def test_embed( sentry_init, - capture_events, capture_items, send_default_pii, - include_prompts, - span_streaming, ): sentry_init( - integrations=[CohereIntegration(include_prompts=include_prompts)], + integrations=[CohereIntegration()], traces_sample_rate=1.0, send_default_pii=send_default_pii, - trace_lifecycle="stream" if span_streaming else "static", ) client = Client(api_key="z") @@ -366,189 +235,99 @@ def test_embed( }, ) ) + items = capture_items("span") - if span_streaming: - items = capture_items("span") - - with start_transaction(name="cohere tx"): - response = client.embed(texts=["hello"], model="text-embedding-3-large") - - assert len(response.embeddings[0]) == 3 - sentry_sdk.flush() + response = client.embed(texts=["hello"], model="text-embedding-3-large") - assert len(items) == 1 - span = items[0].payload + assert len(response.embeddings[0]) == 3 + sentry_sdk.flush() - assert span["attributes"]["sentry.op"] == "ai.embeddings.create.cohere" - if send_default_pii and include_prompts: - assert "hello" in span["attributes"][SPANDATA.AI_INPUT_MESSAGES] - else: - assert SPANDATA.AI_INPUT_MESSAGES not in span["attributes"] + assert len(items) == 1 + span = items[0].payload - assert span["attributes"]["gen_ai.usage.input_tokens"] == 10 - assert span["attributes"]["gen_ai.usage.total_tokens"] == 10 + assert span["attributes"]["sentry.op"] == "ai.embeddings.create.cohere" + if send_default_pii: + assert "hello" in span["attributes"][SPANDATA.AI_INPUT_MESSAGES] else: - events = capture_events() - - with start_transaction(name="cohere tx"): - response = client.embed(texts=["hello"], model="text-embedding-3-large") + assert SPANDATA.AI_INPUT_MESSAGES not in span["attributes"] - assert len(response.embeddings[0]) == 3 + assert span["attributes"]["gen_ai.usage.input_tokens"] == 10 + assert span["attributes"]["gen_ai.usage.total_tokens"] == 10 - tx = events[0] - assert tx["type"] == "transaction" - assert len(tx["spans"]) == 1 - span = tx["spans"][0] - assert span["op"] == "ai.embeddings.create.cohere" - if send_default_pii and include_prompts: - assert "hello" in span["data"][SPANDATA.AI_INPUT_MESSAGES] - else: - assert SPANDATA.AI_INPUT_MESSAGES not in span["data"] - assert span["data"]["gen_ai.usage.input_tokens"] == 10 - assert span["data"]["gen_ai.usage.total_tokens"] == 10 - - -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_span_origin_chat(sentry_init, capture_events, capture_items, span_streaming): +def test_span_origin_chat(sentry_init, capture_items): sentry_init( integrations=[CohereIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") - - client = Client(api_key="z") - HTTPXClient.request = mock.Mock( - return_value=httpx.Response( - 200, - json={ - "text": "the model response", - "meta": { - "billed_units": { - "output_tokens": 10, - "input_tokens": 20, - } - }, - }, - ) - ) - - with start_transaction(name="cohere tx"): - client.chat( - model="some-model", - chat_history=[ChatMessage(role="SYSTEM", message="some context")], - message="hello", - ).text + items = capture_items("span") - sentry_sdk.flush() - (span,) = (item.payload for item in items) - assert span["attributes"]["sentry.origin"] == "auto.ai.cohere" - else: - events = capture_events() - - client = Client(api_key="z") - HTTPXClient.request = mock.Mock( - return_value=httpx.Response( - 200, - json={ - "text": "the model response", - "meta": { - "billed_units": { - "output_tokens": 10, - "input_tokens": 20, - } - }, + client = Client(api_key="z") + HTTPXClient.request = mock.Mock( + return_value=httpx.Response( + 200, + json={ + "text": "the model response", + "meta": { + "billed_units": { + "output_tokens": 10, + "input_tokens": 20, + } }, - ) + }, ) + ) - with start_transaction(name="cohere tx"): - client.chat( - model="some-model", - chat_history=[ChatMessage(role="SYSTEM", message="some context")], - message="hello", - ).text - - (event,) = events + client.chat( + model="some-model", + chat_history=[ChatMessage(role="SYSTEM", message="some context")], + message="hello", + ).text - assert event["contexts"]["trace"]["origin"] == "manual" - assert event["spans"][0]["origin"] == "auto.ai.cohere" + sentry_sdk.flush() + (span,) = (item.payload for item in items) + assert span["attributes"]["sentry.origin"] == "auto.ai.cohere" -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_span_origin_embed(sentry_init, capture_events, capture_items, span_streaming): +def test_span_origin_embed(sentry_init, capture_items): sentry_init( integrations=[CohereIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") - - client = Client(api_key="z") - HTTPXClient.request = mock.Mock( - return_value=httpx.Response( - 200, - json={ - "response_type": "embeddings_floats", - "id": "1", - "texts": ["hello"], - "embeddings": [[1.0, 2.0, 3.0]], - "meta": { - "billed_units": { - "input_tokens": 10, - } - }, - }, - ) - ) - - with start_transaction(name="cohere tx"): - client.embed(texts=["hello"], model="text-embedding-3-large") + items = capture_items("span") - sentry_sdk.flush() - (span,) = (item.payload for item in items) - assert span["attributes"]["sentry.origin"] == "auto.ai.cohere" - else: - events = capture_events() - - client = Client(api_key="z") - HTTPXClient.request = mock.Mock( - return_value=httpx.Response( - 200, - json={ - "response_type": "embeddings_floats", - "id": "1", - "texts": ["hello"], - "embeddings": [[1.0, 2.0, 3.0]], - "meta": { - "billed_units": { - "input_tokens": 10, - } - }, + client = Client(api_key="z") + HTTPXClient.request = mock.Mock( + return_value=httpx.Response( + 200, + json={ + "response_type": "embeddings_floats", + "id": "1", + "texts": ["hello"], + "embeddings": [[1.0, 2.0, 3.0]], + "meta": { + "billed_units": { + "input_tokens": 10, + } }, - ) + }, ) + ) - with start_transaction(name="cohere tx"): - client.embed(texts=["hello"], model="text-embedding-3-large") - - (event,) = events + client.embed(texts=["hello"], model="text-embedding-3-large") - assert event["contexts"]["trace"]["origin"] == "manual" - assert event["spans"][0]["origin"] == "auto.ai.cohere" + sentry_sdk.flush() + (span,) = (item.payload for item in items) + assert span["attributes"]["sentry.origin"] == "auto.ai.cohere" -# data_collection config, send_default_pii, include_prompts, expect_inputs, expect_outputs +# data_collection config, send_default_pii, expect_inputs, expect_outputs DATA_COLLECTION_CASES = [ pytest.param( {"gen_ai": {"inputs": True, "outputs": True}}, False, - False, True, True, id="gen-ai-inputs-and-outputs-enabled-override-legacy-off", @@ -556,7 +335,6 @@ def test_span_origin_embed(sentry_init, capture_events, capture_items, span_stre pytest.param( {"gen_ai": {"inputs": False, "outputs": False}}, True, - True, False, False, id="gen-ai-inputs-and-outputs-disabled-override-legacy-on", @@ -564,7 +342,6 @@ def test_span_origin_embed(sentry_init, capture_events, capture_items, span_stre pytest.param( {"gen_ai": {"inputs": True, "outputs": False}}, False, - False, True, False, id="gen-ai-inputs-enabled-outputs-disabled", @@ -573,14 +350,12 @@ def test_span_origin_embed(sentry_init, capture_events, capture_items, span_stre {"gen_ai": {"inputs": False, "outputs": True}}, False, False, - False, True, id="gen-ai-outputs-enabled-inputs-disabled", ), pytest.param( {"gen_ai": {}}, False, - False, True, True, id="gen-ai-inputs-and-outputs-omitted-default-to-enabled", @@ -590,13 +365,11 @@ def test_span_origin_embed(sentry_init, capture_events, capture_items, span_stre True, True, True, - True, - id="no-gen-ai-config-legacy-pii-and-include-prompts-enabled", + id="no-gen-ai-config-legacy-pii", ), pytest.param( None, False, - True, False, False, id="no-gen-ai-config-legacy-pii-disabled", @@ -605,13 +378,14 @@ def test_span_origin_embed(sentry_init, capture_events, capture_items, span_stre def _init_with_data_collection( - sentry_init, data_collection, send_default_pii, include_prompts, span_streaming + sentry_init, + data_collection, + send_default_pii, ): kwargs = dict( - integrations=[CohereIntegration(include_prompts=include_prompts)], + integrations=[CohereIntegration()], traces_sample_rate=1.0, send_default_pii=send_default_pii, - trace_lifecycle="stream" if span_streaming else "static", ) if data_collection is not None: kwargs["data_collection"] = data_collection @@ -619,24 +393,22 @@ def _init_with_data_collection( sentry_init(**kwargs) -@pytest.mark.parametrize("span_streaming", [True, False]) @pytest.mark.parametrize( - "data_collection, send_default_pii, include_prompts, expect_inputs, expect_outputs", + "data_collection, send_default_pii, expect_inputs, expect_outputs", DATA_COLLECTION_CASES, ) def test_nonstreaming_chat_data_collection( sentry_init, - capture_events, capture_items, data_collection, send_default_pii, - include_prompts, expect_inputs, expect_outputs, - span_streaming, ): _init_with_data_collection( - sentry_init, data_collection, send_default_pii, include_prompts, span_streaming + sentry_init, + data_collection, + send_default_pii, ) client = Client(api_key="z") @@ -663,26 +435,17 @@ def test_nonstreaming_chat_data_collection( }, ) ) + items = capture_items("span") - if span_streaming: - items = capture_items("span") - else: - events = capture_events() - - with start_transaction(name="cohere tx"): - client.chat( - model="some-model", - chat_history=[ChatMessage(role="SYSTEM", message="some context")], - message="hello", - preamble="be concise", - ) - - if span_streaming: - sentry_sdk.flush() - assert len(items) == 1 - attributes = items[0].payload["attributes"] - else: - attributes = events[0]["spans"][0]["data"] + client.chat( + model="some-model", + chat_history=[ChatMessage(role="SYSTEM", message="some context")], + message="hello", + preamble="be concise", + ) + sentry_sdk.flush() + assert len(items) == 1 + attributes = items[0].payload["attributes"] assert attributes[SPANDATA.AI_MODEL_ID] == "some-model" assert attributes["gen_ai.usage.input_tokens"] == 20 @@ -706,24 +469,22 @@ def test_nonstreaming_chat_data_collection( assert "ai.citations" not in attributes -@pytest.mark.parametrize("span_streaming", [True, False]) @pytest.mark.parametrize( - "data_collection, send_default_pii, include_prompts, expect_inputs, expect_outputs", + "data_collection, send_default_pii, expect_inputs, expect_outputs", DATA_COLLECTION_CASES, ) def test_streaming_chat_data_collection( sentry_init, - capture_events, capture_items, data_collection, send_default_pii, - include_prompts, expect_inputs, expect_outputs, - span_streaming, ): _init_with_data_collection( - sentry_init, data_collection, send_default_pii, include_prompts, span_streaming + sentry_init, + data_collection, + send_default_pii, ) client = Client(api_key="z") @@ -762,28 +523,19 @@ def test_streaming_chat_data_collection( ), ) ) + items = capture_items("span") - if span_streaming: - items = capture_items("span") - else: - events = capture_events() - - with start_transaction(name="cohere tx"): - list( - client.chat_stream( - model="some-model", - chat_history=[ChatMessage(role="SYSTEM", message="some context")], - message="hello", - preamble="be concise", - ) + list( + client.chat_stream( + model="some-model", + chat_history=[ChatMessage(role="SYSTEM", message="some context")], + message="hello", + preamble="be concise", ) - - if span_streaming: - sentry_sdk.flush() - assert len(items) == 1 - attributes = items[0].payload["attributes"] - else: - attributes = events[0]["spans"][0]["data"] + ) + sentry_sdk.flush() + assert len(items) == 1 + attributes = items[0].payload["attributes"] assert attributes[SPANDATA.AI_MODEL_ID] == "some-model" assert attributes["gen_ai.usage.input_tokens"] == 20 @@ -806,24 +558,22 @@ def test_streaming_chat_data_collection( assert "ai.citations" not in attributes -@pytest.mark.parametrize("span_streaming", [True, False]) @pytest.mark.parametrize( - "data_collection, send_default_pii, include_prompts, expect_inputs, expect_outputs", + "data_collection, send_default_pii, expect_inputs, expect_outputs", DATA_COLLECTION_CASES, ) def test_embed_data_collection( sentry_init, - capture_events, capture_items, data_collection, send_default_pii, - include_prompts, expect_inputs, expect_outputs, - span_streaming, ): _init_with_data_collection( - sentry_init, data_collection, send_default_pii, include_prompts, span_streaming + sentry_init, + data_collection, + send_default_pii, ) client = Client(api_key="z") @@ -843,21 +593,12 @@ def test_embed_data_collection( }, ) ) + items = capture_items("span") - if span_streaming: - items = capture_items("span") - else: - events = capture_events() - - with start_transaction(name="cohere tx"): - client.embed(texts=["hello"], model="text-embedding-3-large") - - if span_streaming: - sentry_sdk.flush() - assert len(items) == 1 - attributes = items[0].payload["attributes"] - else: - attributes = events[0]["spans"][0]["data"] + client.embed(texts=["hello"], model="text-embedding-3-large") + sentry_sdk.flush() + assert len(items) == 1 + attributes = items[0].payload["attributes"] assert attributes[SPANDATA.AI_MODEL_ID] == "text-embedding-3-large" assert attributes["gen_ai.usage.input_tokens"] == 10 diff --git a/tests/integrations/conftest.py b/tests/integrations/conftest.py index 70a4b498d7..d97ba3265f 100644 --- a/tests/integrations/conftest.py +++ b/tests/integrations/conftest.py @@ -7,28 +7,16 @@ def capture_exceptions(monkeypatch): def inner(): errors = set() - old_capture_event_hub = sentry_sdk.Hub.capture_event - old_capture_event_scope = sentry_sdk.Scope.capture_event + old_capture_event = sentry_sdk.Scope.capture_event - def capture_event_hub(self, event, hint=None, scope=None): - """ - Can be removed when we remove push_scope and the Hub from the SDK. - """ + def capture_event(self, event, hint=None, scope=None): if hint: if "exc_info" in hint: error = hint["exc_info"][1] errors.add(error) - return old_capture_event_hub(self, event, hint=hint, scope=scope) + return old_capture_event(self, event, hint=hint, scope=scope) - def capture_event_scope(self, event, hint=None, scope=None): - if hint: - if "exc_info" in hint: - error = hint["exc_info"][1] - errors.add(error) - return old_capture_event_scope(self, event, hint=hint, scope=scope) - - monkeypatch.setattr(sentry_sdk.Hub, "capture_event", capture_event_hub) - monkeypatch.setattr(sentry_sdk.Scope, "capture_event", capture_event_scope) + monkeypatch.setattr(sentry_sdk.Scope, "capture_event", capture_event) return errors diff --git a/tests/integrations/django/asgi/test_asgi.py b/tests/integrations/django/asgi/test_asgi.py index 42489d690c..e5b6775c99 100644 --- a/tests/integrations/django/asgi/test_asgi.py +++ b/tests/integrations/django/asgi/test_asgi.py @@ -4,7 +4,6 @@ import json import os import sys -from unittest import mock import django import pytest @@ -46,104 +45,58 @@ def make_asgi_application(): @pytest.mark.skipif( django.VERSION < (3, 0), reason="Django ASGI support shipped in 3.0" ) -@pytest.mark.parametrize("span_streaming", [True, False]) async def test_basic( sentry_init, - capture_events, capture_items, application, - span_streaming, ): sentry_init( integrations=[DjangoIntegration()], send_default_pii=True, - trace_lifecycle="stream" if span_streaming else "static", ) import channels # type: ignore[import-not-found] - if span_streaming: - items = capture_items("event") - - if ( - sys.version_info < (3, 9) - and channels.__version__ < "4.0.0" - and django.VERSION >= (3, 0) - and django.VERSION < (4, 0) - ): - # We emit a UserWarning for channels 2.x and 3.x on Python 3.8 and older - # because the async support was not really good back then and there is a known issue. - # See the TreadingIntegration for details. - with pytest.warns(UserWarning): - comm = HttpCommunicator(application, "GET", "/view-exc?test=query") - response = await comm.get_response() - await comm.wait() - else: + items = capture_items("event") + + if ( + sys.version_info < (3, 9) + and channels.__version__ < "4.0.0" + and django.VERSION >= (3, 0) + and django.VERSION < (4, 0) + ): + # We emit a UserWarning for channels 2.x and 3.x on Python 3.8 and older + # because the async support was not really good back then and there is a known issue. + # See the TreadingIntegration for details. + with pytest.warns(UserWarning): comm = HttpCommunicator(application, "GET", "/view-exc?test=query") response = await comm.get_response() await comm.wait() + else: + comm = HttpCommunicator(application, "GET", "/view-exc?test=query") + response = await comm.get_response() + await comm.wait() - assert response["status"] == 500 + assert response["status"] == 500 - (event,) = (item.payload for item in items) + (event,) = (item.payload for item in items) - (exception,) = event["exception"]["values"] - assert exception["type"] == "ZeroDivisionError" - - # Test that the ASGI middleware got set up correctly. Right now this needs - # to be installed manually (see myapp/asgi.py) - assert event["transaction"] == "/view-exc" - assert event["request"] == { - "cookies": {}, - "headers": {}, - "method": "GET", - "query_string": "test=query", - "url": "/view-exc", - } - - capture_message("hi") - event = items[-1].payload - else: - events = capture_events() - - if ( - sys.version_info < (3, 9) - and channels.__version__ < "4.0.0" - and django.VERSION >= (3, 0) - and django.VERSION < (4, 0) - ): - # We emit a UserWarning for channels 2.x and 3.x on Python 3.8 and older - # because the async support was not really good back then and there is a known issue. - # See the TreadingIntegration for details. - with pytest.warns(UserWarning): - comm = HttpCommunicator(application, "GET", "/view-exc?test=query") - response = await comm.get_response() - await comm.wait() - else: - comm = HttpCommunicator(application, "GET", "/view-exc?test=query") - response = await comm.get_response() - await comm.wait() + (exception,) = event["exception"]["values"] + assert exception["type"] == "ZeroDivisionError" - assert response["status"] == 500 + # Test that the ASGI middleware got set up correctly. Right now this needs + # to be installed manually (see myapp/asgi.py) + assert event["transaction"] == "/view-exc" + assert event["request"] == { + "cookies": {}, + "headers": {}, + "method": "GET", + "query_string": "test=query", + "url": "/view-exc", + } - (event,) = events - - (exception,) = event["exception"]["values"] - assert exception["type"] == "ZeroDivisionError" - - # Test that the ASGI middleware got set up correctly. Right now this needs - # to be installed manually (see myapp/asgi.py) - assert event["transaction"] == "/view-exc" - assert event["request"] == { - "cookies": {}, - "headers": {}, - "method": "GET", - "query_string": "test=query", - "url": "/view-exc", - } - - capture_message("hi") - event = events[-1] + capture_message("hi") + event = items[-1].payload assert "request" not in event @@ -153,39 +106,25 @@ async def test_basic( @pytest.mark.skipif( django.VERSION < (3, 1), reason="async views have been introduced in Django 3.1" ) -@pytest.mark.parametrize("span_streaming", [True, False]) async def test_async_views( sentry_init, - capture_events, capture_items, application, - span_streaming, ): sentry_init( integrations=[DjangoIntegration()], send_default_pii=True, - trace_lifecycle="stream" if span_streaming else "static", ) comm = HttpCommunicator(application, "GET", "/async_message") - if span_streaming: - items = capture_items("event") - - response = await comm.get_response() - await comm.wait() - - assert response["status"] == 200 - - (event,) = (item.payload for item in items) - else: - events = capture_events() + items = capture_items("event") - response = await comm.get_response() - await comm.wait() + response = await comm.get_response() + await comm.wait() - assert response["status"] == 200 + assert response["status"] == 200 - (event,) = events + (event,) = (item.payload for item in items) assert event["transaction"] == "/async_message" assert event["request"] == { @@ -210,7 +149,6 @@ async def test_http_route( sentry_init( integrations=[DjangoIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", ) items = capture_items("span") @@ -224,85 +162,6 @@ async def test_http_route( assert segment["attributes"][SPANDATA.HTTP_ROUTE] == "/async_message" -@pytest.mark.parametrize("application", APPS) -@pytest.mark.parametrize("endpoint", ["/sync/thread_ids", "/async/thread_ids"]) -@pytest.mark.parametrize("middleware_spans", [False, True]) -@pytest.mark.asyncio -@pytest.mark.skipif( - django.VERSION < (3, 1), reason="async views have been introduced in Django 3.1" -) -@pytest.mark.parametrize("span_streaming", [True, False]) -async def test_active_thread_id( - sentry_init, - capture_envelopes, - capture_items, - teardown_profiling, - endpoint, - application, - middleware_spans, - span_streaming, -): - sentry_init( - integrations=[DjangoIntegration(middleware_spans=middleware_spans)], - traces_sample_rate=1.0, - profiles_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", - ) - - comm = HttpCommunicator(application, "GET", endpoint) - - if span_streaming: - with mock.patch( - "sentry_sdk.profiler.transaction_profiler.PROFILE_MINIMUM_SAMPLES", 0 - ): - items = capture_items("span") - response = await comm.get_response() - await comm.wait() - - assert response["status"] == 200, response["body"] - - data = json.loads(response["body"]) - - sentry_sdk.flush() - spans = [item.payload for item in items] - - for span in spans: - if span["is_segment"] is False: - continue - assert str(data["active"]) == span["attributes"]["thread.id"] - else: - with mock.patch( - "sentry_sdk.profiler.transaction_profiler.PROFILE_MINIMUM_SAMPLES", 0 - ): - envelopes = capture_envelopes() - response = await comm.get_response() - await comm.wait() - - assert response["status"] == 200, response["body"] - - assert len(envelopes) == 1 - - profiles = [item for item in envelopes[0].items if item.type == "profile"] - assert len(profiles) == 1 - - data = json.loads(response["body"]) - - for item in profiles: - transactions = item.payload.json["transactions"] - assert len(transactions) == 1 - assert str(data["active"]) == transactions[0]["active_thread_id"] - - transactions = [ - item for item in envelopes[0].items if item.type == "transaction" - ] - assert len(transactions) == 1 - - for item in transactions: - transaction = item.payload.json - trace_context = transaction["contexts"]["trace"] - assert str(data["active"]) == trace_context["data"]["thread.id"] - - @pytest.mark.asyncio @pytest.mark.skipif( django.VERSION < (3, 1), reason="async views have been introduced in Django 3.1" @@ -385,14 +244,11 @@ async def test_async_middleware_that_is_function_concurrent_execution( @pytest.mark.skipif( django.VERSION < (3, 1), reason="async views have been introduced in Django 3.1" ) -@pytest.mark.parametrize("span_streaming", [True, False]) async def test_async_middleware_spans( sentry_init, render_span_tree, - capture_events, capture_items, settings, - span_streaming, make_asgi_application, ): settings.MIDDLEWARE = [ @@ -404,7 +260,6 @@ async def test_async_middleware_spans( sentry_init( integrations=[DjangoIntegration(middleware_spans=True)], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", _experiments={ "record_sql_params": True, }, @@ -413,24 +268,23 @@ async def test_async_middleware_spans( application = make_asgi_application() comm = HttpCommunicator(application, "GET", "/simple_async_view") - if span_streaming: - items = capture_items("span") + items = capture_items("span") - response = await comm.get_response() - await comm.wait() + response = await comm.get_response() + await comm.wait() - assert response["status"] == 200 + assert response["status"] == 200 - sentry_sdk.flush() - spans = [item.payload for item in items] + sentry_sdk.flush() + spans = [item.payload for item in items] - # Filter out signal-receiver spans — their ordering depends on Django - # module import order and is not what this middleware test verifies. - spans = [s for s in spans if s["attributes"].get("sentry.op") != "event.django"] + # Filter out signal-receiver spans — their ordering depends on Django + # module import order and is not what this middleware test verifies. + spans = [s for s in spans if s["attributes"].get("sentry.op") != "event.django"] - assert ( - render_span_tree(spans) - == """\ + assert ( + render_span_tree(spans) + == """\ - sentry.op="http.server": name="/simple_async_view" - sentry.op="middleware.django": name="django.contrib.sessions.middleware.SessionMiddleware.__acall__" - sentry.op="middleware.django": name="django.contrib.auth.middleware.AuthenticationMiddleware.__acall__" @@ -438,131 +292,70 @@ async def test_async_middleware_spans( - sentry.op="middleware.django": name="tests.integrations.django.myapp.settings.TestMiddleware.__acall__" - sentry.op="middleware.django": name="django.middleware.csrf.CsrfViewMiddleware.process_view" - sentry.op="view.render": name="simple_async_view\"""" - ) - else: - events = capture_events() - - response = await comm.get_response() - await comm.wait() - - assert response["status"] == 200 - - (transaction,) = events - - assert transaction["type"] == "transaction" - - # Filter out signal-receiver spans — their ordering depends on Django - # module import order and is not what this middleware test verifies. - spans = [s for s in transaction["spans"] if s.get("op") != "event.django"] - - assert ( - render_span_tree(spans, transaction["contexts"]["trace"]) - == """\ -- op="http.server": description=null - - op="middleware.django": description="django.contrib.sessions.middleware.SessionMiddleware.__acall__" - - op="middleware.django": description="django.contrib.auth.middleware.AuthenticationMiddleware.__acall__" - - op="middleware.django": description="django.middleware.csrf.CsrfViewMiddleware.__acall__" - - op="middleware.django": description="tests.integrations.django.myapp.settings.TestMiddleware.__acall__" - - op="middleware.django": description="django.middleware.csrf.CsrfViewMiddleware.process_view" - - op="view.render": description="simple_async_view\"""" - ) + ) @pytest.mark.asyncio @pytest.mark.skipif( django.VERSION < (3, 1), reason="async views have been introduced in Django 3.1" ) -@pytest.mark.parametrize("span_streaming", [True, False]) async def test_has_trace_if_performance_enabled( sentry_init, - capture_events, capture_items, - span_streaming, ): sentry_init( integrations=[DjangoIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) comm = HttpCommunicator(asgi_application, "GET", "/view-exc-with-msg") - if span_streaming: - items = capture_items("event", "span") + items = capture_items("event", "span") - response = await comm.get_response() - await comm.wait() - - assert response["status"] == 500 - - ( - msg_event, - error_event, - ) = (item.payload for item in items if item.type == "event") - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert spans[6]["is_segment"] is True - - assert ( - msg_event["contexts"]["trace"]["trace_id"] - == error_event["contexts"]["trace"]["trace_id"] - == spans[6]["trace_id"] - ) - else: - events = capture_events() + response = await comm.get_response() + await comm.wait() - response = await comm.get_response() - await comm.wait() + assert response["status"] == 500 - assert response["status"] == 500 + ( + msg_event, + error_event, + ) = (item.payload for item in items if item.type == "event") - (msg_event, error_event, transaction_event) = events + sentry_sdk.flush() + spans = [item.payload for item in items if item.type == "span"] + assert spans[6]["is_segment"] is True - assert ( - msg_event["contexts"]["trace"]["trace_id"] - == error_event["contexts"]["trace"]["trace_id"] - == transaction_event["contexts"]["trace"]["trace_id"] - ) + assert ( + msg_event["contexts"]["trace"]["trace_id"] + == error_event["contexts"]["trace"]["trace_id"] + == spans[6]["trace_id"] + ) @pytest.mark.asyncio @pytest.mark.skipif( django.VERSION < (3, 1), reason="async views have been introduced in Django 3.1" ) -@pytest.mark.parametrize("span_streaming", [True, False]) async def test_has_trace_if_performance_disabled( sentry_init, - capture_events, capture_items, - span_streaming, ): sentry_init( integrations=[DjangoIntegration()], - trace_lifecycle="stream" if span_streaming else "static", ) comm = HttpCommunicator(asgi_application, "GET", "/view-exc-with-msg") - if span_streaming: - items = capture_items("event") - - response = await comm.get_response() - await comm.wait() - - assert response["status"] == 500 - - ( - msg_event, - error_event, - ) = (item.payload for item in items) - else: - events = capture_events() + items = capture_items("event") - response = await comm.get_response() - await comm.wait() + response = await comm.get_response() + await comm.wait() - assert response["status"] == 500 + assert response["status"] == 500 - (msg_event, error_event) = events + ( + msg_event, + error_event, + ) = (item.payload for item in items) assert msg_event["contexts"]["trace"] assert "trace_id" in msg_event["contexts"]["trace"] @@ -579,17 +372,13 @@ async def test_has_trace_if_performance_disabled( @pytest.mark.skipif( django.VERSION < (3, 1), reason="async views have been introduced in Django 3.1" ) -@pytest.mark.parametrize("span_streaming", [True, False]) async def test_trace_from_headers_if_performance_enabled( sentry_init, - capture_events, capture_items, - span_streaming, ): sentry_init( integrations=[DjangoIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) trace_id = "582b43a4192642f0b136d5159a501701" @@ -602,55 +391,37 @@ async def test_trace_from_headers_if_performance_enabled( headers=[(b"sentry-trace", sentry_trace_header.encode())], ) - if span_streaming: - items = capture_items("event", "span") - - response = await comm.get_response() - await comm.wait() - - assert response["status"] == 500 - - ( - msg_event, - error_event, - ) = (item.payload for item in items if item.type == "event") - - assert msg_event["contexts"]["trace"]["trace_id"] == trace_id - assert error_event["contexts"]["trace"]["trace_id"] == trace_id + items = capture_items("event", "span") - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert spans[6]["is_segment"] is True - assert spans[6]["trace_id"] == trace_id - else: - events = capture_events() + response = await comm.get_response() + await comm.wait() - response = await comm.get_response() - await comm.wait() + assert response["status"] == 500 - assert response["status"] == 500 + ( + msg_event, + error_event, + ) = (item.payload for item in items if item.type == "event") - (msg_event, error_event, transaction_event) = events + assert msg_event["contexts"]["trace"]["trace_id"] == trace_id + assert error_event["contexts"]["trace"]["trace_id"] == trace_id - assert msg_event["contexts"]["trace"]["trace_id"] == trace_id - assert error_event["contexts"]["trace"]["trace_id"] == trace_id - assert transaction_event["contexts"]["trace"]["trace_id"] == trace_id + sentry_sdk.flush() + spans = [item.payload for item in items if item.type == "span"] + assert spans[6]["is_segment"] is True + assert spans[6]["trace_id"] == trace_id @pytest.mark.asyncio @pytest.mark.skipif( django.VERSION < (3, 1), reason="async views have been introduced in Django 3.1" ) -@pytest.mark.parametrize("span_streaming", [True, False]) async def test_trace_from_headers_if_performance_disabled( sentry_init, - capture_events, capture_items, - span_streaming, ): sentry_init( integrations=[DjangoIntegration()], - trace_lifecycle="stream" if span_streaming else "static", ) trace_id = "582b43a4192642f0b136d5159a501701" @@ -663,24 +434,14 @@ async def test_trace_from_headers_if_performance_disabled( headers=[(b"sentry-trace", sentry_trace_header.encode())], ) - if span_streaming: - items = capture_items("event") - - response = await comm.get_response() - await comm.wait() - - assert response["status"] == 500 - - (msg_event, error_event) = (item.payload for item in items) - else: - events = capture_events() + items = capture_items("event") - response = await comm.get_response() - await comm.wait() + response = await comm.get_response() + await comm.wait() - assert response["status"] == 500 + assert response["status"] == 500 - (msg_event, error_event) = events + (msg_event, error_event) = (item.payload for item in items) assert msg_event["contexts"]["trace"]["trace_id"] == trace_id assert error_event["contexts"]["trace"]["trace_id"] == trace_id @@ -789,10 +550,8 @@ async def test_trace_from_headers_if_performance_disabled( @pytest.mark.skipif( django.VERSION < (3, 1), reason="async views have been introduced in Django 3.1" ) -@pytest.mark.parametrize("span_streaming", [True, False]) -async def test_asgi_request_body( +async def test_asgi_request_body_send_default_pii( sentry_init, - capture_envelopes, capture_items, application, send_default_pii, @@ -801,12 +560,10 @@ async def test_asgi_request_body( url_name, body, expected_data, - span_streaming, ): sentry_init( integrations=[DjangoIntegration()], send_default_pii=send_default_pii, - trace_lifecycle="stream" if span_streaming else "static", ) comm = HttpCommunicator( @@ -817,28 +574,17 @@ async def test_asgi_request_body( body=body, ) - if span_streaming: - items = capture_items("event") - - response = await comm.get_response() - await comm.wait() - - assert response["status"] == 200 - assert response["body"] == body + items = capture_items("event") - sentry_sdk.flush() - (event,) = (item.payload for item in items) - else: - envelopes = capture_envelopes() + response = await comm.get_response() + await comm.wait() - response = await comm.get_response() - await comm.wait() + assert response["status"] == 200 + assert response["body"] == body - assert response["status"] == 200 - assert response["body"] == body + sentry_sdk.flush() - (envelope,) = envelopes - event = envelope.get_event() + (event,) = [item.payload for item in items] if expected_data is not None: assert event["request"]["data"] == expected_data @@ -936,39 +682,6 @@ async def test_asgi_request_body_dropped_with_form_and_files_data_collection( assert "data" not in event.get("_meta", {}).get("request", {}) -@pytest.mark.parametrize("application", APPS) -@pytest.mark.asyncio -@pytest.mark.skipif( - django.VERSION < (3, 1), reason="async views have been introduced in Django 3.1" -) -async def test_asgi_transaction_request_body_data_collection( - sentry_init, capture_events, application -): - sentry_init( - integrations=[DjangoIntegration()], - traces_sample_rate=1.0, - data_collection={"http_bodies": []}, - ) - events = capture_events() - - comm = HttpCommunicator( - application, - method="POST", - headers=[(b"content-type", b"application/json")], - path=reverse("post_echo_async"), - body=json.dumps({"hey": 42}).encode("utf-8"), - ) - response = await comm.get_response() - await comm.wait() - - assert response["status"] == 200 - - (event, transaction_event) = events - - assert "data" not in event["request"] - assert "data" not in transaction_event["request"] - - @pytest.mark.parametrize("application", APPS) @pytest.mark.asyncio @pytest.mark.skipif( @@ -1076,39 +789,25 @@ def get_response(): ... @pytest.mark.skipif( django.VERSION < (3, 1), reason="async views have been introduced in Django 3.1" ) -@pytest.mark.parametrize("span_streaming", [True, False]) async def test_async_view( sentry_init, - capture_events, capture_items, application, - span_streaming, ): sentry_init( integrations=[DjangoIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) comm = HttpCommunicator(application, "GET", "/simple_async_view") - if span_streaming: - items = capture_items("span") - - await comm.get_response() - await comm.wait() - - sentry_sdk.flush() - spans = [item.payload for item in items] - assert spans[5]["name"] == "/simple_async_view" - else: - events = capture_events() + items = capture_items("span") - await comm.get_response() - await comm.wait() + await comm.get_response() + await comm.wait() - (event,) = events - assert event["type"] == "transaction" - assert event["transaction"] == "/simple_async_view" + sentry_sdk.flush() + spans = [item.payload for item in items] + assert spans[5]["name"] == "/simple_async_view" @pytest.mark.parametrize("application", APPS) @@ -1116,13 +815,10 @@ async def test_async_view( @pytest.mark.skipif( django.VERSION < (3, 0), reason="Django ASGI support shipped in 3.0" ) -@pytest.mark.parametrize("span_streaming", [True, False]) async def test_transaction_http_method_default( sentry_init, - capture_events, capture_items, application, - span_streaming, ): """ By default OPTIONS and HEAD requests do not create a transaction. @@ -1130,45 +826,24 @@ async def test_transaction_http_method_default( sentry_init( integrations=[DjangoIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") - - comm = HttpCommunicator(application, "GET", "/simple_async_view") - await comm.get_response() - await comm.wait() - - comm = HttpCommunicator(application, "OPTIONS", "/simple_async_view") - await comm.get_response() - await comm.wait() - - comm = HttpCommunicator(application, "HEAD", "/simple_async_view") - await comm.get_response() - await comm.wait() - - sentry_sdk.flush() - spans = [item.payload for item in items] - assert spans[5]["attributes"]["http.request.method"] == "GET" - else: - events = capture_events() - - comm = HttpCommunicator(application, "GET", "/simple_async_view") - await comm.get_response() - await comm.wait() + items = capture_items("span") - comm = HttpCommunicator(application, "OPTIONS", "/simple_async_view") - await comm.get_response() - await comm.wait() + comm = HttpCommunicator(application, "GET", "/simple_async_view") + await comm.get_response() + await comm.wait() - comm = HttpCommunicator(application, "HEAD", "/simple_async_view") - await comm.get_response() - await comm.wait() + comm = HttpCommunicator(application, "OPTIONS", "/simple_async_view") + await comm.get_response() + await comm.wait() - (event,) = events + comm = HttpCommunicator(application, "HEAD", "/simple_async_view") + await comm.get_response() + await comm.wait() - assert len(events) == 1 - assert event["request"]["method"] == "GET" + sentry_sdk.flush() + spans = [item.payload for item in items] + assert spans[5]["attributes"]["http.request.method"] == "GET" @pytest.mark.parametrize("application", APPS) @@ -1176,13 +851,10 @@ async def test_transaction_http_method_default( @pytest.mark.skipif( django.VERSION < (3, 0), reason="Django ASGI support shipped in 3.0" ) -@pytest.mark.parametrize("span_streaming", [True, False]) async def test_transaction_http_method_custom( sentry_init, - capture_events, capture_items, application, - span_streaming, ): sentry_init( integrations=[ @@ -1194,48 +866,26 @@ async def test_transaction_http_method_custom( ) ], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") - - comm = HttpCommunicator(application, "GET", "/simple_async_view") - await comm.get_response() - await comm.wait() - - comm = HttpCommunicator(application, "OPTIONS", "/simple_async_view") - await comm.get_response() - await comm.wait() - - comm = HttpCommunicator(application, "HEAD", "/simple_async_view") - await comm.get_response() - await comm.wait() - - sentry_sdk.flush() - spans = [item.payload for item in items] - - assert spans[5]["attributes"][SPANDATA.HTTP_REQUEST_METHOD] == "OPTIONS" - assert spans[11]["attributes"][SPANDATA.HTTP_REQUEST_METHOD] == "HEAD" - else: - events = capture_events() + items = capture_items("span") - comm = HttpCommunicator(application, "GET", "/simple_async_view") - await comm.get_response() - await comm.wait() + comm = HttpCommunicator(application, "GET", "/simple_async_view") + await comm.get_response() + await comm.wait() - comm = HttpCommunicator(application, "OPTIONS", "/simple_async_view") - await comm.get_response() - await comm.wait() + comm = HttpCommunicator(application, "OPTIONS", "/simple_async_view") + await comm.get_response() + await comm.wait() - comm = HttpCommunicator(application, "HEAD", "/simple_async_view") - await comm.get_response() - await comm.wait() + comm = HttpCommunicator(application, "HEAD", "/simple_async_view") + await comm.get_response() + await comm.wait() - assert len(events) == 2 + sentry_sdk.flush() + spans = [item.payload for item in items] - (event1, event2) = events - assert event1["request"]["method"] == "OPTIONS" - assert event2["request"]["method"] == "HEAD" + assert spans[5]["attributes"][SPANDATA.HTTP_REQUEST_METHOD] == "OPTIONS" + assert spans[11]["attributes"][SPANDATA.HTTP_REQUEST_METHOD] == "HEAD" @pytest.mark.asyncio diff --git a/tests/integrations/django/test_basic.py b/tests/integrations/django/test_basic.py index 59afe9be6b..8572031f38 100644 --- a/tests/integrations/django/test_basic.py +++ b/tests/integrations/django/test_basic.py @@ -34,7 +34,7 @@ from sentry_sdk.integrations.django.signals_handlers import _get_receiver_name from sentry_sdk.integrations.executing import ExecutingIntegration from sentry_sdk.profiler.utils import get_frame_name -from sentry_sdk.tracing import Span +from sentry_sdk.traces import Span from tests.conftest import unpack_werkzeug_response from tests.integrations.django.myapp.signals import myapp_custom_signal_silenced from tests.integrations.django.myapp.wsgi import application @@ -133,18 +133,14 @@ def test_middleware_exceptions(sentry_init, client, capture_exceptions): assert isinstance(error, ZeroDivisionError) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_request_captured( sentry_init, client, - capture_events, capture_items, - span_streaming, ): sentry_init( integrations=[DjangoIntegration()], send_default_pii=True, - trace_lifecycle="stream" if span_streaming else "static", ) items = capture_items("event") content, status, headers = unpack_werkzeug_response(client.get(reverse("message"))) @@ -164,49 +160,32 @@ def test_request_captured( } -@pytest.mark.parametrize("span_streaming", [True, False]) def test_transaction_with_class_view( sentry_init, client, - capture_events, capture_items, - span_streaming, ): sentry_init( integrations=[DjangoIntegration(transaction_style="function_name")], send_default_pii=True, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("event") - content, status, headers = unpack_werkzeug_response( - client.head(reverse("classbased")) - ) - assert status.lower() == "200 ok" - - (event,) = (item.payload for item in items) - else: - events = capture_events() - content, status, headers = unpack_werkzeug_response( - client.head(reverse("classbased")) - ) - assert status.lower() == "200 ok" - - (event,) = events + items = capture_items("event") + content, status, headers = unpack_werkzeug_response( + client.head(reverse("classbased")) + ) + assert status.lower() == "200 ok" + (event,) = (item.payload for item in items) assert ( event["transaction"] == "tests.integrations.django.myapp.views.ClassBasedView" ) assert event["message"] == "hi" -@pytest.mark.parametrize("span_streaming", [True, False]) def test_has_trace_if_performance_enabled( sentry_init, client, - capture_events, capture_items, - span_streaming, ): sentry_init( integrations=[ @@ -215,80 +194,48 @@ def test_has_trace_if_performance_enabled( ) ], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("event", "span") - client.head(reverse("view_exc_with_msg")) - - ( - msg_event, - error_event, - ) = (item.payload for item in items if item.type == "event") - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert spans[3]["is_segment"] is True - assert "trace_id" in spans[3] - - assert msg_event["contexts"]["trace"] - assert "trace_id" in msg_event["contexts"]["trace"] - - assert error_event["contexts"]["trace"] - assert "trace_id" in error_event["contexts"]["trace"] - - assert ( - msg_event["contexts"]["trace"]["trace_id"] - == error_event["contexts"]["trace"]["trace_id"] - == spans[3]["trace_id"] - ) - else: - events = capture_events() - client.head(reverse("view_exc_with_msg")) + items = capture_items("event", "span") + client.head(reverse("view_exc_with_msg")) - (msg_event, error_event, transaction_event) = events + ( + msg_event, + error_event, + ) = (item.payload for item in items if item.type == "event") - assert transaction_event["contexts"]["trace"] - assert "trace_id" in transaction_event["contexts"]["trace"] + sentry_sdk.flush() + spans = [item.payload for item in items if item.type == "span"] + assert spans[3]["is_segment"] is True + assert "trace_id" in spans[3] - assert msg_event["contexts"]["trace"] - assert "trace_id" in msg_event["contexts"]["trace"] + assert msg_event["contexts"]["trace"] + assert "trace_id" in msg_event["contexts"]["trace"] - assert error_event["contexts"]["trace"] - assert "trace_id" in error_event["contexts"]["trace"] + assert error_event["contexts"]["trace"] + assert "trace_id" in error_event["contexts"]["trace"] - assert ( - msg_event["contexts"]["trace"]["trace_id"] - == error_event["contexts"]["trace"]["trace_id"] - == transaction_event["contexts"]["trace"]["trace_id"] - ) + assert ( + msg_event["contexts"]["trace"]["trace_id"] + == error_event["contexts"]["trace"]["trace_id"] + == spans[3]["trace_id"] + ) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_has_trace_if_performance_disabled( sentry_init, client, - capture_events, capture_items, - span_streaming, ): sentry_init( integrations=[DjangoIntegration()], - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("event") - client.head(reverse("view_exc_with_msg")) - - ( - msg_event, - error_event, - ) = (item.payload for item in items) - else: - events = capture_events() - client.head(reverse("view_exc_with_msg")) + items = capture_items("event") + client.head(reverse("view_exc_with_msg")) - (msg_event, error_event) = events + ( + msg_event, + error_event, + ) = (item.payload for item in items) assert msg_event["contexts"]["trace"] assert "trace_id" in msg_event["contexts"]["trace"] @@ -302,13 +249,10 @@ def test_has_trace_if_performance_disabled( ) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_trace_from_headers_if_performance_enabled( sentry_init, client, - capture_events, capture_items, - span_streaming, ): sentry_init( integrations=[ @@ -317,66 +261,41 @@ def test_trace_from_headers_if_performance_enabled( ) ], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) trace_id = "582b43a4192642f0b136d5159a501701" sentry_trace_header = "{}-{}-{}".format(trace_id, "6e8f22c393e68f19", 1) - if span_streaming: - items = capture_items("event", "span") - client.head( - reverse("view_exc_with_msg"), headers={"sentry-trace": sentry_trace_header} - ) - - ( - msg_event, - error_event, - ) = (item.payload for item in items if item.type == "event") - - assert msg_event["contexts"]["trace"] - assert "trace_id" in msg_event["contexts"]["trace"] - - assert error_event["contexts"]["trace"] - assert "trace_id" in error_event["contexts"]["trace"] - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert spans[3]["is_segment"] is True - assert "trace_id" in spans[3] - - assert msg_event["contexts"]["trace"]["trace_id"] == trace_id - assert error_event["contexts"]["trace"]["trace_id"] == trace_id - assert spans[3]["trace_id"] == trace_id - else: - events = capture_events() - client.head( - reverse("view_exc_with_msg"), headers={"sentry-trace": sentry_trace_header} - ) + items = capture_items("event", "span") + client.head( + reverse("view_exc_with_msg"), headers={"sentry-trace": sentry_trace_header} + ) - (msg_event, error_event, transaction_event) = events + ( + msg_event, + error_event, + ) = (item.payload for item in items if item.type == "event") - assert msg_event["contexts"]["trace"] - assert "trace_id" in msg_event["contexts"]["trace"] + assert msg_event["contexts"]["trace"] + assert "trace_id" in msg_event["contexts"]["trace"] - assert error_event["contexts"]["trace"] - assert "trace_id" in error_event["contexts"]["trace"] + assert error_event["contexts"]["trace"] + assert "trace_id" in error_event["contexts"]["trace"] - assert transaction_event["contexts"]["trace"] - assert "trace_id" in transaction_event["contexts"]["trace"] + sentry_sdk.flush() + spans = [item.payload for item in items if item.type == "span"] + assert spans[3]["is_segment"] is True + assert "trace_id" in spans[3] - assert msg_event["contexts"]["trace"]["trace_id"] == trace_id - assert error_event["contexts"]["trace"]["trace_id"] == trace_id - assert transaction_event["contexts"]["trace"]["trace_id"] == trace_id + assert msg_event["contexts"]["trace"]["trace_id"] == trace_id + assert error_event["contexts"]["trace"]["trace_id"] == trace_id + assert spans[3]["trace_id"] == trace_id -@pytest.mark.parametrize("span_streaming", [True, False]) def test_trace_from_headers_if_performance_disabled( sentry_init, client, - capture_events, capture_items, - span_streaming, ): sentry_init( integrations=[ @@ -384,29 +303,20 @@ def test_trace_from_headers_if_performance_disabled( http_methods_to_capture=("HEAD",), ) ], - trace_lifecycle="stream" if span_streaming else "static", ) trace_id = "582b43a4192642f0b136d5159a501701" sentry_trace_header = "{}-{}-{}".format(trace_id, "6e8f22c393e68f19", 1) - if span_streaming: - items = capture_items("event") - client.head( - reverse("view_exc_with_msg"), headers={"sentry-trace": sentry_trace_header} - ) - - ( - msg_event, - error_event, - ) = (item.payload for item in items) - else: - events = capture_events() - client.head( - reverse("view_exc_with_msg"), headers={"sentry-trace": sentry_trace_header} - ) + items = capture_items("event") + client.head( + reverse("view_exc_with_msg"), headers={"sentry-trace": sentry_trace_header} + ) - (msg_event, error_event) = events + ( + msg_event, + error_event, + ) = (item.payload for item in items) assert msg_event["contexts"]["trace"] assert "trace_id" in msg_event["contexts"]["trace"] @@ -420,50 +330,26 @@ def test_trace_from_headers_if_performance_disabled( @pytest.mark.forked @pytest_mark_django_db_decorator() -@pytest.mark.parametrize("span_streaming", [True, False]) def test_user_captured( sentry_init, client, - capture_events, capture_items, - span_streaming, ): sentry_init( integrations=[DjangoIntegration()], send_default_pii=True, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("event") - content, status, headers = unpack_werkzeug_response( - client.get(reverse("mylogin")) - ) - assert content == b"ok" - - sentry_sdk.flush() - assert not items - - content, status, headers = unpack_werkzeug_response( - client.get(reverse("message")) - ) - assert content == b"ok" - - (event,) = (item.payload for item in items) - else: - events = capture_events() - content, status, headers = unpack_werkzeug_response( - client.get(reverse("mylogin")) - ) - assert content == b"ok" + items = capture_items("event") + content, status, headers = unpack_werkzeug_response(client.get(reverse("mylogin"))) + assert content == b"ok" - assert not events + sentry_sdk.flush() + assert not items - content, status, headers = unpack_werkzeug_response( - client.get(reverse("message")) - ) - assert content == b"ok" + content, status, headers = unpack_werkzeug_response(client.get(reverse("message"))) + assert content == b"ok" - (event,) = events + (event,) = (item.payload for item in items) assert event["user"] == { "email": "lennon@thebeatles.com", @@ -483,7 +369,6 @@ def test_materialized_user_captured( integrations=[DjangoIntegration()], send_default_pii=True, traces_sample_rate=1.0, - trace_lifecycle="stream", ) content, status, headers = unpack_werkzeug_response(client.get(reverse("mylogin"))) @@ -680,47 +565,31 @@ def test_sql_dict_query_params( @pytest.mark.forked -@pytest.mark.parametrize("span_streaming", [True, False]) def test_response_trace( sentry_init, client, - capture_events, capture_items, render_span_tree, - span_streaming, ): pytest.importorskip("rest_framework") sentry_init( integrations=[DjangoIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") - content, status, headers = unpack_werkzeug_response( - client.get(reverse("rest_json_response")) - ) - assert status == "200 OK" - - sentry_sdk.flush() - spans = [item.payload for item in items] + items = capture_items("span") + content, status, headers = unpack_werkzeug_response( + client.get(reverse("rest_json_response")) + ) + assert status == "200 OK" - assert ( - '- sentry.op="view.response.render": name="serialize response"' - in render_span_tree(spans) - ) - else: - events = capture_events() - content, status, headers = unpack_werkzeug_response( - client.get(reverse("rest_json_response")) - ) - assert status == "200 OK" + sentry_sdk.flush() + spans = [item.payload for item in items] - assert ( - '- op="view.response.render": description="serialize response"' - in render_span_tree(events[0]["spans"], events[0]["contexts"]["trace"]) - ) + assert ( + '- sentry.op="view.response.render": name="serialize response"' + in render_span_tree(spans) + ) @pytest.mark.parametrize( @@ -839,14 +708,11 @@ def test_sql_psycopg2_placeholders( @pytest.mark.forked @pytest_mark_django_db_decorator(transaction=True) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_django_connect_trace( sentry_init, client, - capture_events, capture_items, render_span_tree, - span_streaming, ): """ Verify we record a span when opening a new database. @@ -855,7 +721,6 @@ def test_django_connect_trace( integrations=[DjangoIntegration()], send_default_pii=True, traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) from django.db import connections @@ -866,41 +731,22 @@ def test_django_connect_trace( # trigger Django to open a new connection by marking the existing one as None. connections["postgres"].connection = None - if span_streaming: - items = capture_items("span") - - content, status, headers = unpack_werkzeug_response( - client.get(reverse("postgres_select")) - ) - assert status == "200 OK" - - sentry_sdk.flush() - spans = [item.payload for item in items] - - for span in spans: - if span["attributes"].get("sentry.op") == "db": - attributes = span.get("attributes") - assert attributes.get(SPANDATA.DB_SYSTEM_NAME) == "postgresql" - - assert '- sentry.op="db": name="connect"' in render_span_tree(spans) - else: - events = capture_events() + items = capture_items("span") - content, status, headers = unpack_werkzeug_response( - client.get(reverse("postgres_select")) - ) - assert status == "200 OK" + content, status, headers = unpack_werkzeug_response( + client.get(reverse("postgres_select")) + ) + assert status == "200 OK" - (event,) = events + sentry_sdk.flush() + spans = [item.payload for item in items] - for span in event["spans"]: - if span.get("op") == "db": - data = span.get("data") - assert data.get(SPANDATA.DB_SYSTEM) == "postgresql" + for span in spans: + if span["attributes"].get("sentry.op") == "db": + attributes = span.get("attributes") + assert attributes.get(SPANDATA.DB_SYSTEM_NAME) == "postgresql" - assert '- op="db": description="connect"' in render_span_tree( - event["spans"], event["contexts"]["trace"] - ) + assert '- sentry.op="db": name="connect"' in render_span_tree(spans) @pytest.mark.forked @@ -945,19 +791,15 @@ def test_django_connect_breadcrumbs( @pytest.mark.forked @pytest_mark_django_db_decorator(transaction=True) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_db_connection_span_data( sentry_init, client, - capture_events, capture_items, - span_streaming, ): sentry_init( integrations=[DjangoIntegration()], send_default_pii=True, traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) from django.db import connections @@ -968,57 +810,32 @@ def test_db_connection_span_data( # trigger Django to open a new connection by marking the existing one as None. connections["postgres"].connection = None - if span_streaming: - items = capture_items("span") + items = capture_items("span") - content, status, headers = unpack_werkzeug_response( - client.get(reverse("postgres_select")) - ) - assert status == "200 OK" + content, status, headers = unpack_werkzeug_response( + client.get(reverse("postgres_select")) + ) + assert status == "200 OK" - sentry_sdk.flush() - spans = [item.payload for item in items] + sentry_sdk.flush() - for span in spans: - if span["attributes"].get("sentry.op") == "db": - attributes = span.get("attributes") - assert attributes.get(SPANDATA.DB_SYSTEM_NAME) == "postgresql" - conn_params = connections["postgres"].get_connection_params() - assert attributes.get(SPANDATA.DB_NAMESPACE) is not None - assert attributes.get(SPANDATA.DB_NAMESPACE) == conn_params.get( - "database" - ) or conn_params.get("dbname") - assert attributes.get(SPANDATA.SERVER_ADDRESS) == os.environ.get( - "SENTRY_PYTHON_TEST_POSTGRES_HOST", "localhost" - ) - assert attributes.get(SPANDATA.SERVER_PORT) == os.environ.get( - "SENTRY_PYTHON_TEST_POSTGRES_PORT", "5432" - ) - else: - events = capture_events() + spans = [item.payload for item in items] - content, status, headers = unpack_werkzeug_response( - client.get(reverse("postgres_select")) - ) - assert status == "200 OK" - - (event,) = events - - for span in event["spans"]: - if span.get("op") == "db": - data = span.get("data") - assert data.get(SPANDATA.DB_SYSTEM) == "postgresql" - conn_params = connections["postgres"].get_connection_params() - assert data.get(SPANDATA.DB_NAME) is not None - assert data.get(SPANDATA.DB_NAME) == conn_params.get( - "database" - ) or conn_params.get("dbname") - assert data.get(SPANDATA.SERVER_ADDRESS) == os.environ.get( - "SENTRY_PYTHON_TEST_POSTGRES_HOST", "localhost" - ) - assert data.get(SPANDATA.SERVER_PORT) == os.environ.get( - "SENTRY_PYTHON_TEST_POSTGRES_PORT", "5432" - ) + for span in spans: + if span["attributes"].get("sentry.op") == "db": + attributes = span.get("attributes") + assert attributes.get(SPANDATA.DB_SYSTEM_NAME) == "postgresql" + conn_params = connections["postgres"].get_connection_params() + assert attributes.get(SPANDATA.DB_NAMESPACE) is not None + assert attributes.get(SPANDATA.DB_NAMESPACE) == conn_params.get( + "database" + ) or conn_params.get("dbname") + assert attributes.get(SPANDATA.SERVER_ADDRESS) == os.environ.get( + "SENTRY_PYTHON_TEST_POSTGRES_HOST", "localhost" + ) + assert attributes.get(SPANDATA.SERVER_PORT) == os.environ.get( + "SENTRY_PYTHON_TEST_POSTGRES_PORT", "5432" + ) def test_set_db_data_custom_backend(): @@ -1034,7 +851,7 @@ def get_connection_params(self): return {} try: - _set_db_data(Span(), DummyBackend()) + _set_db_data(Span(name="name", scope=sentry_sdk.Scope()), DummyBackend()) except TypeError: pytest.fail("A TypeError was raised") @@ -1053,47 +870,33 @@ def get_connection_params(self): ("url", "/404", "/404", "url", b"404"), ], ) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_transaction_style( sentry_init, client, - capture_events, capture_items, transaction_style, client_url, expected_transaction, expected_source, expected_response, - span_streaming, ): sentry_init( integrations=[DjangoIntegration(transaction_style=transaction_style)], traces_sample_rate=1.0, send_default_pii=True, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("event", "span") + items = capture_items("event", "span") - content, status, headers = unpack_werkzeug_response(client.get(client_url)) - assert content == expected_response + content, status, headers = unpack_werkzeug_response(client.get(client_url)) + assert content == expected_response - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - - assert spans[2]["is_segment"] is True - assert spans[2]["attributes"]["sentry.segment.name.source"] == expected_source - - (event,) = (item.payload for item in items if item.type == "event") - else: - events = capture_events() + sentry_sdk.flush() + spans = [item.payload for item in items if item.type == "span"] - content, status, headers = unpack_werkzeug_response(client.get(client_url)) - assert content == expected_response + assert spans[2]["is_segment"] is True + assert spans[2]["attributes"]["sentry.segment.name.source"] == expected_source - (event, transaction) = events - assert transaction["transaction"] == expected_transaction - assert transaction["transaction_info"] == {"source": expected_source} + (event,) = (item.payload for item in items if item.type == "event") assert event["transaction"] == expected_transaction @@ -1112,38 +915,26 @@ def test_transaction_style( ("url", "/404", "/404", "url", b"404"), ], ) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_transaction_style_tracing_disabled( sentry_init, client, - capture_events, capture_items, transaction_style, client_url, expected_transaction, expected_source, expected_response, - span_streaming, ): sentry_init( integrations=[DjangoIntegration(transaction_style=transaction_style)], send_default_pii=True, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("event") - - content, status, headers = unpack_werkzeug_response(client.get(client_url)) - assert content == expected_response - - (event,) = (item.payload for item in items if item.type == "event") - else: - events = capture_events() + items = capture_items("event") - content, status, headers = unpack_werkzeug_response(client.get(client_url)) - assert content == expected_response + content, status, headers = unpack_werkzeug_response(client.get(client_url)) + assert content == expected_response - (event,) = events + (event,) = (item.payload for item in items if item.type == "event") assert event["transaction"] == expected_transaction @@ -1156,7 +947,6 @@ def test_http_route( sentry_init( integrations=[DjangoIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", ) items = capture_items("span") @@ -1168,12 +958,10 @@ def test_http_route( assert segment["attributes"][SPANDATA.HTTP_ROUTE] == "/message" -@pytest.mark.parametrize("span_streaming", [True, False]) def test_request_body( sentry_init, client, capture_items, - span_streaming, ): sentry_init( integrations=[DjangoIntegration()], @@ -1282,29 +1070,6 @@ def test_request_body_dropped_with_form_and_files_data_collection( assert "data" not in event.get("_meta", {}).get("request", {}) -def test_transaction_request_body_data_collection(sentry_init, client, capture_events): - sentry_init( - integrations=[DjangoIntegration()], - traces_sample_rate=1.0, - data_collection={"http_bodies": []}, - ) - events = capture_events() - - content, status, headers = unpack_werkzeug_response( - client.post( - reverse("post_echo"), - data=json.dumps({"hey": 42}).encode("utf-8"), - content_type="application/json", - ) - ) - assert status.lower() == "200 ok" - - event, transaction_event = events - - assert "data" not in event["request"] - assert "data" not in transaction_event["request"] - - def test_oversized_request_body_not_annotated_data_collection( sentry_init, client, capture_items ): @@ -1334,12 +1099,10 @@ def test_oversized_request_body_not_annotated_data_collection( assert "data" not in event.get("_meta", {}).get("request", {}) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_read_request( sentry_init, client, capture_items, - span_streaming, ): sentry_init( integrations=[DjangoIntegration()], @@ -1389,17 +1152,13 @@ def raw_data(self): assert "data" not in event["request"] -@pytest.mark.parametrize("span_streaming", [True, False]) def test_template_tracing_meta( sentry_init, client, - capture_events, capture_items, - span_streaming, ): sentry_init( integrations=[DjangoIntegration()], - trace_lifecycle="stream" if span_streaming else "static", ) items = capture_items("event") @@ -1490,58 +1249,36 @@ def test_template_exception( ["application/x-www-form-urlencoded", {"foo": "bar"}], ], ) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_rest_framework_basic( sentry_init, client, - capture_events, capture_items, capture_exceptions, ct, body, route, - span_streaming, ): pytest.importorskip("rest_framework") sentry_init( integrations=[DjangoIntegration()], send_default_pii=True, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - exceptions = capture_exceptions() - items = capture_items("event") - - if ct == "application/json": - client.post( - reverse(route), data=json.dumps(body), content_type="application/json" - ) - elif ct == "application/x-www-form-urlencoded": - client.post(reverse(route), data=body) - else: - raise AssertionError("unreachable") - - (error,) = exceptions - assert isinstance(error, ZeroDivisionError) + exceptions = capture_exceptions() + items = capture_items("event") - (event,) = (item.payload for item in items) + if ct == "application/json": + client.post( + reverse(route), data=json.dumps(body), content_type="application/json" + ) + elif ct == "application/x-www-form-urlencoded": + client.post(reverse(route), data=body) else: - exceptions = capture_exceptions() - events = capture_events() - - if ct == "application/json": - client.post( - reverse(route), data=json.dumps(body), content_type="application/json" - ) - elif ct == "application/x-www-form-urlencoded": - client.post(reverse(route), data=body) - else: - raise AssertionError("unreachable") + raise AssertionError("unreachable") - (error,) = exceptions - assert isinstance(error, ZeroDivisionError) + (error,) = exceptions + assert isinstance(error, ZeroDivisionError) - (event,) = events + (event,) = (item.payload for item in items) assert event["exception"]["values"][0]["mechanism"]["type"] == "django" @@ -1549,14 +1286,11 @@ def test_rest_framework_basic( assert event["request"]["headers"]["Content-Type"] == ct -@pytest.mark.parametrize("span_streaming", [True, False]) def test_rest_framework_authentication_span( sentry_init, client, - capture_events, capture_items, render_span_tree, - span_streaming, ): pytest.importorskip("rest_framework") sentry_init( @@ -1564,46 +1298,27 @@ def test_rest_framework_authentication_span( DjangoIntegration(middleware_spans=False, signals_spans=False), ], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") + items = capture_items("span") - client.get(reverse("rest_authenticated_hello")) + client.get(reverse("rest_authenticated_hello")) - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] + sentry_sdk.flush() + spans = [item.payload for item in items if item.type == "span"] - assert ( - render_span_tree(spans) - == """\ + assert ( + render_span_tree(spans) + == """\ - sentry.op="http.server": name="/rest-authenticated-hello" - sentry.op="view.authenticate": name="authenticate"\ """ - ) - else: - events = capture_events() - - client.get(reverse("rest_authenticated_hello")) - - (transaction,) = events - - assert ( - render_span_tree(transaction["spans"], transaction["contexts"]["trace"]) - == """\ -- op="http.server": description=null - - op="view.authenticate": description="authenticate"\ -""" - ) + ) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_rest_framework_authentication_span_without_authenticators( sentry_init, client, - capture_events, capture_items, - span_streaming, ): pytest.importorskip("rest_framework") sentry_init( @@ -1611,49 +1326,35 @@ def test_rest_framework_authentication_span_without_authenticators( DjangoIntegration(middleware_spans=False, signals_spans=False), ], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") - - client.get(reverse("rest_unauthenticated_hello")) - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - - # only the root span - assert len(spans) == 1 - else: - events = capture_events() + items = capture_items("span") - client.get(reverse("rest_unauthenticated_hello")) + client.get(reverse("rest_unauthenticated_hello")) - (transaction,) = events + sentry_sdk.flush() + spans = [item.payload for item in items if item.type == "span"] - assert transaction["spans"] == [] + # only the root span + assert len(spans) == 1 @pytest.mark.parametrize( "endpoint", ["rest_permission_denied_exc", "permission_denied_exc"] ) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_does_not_capture_403( sentry_init, client, - capture_events, capture_items, endpoint, - span_streaming, ): if endpoint == "rest_permission_denied_exc": pytest.importorskip("rest_framework") sentry_init( integrations=[DjangoIntegration()], - trace_lifecycle="stream" if span_streaming else "static", ) - items = capture_items("event", "transaction", "span") + items = capture_items("event", "span") _, status, _ = unpack_werkzeug_response(client.get(reverse(endpoint))) assert status.lower() == "403 forbidden" @@ -1751,67 +1452,42 @@ def test_failed_request_status_codes_unhandled_exception( assert exception["mechanism"]["handled"] is False -@pytest.mark.parametrize("span_streaming", [True, False]) def test_render_spans( sentry_init, client, - capture_events, capture_items, render_span_tree, - span_streaming, ): sentry_init( integrations=[DjangoIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - views_tests = [ - ( - reverse("template_test2"), - '- sentry.op="template.render": name="[user_name.html, ...]"', - ), - ] - if DJANGO_VERSION >= (1, 7): - views_tests.append( - ( - reverse("template_test"), - '- sentry.op="template.render": name="user_name.html"', - ), - ) - - for url, expected_line in views_tests: - items = capture_items("span") - client.get(url) - sentry_sdk.flush() - spans = [item.payload for item in items] - assert expected_line in render_span_tree(spans) - else: - views_tests = [ + views_tests = [ + ( + reverse("template_test2"), + '- sentry.op="template.render": name="[user_name.html, ...]"', + ), + ] + if DJANGO_VERSION >= (1, 7): + views_tests.append( ( - reverse("template_test2"), - '- op="template.render": description="[user_name.html, ...]"', + reverse("template_test"), + '- sentry.op="template.render": name="user_name.html"', ), - ] - if DJANGO_VERSION >= (1, 7): - views_tests.append( - ( - reverse("template_test"), - '- op="template.render": description="user_name.html"', - ), - ) + ) - for url, expected_line in views_tests: - events = capture_events() - client.get(url) - transaction = events[0] - assert expected_line in render_span_tree( - transaction["spans"], transaction["contexts"]["trace"] - ) + for url, expected_line in views_tests: + items = capture_items("span") + client.get(url) + sentry_sdk.flush() + spans = [item.payload for item in items] + assert expected_line in render_span_tree(spans) -@pytest.mark.skipif(DJANGO_VERSION < (1, 9), reason="Requires Django >= 1.9") @pytest.mark.forked +@pytest.mark.xfail( + reason="This test needs to be adapted to span streaming once we re-add template context on spans: https://github.com/getsentry/sentry-python/issues/7273" +) @pytest_mark_django_db_decorator() def test_render_spans_queryset_in_data(sentry_init, client, capture_events): sentry_init( @@ -1848,35 +1524,30 @@ def test_render_spans_queryset_in_data(sentry_init, client, capture_events): ) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_middleware_spans( sentry_init, client, - capture_events, capture_items, render_span_tree, - span_streaming, ): sentry_init( integrations=[ DjangoIntegration(middleware_spans=True, signals_spans=False), ], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("event", "span") + items = capture_items("event", "span") - client.get(reverse("message")) + client.get(reverse("message")) - (message,) = (item.payload for item in items if item.type == "event") - assert message["message"] == "hi" + (message,) = (item.payload for item in items if item.type == "event") + assert message["message"] == "hi" - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] + sentry_sdk.flush() + spans = [item.payload for item in items if item.type == "span"] - if DJANGO_VERSION >= (1, 10): - EXPECTED_MIDDLEWARE_SPANS = """\ + if DJANGO_VERSION >= (1, 10): + EXPECTED_MIDDLEWARE_SPANS = """\ - sentry.op="http.server": name="/message" - sentry.op="middleware.django": name="django.contrib.sessions.middleware.SessionMiddleware.__call__" - sentry.op="middleware.django": name="django.contrib.auth.middleware.AuthenticationMiddleware.__call__" @@ -1886,8 +1557,8 @@ def test_middleware_spans( - sentry.op="middleware.django": name="django.middleware.csrf.CsrfViewMiddleware.process_view" - sentry.op="view.render": name="message"\ """ - else: - EXPECTED_MIDDLEWARE_SPANS = """\ + else: + EXPECTED_MIDDLEWARE_SPANS = """\ - sentry.op="http.server": name="/message" - sentry.op="middleware.django": name="django.contrib.sessions.middleware.SessionMiddleware.process_request" - sentry.op="middleware.django": name="django.contrib.auth.middleware.AuthenticationMiddleware.process_request" @@ -1898,196 +1569,101 @@ def test_middleware_spans( - sentry.op="middleware.django": name="django.middleware.csrf.CsrfViewMiddleware.process_response" - sentry.op="middleware.django": name="django.contrib.sessions.middleware.SessionMiddleware.process_response"\ """ - assert render_span_tree(spans) == EXPECTED_MIDDLEWARE_SPANS - else: - events = capture_events() - - client.get(reverse("message")) - - message, transaction = events - - assert message["message"] == "hi" - if DJANGO_VERSION >= (1, 10): - EXPECTED_MIDDLEWARE_SPANS = """\ -- op="http.server": description=null - - op="middleware.django": description="django.contrib.sessions.middleware.SessionMiddleware.__call__" - - op="middleware.django": description="django.contrib.auth.middleware.AuthenticationMiddleware.__call__" - - op="middleware.django": description="django.middleware.csrf.CsrfViewMiddleware.__call__" - - op="middleware.django": description="tests.integrations.django.myapp.settings.TestMiddleware.__call__" - - op="middleware.django": description="tests.integrations.django.myapp.settings.TestFunctionMiddleware.__call__" - - op="middleware.django": description="django.middleware.csrf.CsrfViewMiddleware.process_view" - - op="view.render": description="message"\ -""" - else: - EXPECTED_MIDDLEWARE_SPANS = """\ -- op="http.server": description=null - - op="middleware.django": description="django.contrib.sessions.middleware.SessionMiddleware.process_request" - - op="middleware.django": description="django.contrib.auth.middleware.AuthenticationMiddleware.process_request" - - op="middleware.django": description="tests.integrations.django.myapp.settings.TestMiddleware.process_request" - - op="middleware.django": description="django.middleware.csrf.CsrfViewMiddleware.process_view" - - op="view.render": description="message" - - op="middleware.django": description="tests.integrations.django.myapp.settings.TestMiddleware.process_response" - - op="middleware.django": description="django.middleware.csrf.CsrfViewMiddleware.process_response" - - op="middleware.django": description="django.contrib.sessions.middleware.SessionMiddleware.process_response"\ -""" - assert ( - render_span_tree(transaction["spans"], transaction["contexts"]["trace"]) - == EXPECTED_MIDDLEWARE_SPANS - ) + assert render_span_tree(spans) == EXPECTED_MIDDLEWARE_SPANS -@pytest.mark.parametrize("span_streaming", [True, False]) def test_middleware_spans_disabled( sentry_init, client, - capture_events, capture_items, - span_streaming, ): sentry_init( integrations=[ DjangoIntegration(signals_spans=False), ], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("event", "span") + items = capture_items("event", "span") - client.get(reverse("message")) - - (message,) = (item.payload for item in items if item.type == "event") - - assert message["message"] == "hi" - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert len(spans) == 1 - else: - events = capture_events() + client.get(reverse("message")) - client.get(reverse("message")) + (message,) = (item.payload for item in items if item.type == "event") - message, transaction = events + assert message["message"] == "hi" - assert message["message"] == "hi" - assert not len(transaction["spans"]) + sentry_sdk.flush() + spans = [item.payload for item in items if item.type == "span"] + assert len(spans) == 1 -@pytest.mark.parametrize("span_streaming", [True, False]) def test_signals_spans( sentry_init, client, - capture_events, capture_items, render_span_tree, - span_streaming, ): sentry_init( integrations=[ DjangoIntegration(middleware_spans=False), ], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("event", "span") + items = capture_items("event", "span") - client.get(reverse("message")) + client.get(reverse("message")) - (message,) = (item.payload for item in items if item.type == "event") + (message,) = (item.payload for item in items if item.type == "event") - assert message["message"] == "hi" + assert message["message"] == "hi" - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert ( - render_span_tree(spans) - == """\ + sentry_sdk.flush() + spans = [item.payload for item in items if item.type == "span"] + assert ( + render_span_tree(spans) + == """\ - sentry.op="http.server": name="/message" - sentry.op="event.django": name="django.db.reset_queries" - sentry.op="event.django": name="django.db.close_old_connections"\ """ - ) - - assert spans[0]["attributes"]["sentry.op"] == "event.django" - assert spans[0]["name"] == "django.db.reset_queries" - - assert spans[1]["attributes"]["sentry.op"] == "event.django" - assert spans[1]["name"] == "django.db.close_old_connections" - else: - events = capture_events() - - client.get(reverse("message")) - - message, transaction = events - - assert message["message"] == "hi" - assert ( - render_span_tree(transaction["spans"], transaction["contexts"]["trace"]) - == """\ -- op="http.server": description=null - - op="event.django": description="django.db.reset_queries" - - op="event.django": description="django.db.close_old_connections"\ -""" - ) + ) - assert transaction["spans"][0]["op"] == "event.django" - assert transaction["spans"][0]["description"] == "django.db.reset_queries" + assert spans[0]["attributes"]["sentry.op"] == "event.django" + assert spans[0]["name"] == "django.db.reset_queries" - assert transaction["spans"][1]["op"] == "event.django" - assert ( - transaction["spans"][1]["description"] == "django.db.close_old_connections" - ) + assert spans[1]["attributes"]["sentry.op"] == "event.django" + assert spans[1]["name"] == "django.db.close_old_connections" -@pytest.mark.parametrize("span_streaming", [True, False]) def test_signals_spans_disabled( sentry_init, client, - capture_events, capture_items, - span_streaming, ): sentry_init( integrations=[ DjangoIntegration(middleware_spans=False, signals_spans=False), ], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("event", "span") + items = capture_items("event", "span") - client.get(reverse("message")) + client.get(reverse("message")) - sentry_sdk.flush() - (message,) = (item.payload for item in items if item.type == "event") - - assert message["message"] == "hi" - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert len(spans) == 1 - else: - events = capture_events() - - client.get(reverse("message")) + sentry_sdk.flush() + (message,) = (item.payload for item in items if item.type == "event") - message, transaction = events + assert message["message"] == "hi" - assert message["message"] == "hi" - assert not transaction["spans"] + sentry_sdk.flush() + spans = [item.payload for item in items if item.type == "span"] + assert len(spans) == 1 -@pytest.mark.parametrize("span_streaming", [True, False]) def test_signals_spans_filtering( sentry_init, client, - capture_events, capture_items, render_span_tree, - span_streaming, ): sentry_init( integrations=[ @@ -2099,65 +1675,31 @@ def test_signals_spans_filtering( ), ], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") + items = capture_items("span") - client.get(reverse("send_myapp_custom_signal")) + client.get(reverse("send_myapp_custom_signal")) - sentry_sdk.flush() - spans = [item.payload for item in items] - assert ( - render_span_tree(spans) - == """\ + sentry_sdk.flush() + spans = [item.payload for item in items] + assert ( + render_span_tree(spans) + == """\ - sentry.op="http.server": name="/send-myapp-custom-signal" - sentry.op="event.django": name="django.db.reset_queries" - sentry.op="event.django": name="django.db.close_old_connections" - sentry.op="event.django": name="tests.integrations.django.myapp.signals.signal_handler"\ """ - ) - - assert spans[0]["attributes"]["sentry.op"] == "event.django" - assert spans[0]["name"] == "django.db.reset_queries" - - assert spans[1]["attributes"]["sentry.op"] == "event.django" - assert spans[1]["name"] == "django.db.close_old_connections" - - assert spans[2]["attributes"]["sentry.op"] == "event.django" - assert ( - spans[2]["name"] == "tests.integrations.django.myapp.signals.signal_handler" - ) - else: - events = capture_events() - - client.get(reverse("send_myapp_custom_signal")) - - (transaction,) = events - - assert ( - render_span_tree(transaction["spans"], transaction["contexts"]["trace"]) - == """\ -- op="http.server": description=null - - op="event.django": description="django.db.reset_queries" - - op="event.django": description="django.db.close_old_connections" - - op="event.django": description="tests.integrations.django.myapp.signals.signal_handler"\ -""" - ) + ) - assert transaction["spans"][0]["op"] == "event.django" - assert transaction["spans"][0]["description"] == "django.db.reset_queries" + assert spans[0]["attributes"]["sentry.op"] == "event.django" + assert spans[0]["name"] == "django.db.reset_queries" - assert transaction["spans"][1]["op"] == "event.django" - assert ( - transaction["spans"][1]["description"] == "django.db.close_old_connections" - ) + assert spans[1]["attributes"]["sentry.op"] == "event.django" + assert spans[1]["name"] == "django.db.close_old_connections" - assert transaction["spans"][2]["op"] == "event.django" - assert ( - transaction["spans"][2]["description"] - == "tests.integrations.django.myapp.signals.signal_handler" - ) + assert spans[2]["attributes"]["sentry.op"] == "event.django" + assert spans[2]["name"] == "tests.integrations.django.myapp.signals.signal_handler" def test_csrf(sentry_init, client): @@ -2197,18 +1739,14 @@ def test_csrf(sentry_init, client): assert content == b"ok" -@pytest.mark.skipif(DJANGO_VERSION < (2, 0), reason="Requires Django > 2.0") @pytest.mark.parametrize("middleware_spans", [False, True]) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_custom_urlconf_middleware( settings, sentry_init, client, - capture_events, capture_items, render_span_tree, middleware_spans, - span_streaming, ): """ Some middlewares (for instance in django-tenants) overwrite request.urlconf. @@ -2222,85 +1760,42 @@ def test_custom_urlconf_middleware( sentry_init( integrations=[DjangoIntegration(middleware_spans=middleware_spans)], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("event", "span") + items = capture_items("event", "span") - try: - content, status, _headers = unpack_werkzeug_response( - client.get("/custom/ok") - ) - assert status.lower() == "200 ok" - assert content == b"custom ok" - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] + try: + content, status, _headers = unpack_werkzeug_response(client.get("/custom/ok")) + assert status.lower() == "200 ok" + assert content == b"custom ok" - if middleware_spans: - assert spans[10]["name"] == "/custom/ok" - assert "custom_urlconf_middleware" in render_span_tree(spans) - else: - assert spans[2]["name"] == "/custom/ok" + sentry_sdk.flush() + spans = [item.payload for item in items if item.type == "span"] - _content, status, _headers = unpack_werkzeug_response( - client.get("/custom/exc") - ) - assert status.lower() == "500 internal server error" + if middleware_spans: + assert spans[10]["name"] == "/custom/ok" + assert "custom_urlconf_middleware" in render_span_tree(spans) + else: + assert spans[2]["name"] == "/custom/ok" - (error_event,) = (item.payload for item in items if item.type == "event") - assert error_event["transaction"] == "/custom/exc" - assert ( - error_event["exception"]["values"][-1]["mechanism"]["type"] == "django" - ) + _content, status, _headers = unpack_werkzeug_response(client.get("/custom/exc")) + assert status.lower() == "500 internal server error" - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - - if middleware_spans: - assert spans[22]["name"] == "/custom/exc" - assert "custom_urlconf_middleware" in render_span_tree(spans) - else: - assert spans[6]["name"] == "/custom/exc" - finally: - settings.MIDDLEWARE.pop(0) - client.application.load_middleware() - else: - events = capture_events() + (error_event,) = (item.payload for item in items if item.type == "event") + assert error_event["transaction"] == "/custom/exc" + assert error_event["exception"]["values"][-1]["mechanism"]["type"] == "django" - try: - content, status, _headers = unpack_werkzeug_response( - client.get("/custom/ok") - ) - assert status.lower() == "200 ok" - assert content == b"custom ok" - - event = events.pop(0) - assert event["transaction"] == "/custom/ok" - if middleware_spans: - assert "custom_urlconf_middleware" in render_span_tree( - event["spans"], event["contexts"]["trace"] - ) - - _content, status, _headers = unpack_werkzeug_response( - client.get("/custom/exc") - ) - assert status.lower() == "500 internal server error" + sentry_sdk.flush() + spans = [item.payload for item in items if item.type == "span"] - error_event, transaction_event = events - assert error_event["transaction"] == "/custom/exc" - assert ( - error_event["exception"]["values"][-1]["mechanism"]["type"] == "django" - ) - assert transaction_event["transaction"] == "/custom/exc" - if middleware_spans: - assert "custom_urlconf_middleware" in render_span_tree( - transaction_event["spans"], transaction_event["contexts"]["trace"] - ) - finally: - settings.MIDDLEWARE.pop(0) - client.application.load_middleware() + if middleware_spans: + assert spans[22]["name"] == "/custom/exc" + assert "custom_urlconf_middleware" in render_span_tree(spans) + else: + assert spans[6]["name"] == "/custom/exc" + finally: + settings.MIDDLEWARE.pop(0) + client.application.load_middleware() def test_get_receiver_name(): @@ -2322,14 +1817,10 @@ def dummy(a, b): assert name == "partial()" -@pytest.mark.skipif(DJANGO_VERSION <= (1, 11), reason="Requires Django > 1.11") -@pytest.mark.parametrize("span_streaming", [True, False]) def test_span_origin( sentry_init, client, - capture_events, capture_items, - span_streaming, ): sentry_init( integrations=[ @@ -2340,47 +1831,29 @@ def test_span_origin( ) ], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) signal_span_found = False - if span_streaming: - items = capture_items("span") - - client.get(reverse("view_with_signal")) - - sentry_sdk.flush() - spans = [item.payload for item in items] - - assert spans[-1]["attributes"]["sentry.origin"] == "auto.http.django" - - for span in spans: - assert span["attributes"]["sentry.origin"] == "auto.http.django" - if span["attributes"]["sentry.op"] == "event.django": - signal_span_found = True - else: - events = capture_events() + items = capture_items("span") - client.get(reverse("view_with_signal")) + client.get(reverse("view_with_signal")) - (transaction,) = events + sentry_sdk.flush() + spans = [item.payload for item in items] - assert transaction["contexts"]["trace"]["origin"] == "auto.http.django" + assert spans[-1]["attributes"]["sentry.origin"] == "auto.http.django" - for span in transaction["spans"]: - assert span["origin"] == "auto.http.django" - if span["op"] == "event.django": - signal_span_found = True + for span in spans: + assert span["attributes"]["sentry.origin"] == "auto.http.django" + if span["attributes"]["sentry.op"] == "event.django": + signal_span_found = True assert signal_span_found -@pytest.mark.parametrize("span_streaming", [True, False]) def test_transaction_http_method_default( sentry_init, client, - capture_events, capture_items, - span_streaming, ): """ By default OPTIONS and HEAD requests do not create a transaction. @@ -2388,39 +1861,23 @@ def test_transaction_http_method_default( sentry_init( integrations=[DjangoIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") - - client.get("/nomessage") - client.options("/nomessage") - client.head("/nomessage") - - sentry_sdk.flush() - spans = [item.payload for item in items] - - assert spans[2]["attributes"][SPANDATA.HTTP_REQUEST_METHOD] == "GET" - else: - events = capture_events() + items = capture_items("span") - client.get("/nomessage") - client.options("/nomessage") - client.head("/nomessage") + client.get("/nomessage") + client.options("/nomessage") + client.head("/nomessage") - (event,) = events + sentry_sdk.flush() + spans = [item.payload for item in items] - assert len(events) == 1 - assert event["request"]["method"] == "GET" + assert spans[2]["attributes"][SPANDATA.HTTP_REQUEST_METHOD] == "GET" -@pytest.mark.parametrize("span_streaming", [True, False]) def test_transaction_http_method_custom( sentry_init, client, - capture_events, capture_items, - span_streaming, ): sentry_init( integrations=[ @@ -2432,92 +1889,23 @@ def test_transaction_http_method_custom( ) ], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") - - client.get("/nomessage") - client.options("/nomessage") - - sentry_sdk.flush() - spans = [item.payload for item in items] - - assert spans[2]["attributes"][SPANDATA.HTTP_REQUEST_METHOD] == "OPTIONS" - - client.head("/nomessage") - - sentry_sdk.flush() - spans = [item.payload for item in items] - - assert spans[5]["attributes"][SPANDATA.HTTP_REQUEST_METHOD] == "HEAD" - else: - events = capture_events() - - client.get("/nomessage") - client.options("/nomessage") - client.head("/nomessage") - - assert len(events) == 2 - - (event1, event2) = events - assert event1["request"]["method"] == "OPTIONS" - assert event2["request"]["method"] == "HEAD" - - -def test_ensures_spotlight_middleware_when_spotlight_is_enabled(sentry_init, settings): - """ - Test that ensures if Spotlight is enabled, relevant SpotlightMiddleware - is added to middleware list in settings. - """ - settings.DEBUG = True - original_middleware = frozenset(settings.MIDDLEWARE) - - sentry_init(integrations=[DjangoIntegration()], spotlight=True) - - added = frozenset(settings.MIDDLEWARE) ^ original_middleware - - assert "sentry_sdk.spotlight.SpotlightMiddleware" in added - - -def test_ensures_no_spotlight_middleware_when_env_killswitch_is_false( - monkeypatch, sentry_init, settings -): - """ - Test that ensures if Spotlight is enabled, but is set to a falsy value - the relevant SpotlightMiddleware is NOT added to middleware list in settings. - """ - settings.DEBUG = True - monkeypatch.setenv("SENTRY_SPOTLIGHT_ON_ERROR", "no") - - original_middleware = frozenset(settings.MIDDLEWARE) - - sentry_init(integrations=[DjangoIntegration()], spotlight=True) - - added = frozenset(settings.MIDDLEWARE) ^ original_middleware - - assert "sentry_sdk.spotlight.SpotlightMiddleware" not in added + items = capture_items("span") + client.get("/nomessage") + client.options("/nomessage") -def test_ensures_no_spotlight_middleware_when_no_spotlight( - monkeypatch, sentry_init, settings -): - """ - Test that ensures if Spotlight is not enabled - the relevant SpotlightMiddleware is NOT added to middleware list in settings. - """ - settings.DEBUG = True - - # We should NOT have the middleware even if the env var is truthy if Spotlight is off - monkeypatch.setenv("SENTRY_SPOTLIGHT_ON_ERROR", "1") + sentry_sdk.flush() + spans = [item.payload for item in items] - original_middleware = frozenset(settings.MIDDLEWARE) + assert spans[2]["attributes"][SPANDATA.HTTP_REQUEST_METHOD] == "OPTIONS" - sentry_init(integrations=[DjangoIntegration()], spotlight=False) + client.head("/nomessage") - added = frozenset(settings.MIDDLEWARE) ^ original_middleware + sentry_sdk.flush() + spans = [item.payload for item in items] - assert "sentry_sdk.spotlight.SpotlightMiddleware" not in added + assert spans[5]["attributes"][SPANDATA.HTTP_REQUEST_METHOD] == "HEAD" def test_get_frame_name_when_in_lazy_object(): diff --git a/tests/integrations/django/test_cache_module.py b/tests/integrations/django/test_cache_module.py index 3766006c9b..dd6c24ee29 100644 --- a/tests/integrations/django/test_cache_module.py +++ b/tests/integrations/django/test_cache_module.py @@ -90,15 +90,11 @@ def use_django_caching_with_cluster(settings): @pytest.mark.forked @pytest_mark_django_db_decorator() -@pytest.mark.skipif(DJANGO_VERSION < (1, 9), reason="Requires Django >= 1.9") -@pytest.mark.parametrize("span_streaming", [True, False]) def test_cache_spans_disabled_middleware( sentry_init, client, - capture_events, capture_items, use_django_caching_with_middlewares, - span_streaming, ): sentry_init( integrations=[ @@ -109,39 +105,24 @@ def test_cache_spans_disabled_middleware( ) ], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") + items = capture_items("span") - client.get(reverse("not_cached_view")) - client.get(reverse("not_cached_view")) + client.get(reverse("not_cached_view")) + client.get(reverse("not_cached_view")) - sentry_sdk.flush() - spans = [item.payload for item in items] - assert len(spans) == 2 - else: - events = capture_events() - - client.get(reverse("not_cached_view")) - client.get(reverse("not_cached_view")) - - (first_event, second_event) = events - assert len(first_event["spans"]) == 0 - assert len(second_event["spans"]) == 0 + sentry_sdk.flush() + spans = [item.payload for item in items] + assert len(spans) == 2 @pytest.mark.forked @pytest_mark_django_db_decorator() -@pytest.mark.skipif(DJANGO_VERSION < (1, 9), reason="Requires Django >= 1.9") -@pytest.mark.parametrize("span_streaming", [True, False]) def test_cache_spans_disabled_decorator( sentry_init, client, - capture_events, capture_items, use_django_caching, - span_streaming, ): sentry_init( integrations=[ @@ -152,39 +133,24 @@ def test_cache_spans_disabled_decorator( ) ], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") - - client.get(reverse("cached_view")) - client.get(reverse("cached_view")) - - sentry_sdk.flush() - spans = [item.payload for item in items] - assert len(spans) == 2 - else: - events = capture_events() + items = capture_items("span") - client.get(reverse("cached_view")) - client.get(reverse("cached_view")) + client.get(reverse("cached_view")) + client.get(reverse("cached_view")) - (first_event, second_event) = events - assert len(first_event["spans"]) == 0 - assert len(second_event["spans"]) == 0 + sentry_sdk.flush() + spans = [item.payload for item in items] + assert len(spans) == 2 @pytest.mark.forked @pytest_mark_django_db_decorator() -@pytest.mark.skipif(DJANGO_VERSION < (1, 9), reason="Requires Django >= 1.9") -@pytest.mark.parametrize("span_streaming", [True, False]) def test_cache_spans_disabled_templatetag( sentry_init, client, - capture_events, capture_items, use_django_caching, - span_streaming, ): sentry_init( integrations=[ @@ -195,39 +161,24 @@ def test_cache_spans_disabled_templatetag( ) ], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") + items = capture_items("span") - client.get(reverse("view_with_cached_template_fragment")) - client.get(reverse("view_with_cached_template_fragment")) + client.get(reverse("view_with_cached_template_fragment")) + client.get(reverse("view_with_cached_template_fragment")) - sentry_sdk.flush() - spans = [item.payload for item in items] - assert len(spans) == 2 - else: - events = capture_events() - - client.get(reverse("view_with_cached_template_fragment")) - client.get(reverse("view_with_cached_template_fragment")) - - (first_event, second_event) = events - assert len(first_event["spans"]) == 0 - assert len(second_event["spans"]) == 0 + sentry_sdk.flush() + spans = [item.payload for item in items] + assert len(spans) == 2 @pytest.mark.forked @pytest_mark_django_db_decorator() -@pytest.mark.skipif(DJANGO_VERSION < (1, 9), reason="Requires Django >= 1.9") -@pytest.mark.parametrize("span_streaming", [True, False]) def test_cache_spans_middleware( sentry_init, client, - capture_events, capture_items, use_django_caching_with_middlewares, - span_streaming, ): sentry_init( integrations=[ @@ -238,122 +189,96 @@ def test_cache_spans_middleware( ) ], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) client.application.load_middleware() - if span_streaming: - items = capture_items("span") - - client.get(reverse("not_cached_view")) - - sentry_sdk.flush() - spans = [item.payload for item in items] - # first_event - cache.get - assert spans[0]["attributes"]["sentry.op"] == "cache.get" - assert spans[0]["name"].startswith("views.decorators.cache.cache_header.") - assert spans[0]["attributes"]["network.peer.address"] is not None - assert spans[0]["attributes"]["cache.key"][0].startswith( - "views.decorators.cache.cache_header." - ) - assert not spans[0]["attributes"]["cache.hit"] - assert "cache.item_size" not in spans[0]["attributes"] - # first_event - cache.put - assert spans[1]["attributes"]["sentry.op"] == "cache.put" - assert spans[1]["name"].startswith("views.decorators.cache.cache_header.") - assert spans[1]["attributes"]["network.peer.address"] is not None - assert spans[1]["attributes"]["cache.key"][0].startswith( - "views.decorators.cache.cache_header." - ) - assert "cache.hit" not in spans[1]["attributes"] - assert spans[1]["attributes"]["cache.item_size"] == 2 - - client.get(reverse("not_cached_view")) - - sentry_sdk.flush() - spans = [item.payload for item in items] - # second_event - cache.get - assert spans[4]["attributes"]["sentry.op"] == "cache.get" - assert spans[4]["name"].startswith("views.decorators.cache.cache_header.") - assert spans[4]["attributes"]["network.peer.address"] is not None - assert spans[4]["attributes"]["cache.key"][0].startswith( - "views.decorators.cache.cache_header." - ) - assert spans[4]["attributes"]["cache.hit"] - assert spans[4]["attributes"]["cache.item_size"] == 2 - # second_event - cache.get 2 - assert spans[5]["attributes"]["sentry.op"] == "cache.get" - assert spans[5]["name"].startswith("views.decorators.cache.cache_page.") - assert spans[5]["attributes"]["network.peer.address"] is not None - assert spans[5]["attributes"]["cache.key"][0].startswith( - "views.decorators.cache.cache_page." - ) - assert spans[5]["attributes"]["cache.hit"] - assert spans[5]["attributes"]["cache.item_size"] == 58 - else: - events = capture_events() - - client.get(reverse("not_cached_view")) - client.get(reverse("not_cached_view")) - - (first_event, second_event) = events - # first_event - cache.get - assert first_event["spans"][0]["op"] == "cache.get" - assert first_event["spans"][0]["description"].startswith( - "views.decorators.cache.cache_header." - ) - assert first_event["spans"][0]["data"]["network.peer.address"] is not None - assert first_event["spans"][0]["data"]["cache.key"][0].startswith( - "views.decorators.cache.cache_header." - ) - assert not first_event["spans"][0]["data"]["cache.hit"] - assert "cache.item_size" not in first_event["spans"][0]["data"] - # first_event - cache.put - assert first_event["spans"][1]["op"] == "cache.put" - assert first_event["spans"][1]["description"].startswith( - "views.decorators.cache.cache_header." - ) - assert first_event["spans"][1]["data"]["network.peer.address"] is not None - assert first_event["spans"][1]["data"]["cache.key"][0].startswith( - "views.decorators.cache.cache_header." - ) - assert "cache.hit" not in first_event["spans"][1]["data"] - assert first_event["spans"][1]["data"]["cache.item_size"] == 2 - # second_event - cache.get - assert second_event["spans"][0]["op"] == "cache.get" - assert second_event["spans"][0]["description"].startswith( - "views.decorators.cache.cache_header." - ) - assert second_event["spans"][0]["data"]["network.peer.address"] is not None - assert second_event["spans"][0]["data"]["cache.key"][0].startswith( - "views.decorators.cache.cache_header." - ) - assert second_event["spans"][0]["data"]["cache.hit"] - assert second_event["spans"][0]["data"]["cache.item_size"] == 2 - # second_event - cache.get 2 - assert second_event["spans"][1]["op"] == "cache.get" - assert second_event["spans"][1]["description"].startswith( - "views.decorators.cache.cache_page." - ) - assert second_event["spans"][1]["data"]["network.peer.address"] is not None - assert second_event["spans"][1]["data"]["cache.key"][0].startswith( - "views.decorators.cache.cache_page." - ) - assert second_event["spans"][1]["data"]["cache.hit"] - assert second_event["spans"][1]["data"]["cache.item_size"] == 58 + items = capture_items("span") + + client.get(reverse("not_cached_view")) + + sentry_sdk.flush() + spans = [item.payload for item in items] + # first_event - cache.get + assert spans[0]["attributes"]["sentry.op"] == "cache.get" + assert spans[0]["name"].startswith("views.decorators.cache.cache_header.") + assert spans[0]["attributes"]["network.peer.address"] is not None + assert spans[0]["attributes"]["cache.key"][0].startswith( + "views.decorators.cache.cache_header." + ) + assert not spans[0]["attributes"]["cache.hit"] + assert "cache.item_size" not in spans[0]["attributes"] + # first_event - cache.put + assert spans[1]["attributes"]["sentry.op"] == "cache.put" + assert spans[1]["name"].startswith("views.decorators.cache.cache_header.") + assert spans[1]["attributes"]["network.peer.address"] is not None + assert spans[1]["attributes"]["cache.key"][0].startswith( + "views.decorators.cache.cache_header." + ) + assert "cache.hit" not in spans[1]["attributes"] + assert spans[1]["attributes"]["cache.item_size"] == 2 + + client.get(reverse("not_cached_view")) + + sentry_sdk.flush() + spans = [item.payload for item in items] + # second_event - cache.get + assert spans[4]["attributes"]["sentry.op"] == "cache.get" + assert spans[4]["name"].startswith("views.decorators.cache.cache_header.") + assert spans[4]["attributes"]["network.peer.address"] is not None + assert spans[4]["attributes"]["cache.key"][0].startswith( + "views.decorators.cache.cache_header." + ) + assert spans[4]["attributes"]["cache.hit"] + assert spans[4]["attributes"]["cache.item_size"] == 2 + # second_event - cache.get 2 + assert spans[5]["attributes"]["sentry.op"] == "cache.get" + assert spans[5]["name"].startswith("views.decorators.cache.cache_page.") + assert spans[5]["attributes"]["network.peer.address"] is not None + assert spans[5]["attributes"]["cache.key"][0].startswith( + "views.decorators.cache.cache_page." + ) + assert spans[5]["attributes"]["cache.hit"] + assert spans[5]["attributes"]["cache.item_size"] == 58 + + +@pytest.mark.forked +@pytest_mark_django_db_decorator() +def test_cache_spans_enabled_by_default( + sentry_init, + client, + capture_items, + use_django_caching_with_middlewares, +): + sentry_init( + integrations=[ + DjangoIntegration( + middleware_spans=False, + signals_spans=False, + ) + ], + traces_sample_rate=1.0, + ) + + client.application.load_middleware() + items = capture_items("span") + + client.get(reverse("not_cached_view")) + + sentry_sdk.flush() + spans = [item.payload for item in items] + assert spans[0]["attributes"]["sentry.op"] == "cache.get" + assert spans[0]["name"].startswith("views.decorators.cache.cache_header.") + assert spans[1]["attributes"]["sentry.op"] == "cache.put" + assert spans[1]["name"].startswith("views.decorators.cache.cache_header.") @pytest.mark.forked @pytest_mark_django_db_decorator() -@pytest.mark.skipif(DJANGO_VERSION < (1, 9), reason="Requires Django >= 1.9") -@pytest.mark.parametrize("span_streaming", [True, False]) def test_cache_spans_decorator( sentry_init, client, - capture_events, capture_items, use_django_caching, - span_streaming, ): sentry_init( integrations=[ @@ -364,96 +289,50 @@ def test_cache_spans_decorator( ) ], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") - - client.get(reverse("cached_view")) - client.get(reverse("cached_view")) - - sentry_sdk.flush() - spans = [item.payload for item in items] - # first_event - cache.get - assert spans[0]["attributes"]["sentry.op"] == "cache.get" - assert spans[0]["name"].startswith("views.decorators.cache.cache_header.") - assert spans[0]["attributes"]["network.peer.address"] is not None - assert spans[0]["attributes"]["cache.key"][0].startswith( - "views.decorators.cache.cache_header." - ) - assert not spans[0]["attributes"]["cache.hit"] - assert "cache.item_size" not in spans[0]["attributes"] - # first_event - cache.put - assert spans[1]["attributes"]["sentry.op"] == "cache.put" - assert spans[1]["name"].startswith("views.decorators.cache.cache_header.") - assert spans[1]["attributes"]["network.peer.address"] is not None - assert spans[1]["attributes"]["cache.key"][0].startswith( - "views.decorators.cache.cache_header." - ) - assert "cache.hit" not in spans[1]["attributes"] - assert spans[1]["attributes"]["cache.item_size"] == 2 - # second_event - cache.get - assert spans[5]["attributes"]["sentry.op"] == "cache.get" - assert spans[5]["name"].startswith("views.decorators.cache.cache_page.") - assert spans[5]["attributes"]["network.peer.address"] is not None - assert spans[5]["attributes"]["cache.key"][0].startswith( - "views.decorators.cache.cache_page." - ) - assert spans[5]["attributes"]["cache.hit"] - assert spans[5]["attributes"]["cache.item_size"] == 58 - else: - events = capture_events() - - client.get(reverse("cached_view")) - client.get(reverse("cached_view")) - - (first_event, second_event) = events - # first_event - cache.get - assert first_event["spans"][0]["op"] == "cache.get" - assert first_event["spans"][0]["description"].startswith( - "views.decorators.cache.cache_header." - ) - assert first_event["spans"][0]["data"]["network.peer.address"] is not None - assert first_event["spans"][0]["data"]["cache.key"][0].startswith( - "views.decorators.cache.cache_header." - ) - assert not first_event["spans"][0]["data"]["cache.hit"] - assert "cache.item_size" not in first_event["spans"][0]["data"] - # first_event - cache.put - assert first_event["spans"][1]["op"] == "cache.put" - assert first_event["spans"][1]["description"].startswith( - "views.decorators.cache.cache_header." - ) - assert first_event["spans"][1]["data"]["network.peer.address"] is not None - assert first_event["spans"][1]["data"]["cache.key"][0].startswith( - "views.decorators.cache.cache_header." - ) - assert "cache.hit" not in first_event["spans"][1]["data"] - assert first_event["spans"][1]["data"]["cache.item_size"] == 2 - # second_event - cache.get - assert second_event["spans"][1]["op"] == "cache.get" - assert second_event["spans"][1]["description"].startswith( - "views.decorators.cache.cache_page." - ) - assert second_event["spans"][1]["data"]["network.peer.address"] is not None - assert second_event["spans"][1]["data"]["cache.key"][0].startswith( - "views.decorators.cache.cache_page." - ) - assert second_event["spans"][1]["data"]["cache.hit"] - assert second_event["spans"][1]["data"]["cache.item_size"] == 58 + items = capture_items("span") + + client.get(reverse("cached_view")) + client.get(reverse("cached_view")) + + sentry_sdk.flush() + spans = [item.payload for item in items] + # first_event - cache.get + assert spans[0]["attributes"]["sentry.op"] == "cache.get" + assert spans[0]["name"].startswith("views.decorators.cache.cache_header.") + assert spans[0]["attributes"]["network.peer.address"] is not None + assert spans[0]["attributes"]["cache.key"][0].startswith( + "views.decorators.cache.cache_header." + ) + assert not spans[0]["attributes"]["cache.hit"] + assert "cache.item_size" not in spans[0]["attributes"] + # first_event - cache.put + assert spans[1]["attributes"]["sentry.op"] == "cache.put" + assert spans[1]["name"].startswith("views.decorators.cache.cache_header.") + assert spans[1]["attributes"]["network.peer.address"] is not None + assert spans[1]["attributes"]["cache.key"][0].startswith( + "views.decorators.cache.cache_header." + ) + assert "cache.hit" not in spans[1]["attributes"] + assert spans[1]["attributes"]["cache.item_size"] == 2 + # second_event - cache.get + assert spans[5]["attributes"]["sentry.op"] == "cache.get" + assert spans[5]["name"].startswith("views.decorators.cache.cache_page.") + assert spans[5]["attributes"]["network.peer.address"] is not None + assert spans[5]["attributes"]["cache.key"][0].startswith( + "views.decorators.cache.cache_page." + ) + assert spans[5]["attributes"]["cache.hit"] + assert spans[5]["attributes"]["cache.item_size"] == 58 @pytest.mark.forked @pytest_mark_django_db_decorator() -@pytest.mark.skipif(DJANGO_VERSION < (1, 9), reason="Requires Django >= 1.9") -@pytest.mark.parametrize("span_streaming", [True, False]) def test_cache_spans_templatetag( sentry_init, client, - capture_events, capture_items, use_django_caching, - span_streaming, ): sentry_init( integrations=[ @@ -464,85 +343,42 @@ def test_cache_spans_templatetag( ) ], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") - - client.get(reverse("view_with_cached_template_fragment")) - client.get(reverse("view_with_cached_template_fragment")) - - sentry_sdk.flush() - spans = [item.payload for item in items] - assert len(spans) == 5 - # first_event - cache.get - assert spans[0]["attributes"]["sentry.op"] == "cache.get" - assert spans[0]["name"].startswith("template.cache.some_identifier.") - assert spans[0]["attributes"]["network.peer.address"] is not None - assert spans[0]["attributes"]["cache.key"][0].startswith( - "template.cache.some_identifier." - ) - assert not spans[0]["attributes"]["cache.hit"] - assert "cache.item_size" not in spans[0]["attributes"] - # first_event - cache.put - assert spans[1]["attributes"]["sentry.op"] == "cache.put" - assert spans[1]["name"].startswith("template.cache.some_identifier.") - assert spans[1]["attributes"]["network.peer.address"] is not None - assert spans[1]["attributes"]["cache.key"][0].startswith( - "template.cache.some_identifier." - ) - assert "cache.hit" not in spans[1]["attributes"] - assert spans[1]["attributes"]["cache.item_size"] == 51 - # second_event - cache.get - assert spans[3]["attributes"]["sentry.op"] == "cache.get" - assert spans[3]["name"].startswith("template.cache.some_identifier.") - assert spans[3]["attributes"]["network.peer.address"] is not None - assert spans[3]["attributes"]["cache.key"][0].startswith( - "template.cache.some_identifier." - ) - assert spans[3]["attributes"]["cache.hit"] - assert spans[3]["attributes"]["cache.item_size"] == 51 - else: - events = capture_events() - - client.get(reverse("view_with_cached_template_fragment")) - client.get(reverse("view_with_cached_template_fragment")) - - (first_event, second_event) = events - assert len(first_event["spans"]) == 2 - # first_event - cache.get - assert first_event["spans"][0]["op"] == "cache.get" - assert first_event["spans"][0]["description"].startswith( - "template.cache.some_identifier." - ) - assert first_event["spans"][0]["data"]["network.peer.address"] is not None - assert first_event["spans"][0]["data"]["cache.key"][0].startswith( - "template.cache.some_identifier." - ) - assert not first_event["spans"][0]["data"]["cache.hit"] - assert "cache.item_size" not in first_event["spans"][0]["data"] - # first_event - cache.put - assert first_event["spans"][1]["op"] == "cache.put" - assert first_event["spans"][1]["description"].startswith( - "template.cache.some_identifier." - ) - assert first_event["spans"][1]["data"]["network.peer.address"] is not None - assert first_event["spans"][1]["data"]["cache.key"][0].startswith( - "template.cache.some_identifier." - ) - assert "cache.hit" not in first_event["spans"][1]["data"] - assert first_event["spans"][1]["data"]["cache.item_size"] == 51 - # second_event - cache.get - assert second_event["spans"][0]["op"] == "cache.get" - assert second_event["spans"][0]["description"].startswith( - "template.cache.some_identifier." - ) - assert second_event["spans"][0]["data"]["network.peer.address"] is not None - assert second_event["spans"][0]["data"]["cache.key"][0].startswith( - "template.cache.some_identifier." - ) - assert second_event["spans"][0]["data"]["cache.hit"] - assert second_event["spans"][0]["data"]["cache.item_size"] == 51 + items = capture_items("span") + + client.get(reverse("view_with_cached_template_fragment")) + client.get(reverse("view_with_cached_template_fragment")) + + sentry_sdk.flush() + spans = [item.payload for item in items] + assert len(spans) == 5 + # first_event - cache.get + assert spans[0]["attributes"]["sentry.op"] == "cache.get" + assert spans[0]["name"].startswith("template.cache.some_identifier.") + assert spans[0]["attributes"]["network.peer.address"] is not None + assert spans[0]["attributes"]["cache.key"][0].startswith( + "template.cache.some_identifier." + ) + assert not spans[0]["attributes"]["cache.hit"] + assert "cache.item_size" not in spans[0]["attributes"] + # first_event - cache.put + assert spans[1]["attributes"]["sentry.op"] == "cache.put" + assert spans[1]["name"].startswith("template.cache.some_identifier.") + assert spans[1]["attributes"]["network.peer.address"] is not None + assert spans[1]["attributes"]["cache.key"][0].startswith( + "template.cache.some_identifier." + ) + assert "cache.hit" not in spans[1]["attributes"] + assert spans[1]["attributes"]["cache.item_size"] == 51 + # second_event - cache.get + assert spans[3]["attributes"]["sentry.op"] == "cache.get" + assert spans[3]["name"].startswith("template.cache.some_identifier.") + assert spans[3]["attributes"]["network.peer.address"] is not None + assert spans[3]["attributes"]["cache.key"][0].startswith( + "template.cache.some_identifier." + ) + assert spans[3]["attributes"]["cache.hit"] + assert spans[3]["attributes"]["cache.item_size"] == 51 @pytest.mark.parametrize( @@ -580,14 +416,11 @@ def test_cache_spans_get_span_name(method_name, args, kwargs, expected_name): @pytest.mark.forked @pytest_mark_django_db_decorator() -@pytest.mark.parametrize("span_streaming", [True, False]) def test_cache_spans_location_with_port( sentry_init, client, - capture_events, capture_items, use_django_caching_with_port, - span_streaming, ): sentry_init( integrations=[ @@ -598,49 +431,32 @@ def test_cache_spans_location_with_port( ) ], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") + items = capture_items("span") - client.get(reverse("cached_view")) - client.get(reverse("cached_view")) + client.get(reverse("cached_view")) + client.get(reverse("cached_view")) - sentry_sdk.flush() - spans = [item.payload for item in items] + sentry_sdk.flush() + spans = [item.payload for item in items] - for span in spans: - if span["is_segment"] is True: - continue + for span in spans: + if span["is_segment"] is True: + continue - assert ( - span["attributes"]["network.peer.address"] == "redis://127.0.0.1" - ) # Note: the username/password are not included in the address - assert span["attributes"]["network.peer.port"] == 6379 - else: - events = capture_events() - - client.get(reverse("cached_view")) - client.get(reverse("cached_view")) - - for event in events: - for span in event["spans"]: - assert ( - span["data"]["network.peer.address"] == "redis://127.0.0.1" - ) # Note: the username/password are not included in the address - assert span["data"]["network.peer.port"] == 6379 + assert ( + span["attributes"]["network.peer.address"] == "redis://127.0.0.1" + ) # Note: the username/password are not included in the address + assert span["attributes"]["network.peer.port"] == 6379 @pytest.mark.forked @pytest_mark_django_db_decorator() -@pytest.mark.parametrize("span_streaming", [True, False]) def test_cache_spans_location_without_port( sentry_init, client, - capture_events, capture_items, use_django_caching_without_port, - span_streaming, ): sentry_init( integrations=[ @@ -651,45 +467,30 @@ def test_cache_spans_location_without_port( ) ], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") + items = capture_items("span") - client.get(reverse("cached_view")) - client.get(reverse("cached_view")) + client.get(reverse("cached_view")) + client.get(reverse("cached_view")) - sentry_sdk.flush() - spans = [item.payload for item in items] - - for span in spans: - if span["is_segment"] is True: - continue - - assert span["attributes"]["network.peer.address"] == "redis://example.com" - assert "network.peer.port" not in span["attributes"] - else: - events = capture_events() + sentry_sdk.flush() + spans = [item.payload for item in items] - client.get(reverse("cached_view")) - client.get(reverse("cached_view")) + for span in spans: + if span["is_segment"] is True: + continue - for event in events: - for span in event["spans"]: - assert span["data"]["network.peer.address"] == "redis://example.com" - assert "network.peer.port" not in span["data"] + assert span["attributes"]["network.peer.address"] == "redis://example.com" + assert "network.peer.port" not in span["attributes"] @pytest.mark.forked @pytest_mark_django_db_decorator() -@pytest.mark.parametrize("span_streaming", [True, False]) def test_cache_spans_location_with_cluster( sentry_init, client, - capture_events, capture_items, use_django_caching_with_cluster, - span_streaming, ): sentry_init( integrations=[ @@ -700,44 +501,28 @@ def test_cache_spans_location_with_cluster( ) ], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") + items = capture_items("span") - client.get(reverse("cached_view")) - client.get(reverse("cached_view")) + client.get(reverse("cached_view")) + client.get(reverse("cached_view")) - sentry_sdk.flush() - spans = [item.payload for item in items] + sentry_sdk.flush() + spans = [item.payload for item in items] - for span in spans: - # because it is a cluster we do not know what host is actually accessed, so we omit the data - assert "network.peer.address" not in span["attributes"].keys() - assert "network.peer.port" not in span["attributes"].keys() - else: - events = capture_events() - - client.get(reverse("cached_view")) - client.get(reverse("cached_view")) - - for event in events: - for span in event["spans"]: - # because it is a cluster we do not know what host is actually accessed, so we omit the data - assert "network.peer.address" not in span["data"].keys() - assert "network.peer.port" not in span["data"].keys() + for span in spans: + # because it is a cluster we do not know what host is actually accessed, so we omit the data + assert "network.peer.address" not in span["attributes"].keys() + assert "network.peer.port" not in span["attributes"].keys() @pytest.mark.forked @pytest_mark_django_db_decorator() -@pytest.mark.parametrize("span_streaming", [True, False]) def test_cache_spans_item_size( sentry_init, client, - capture_events, capture_items, use_django_caching, - span_streaming, ): sentry_init( integrations=[ @@ -748,75 +533,42 @@ def test_cache_spans_item_size( ) ], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") - - client.get(reverse("cached_view")) - client.get(reverse("cached_view")) - - sentry_sdk.flush() - spans = [item.payload for item in items] - assert len(spans) == 7 - assert spans[0]["attributes"]["sentry.op"] == "cache.get" - assert not spans[0]["attributes"]["cache.hit"] - assert "cache.item_size" not in spans[0]["attributes"] - - assert spans[1]["attributes"]["sentry.op"] == "cache.put" - assert "cache.hit" not in spans[1]["attributes"] - assert spans[1]["attributes"]["cache.item_size"] == 2 - - assert spans[2]["attributes"]["sentry.op"] == "cache.put" - assert "cache.hit" not in spans[2]["attributes"] - assert spans[2]["attributes"]["cache.item_size"] == 58 - - assert spans[4]["attributes"]["sentry.op"] == "cache.get" - assert spans[4]["attributes"]["cache.hit"] - assert spans[4]["attributes"]["cache.item_size"] == 2 - - assert spans[5]["attributes"]["sentry.op"] == "cache.get" - assert spans[5]["attributes"]["cache.hit"] - assert spans[5]["attributes"]["cache.item_size"] == 58 - else: - events = capture_events() + items = capture_items("span") - client.get(reverse("cached_view")) - client.get(reverse("cached_view")) + client.get(reverse("cached_view")) + client.get(reverse("cached_view")) - (first_event, second_event) = events - assert len(first_event["spans"]) == 3 - assert first_event["spans"][0]["op"] == "cache.get" - assert not first_event["spans"][0]["data"]["cache.hit"] - assert "cache.item_size" not in first_event["spans"][0]["data"] + sentry_sdk.flush() + spans = [item.payload for item in items] + assert len(spans) == 7 + assert spans[0]["attributes"]["sentry.op"] == "cache.get" + assert not spans[0]["attributes"]["cache.hit"] + assert "cache.item_size" not in spans[0]["attributes"] - assert first_event["spans"][1]["op"] == "cache.put" - assert "cache.hit" not in first_event["spans"][1]["data"] - assert first_event["spans"][1]["data"]["cache.item_size"] == 2 + assert spans[1]["attributes"]["sentry.op"] == "cache.put" + assert "cache.hit" not in spans[1]["attributes"] + assert spans[1]["attributes"]["cache.item_size"] == 2 - assert first_event["spans"][2]["op"] == "cache.put" - assert "cache.hit" not in first_event["spans"][2]["data"] - assert first_event["spans"][2]["data"]["cache.item_size"] == 58 + assert spans[2]["attributes"]["sentry.op"] == "cache.put" + assert "cache.hit" not in spans[2]["attributes"] + assert spans[2]["attributes"]["cache.item_size"] == 58 - assert len(second_event["spans"]) == 2 - assert second_event["spans"][0]["op"] == "cache.get" - assert second_event["spans"][0]["data"]["cache.hit"] - assert second_event["spans"][0]["data"]["cache.item_size"] == 2 + assert spans[4]["attributes"]["sentry.op"] == "cache.get" + assert spans[4]["attributes"]["cache.hit"] + assert spans[4]["attributes"]["cache.item_size"] == 2 - assert second_event["spans"][1]["op"] == "cache.get" - assert second_event["spans"][1]["data"]["cache.hit"] - assert second_event["spans"][1]["data"]["cache.item_size"] == 58 + assert spans[5]["attributes"]["sentry.op"] == "cache.get" + assert spans[5]["attributes"]["cache.hit"] + assert spans[5]["attributes"]["cache.item_size"] == 58 @pytest.mark.forked @pytest_mark_django_db_decorator() -@pytest.mark.parametrize("span_streaming", [True, False]) def test_cache_spans_get_custom_default( sentry_init, - capture_events, capture_items, use_django_caching, - span_streaming, ): sentry_init( integrations=[ @@ -827,109 +579,62 @@ def test_cache_spans_get_custom_default( ) ], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) id = os.getpid() from django.core.cache import cache - if span_streaming: - items = capture_items("span") - - with sentry_sdk.traces.start_span(name="custom parent"): - cache.set(f"S{id}", "Sensitive1") - cache.set(f"S{id + 1}", "") + items = capture_items("span") - cache.get(f"S{id}", "null") - cache.get(f"S{id}", default="null") + with sentry_sdk.start_span(name="custom parent"): + cache.set(f"S{id}", "Sensitive1") + cache.set(f"S{id + 1}", "") - cache.get(f"S{id + 1}", "null") - cache.get(f"S{id + 1}", default="null") + cache.get(f"S{id}", "null") + cache.get(f"S{id}", default="null") - cache.get(f"S{id + 2}", "null") - cache.get(f"S{id + 2}", default="null") + cache.get(f"S{id + 1}", "null") + cache.get(f"S{id + 1}", default="null") - sentry_sdk.flush() - spans = [item.payload for item in items] - assert len(spans) == 9 + cache.get(f"S{id + 2}", "null") + cache.get(f"S{id + 2}", default="null") - assert spans[0]["attributes"]["sentry.op"] == "cache.put" - assert spans[0]["name"] == f"S{id}" + sentry_sdk.flush() + spans = [item.payload for item in items] + assert len(spans) == 9 - assert spans[1]["attributes"]["sentry.op"] == "cache.put" - assert spans[1]["name"] == f"S{id + 1}" + assert spans[0]["attributes"]["sentry.op"] == "cache.put" + assert spans[0]["name"] == f"S{id}" - for span in (spans[2], spans[3]): - assert span["attributes"]["sentry.op"] == "cache.get" - assert span["name"] == f"S{id}" - assert span["attributes"]["cache.hit"] - assert span["attributes"]["cache.item_size"] == 10 + assert spans[1]["attributes"]["sentry.op"] == "cache.put" + assert spans[1]["name"] == f"S{id + 1}" - for span in (spans[4], spans[5]): - assert span["attributes"]["sentry.op"] == "cache.get" - assert span["name"] == f"S{id + 1}" - assert span["attributes"]["cache.hit"] - assert span["attributes"]["cache.item_size"] == 0 + for span in (spans[2], spans[3]): + assert span["attributes"]["sentry.op"] == "cache.get" + assert span["name"] == f"S{id}" + assert span["attributes"]["cache.hit"] + assert span["attributes"]["cache.item_size"] == 10 - for span in (spans[6], spans[7]): - assert span["attributes"]["sentry.op"] == "cache.get" - assert span["name"] == f"S{id + 2}" - assert not span["attributes"]["cache.hit"] - assert "cache.item_size" not in span["attributes"] - else: - events = capture_events() - - with sentry_sdk.start_transaction(): - cache.set(f"S{id}", "Sensitive1") - cache.set(f"S{id + 1}", "") - - cache.get(f"S{id}", "null") - cache.get(f"S{id}", default="null") - - cache.get(f"S{id + 1}", "null") - cache.get(f"S{id + 1}", default="null") - - cache.get(f"S{id + 2}", "null") - cache.get(f"S{id + 2}", default="null") - - (transaction,) = events - assert len(transaction["spans"]) == 8 + for span in (spans[4], spans[5]): + assert span["attributes"]["sentry.op"] == "cache.get" + assert span["name"] == f"S{id + 1}" + assert span["attributes"]["cache.hit"] + assert span["attributes"]["cache.item_size"] == 0 - assert transaction["spans"][0]["op"] == "cache.put" - assert transaction["spans"][0]["description"] == f"S{id}" - - assert transaction["spans"][1]["op"] == "cache.put" - assert transaction["spans"][1]["description"] == f"S{id + 1}" - - for span in (transaction["spans"][2], transaction["spans"][3]): - assert span["op"] == "cache.get" - assert span["description"] == f"S{id}" - assert span["data"]["cache.hit"] - assert span["data"]["cache.item_size"] == 10 - - for span in (transaction["spans"][4], transaction["spans"][5]): - assert span["op"] == "cache.get" - assert span["description"] == f"S{id + 1}" - assert span["data"]["cache.hit"] - assert span["data"]["cache.item_size"] == 0 - - for span in (transaction["spans"][6], transaction["spans"][7]): - assert span["op"] == "cache.get" - assert span["description"] == f"S{id + 2}" - assert not span["data"]["cache.hit"] - assert "cache.item_size" not in span["data"] + for span in (spans[6], spans[7]): + assert span["attributes"]["sentry.op"] == "cache.get" + assert span["name"] == f"S{id + 2}" + assert not span["attributes"]["cache.hit"] + assert "cache.item_size" not in span["attributes"] @pytest.mark.forked @pytest_mark_django_db_decorator() -@pytest.mark.parametrize("span_streaming", [True, False]) def test_cache_spans_get_many( sentry_init, - capture_events, capture_items, use_django_caching, - span_streaming, ): sentry_init( integrations=[ @@ -940,99 +645,57 @@ def test_cache_spans_get_many( ) ], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) id = os.getpid() from django.core.cache import cache - if span_streaming: - items = capture_items("span") + items = capture_items("span") - with sentry_sdk.traces.start_span(name="custom parent"): - cache.get_many([f"S{id}", f"S{id + 1}"]) - cache.set(f"S{id}", "Sensitive1") - cache.get_many([f"S{id}", f"S{id + 1}"]) + with sentry_sdk.start_span(name="custom parent"): + cache.get_many([f"S{id}", f"S{id + 1}"]) + cache.set(f"S{id}", "Sensitive1") + cache.get_many([f"S{id}", f"S{id + 1}"]) - sentry_sdk.flush() - spans = [item.payload for item in items] - assert len(spans) == 8 + sentry_sdk.flush() + spans = [item.payload for item in items] + assert len(spans) == 8 - assert spans[2]["attributes"]["sentry.op"] == "cache.get" - assert spans[2]["name"] == f"S{id}, S{id + 1}" - assert not spans[2]["attributes"]["cache.hit"] + assert spans[2]["attributes"]["sentry.op"] == "cache.get" + assert spans[2]["name"] == f"S{id}, S{id + 1}" + assert not spans[2]["attributes"]["cache.hit"] - assert spans[0]["attributes"]["sentry.op"] == "cache.get" - assert spans[0]["name"] == f"S{id}" - assert not spans[0]["attributes"]["cache.hit"] + assert spans[0]["attributes"]["sentry.op"] == "cache.get" + assert spans[0]["name"] == f"S{id}" + assert not spans[0]["attributes"]["cache.hit"] - assert spans[1]["attributes"]["sentry.op"] == "cache.get" - assert spans[1]["name"] == f"S{id + 1}" - assert not spans[1]["attributes"]["cache.hit"] + assert spans[1]["attributes"]["sentry.op"] == "cache.get" + assert spans[1]["name"] == f"S{id + 1}" + assert not spans[1]["attributes"]["cache.hit"] - assert spans[3]["attributes"]["sentry.op"] == "cache.put" - assert spans[3]["name"] == f"S{id}" + assert spans[3]["attributes"]["sentry.op"] == "cache.put" + assert spans[3]["name"] == f"S{id}" - assert spans[6]["attributes"]["sentry.op"] == "cache.get" - assert spans[6]["name"] == f"S{id}, S{id + 1}" - assert spans[6]["attributes"]["cache.hit"] + assert spans[6]["attributes"]["sentry.op"] == "cache.get" + assert spans[6]["name"] == f"S{id}, S{id + 1}" + assert spans[6]["attributes"]["cache.hit"] - assert spans[4]["attributes"]["sentry.op"] == "cache.get" - assert spans[4]["name"] == f"S{id}" - assert spans[4]["attributes"]["cache.hit"] + assert spans[4]["attributes"]["sentry.op"] == "cache.get" + assert spans[4]["name"] == f"S{id}" + assert spans[4]["attributes"]["cache.hit"] - assert spans[5]["attributes"]["sentry.op"] == "cache.get" - assert spans[5]["name"] == f"S{id + 1}" - assert not spans[5]["attributes"]["cache.hit"] - else: - events = capture_events() - - with sentry_sdk.start_transaction(): - cache.get_many([f"S{id}", f"S{id + 1}"]) - cache.set(f"S{id}", "Sensitive1") - cache.get_many([f"S{id}", f"S{id + 1}"]) - - (transaction,) = events - assert len(transaction["spans"]) == 7 - - assert transaction["spans"][0]["op"] == "cache.get" - assert transaction["spans"][0]["description"] == f"S{id}, S{id + 1}" - assert not transaction["spans"][0]["data"]["cache.hit"] - - assert transaction["spans"][1]["op"] == "cache.get" - assert transaction["spans"][1]["description"] == f"S{id}" - assert not transaction["spans"][1]["data"]["cache.hit"] - - assert transaction["spans"][2]["op"] == "cache.get" - assert transaction["spans"][2]["description"] == f"S{id + 1}" - assert not transaction["spans"][2]["data"]["cache.hit"] - - assert transaction["spans"][3]["op"] == "cache.put" - assert transaction["spans"][3]["description"] == f"S{id}" - - assert transaction["spans"][4]["op"] == "cache.get" - assert transaction["spans"][4]["description"] == f"S{id}, S{id + 1}" - assert transaction["spans"][4]["data"]["cache.hit"] - - assert transaction["spans"][5]["op"] == "cache.get" - assert transaction["spans"][5]["description"] == f"S{id}" - assert transaction["spans"][5]["data"]["cache.hit"] - - assert transaction["spans"][6]["op"] == "cache.get" - assert transaction["spans"][6]["description"] == f"S{id + 1}" - assert not transaction["spans"][6]["data"]["cache.hit"] + assert spans[5]["attributes"]["sentry.op"] == "cache.get" + assert spans[5]["name"] == f"S{id + 1}" + assert not spans[5]["attributes"]["cache.hit"] @pytest.mark.forked @pytest_mark_django_db_decorator() -@pytest.mark.parametrize("span_streaming", [True, False]) def test_cache_spans_set_many( sentry_init, - capture_events, capture_items, use_django_caching, - span_streaming, ): sentry_init( integrations=[ @@ -1043,69 +706,42 @@ def test_cache_spans_set_many( ) ], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) id = os.getpid() from django.core.cache import cache - if span_streaming: - items = capture_items("span") + items = capture_items("span") - with sentry_sdk.traces.start_span(name="custom parent"): - cache.set_many({f"S{id}": "Sensitive1", f"S{id + 1}": "Sensitive2"}) - cache.get(f"S{id}") + with sentry_sdk.start_span(name="custom parent"): + cache.set_many({f"S{id}": "Sensitive1", f"S{id + 1}": "Sensitive2"}) + cache.get(f"S{id}") - sentry_sdk.flush() - spans = [item.payload for item in items] - assert len(spans) == 5 + sentry_sdk.flush() + spans = [item.payload for item in items] + assert len(spans) == 5 - assert spans[2]["attributes"]["sentry.op"] == "cache.put" - assert spans[2]["name"] == f"S{id}, S{id + 1}" + assert spans[2]["attributes"]["sentry.op"] == "cache.put" + assert spans[2]["name"] == f"S{id}, S{id + 1}" - assert spans[0]["attributes"]["sentry.op"] == "cache.put" - assert spans[0]["name"] == f"S{id}" + assert spans[0]["attributes"]["sentry.op"] == "cache.put" + assert spans[0]["name"] == f"S{id}" - assert spans[1]["attributes"]["sentry.op"] == "cache.put" - assert spans[1]["name"] == f"S{id + 1}" - - assert spans[3]["attributes"]["sentry.op"] == "cache.get" - assert spans[3]["name"] == f"S{id}" - else: - events = capture_events() + assert spans[1]["attributes"]["sentry.op"] == "cache.put" + assert spans[1]["name"] == f"S{id + 1}" - with sentry_sdk.start_transaction(): - cache.set_many({f"S{id}": "Sensitive1", f"S{id + 1}": "Sensitive2"}) - cache.get(f"S{id}") - - (transaction,) = events - assert len(transaction["spans"]) == 4 - - assert transaction["spans"][0]["op"] == "cache.put" - assert transaction["spans"][0]["description"] == f"S{id}, S{id + 1}" - - assert transaction["spans"][1]["op"] == "cache.put" - assert transaction["spans"][1]["description"] == f"S{id}" - - assert transaction["spans"][2]["op"] == "cache.put" - assert transaction["spans"][2]["description"] == f"S{id + 1}" - - assert transaction["spans"][3]["op"] == "cache.get" - assert transaction["spans"][3]["description"] == f"S{id}" + assert spans[3]["attributes"]["sentry.op"] == "cache.get" + assert spans[3]["name"] == f"S{id}" @pytest.mark.forked @pytest_mark_django_db_decorator() -@pytest.mark.skipif(DJANGO_VERSION <= (1, 11), reason="Requires Django > 1.11") -@pytest.mark.parametrize("span_streaming", [True, False]) def test_span_origin_cache( sentry_init, client, - capture_events, capture_items, use_django_caching, - span_streaming, ): sentry_init( integrations=[ @@ -1116,35 +752,20 @@ def test_span_origin_cache( ) ], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) cache_span_found = False - if span_streaming: - items = capture_items("span") - - client.get(reverse("cached_view")) - - sentry_sdk.flush() - spans = [item.payload for item in items] - - assert spans[1]["attributes"]["sentry.origin"] == "auto.http.django" - - for span in spans: - assert span["attributes"]["sentry.origin"] == "auto.http.django" - if span["attributes"]["sentry.op"].startswith("cache."): - cache_span_found = True - else: - events = capture_events() + items = capture_items("span") - client.get(reverse("cached_view")) + client.get(reverse("cached_view")) - (transaction,) = events + sentry_sdk.flush() + spans = [item.payload for item in items] - assert transaction["contexts"]["trace"]["origin"] == "auto.http.django" + assert spans[1]["attributes"]["sentry.origin"] == "auto.http.django" - for span in transaction["spans"]: - assert span["origin"] == "auto.http.django" - if span["op"].startswith("cache."): - cache_span_found = True + for span in spans: + assert span["attributes"]["sentry.origin"] == "auto.http.django" + if span["attributes"]["sentry.op"].startswith("cache."): + cache_span_found = True assert cache_span_found diff --git a/tests/integrations/django/test_data_scrubbing.py b/tests/integrations/django/test_data_scrubbing.py index a660341fea..6d452ea8b2 100644 --- a/tests/integrations/django/test_data_scrubbing.py +++ b/tests/integrations/django/test_data_scrubbing.py @@ -317,7 +317,6 @@ def test_span_http_query_data_collection( sentry_init( integrations=[DjangoIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", **init_kwargs, ) @@ -378,7 +377,6 @@ def test_user_info_span_attributes_data_collection( sentry_init( integrations=[DjangoIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", **init_kwargs, ) @@ -410,7 +408,6 @@ def test_user_identity_span_attributes_data_collection( sentry_init( integrations=[DjangoIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", **init_kwargs, ) diff --git a/tests/integrations/django/test_db_query_data.py b/tests/integrations/django/test_db_query_data.py index 0739b0992b..b20a1600f1 100644 --- a/tests/integrations/django/test_db_query_data.py +++ b/tests/integrations/django/test_db_query_data.py @@ -14,7 +14,6 @@ from werkzeug.test import Client import sentry_sdk -from sentry_sdk import start_transaction from sentry_sdk.consts import SPANDATA from sentry_sdk.integrations.django import DjangoIntegration from sentry_sdk.tracing_utils import ( @@ -32,13 +31,10 @@ def client(): @pytest.mark.forked @pytest_mark_django_db_decorator(transaction=True) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_query_source_disabled( sentry_init, client, - capture_events, capture_items, - span_streaming, ): sentry_options = { "integrations": [DjangoIntegration()], @@ -46,7 +42,6 @@ def test_query_source_disabled( "traces_sample_rate": 1.0, "enable_db_query_source": False, "db_query_source_threshold_ms": 0, - "trace_lifecycle": "stream" if span_streaming else "static", } sentry_init(**sentry_options) @@ -57,70 +52,43 @@ def test_query_source_disabled( # trigger Django to open a new connection by marking the existing one as None. connections["postgres"].connection = None - if span_streaming: - items = capture_items("span") + items = capture_items("span") - _, status, _ = unpack_werkzeug_response( - client.get(reverse("postgres_select_orm")) - ) - assert status == "200 OK" - - sentry_sdk.flush() - spans = [item.payload for item in items] - - for span in spans: - if span["attributes"].get("sentry.op") == "db" and "auth_user" in span.get( - "name" - ): - attributes = span.get("attributes", {}) - - assert SPANDATA.CODE_LINE_NUMBER not in attributes - assert SPANDATA.CODE_NAMESPACE not in attributes - assert SPANDATA.CODE_FILE_PATH not in attributes - assert SPANDATA.CODE_FUNCTION not in attributes - break - else: - raise AssertionError("No db span found") - else: - events = capture_events() + _, status, _ = unpack_werkzeug_response(client.get(reverse("postgres_select_orm"))) + assert status == "200 OK" - _, status, _ = unpack_werkzeug_response( - client.get(reverse("postgres_select_orm")) - ) - assert status == "200 OK" - - (event,) = events - for span in event["spans"]: - if span.get("op") == "db" and "auth_user" in span.get("description"): - data = span.get("data", {}) - - assert SPANDATA.CODE_LINENO not in data - assert SPANDATA.CODE_NAMESPACE not in data - assert SPANDATA.CODE_FILEPATH not in data - assert SPANDATA.CODE_FUNCTION not in data - break - else: - raise AssertionError("No db span found") + sentry_sdk.flush() + spans = [item.payload for item in items] + + for span in spans: + if span["attributes"].get("sentry.op") == "db" and "auth_user" in span.get( + "name" + ): + attributes = span.get("attributes", {}) + + assert SPANDATA.CODE_LINE_NUMBER not in attributes + assert SPANDATA.CODE_NAMESPACE not in attributes + assert SPANDATA.CODE_FILE_PATH not in attributes + assert SPANDATA.CODE_FUNCTION not in attributes + break + else: + raise AssertionError("No db span found") @pytest.mark.forked @pytest_mark_django_db_decorator(transaction=True) @pytest.mark.parametrize("enable_db_query_source", [None, True]) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_query_source_enabled( sentry_init, client, - capture_events, capture_items, enable_db_query_source, - span_streaming, ): sentry_options = { "integrations": [DjangoIntegration()], "send_default_pii": True, "traces_sample_rate": 1.0, "db_query_source_threshold_ms": 0, - "trace_lifecycle": "stream" if span_streaming else "static", } if enable_db_query_source is not None: @@ -134,61 +102,35 @@ def test_query_source_enabled( # trigger Django to open a new connection by marking the existing one as None. connections["postgres"].connection = None - if span_streaming: - items = capture_items("span") + items = capture_items("span") - _, status, _ = unpack_werkzeug_response( - client.get(reverse("postgres_select_orm")) - ) - assert status == "200 OK" - - sentry_sdk.flush() - spans = [item.payload for item in items] - - for span in spans: - if span["attributes"].get("sentry.op") == "db" and "auth_user" in span.get( - "name" - ): - attributes = span.get("attributes", {}) - - assert SPANDATA.CODE_LINE_NUMBER in attributes - assert SPANDATA.CODE_NAMESPACE in attributes - assert SPANDATA.CODE_FILE_PATH in attributes - assert SPANDATA.CODE_FUNCTION in attributes - break - else: - raise AssertionError("No db span found") - else: - events = capture_events() + _, status, _ = unpack_werkzeug_response(client.get(reverse("postgres_select_orm"))) + assert status == "200 OK" - _, status, _ = unpack_werkzeug_response( - client.get(reverse("postgres_select_orm")) - ) - assert status == "200 OK" - - (event,) = events - for span in event["spans"]: - if span.get("op") == "db" and "auth_user" in span.get("description"): - data = span.get("data", {}) - - assert SPANDATA.CODE_LINENO in data - assert SPANDATA.CODE_NAMESPACE in data - assert SPANDATA.CODE_FILEPATH in data - assert SPANDATA.CODE_FUNCTION in data - break - else: - raise AssertionError("No db span found") + sentry_sdk.flush() + spans = [item.payload for item in items] + + for span in spans: + if span["attributes"].get("sentry.op") == "db" and "auth_user" in span.get( + "name" + ): + attributes = span.get("attributes", {}) + + assert SPANDATA.CODE_LINE_NUMBER in attributes + assert SPANDATA.CODE_NAMESPACE in attributes + assert SPANDATA.CODE_FILE_PATH in attributes + assert SPANDATA.CODE_FUNCTION in attributes + break + else: + raise AssertionError("No db span found") @pytest.mark.forked @pytest_mark_django_db_decorator(transaction=True) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_query_source( sentry_init, client, - capture_events, capture_items, - span_streaming, ): sentry_init( integrations=[DjangoIntegration()], @@ -196,7 +138,6 @@ def test_query_source( traces_sample_rate=1.0, enable_db_query_source=True, db_query_source_threshold_ms=0, - trace_lifecycle="stream" if span_streaming else "static", ) if "postgres" not in connections: @@ -205,93 +146,51 @@ def test_query_source( # trigger Django to open a new connection by marking the existing one as None. connections["postgres"].connection = None - if span_streaming: - items = capture_items("span") + items = capture_items("span") - _, status, _ = unpack_werkzeug_response( - client.get(reverse("postgres_select_orm")) - ) - assert status == "200 OK" + _, status, _ = unpack_werkzeug_response(client.get(reverse("postgres_select_orm"))) + assert status == "200 OK" - sentry_sdk.flush() - spans = [item.payload for item in items] + sentry_sdk.flush() + spans = [item.payload for item in items] - for span in spans: - if span["attributes"].get("sentry.op") == "db" and "auth_user" in span.get( - "name" - ): - attributes = span.get("attributes", {}) + for span in spans: + if span["attributes"].get("sentry.op") == "db" and "auth_user" in span.get( + "name" + ): + attributes = span.get("attributes", {}) - assert SPANDATA.CODE_LINE_NUMBER in attributes - assert SPANDATA.CODE_NAMESPACE in attributes - assert SPANDATA.CODE_FILE_PATH in attributes - assert SPANDATA.CODE_FUNCTION in attributes + assert SPANDATA.CODE_LINE_NUMBER in attributes + assert SPANDATA.CODE_NAMESPACE in attributes + assert SPANDATA.CODE_FILE_PATH in attributes + assert SPANDATA.CODE_FUNCTION in attributes - assert type(attributes.get(SPANDATA.CODE_LINE_NUMBER)) == int - assert attributes.get(SPANDATA.CODE_LINE_NUMBER) > 0 + assert type(attributes.get(SPANDATA.CODE_LINE_NUMBER)) == int + assert attributes.get(SPANDATA.CODE_LINE_NUMBER) > 0 - assert ( - attributes.get(SPANDATA.CODE_NAMESPACE) - == "tests.integrations.django.myapp.views" - ) - assert attributes.get(SPANDATA.CODE_FILE_PATH).endswith( - "tests/integrations/django/myapp/views.py" - ) + assert ( + attributes.get(SPANDATA.CODE_NAMESPACE) + == "tests.integrations.django.myapp.views" + ) + assert attributes.get(SPANDATA.CODE_FILE_PATH).endswith( + "tests/integrations/django/myapp/views.py" + ) - is_relative_path = attributes.get(SPANDATA.CODE_FILE_PATH)[0] != os.sep - assert is_relative_path + is_relative_path = attributes.get(SPANDATA.CODE_FILE_PATH)[0] != os.sep + assert is_relative_path - assert attributes.get(SPANDATA.CODE_FUNCTION) == "postgres_select_orm" - break - else: - raise AssertionError("No db span found") + assert attributes.get(SPANDATA.CODE_FUNCTION) == "postgres_select_orm" + break else: - events = capture_events() - - _, status, _ = unpack_werkzeug_response( - client.get(reverse("postgres_select_orm")) - ) - assert status == "200 OK" - - (event,) = events - for span in event["spans"]: - if span.get("op") == "db" and "auth_user" in span.get("description"): - data = span.get("data", {}) - - assert SPANDATA.CODE_LINENO in data - assert SPANDATA.CODE_NAMESPACE in data - assert SPANDATA.CODE_FILEPATH in data - assert SPANDATA.CODE_FUNCTION in data - - assert type(data.get(SPANDATA.CODE_LINENO)) == int - assert data.get(SPANDATA.CODE_LINENO) > 0 - - assert ( - data.get(SPANDATA.CODE_NAMESPACE) - == "tests.integrations.django.myapp.views" - ) - assert data.get(SPANDATA.CODE_FILEPATH).endswith( - "tests/integrations/django/myapp/views.py" - ) - - is_relative_path = data.get(SPANDATA.CODE_FILEPATH)[0] != os.sep - assert is_relative_path - - assert data.get(SPANDATA.CODE_FUNCTION) == "postgres_select_orm" - break - else: - raise AssertionError("No db span found") + raise AssertionError("No db span found") @pytest.mark.forked @pytest_mark_django_db_decorator(transaction=True) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_query_source_with_module_in_search_path( sentry_init, client, - capture_events, capture_items, - span_streaming, ): """ Test that query source is relative to the path of the module it ran in @@ -304,7 +203,6 @@ def test_query_source_with_module_in_search_path( traces_sample_rate=1.0, enable_db_query_source=True, db_query_source_threshold_ms=0, - trace_lifecycle="stream" if span_streaming else "static", ) if "postgres" not in connections: @@ -313,83 +211,47 @@ def test_query_source_with_module_in_search_path( # trigger Django to open a new connection by marking the existing one as None. connections["postgres"].connection = None - if span_streaming: - items = capture_items("span") + items = capture_items("span") - _, status, _ = unpack_werkzeug_response( - client.get(reverse("postgres_select_slow_from_supplement")) - ) - assert status == "200 OK" + _, status, _ = unpack_werkzeug_response( + client.get(reverse("postgres_select_slow_from_supplement")) + ) + assert status == "200 OK" - sentry_sdk.flush() - spans = [item.payload for item in items] + sentry_sdk.flush() + spans = [item.payload for item in items] - for span in spans: - if span["attributes"].get("sentry.op") == "db" and "auth_user" in span.get( - "name" - ): - attributes = span.get("attributes", {}) + for span in spans: + if span["attributes"].get("sentry.op") == "db" and "auth_user" in span.get( + "name" + ): + attributes = span.get("attributes", {}) - assert SPANDATA.CODE_LINE_NUMBER in attributes - assert SPANDATA.CODE_NAMESPACE in attributes - assert SPANDATA.CODE_FILE_PATH in attributes - assert SPANDATA.CODE_FUNCTION in attributes + assert SPANDATA.CODE_LINE_NUMBER in attributes + assert SPANDATA.CODE_NAMESPACE in attributes + assert SPANDATA.CODE_FILE_PATH in attributes + assert SPANDATA.CODE_FUNCTION in attributes - assert type(attributes.get(SPANDATA.CODE_LINE_NUMBER)) == int - assert attributes.get(SPANDATA.CODE_LINE_NUMBER) > 0 - assert attributes.get(SPANDATA.CODE_NAMESPACE) == "django_helpers.views" - assert ( - attributes.get(SPANDATA.CODE_FILE_PATH) == "django_helpers/views.py" - ) + assert type(attributes.get(SPANDATA.CODE_LINE_NUMBER)) == int + assert attributes.get(SPANDATA.CODE_LINE_NUMBER) > 0 + assert attributes.get(SPANDATA.CODE_NAMESPACE) == "django_helpers.views" + assert attributes.get(SPANDATA.CODE_FILE_PATH) == "django_helpers/views.py" - is_relative_path = attributes.get(SPANDATA.CODE_FILE_PATH)[0] != os.sep - assert is_relative_path + is_relative_path = attributes.get(SPANDATA.CODE_FILE_PATH)[0] != os.sep + assert is_relative_path - assert attributes.get(SPANDATA.CODE_FUNCTION) == "postgres_select_orm" - break - else: - raise AssertionError("No db span found") + assert attributes.get(SPANDATA.CODE_FUNCTION) == "postgres_select_orm" + break else: - events = capture_events() - - _, status, _ = unpack_werkzeug_response( - client.get(reverse("postgres_select_slow_from_supplement")) - ) - assert status == "200 OK" - - (event,) = events - for span in event["spans"]: - if span.get("op") == "db" and "auth_user" in span.get("description"): - data = span.get("data", {}) - - assert SPANDATA.CODE_LINENO in data - assert SPANDATA.CODE_NAMESPACE in data - assert SPANDATA.CODE_FILEPATH in data - assert SPANDATA.CODE_FUNCTION in data - - assert type(data.get(SPANDATA.CODE_LINENO)) == int - assert data.get(SPANDATA.CODE_LINENO) > 0 - assert data.get(SPANDATA.CODE_NAMESPACE) == "django_helpers.views" - assert data.get(SPANDATA.CODE_FILEPATH) == "django_helpers/views.py" - - is_relative_path = data.get(SPANDATA.CODE_FILEPATH)[0] != os.sep - assert is_relative_path - - assert data.get(SPANDATA.CODE_FUNCTION) == "postgres_select_orm" - break - else: - raise AssertionError("No db span found") + raise AssertionError("No db span found") @pytest.mark.forked @pytest_mark_django_db_decorator(transaction=True) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_query_source_with_in_app_exclude( sentry_init, client, - capture_events, capture_items, - span_streaming, ): sentry_init( integrations=[DjangoIntegration()], @@ -398,7 +260,6 @@ def test_query_source_with_in_app_exclude( enable_db_query_source=True, db_query_source_threshold_ms=0, in_app_exclude=["tests.integrations.django.myapp.views"], - trace_lifecycle="stream" if span_streaming else "static", ) if "postgres" not in connections: @@ -407,111 +268,60 @@ def test_query_source_with_in_app_exclude( # trigger Django to open a new connection by marking the existing one as None. connections["postgres"].connection = None - if span_streaming: - items = capture_items("span") + items = capture_items("span") - _, status, _ = unpack_werkzeug_response( - client.get(reverse("postgres_select_orm")) - ) - assert status == "200 OK" - - sentry_sdk.flush() - spans = [item.payload for item in items] - - for span in spans: - if span["attributes"].get("sentry.op") == "db" and "auth_user" in span.get( - "name" - ): - attributes = span.get("attributes", {}) - - assert SPANDATA.CODE_LINE_NUMBER in attributes - assert SPANDATA.CODE_NAMESPACE in attributes - assert SPANDATA.CODE_FILE_PATH in attributes - assert SPANDATA.CODE_FUNCTION in attributes - - assert type(attributes.get(SPANDATA.CODE_LINE_NUMBER)) == int - assert attributes.get(SPANDATA.CODE_LINE_NUMBER) > 0 - - if DJANGO_VERSION >= (1, 11): - assert ( - attributes.get(SPANDATA.CODE_NAMESPACE) - == "tests.integrations.django.myapp.settings" - ) - assert attributes.get(SPANDATA.CODE_FILE_PATH).endswith( - "tests/integrations/django/myapp/settings.py" - ) - assert attributes.get(SPANDATA.CODE_FUNCTION) == "middleware" - else: - assert ( - attributes.get(SPANDATA.CODE_NAMESPACE) - == "tests.integrations.django.test_db_query_data" - ) - assert attributes.get(SPANDATA.CODE_FILE_PATH).endswith( - "tests/integrations/django/test_db_query_data.py" - ) - assert ( - attributes.get(SPANDATA.CODE_FUNCTION) - == "test_query_source_with_in_app_exclude" - ) - break - else: - raise AssertionError("No db span found") - else: - events = capture_events() + _, status, _ = unpack_werkzeug_response(client.get(reverse("postgres_select_orm"))) + assert status == "200 OK" - _, status, _ = unpack_werkzeug_response( - client.get(reverse("postgres_select_orm")) - ) - assert status == "200 OK" - - (event,) = events - for span in event["spans"]: - if span.get("op") == "db" and "auth_user" in span.get("description"): - data = span.get("data", {}) - - assert SPANDATA.CODE_LINENO in data - assert SPANDATA.CODE_NAMESPACE in data - assert SPANDATA.CODE_FILEPATH in data - assert SPANDATA.CODE_FUNCTION in data - - assert type(data.get(SPANDATA.CODE_LINENO)) == int - assert data.get(SPANDATA.CODE_LINENO) > 0 - - if DJANGO_VERSION >= (1, 11): - assert ( - data.get(SPANDATA.CODE_NAMESPACE) - == "tests.integrations.django.myapp.settings" - ) - assert data.get(SPANDATA.CODE_FILEPATH).endswith( - "tests/integrations/django/myapp/settings.py" - ) - assert data.get(SPANDATA.CODE_FUNCTION) == "middleware" - else: - assert ( - data.get(SPANDATA.CODE_NAMESPACE) - == "tests.integrations.django.test_db_query_data" - ) - assert data.get(SPANDATA.CODE_FILEPATH).endswith( - "tests/integrations/django/test_db_query_data.py" - ) - assert ( - data.get(SPANDATA.CODE_FUNCTION) - == "test_query_source_with_in_app_exclude" - ) - break - else: - raise AssertionError("No db span found") + sentry_sdk.flush() + spans = [item.payload for item in items] + + for span in spans: + if span["attributes"].get("sentry.op") == "db" and "auth_user" in span.get( + "name" + ): + attributes = span.get("attributes", {}) + + assert SPANDATA.CODE_LINE_NUMBER in attributes + assert SPANDATA.CODE_NAMESPACE in attributes + assert SPANDATA.CODE_FILE_PATH in attributes + assert SPANDATA.CODE_FUNCTION in attributes + + assert type(attributes.get(SPANDATA.CODE_LINE_NUMBER)) == int + assert attributes.get(SPANDATA.CODE_LINE_NUMBER) > 0 + + if DJANGO_VERSION >= (1, 11): + assert ( + attributes.get(SPANDATA.CODE_NAMESPACE) + == "tests.integrations.django.myapp.settings" + ) + assert attributes.get(SPANDATA.CODE_FILE_PATH).endswith( + "tests/integrations/django/myapp/settings.py" + ) + assert attributes.get(SPANDATA.CODE_FUNCTION) == "middleware" + else: + assert ( + attributes.get(SPANDATA.CODE_NAMESPACE) + == "tests.integrations.django.test_db_query_data" + ) + assert attributes.get(SPANDATA.CODE_FILE_PATH).endswith( + "tests/integrations/django/test_db_query_data.py" + ) + assert ( + attributes.get(SPANDATA.CODE_FUNCTION) + == "test_query_source_with_in_app_exclude" + ) + break + else: + raise AssertionError("No db span found") @pytest.mark.forked @pytest_mark_django_db_decorator(transaction=True) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_query_source_with_in_app_include( sentry_init, client, - capture_events, capture_items, - span_streaming, ): sentry_init( integrations=[DjangoIntegration()], @@ -520,7 +330,6 @@ def test_query_source_with_in_app_include( enable_db_query_source=True, db_query_source_threshold_ms=0, in_app_include=["django"], - trace_lifecycle="stream" if span_streaming else "static", ) if "postgres" not in connections: @@ -529,84 +338,47 @@ def test_query_source_with_in_app_include( # trigger Django to open a new connection by marking the existing one as None. connections["postgres"].connection = None - if span_streaming: - items = capture_items("span") + items = capture_items("span") - _, status, _ = unpack_werkzeug_response( - client.get(reverse("postgres_select_orm")) - ) - assert status == "200 OK" + _, status, _ = unpack_werkzeug_response(client.get(reverse("postgres_select_orm"))) + assert status == "200 OK" - sentry_sdk.flush() - spans = [item.payload for item in items] + sentry_sdk.flush() + spans = [item.payload for item in items] - for span in spans: - if span["attributes"].get("sentry.op") == "db" and "auth_user" in span.get( - "name" - ): - attributes = span.get("attributes", {}) + for span in spans: + if span["attributes"].get("sentry.op") == "db" and "auth_user" in span.get( + "name" + ): + attributes = span.get("attributes", {}) - assert SPANDATA.CODE_LINE_NUMBER in attributes - assert SPANDATA.CODE_NAMESPACE in attributes - assert SPANDATA.CODE_FILE_PATH in attributes - assert SPANDATA.CODE_FUNCTION in attributes + assert SPANDATA.CODE_LINE_NUMBER in attributes + assert SPANDATA.CODE_NAMESPACE in attributes + assert SPANDATA.CODE_FILE_PATH in attributes + assert SPANDATA.CODE_FUNCTION in attributes - assert type(attributes.get(SPANDATA.CODE_LINE_NUMBER)) == int - assert attributes.get(SPANDATA.CODE_LINE_NUMBER) > 0 + assert type(attributes.get(SPANDATA.CODE_LINE_NUMBER)) == int + assert attributes.get(SPANDATA.CODE_LINE_NUMBER) > 0 - assert ( - attributes.get(SPANDATA.CODE_NAMESPACE) - == "django.db.models.sql.compiler" - ) - assert attributes.get(SPANDATA.CODE_FILE_PATH).endswith( - "django/db/models/sql/compiler.py" - ) - assert attributes.get(SPANDATA.CODE_FUNCTION) == "execute_sql" - break - else: - raise AssertionError("No db span found") + assert ( + attributes.get(SPANDATA.CODE_NAMESPACE) + == "django.db.models.sql.compiler" + ) + assert attributes.get(SPANDATA.CODE_FILE_PATH).endswith( + "django/db/models/sql/compiler.py" + ) + assert attributes.get(SPANDATA.CODE_FUNCTION) == "execute_sql" + break else: - events = capture_events() - - _, status, _ = unpack_werkzeug_response( - client.get(reverse("postgres_select_orm")) - ) - assert status == "200 OK" - - (event,) = events - for span in event["spans"]: - if span.get("op") == "db" and "auth_user" in span.get("description"): - data = span.get("data", {}) - - assert SPANDATA.CODE_LINENO in data - assert SPANDATA.CODE_NAMESPACE in data - assert SPANDATA.CODE_FILEPATH in data - assert SPANDATA.CODE_FUNCTION in data - - assert type(data.get(SPANDATA.CODE_LINENO)) == int - assert data.get(SPANDATA.CODE_LINENO) > 0 - - assert ( - data.get(SPANDATA.CODE_NAMESPACE) == "django.db.models.sql.compiler" - ) - assert data.get(SPANDATA.CODE_FILEPATH).endswith( - "django/db/models/sql/compiler.py" - ) - assert data.get(SPANDATA.CODE_FUNCTION) == "execute_sql" - break - else: - raise AssertionError("No db span found") + raise AssertionError("No db span found") @pytest.mark.forked @pytest_mark_django_db_decorator(transaction=True) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_no_query_source_if_duration_too_short( sentry_init, client, - capture_events, capture_items, - span_streaming, ): sentry_init( integrations=[DjangoIntegration()], @@ -614,7 +386,6 @@ def test_no_query_source_if_duration_too_short( traces_sample_rate=1.0, enable_db_query_source=True, db_query_source_threshold_ms=100, - trace_lifecycle="stream" if span_streaming else "static", ) if "postgres" not in connections: @@ -630,89 +401,53 @@ def __init__(self, *args, **kwargs): def __enter__(self): self.span = self._ctx_mgr.__enter__() - if span_streaming: - self.span._start_timestamp = datetime(2024, 1, 1, microsecond=0) - self.span._end_timestamp = datetime(2024, 1, 1, microsecond=99999) + self.span._start_timestamp = datetime(2024, 1, 1, microsecond=0) + self.span._end_timestamp = datetime(2024, 1, 1, microsecond=99999) return self.span def __exit__(self, type, value, traceback): - if span_streaming: - self.span._end_timestamp = None - self._ctx_mgr.__exit__(type, value, traceback) - self.span._start_timestamp = datetime(2024, 1, 1, microsecond=0) - self.span._end_timestamp = datetime(2024, 1, 1, microsecond=99999) - return - - self.span.start_timestamp = datetime(2024, 1, 1, microsecond=0) - self.span.timestamp = datetime(2024, 1, 1, microsecond=99999) + self.span._end_timestamp = None self._ctx_mgr.__exit__(type, value, traceback) + self.span._start_timestamp = datetime(2024, 1, 1, microsecond=0) + self.span._end_timestamp = datetime(2024, 1, 1, microsecond=99999) - if span_streaming: - items = capture_items("span") - - with mock.patch( - "sentry_sdk.integrations.django.record_sql_queries", - fake_record_sql_queries, - ): - _, status, _ = unpack_werkzeug_response( - client.get(reverse("postgres_select_orm")) - ) - - assert status == "200 OK" + items = capture_items("span") - sentry_sdk.flush() - spans = [item.payload for item in items] + with mock.patch( + "sentry_sdk.integrations.django.record_sql_queries", + fake_record_sql_queries, + ): + _, status, _ = unpack_werkzeug_response( + client.get(reverse("postgres_select_orm")) + ) - for span in spans: - if span["attributes"].get("sentry.op") == "db" and "auth_user" in span.get( - "name" - ): - attributes = span.get("attributes", {}) + assert status == "200 OK" - assert SPANDATA.CODE_LINE_NUMBER not in attributes - assert SPANDATA.CODE_NAMESPACE not in attributes - assert SPANDATA.CODE_FILE_PATH not in attributes - assert SPANDATA.CODE_FUNCTION not in attributes - break - else: - raise AssertionError("No db span found") - else: - events = capture_events() + sentry_sdk.flush() + spans = [item.payload for item in items] - with mock.patch( - "sentry_sdk.integrations.django.record_sql_queries", - fake_record_sql_queries, + for span in spans: + if span["attributes"].get("sentry.op") == "db" and "auth_user" in span.get( + "name" ): - _, status, _ = unpack_werkzeug_response( - client.get(reverse("postgres_select_orm")) - ) - - assert status == "200 OK" + attributes = span.get("attributes", {}) - (event,) = events - for span in event["spans"]: - if span.get("op") == "db" and "auth_user" in span.get("description"): - data = span.get("data", {}) - - assert SPANDATA.CODE_LINENO not in data - assert SPANDATA.CODE_NAMESPACE not in data - assert SPANDATA.CODE_FILEPATH not in data - assert SPANDATA.CODE_FUNCTION not in data - break - else: - raise AssertionError("No db span found") + assert SPANDATA.CODE_LINE_NUMBER not in attributes + assert SPANDATA.CODE_NAMESPACE not in attributes + assert SPANDATA.CODE_FILE_PATH not in attributes + assert SPANDATA.CODE_FUNCTION not in attributes + break + else: + raise AssertionError("No db span found") @pytest.mark.forked @pytest_mark_django_db_decorator(transaction=True) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_query_source_if_duration_over_threshold( sentry_init, client, - capture_events, capture_items, - span_streaming, ): sentry_init( integrations=[DjangoIntegration()], @@ -720,7 +455,6 @@ def test_query_source_if_duration_over_threshold( traces_sample_rate=1.0, enable_db_query_source=True, db_query_source_threshold_ms=100, - trace_lifecycle="stream" if span_streaming else "static", ) if "postgres" not in connections: @@ -736,126 +470,73 @@ def __init__(self, *args, **kwargs): def __enter__(self): self.span = self._ctx_mgr.__enter__() - if span_streaming: - self.span._start_timestamp = datetime(2024, 1, 1, microsecond=0) - self.span._end_timestamp = datetime(2024, 1, 1, microsecond=101000) + self.span._start_timestamp = datetime(2024, 1, 1, microsecond=0) + self.span._end_timestamp = datetime(2024, 1, 1, microsecond=101000) return self.span def __exit__(self, type, value, traceback): - if span_streaming: - self.span._end_timestamp = None - self._ctx_mgr.__exit__(type, value, traceback) - self.span._start_timestamp = datetime(2024, 1, 1, microsecond=0) - self.span._end_timestamp = datetime(2024, 1, 1, microsecond=101000) - return - - self.span.start_timestamp = datetime(2024, 1, 1, microsecond=0) - self.span.timestamp = datetime(2024, 1, 1, microsecond=101000) + self.span._end_timestamp = None self._ctx_mgr.__exit__(type, value, traceback) + self.span._start_timestamp = datetime(2024, 1, 1, microsecond=0) + self.span._end_timestamp = datetime(2024, 1, 1, microsecond=101000) - if span_streaming: - items = capture_items("span") - - with mock.patch( - "sentry_sdk.integrations.django.record_sql_queries", - fake_record_sql_queries, - ): - _, status, _ = unpack_werkzeug_response( - client.get(reverse("postgres_select_orm")) - ) - - assert status == "200 OK" - - sentry_sdk.flush() - spans = [item.payload for item in items] + items = capture_items("span") - for span in spans: - if span["attributes"].get("sentry.op") == "db" and "auth_user" in span.get( - "name" - ): - attributes = span.get("attributes", {}) - - assert SPANDATA.CODE_LINE_NUMBER in attributes - assert SPANDATA.CODE_NAMESPACE in attributes - assert SPANDATA.CODE_FILE_PATH in attributes - assert SPANDATA.CODE_FUNCTION in attributes - - assert type(attributes.get(SPANDATA.CODE_LINE_NUMBER)) == int - assert attributes.get(SPANDATA.CODE_LINE_NUMBER) > 0 - - assert ( - attributes.get(SPANDATA.CODE_NAMESPACE) - == "tests.integrations.django.myapp.views" - ) - assert attributes.get(SPANDATA.CODE_FILE_PATH).endswith( - "tests/integrations/django/myapp/views.py" - ) + with mock.patch( + "sentry_sdk.integrations.django.record_sql_queries", + fake_record_sql_queries, + ): + _, status, _ = unpack_werkzeug_response( + client.get(reverse("postgres_select_orm")) + ) - is_relative_path = attributes.get(SPANDATA.CODE_FILE_PATH)[0] != os.sep - assert is_relative_path + assert status == "200 OK" - assert attributes.get(SPANDATA.CODE_FUNCTION) == "postgres_select_orm" - break - else: - raise AssertionError("No db span found") - else: - events = capture_events() + sentry_sdk.flush() + spans = [item.payload for item in items] - with mock.patch( - "sentry_sdk.integrations.django.record_sql_queries", - fake_record_sql_queries, + for span in spans: + if span["attributes"].get("sentry.op") == "db" and "auth_user" in span.get( + "name" ): - _, status, _ = unpack_werkzeug_response( - client.get(reverse("postgres_select_orm")) - ) - - assert status == "200 OK" - - (event,) = events - for span in event["spans"]: - if span.get("op") == "db" and "auth_user" in span.get("description"): - data = span.get("data", {}) + attributes = span.get("attributes", {}) - assert SPANDATA.CODE_LINENO in data - assert SPANDATA.CODE_NAMESPACE in data - assert SPANDATA.CODE_FILEPATH in data - assert SPANDATA.CODE_FUNCTION in data + assert SPANDATA.CODE_LINE_NUMBER in attributes + assert SPANDATA.CODE_NAMESPACE in attributes + assert SPANDATA.CODE_FILE_PATH in attributes + assert SPANDATA.CODE_FUNCTION in attributes - assert type(data.get(SPANDATA.CODE_LINENO)) == int - assert data.get(SPANDATA.CODE_LINENO) > 0 + assert type(attributes.get(SPANDATA.CODE_LINE_NUMBER)) == int + assert attributes.get(SPANDATA.CODE_LINE_NUMBER) > 0 - assert ( - data.get(SPANDATA.CODE_NAMESPACE) - == "tests.integrations.django.myapp.views" - ) - assert data.get(SPANDATA.CODE_FILEPATH).endswith( - "tests/integrations/django/myapp/views.py" - ) + assert ( + attributes.get(SPANDATA.CODE_NAMESPACE) + == "tests.integrations.django.myapp.views" + ) + assert attributes.get(SPANDATA.CODE_FILE_PATH).endswith( + "tests/integrations/django/myapp/views.py" + ) - is_relative_path = data.get(SPANDATA.CODE_FILEPATH)[0] != os.sep - assert is_relative_path + is_relative_path = attributes.get(SPANDATA.CODE_FILE_PATH)[0] != os.sep + assert is_relative_path - assert data.get(SPANDATA.CODE_FUNCTION) == "postgres_select_orm" - break - else: - raise AssertionError("No db span found") + assert attributes.get(SPANDATA.CODE_FUNCTION) == "postgres_select_orm" + break + else: + raise AssertionError("No db span found") @pytest.mark.forked @pytest_mark_django_db_decorator(transaction=True) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_db_span_origin_execute( sentry_init, client, - capture_events, capture_items, - span_streaming, ): sentry_init( integrations=[DjangoIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) if "postgres" not in connections: @@ -864,105 +545,59 @@ def test_db_span_origin_execute( # trigger Django to open a new connection by marking the existing one as None. connections["postgres"].connection = None - if span_streaming: - items = capture_items("span") - - client.get(reverse("postgres_select_orm")) - - sentry_sdk.flush() - spans = [item.payload for item in items] - - assert spans[1]["attributes"]["sentry.origin"] == "auto.http.django" - - for span in spans: - if span["attributes"]["sentry.op"] == "db": - assert span["attributes"]["sentry.origin"] == "auto.db.django" - else: - assert span["attributes"]["sentry.origin"] == "auto.http.django" - else: - events = capture_events() + items = capture_items("span") - client.get(reverse("postgres_select_orm")) + client.get(reverse("postgres_select_orm")) - (event,) = events + sentry_sdk.flush() + spans = [item.payload for item in items] - assert event["contexts"]["trace"]["origin"] == "auto.http.django" + assert spans[1]["attributes"]["sentry.origin"] == "auto.http.django" - for span in event["spans"]: - if span["op"] == "db": - assert span["origin"] == "auto.db.django" - else: - assert span["origin"] == "auto.http.django" + for span in spans: + if span["attributes"]["sentry.op"] == "db": + assert span["attributes"]["sentry.origin"] == "auto.db.django" + else: + assert span["attributes"]["sentry.origin"] == "auto.http.django" @pytest.mark.forked @pytest_mark_django_db_decorator(transaction=True) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_db_span_origin_executemany( sentry_init, - capture_events, capture_items, - span_streaming, ): sentry_init( integrations=[DjangoIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) if "postgres" not in connections: pytest.skip("postgres tests disabled") - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="custom parent"): - from django.db import connection, transaction - - cursor = connection.cursor() - - query = """UPDATE auth_user SET username = %s where id = %s;""" - query_list = ( - ( - "test1", - 1, - ), - ( - "test2", - 2, - ), - ) - cursor.executemany(query, query_list) - - transaction.commit() - - sentry_sdk.flush() - spans = [item.payload for item in items] - - assert spans[1]["attributes"]["sentry.origin"] == "manual" - assert spans[0]["attributes"]["sentry.origin"] == "auto.db.django" - else: - events = capture_events() - with start_transaction(name="test_transaction"): - from django.db import connection, transaction - - cursor = connection.cursor() - - query = """UPDATE auth_user SET username = %s where id = %s;""" - query_list = ( - ( - "test1", - 1, - ), - ( - "test2", - 2, - ), - ) - cursor.executemany(query, query_list) + items = capture_items("span") + with sentry_sdk.start_span(name="custom parent"): + from django.db import connection, transaction + + cursor = connection.cursor() + + query = """UPDATE auth_user SET username = %s where id = %s;""" + query_list = ( + ( + "test1", + 1, + ), + ( + "test2", + 2, + ), + ) + cursor.executemany(query, query_list) - transaction.commit() + transaction.commit() - (event,) = events + sentry_sdk.flush() + spans = [item.payload for item in items] - assert event["contexts"]["trace"]["origin"] == "manual" - assert event["spans"][0]["origin"] == "auto.db.django" + assert spans[1]["attributes"]["sentry.origin"] == "manual" + assert spans[0]["attributes"]["sentry.origin"] == "auto.db.django" diff --git a/tests/integrations/django/test_db_transactions.py b/tests/integrations/django/test_db_transactions.py index 3b5dadfea7..743a329325 100644 --- a/tests/integrations/django/test_db_transactions.py +++ b/tests/integrations/django/test_db_transactions.py @@ -1,4 +1,3 @@ -import itertools import os from datetime import datetime @@ -14,7 +13,6 @@ from werkzeug.test import Client import sentry_sdk -from sentry_sdk import start_transaction from sentry_sdk.consts import SPANDATA, SPANNAME from sentry_sdk.integrations.django import DjangoIntegration from tests.integrations.django.myapp.wsgi import application @@ -28,18 +26,14 @@ def client(): @pytest.mark.forked @pytest_mark_django_db_decorator(transaction=True) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_db_transaction_spans_disabled_no_autocommit( sentry_init, client, - capture_events, capture_items, - span_streaming, ): sentry_init( integrations=[DjangoIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) if "postgres" not in connections: @@ -48,18 +42,17 @@ def test_db_transaction_spans_disabled_no_autocommit( # trigger Django to open a new connection by marking the existing one as None. connections["postgres"].connection = None - if span_streaming: - items = capture_items("span") + items = capture_items("span") - client.get(reverse("postgres_insert_orm_no_autocommit_rollback")) - client.get(reverse("postgres_insert_orm_no_autocommit")) + client.get(reverse("postgres_insert_orm_no_autocommit_rollback")) + client.get(reverse("postgres_insert_orm_no_autocommit")) - with sentry_sdk.traces.start_span(name="custom parent"): - from django.db import connection, transaction + with sentry_sdk.start_span(name="custom parent"): + from django.db import connection, transaction - cursor = connection.cursor() + cursor = connection.cursor() - query = """INSERT INTO auth_user ( + query = """INSERT INTO auth_user ( password, is_superuser, username, @@ -72,34 +65,34 @@ def test_db_transaction_spans_disabled_no_autocommit( ) VALUES ('password', false, %s, %s, %s, %s, false, true, %s);""" - query_list = ( - ( - "user1", - "John", - "Doe", - "user1@example.com", - datetime(1970, 1, 1), - ), - ( - "user2", - "Max", - "Mustermann", - "user2@example.com", - datetime(1970, 1, 1), - ), - ) + query_list = ( + ( + "user1", + "John", + "Doe", + "user1@example.com", + datetime(1970, 1, 1), + ), + ( + "user2", + "Max", + "Mustermann", + "user2@example.com", + datetime(1970, 1, 1), + ), + ) - transaction.set_autocommit(False) - cursor.executemany(query, query_list) - transaction.rollback() - transaction.set_autocommit(True) + transaction.set_autocommit(False) + cursor.executemany(query, query_list) + transaction.rollback() + transaction.set_autocommit(True) - with sentry_sdk.traces.start_span(name="custom parent"): - from django.db import connection, transaction + with sentry_sdk.start_span(name="custom parent"): + from django.db import connection, transaction - cursor = connection.cursor() + cursor = connection.cursor() - query = """INSERT INTO auth_user ( + query = """INSERT INTO auth_user ( password, is_superuser, username, @@ -112,65 +105,84 @@ def test_db_transaction_spans_disabled_no_autocommit( ) VALUES ('password', false, %s, %s, %s, %s, false, true, %s);""" - query_list = ( - ( - "user1", - "John", - "Doe", - "user1@example.com", - datetime(1970, 1, 1), - ), - ( - "user2", - "Max", - "Mustermann", - "user2@example.com", - datetime(1970, 1, 1), - ), - ) + query_list = ( + ( + "user1", + "John", + "Doe", + "user1@example.com", + datetime(1970, 1, 1), + ), + ( + "user2", + "Max", + "Mustermann", + "user2@example.com", + datetime(1970, 1, 1), + ), + ) + + transaction.set_autocommit(False) + cursor.executemany(query, query_list) + transaction.commit() + transaction.set_autocommit(True) + + sentry_sdk.flush() + spans = [item.payload for item in items] + + postgres_rollback = spans[4] + assert postgres_rollback["is_segment"] is True + postgres_commit = spans[9] + assert postgres_commit["is_segment"] is True + sqlite_rollback = spans[11] + assert sqlite_rollback["is_segment"] is True + sqlite_commit = spans[13] + assert sqlite_commit["is_segment"] is True + + # Ensure operation is persisted + assert User.objects.using("postgres").exists() + + assert postgres_rollback["attributes"]["sentry.origin"] == "auto.http.django" + assert postgres_commit["attributes"]["sentry.origin"] == "auto.http.django" + assert sqlite_rollback["attributes"]["sentry.origin"] == "manual" + assert sqlite_commit["attributes"]["sentry.origin"] == "manual" + + commit_spans = [ + span + for span in spans + if span["attributes"].get(SPANDATA.DB_OPERATION_NAME) == SPANNAME.DB_COMMIT + or span["attributes"].get(SPANDATA.DB_OPERATION_NAME) == SPANNAME.DB_ROLLBACK + ] + assert len(commit_spans) == 0 - transaction.set_autocommit(False) - cursor.executemany(query, query_list) - transaction.commit() - transaction.set_autocommit(True) - - sentry_sdk.flush() - spans = [item.payload for item in items] - - postgres_rollback = spans[4] - assert postgres_rollback["is_segment"] is True - postgres_commit = spans[9] - assert postgres_commit["is_segment"] is True - sqlite_rollback = spans[11] - assert sqlite_rollback["is_segment"] is True - sqlite_commit = spans[13] - assert sqlite_commit["is_segment"] is True - - # Ensure operation is persisted - assert User.objects.using("postgres").exists() - - assert postgres_rollback["attributes"]["sentry.origin"] == "auto.http.django" - assert postgres_commit["attributes"]["sentry.origin"] == "auto.http.django" - assert sqlite_rollback["attributes"]["sentry.origin"] == "manual" - assert sqlite_commit["attributes"]["sentry.origin"] == "manual" - - commit_spans = [ - span - for span in spans - if span["attributes"].get(SPANDATA.DB_OPERATION_NAME) == SPANNAME.DB_COMMIT - or span["attributes"].get(SPANDATA.DB_OPERATION_NAME) - == SPANNAME.DB_ROLLBACK - ] - assert len(commit_spans) == 0 - else: - events = capture_events() - - client.get(reverse("postgres_insert_orm_no_autocommit_rollback")) - client.get(reverse("postgres_insert_orm_no_autocommit")) - - with start_transaction(name="test_transaction"): - from django.db import connection, transaction +@pytest.mark.forked +@pytest_mark_django_db_decorator(transaction=True) +def test_db_transaction_spans_disabled_atomic( + sentry_init, + client, + capture_items, +): + sentry_init( + integrations=[DjangoIntegration()], + traces_sample_rate=1.0, + ) + + if "postgres" not in connections: + pytest.skip("postgres tests disabled") + + # trigger Django to open a new connection by marking the existing one as None. + connections["postgres"].connection = None + + items = capture_items("span") + + client.get(reverse("postgres_insert_orm_atomic_rollback")) + client.get(reverse("postgres_insert_orm_atomic")) + + with sentry_sdk.start_span(name="custom parent"): + from django.db import connection, transaction + + with transaction.atomic(): cursor = connection.cursor() query = """INSERT INTO auth_user ( @@ -202,15 +214,13 @@ def test_db_transaction_spans_disabled_no_autocommit( datetime(1970, 1, 1), ), ) - - transaction.set_autocommit(False) cursor.executemany(query, query_list) - transaction.rollback() - transaction.set_autocommit(True) + transaction.set_rollback(True) - with start_transaction(name="test_transaction"): - from django.db import connection, transaction + with sentry_sdk.start_span(name="custom parent"): + from django.db import connection, transaction + with transaction.atomic(): cursor = connection.cursor() query = """INSERT INTO auth_user ( @@ -242,278 +252,39 @@ def test_db_transaction_spans_disabled_no_autocommit( datetime(1970, 1, 1), ), ) - - transaction.set_autocommit(False) cursor.executemany(query, query_list) - transaction.commit() - transaction.set_autocommit(True) - - (postgres_rollback, postgres_commit, sqlite_rollback, sqlite_commit) = events - - # Ensure operation is persisted - assert User.objects.using("postgres").exists() - - assert postgres_rollback["contexts"]["trace"]["origin"] == "auto.http.django" - assert postgres_commit["contexts"]["trace"]["origin"] == "auto.http.django" - assert sqlite_rollback["contexts"]["trace"]["origin"] == "manual" - assert sqlite_commit["contexts"]["trace"]["origin"] == "manual" - - commit_spans = [ - span - for span in itertools.chain( - postgres_rollback["spans"], - postgres_commit["spans"], - sqlite_rollback["spans"], - sqlite_commit["spans"], - ) - if span["data"].get(SPANDATA.DB_OPERATION) == SPANNAME.DB_COMMIT - or span["data"].get(SPANDATA.DB_OPERATION) == SPANNAME.DB_ROLLBACK - ] - assert len(commit_spans) == 0 - - -@pytest.mark.forked -@pytest_mark_django_db_decorator(transaction=True) -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_db_transaction_spans_disabled_atomic( - sentry_init, - client, - capture_events, - capture_items, - span_streaming, -): - sentry_init( - integrations=[DjangoIntegration()], - traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", - ) - - if "postgres" not in connections: - pytest.skip("postgres tests disabled") - - # trigger Django to open a new connection by marking the existing one as None. - connections["postgres"].connection = None - - if span_streaming: - items = capture_items("span") - - client.get(reverse("postgres_insert_orm_atomic_rollback")) - client.get(reverse("postgres_insert_orm_atomic")) - - with sentry_sdk.traces.start_span(name="custom parent"): - from django.db import connection, transaction - - with transaction.atomic(): - cursor = connection.cursor() - - query = """INSERT INTO auth_user ( - password, - is_superuser, - username, - first_name, - last_name, - email, - is_staff, - is_active, - date_joined -) -VALUES ('password', false, %s, %s, %s, %s, false, true, %s);""" - - query_list = ( - ( - "user1", - "John", - "Doe", - "user1@example.com", - datetime(1970, 1, 1), - ), - ( - "user2", - "Max", - "Mustermann", - "user2@example.com", - datetime(1970, 1, 1), - ), - ) - cursor.executemany(query, query_list) - transaction.set_rollback(True) - - with sentry_sdk.traces.start_span(name="custom parent"): - from django.db import connection, transaction - - with transaction.atomic(): - cursor = connection.cursor() - - query = """INSERT INTO auth_user ( - password, - is_superuser, - username, - first_name, - last_name, - email, - is_staff, - is_active, - date_joined -) -VALUES ('password', false, %s, %s, %s, %s, false, true, %s);""" - - query_list = ( - ( - "user1", - "John", - "Doe", - "user1@example.com", - datetime(1970, 1, 1), - ), - ( - "user2", - "Max", - "Mustermann", - "user2@example.com", - datetime(1970, 1, 1), - ), - ) - cursor.executemany(query, query_list) - - sentry_sdk.flush() - spans = [item.payload for item in items] - - postgres_rollback = spans[4] - assert postgres_rollback["is_segment"] is True - postgres_commit = spans[9] - assert postgres_commit["is_segment"] is True - sqlite_rollback = spans[12] - assert sqlite_rollback["is_segment"] is True - sqlite_commit = spans[15] - assert sqlite_commit["is_segment"] is True - - commit_spans = [ - span - for span in spans - if span["attributes"].get(SPANDATA.DB_OPERATION_NAME) == SPANNAME.DB_COMMIT - or span["attributes"].get(SPANDATA.DB_OPERATION_NAME) - == SPANNAME.DB_ROLLBACK - ] - else: - events = capture_events() - - client.get(reverse("postgres_insert_orm_atomic_rollback")) - client.get(reverse("postgres_insert_orm_atomic")) - - with start_transaction(name="test_transaction"): - from django.db import connection, transaction - - with transaction.atomic(): - cursor = connection.cursor() - - query = """INSERT INTO auth_user ( - password, - is_superuser, - username, - first_name, - last_name, - email, - is_staff, - is_active, - date_joined -) -VALUES ('password', false, %s, %s, %s, %s, false, true, %s);""" - - query_list = ( - ( - "user1", - "John", - "Doe", - "user1@example.com", - datetime(1970, 1, 1), - ), - ( - "user2", - "Max", - "Mustermann", - "user2@example.com", - datetime(1970, 1, 1), - ), - ) - cursor.executemany(query, query_list) - transaction.set_rollback(True) - - with start_transaction(name="test_transaction"): - from django.db import connection, transaction - - with transaction.atomic(): - cursor = connection.cursor() - - query = """INSERT INTO auth_user ( - password, - is_superuser, - username, - first_name, - last_name, - email, - is_staff, - is_active, - date_joined -) -VALUES ('password', false, %s, %s, %s, %s, false, true, %s);""" - - query_list = ( - ( - "user1", - "John", - "Doe", - "user1@example.com", - datetime(1970, 1, 1), - ), - ( - "user2", - "Max", - "Mustermann", - "user2@example.com", - datetime(1970, 1, 1), - ), - ) - cursor.executemany(query, query_list) - - (postgres_rollback, postgres_commit, sqlite_rollback, sqlite_commit) = events - - # Ensure operation is persisted - assert User.objects.using("postgres").exists() - - assert postgres_rollback["contexts"]["trace"]["origin"] == "auto.http.django" - assert postgres_commit["contexts"]["trace"]["origin"] == "auto.http.django" - assert sqlite_rollback["contexts"]["trace"]["origin"] == "manual" - assert sqlite_commit["contexts"]["trace"]["origin"] == "manual" - - commit_spans = [ - span - for span in itertools.chain( - postgres_rollback["spans"], - postgres_commit["spans"], - sqlite_rollback["spans"], - sqlite_commit["spans"], - ) - if span["data"].get(SPANDATA.DB_OPERATION) == SPANNAME.DB_COMMIT - or span["data"].get(SPANDATA.DB_OPERATION) == SPANNAME.DB_ROLLBACK - ] + sentry_sdk.flush() + spans = [item.payload for item in items] + + postgres_rollback = spans[4] + assert postgres_rollback["is_segment"] is True + postgres_commit = spans[9] + assert postgres_commit["is_segment"] is True + sqlite_rollback = spans[12] + assert sqlite_rollback["is_segment"] is True + sqlite_commit = spans[15] + assert sqlite_commit["is_segment"] is True + + commit_spans = [ + span + for span in spans + if span["attributes"].get(SPANDATA.DB_OPERATION_NAME) == SPANNAME.DB_COMMIT + or span["attributes"].get(SPANDATA.DB_OPERATION_NAME) == SPANNAME.DB_ROLLBACK + ] assert len(commit_spans) == 0 @pytest.mark.forked @pytest_mark_django_db_decorator(transaction=True) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_db_no_autocommit_execute( sentry_init, client, - capture_events, capture_items, - span_streaming, ): sentry_init( integrations=[DjangoIntegration(db_transaction_spans=True)], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) if "postgres" not in connections: @@ -522,89 +293,44 @@ def test_db_no_autocommit_execute( # trigger Django to open a new connection by marking the existing one as None. connections["postgres"].connection = None - if span_streaming: - items = capture_items("span") - - client.get(reverse("postgres_insert_orm_no_autocommit")) - - sentry_sdk.flush() - spans = [item.payload for item in items] - - # Ensure operation is persisted - assert User.objects.using("postgres").exists() - - assert spans[5]["attributes"]["sentry.origin"] == "auto.http.django" - - commit_spans = [ - span - for span in spans - if span["attributes"].get(SPANDATA.DB_OPERATION_NAME) == SPANNAME.DB_COMMIT - ] - - assert len(commit_spans) == 1 - commit_span = commit_spans[0] - - assert commit_span["attributes"]["sentry.origin"] == "auto.db.django" - - # Verify other database attributes - assert commit_span["attributes"].get(SPANDATA.DB_SYSTEM_NAME) == "postgresql" - conn_params = connections["postgres"].get_connection_params() - assert commit_span["attributes"].get(SPANDATA.DB_NAMESPACE) is not None - assert commit_span["attributes"].get(SPANDATA.DB_NAMESPACE) == conn_params.get( - "database" - ) or conn_params.get("dbname") - assert commit_span["attributes"].get(SPANDATA.SERVER_ADDRESS) == os.environ.get( - "SENTRY_PYTHON_TEST_POSTGRES_HOST", "localhost" - ) - assert commit_span["attributes"].get(SPANDATA.SERVER_PORT) == os.environ.get( - "SENTRY_PYTHON_TEST_POSTGRES_PORT", "5432" - ) - - insert_spans = [ - span for span in spans if span["name"].startswith("INSERT INTO") - ] - else: - events = capture_events() + items = capture_items("span") - client.get(reverse("postgres_insert_orm_no_autocommit")) + client.get(reverse("postgres_insert_orm_no_autocommit")) - (event,) = events + sentry_sdk.flush() + spans = [item.payload for item in items] - # Ensure operation is persisted - assert User.objects.using("postgres").exists() + # Ensure operation is persisted + assert User.objects.using("postgres").exists() - assert event["contexts"]["trace"]["origin"] == "auto.http.django" + assert spans[5]["attributes"]["sentry.origin"] == "auto.http.django" - commit_spans = [ - span - for span in event["spans"] - if span["data"].get(SPANDATA.DB_OPERATION) == SPANNAME.DB_COMMIT - ] + commit_spans = [ + span + for span in spans + if span["attributes"].get(SPANDATA.DB_OPERATION_NAME) == SPANNAME.DB_COMMIT + ] - assert len(commit_spans) == 1 - commit_span = commit_spans[0] + assert len(commit_spans) == 1 + commit_span = commit_spans[0] - assert commit_span["origin"] == "auto.db.django" + assert commit_span["attributes"]["sentry.origin"] == "auto.db.django" - # Verify other database attributes - assert commit_span["data"].get(SPANDATA.DB_SYSTEM) == "postgresql" - conn_params = connections["postgres"].get_connection_params() - assert commit_span["data"].get(SPANDATA.DB_NAME) is not None - assert commit_span["data"].get(SPANDATA.DB_NAME) == conn_params.get( - "database" - ) or conn_params.get("dbname") - assert commit_span["data"].get(SPANDATA.SERVER_ADDRESS) == os.environ.get( - "SENTRY_PYTHON_TEST_POSTGRES_HOST", "localhost" - ) - assert commit_span["data"].get(SPANDATA.SERVER_PORT) == os.environ.get( - "SENTRY_PYTHON_TEST_POSTGRES_PORT", "5432" - ) + # Verify other database attributes + assert commit_span["attributes"].get(SPANDATA.DB_SYSTEM_NAME) == "postgresql" + conn_params = connections["postgres"].get_connection_params() + assert commit_span["attributes"].get(SPANDATA.DB_NAMESPACE) is not None + assert commit_span["attributes"].get(SPANDATA.DB_NAMESPACE) == conn_params.get( + "database" + ) or conn_params.get("dbname") + assert commit_span["attributes"].get(SPANDATA.SERVER_ADDRESS) == os.environ.get( + "SENTRY_PYTHON_TEST_POSTGRES_HOST", "localhost" + ) + assert commit_span["attributes"].get(SPANDATA.SERVER_PORT) == os.environ.get( + "SENTRY_PYTHON_TEST_POSTGRES_PORT", "5432" + ) - insert_spans = [ - span - for span in event["spans"] - if span["description"].startswith("INSERT INTO") - ] + insert_spans = [span for span in spans if span["name"].startswith("INSERT INTO")] assert len(insert_spans) == 1 insert_span = insert_spans[0] @@ -614,27 +340,22 @@ def test_db_no_autocommit_execute( @pytest.mark.forked @pytest_mark_django_db_decorator(transaction=True) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_db_no_autocommit_executemany( sentry_init, - capture_events, capture_items, - span_streaming, ): sentry_init( integrations=[DjangoIntegration(db_transaction_spans=True)], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") + items = capture_items("span") - with sentry_sdk.traces.start_span(name="custom parent"): - from django.db import connection, transaction + with sentry_sdk.start_span(name="custom parent"): + from django.db import connection, transaction - cursor = connection.cursor() + cursor = connection.cursor() - query = """INSERT INTO auth_user ( + query = """INSERT INTO auth_user ( password, is_superuser, username, @@ -647,134 +368,57 @@ def test_db_no_autocommit_executemany( ) VALUES ('password', false, %s, %s, %s, %s, false, true, %s);""" - query_list = ( - ( - "user1", - "John", - "Doe", - "user1@example.com", - datetime(1970, 1, 1), - ), - ( - "user2", - "Max", - "Mustermann", - "user2@example.com", - datetime(1970, 1, 1), - ), - ) - - transaction.set_autocommit(False) - cursor.executemany(query, query_list) - transaction.commit() - transaction.set_autocommit(True) - - sentry_sdk.flush() - spans = [item.payload for item in items] - - # Ensure operation is persisted - assert User.objects.exists() - - assert spans[2]["attributes"]["sentry.origin"] == "manual" - assert spans[0]["attributes"]["sentry.origin"] == "auto.db.django" - - commit_spans = [ - span - for span in spans - if span["attributes"].get(SPANDATA.DB_OPERATION_NAME) == SPANNAME.DB_COMMIT - ] - - assert len(commit_spans) == 1 - commit_span = commit_spans[0] - - assert commit_span["attributes"]["sentry.origin"] == "auto.db.django" - - # Verify other database attributes - assert commit_span["attributes"].get(SPANDATA.DB_SYSTEM_NAME) == "sqlite" - conn_params = connection.get_connection_params() - assert commit_span["attributes"].get(SPANDATA.DB_NAMESPACE) is not None - assert commit_span["attributes"].get(SPANDATA.DB_NAMESPACE) == conn_params.get( - "database" - ) or conn_params.get("dbname") - - insert_spans = [ - span for span in spans if span["name"].startswith("INSERT INTO") - ] - else: - events = capture_events() - - with start_transaction(name="test_transaction"): - from django.db import connection, transaction - - cursor = connection.cursor() - - query = """INSERT INTO auth_user ( - password, - is_superuser, - username, - first_name, - last_name, - email, - is_staff, - is_active, - date_joined -) -VALUES ('password', false, %s, %s, %s, %s, false, true, %s);""" - - query_list = ( - ( - "user1", - "John", - "Doe", - "user1@example.com", - datetime(1970, 1, 1), - ), - ( - "user2", - "Max", - "Mustermann", - "user2@example.com", - datetime(1970, 1, 1), - ), - ) + query_list = ( + ( + "user1", + "John", + "Doe", + "user1@example.com", + datetime(1970, 1, 1), + ), + ( + "user2", + "Max", + "Mustermann", + "user2@example.com", + datetime(1970, 1, 1), + ), + ) - transaction.set_autocommit(False) - cursor.executemany(query, query_list) - transaction.commit() - transaction.set_autocommit(True) + transaction.set_autocommit(False) + cursor.executemany(query, query_list) + transaction.commit() + transaction.set_autocommit(True) - (event,) = events + sentry_sdk.flush() + spans = [item.payload for item in items] - # Ensure operation is persisted - assert User.objects.exists() + # Ensure operation is persisted + assert User.objects.exists() - assert event["contexts"]["trace"]["origin"] == "manual" - assert event["spans"][0]["origin"] == "auto.db.django" + assert spans[2]["attributes"]["sentry.origin"] == "manual" + assert spans[0]["attributes"]["sentry.origin"] == "auto.db.django" - commit_spans = [ - span - for span in event["spans"] - if span["data"].get(SPANDATA.DB_OPERATION) == SPANNAME.DB_COMMIT - ] + commit_spans = [ + span + for span in spans + if span["attributes"].get(SPANDATA.DB_OPERATION_NAME) == SPANNAME.DB_COMMIT + ] - assert len(commit_spans) == 1 - commit_span = commit_spans[0] + assert len(commit_spans) == 1 + commit_span = commit_spans[0] - assert commit_span["origin"] == "auto.db.django" + assert commit_span["attributes"]["sentry.origin"] == "auto.db.django" - # Verify other database attributes - assert commit_span["data"].get(SPANDATA.DB_SYSTEM) == "sqlite" - conn_params = connection.get_connection_params() - assert commit_span["data"].get(SPANDATA.DB_NAME) is not None - assert commit_span["data"].get(SPANDATA.DB_NAME) == conn_params.get( - "database" - ) or conn_params.get("dbname") + # Verify other database attributes + assert commit_span["attributes"].get(SPANDATA.DB_SYSTEM_NAME) == "sqlite" + conn_params = connection.get_connection_params() + assert commit_span["attributes"].get(SPANDATA.DB_NAMESPACE) is not None + assert commit_span["attributes"].get(SPANDATA.DB_NAMESPACE) == conn_params.get( + "database" + ) or conn_params.get("dbname") - insert_spans = [ - span - for span in event["spans"] - if span["description"].startswith("INSERT INTO") - ] + insert_spans = [span for span in spans if span["name"].startswith("INSERT INTO")] # Verify queries and commit statements are siblings for insert_span in insert_spans: @@ -783,18 +427,14 @@ def test_db_no_autocommit_executemany( @pytest.mark.forked @pytest_mark_django_db_decorator(transaction=True) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_db_no_autocommit_rollback_execute( sentry_init, client, - capture_events, capture_items, - span_streaming, ): sentry_init( integrations=[DjangoIntegration(db_transaction_spans=True)], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) if "postgres" not in connections: @@ -803,90 +443,44 @@ def test_db_no_autocommit_rollback_execute( # trigger Django to open a new connection by marking the existing one as None. connections["postgres"].connection = None - if span_streaming: - items = capture_items("span") - - client.get(reverse("postgres_insert_orm_no_autocommit_rollback")) - - sentry_sdk.flush() - spans = [item.payload for item in items] - - # Ensure operation is rolled back - assert not User.objects.using("postgres").exists() - - assert spans[5]["attributes"]["sentry.origin"] == "auto.http.django" - - rollback_spans = [ - span - for span in spans - if span["attributes"].get(SPANDATA.DB_OPERATION_NAME) - == SPANNAME.DB_ROLLBACK - ] + items = capture_items("span") - assert len(rollback_spans) == 1 - rollback_span = rollback_spans[0] + client.get(reverse("postgres_insert_orm_no_autocommit_rollback")) - assert rollback_span["attributes"]["sentry.origin"] == "auto.db.django" + sentry_sdk.flush() + spans = [item.payload for item in items] - # Verify other database attributes - assert rollback_span["attributes"].get(SPANDATA.DB_SYSTEM_NAME) == "postgresql" - conn_params = connections["postgres"].get_connection_params() - assert rollback_span["attributes"].get(SPANDATA.DB_NAMESPACE) is not None - assert rollback_span["attributes"].get( - SPANDATA.DB_NAMESPACE - ) == conn_params.get("database") or conn_params.get("dbname") - assert rollback_span["attributes"].get( - SPANDATA.SERVER_ADDRESS - ) == os.environ.get("SENTRY_PYTHON_TEST_POSTGRES_HOST", "localhost") - assert rollback_span["attributes"].get(SPANDATA.SERVER_PORT) == os.environ.get( - "SENTRY_PYTHON_TEST_POSTGRES_PORT", "5432" - ) - - insert_spans = [ - span for span in spans if span["name"].startswith("INSERT INTO") - ] - else: - events = capture_events() - - client.get(reverse("postgres_insert_orm_no_autocommit_rollback")) + # Ensure operation is rolled back + assert not User.objects.using("postgres").exists() - (event,) = events + assert spans[5]["attributes"]["sentry.origin"] == "auto.http.django" - # Ensure operation is rolled back - assert not User.objects.using("postgres").exists() + rollback_spans = [ + span + for span in spans + if span["attributes"].get(SPANDATA.DB_OPERATION_NAME) == SPANNAME.DB_ROLLBACK + ] - assert event["contexts"]["trace"]["origin"] == "auto.http.django" + assert len(rollback_spans) == 1 + rollback_span = rollback_spans[0] - rollback_spans = [ - span - for span in event["spans"] - if span["data"].get(SPANDATA.DB_OPERATION) == SPANNAME.DB_ROLLBACK - ] + assert rollback_span["attributes"]["sentry.origin"] == "auto.db.django" - assert len(rollback_spans) == 1 - rollback_span = rollback_spans[0] - - assert rollback_span["origin"] == "auto.db.django" - - # Verify other database attributes - assert rollback_span["data"].get(SPANDATA.DB_SYSTEM) == "postgresql" - conn_params = connections["postgres"].get_connection_params() - assert rollback_span["data"].get(SPANDATA.DB_NAME) is not None - assert rollback_span["data"].get(SPANDATA.DB_NAME) == conn_params.get( - "database" - ) or conn_params.get("dbname") - assert rollback_span["data"].get(SPANDATA.SERVER_ADDRESS) == os.environ.get( - "SENTRY_PYTHON_TEST_POSTGRES_HOST", "localhost" - ) - assert rollback_span["data"].get(SPANDATA.SERVER_PORT) == os.environ.get( - "SENTRY_PYTHON_TEST_POSTGRES_PORT", "5432" - ) + # Verify other database attributes + assert rollback_span["attributes"].get(SPANDATA.DB_SYSTEM_NAME) == "postgresql" + conn_params = connections["postgres"].get_connection_params() + assert rollback_span["attributes"].get(SPANDATA.DB_NAMESPACE) is not None + assert rollback_span["attributes"].get(SPANDATA.DB_NAMESPACE) == conn_params.get( + "database" + ) or conn_params.get("dbname") + assert rollback_span["attributes"].get(SPANDATA.SERVER_ADDRESS) == os.environ.get( + "SENTRY_PYTHON_TEST_POSTGRES_HOST", "localhost" + ) + assert rollback_span["attributes"].get(SPANDATA.SERVER_PORT) == os.environ.get( + "SENTRY_PYTHON_TEST_POSTGRES_PORT", "5432" + ) - insert_spans = [ - span - for span in event["spans"] - if span["description"].startswith("INSERT INTO") - ] + insert_spans = [span for span in spans if span["name"].startswith("INSERT INTO")] assert len(insert_spans) == 1 insert_span = insert_spans[0] @@ -896,166 +490,84 @@ def test_db_no_autocommit_rollback_execute( @pytest.mark.forked @pytest_mark_django_db_decorator(transaction=True) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_db_no_autocommit_rollback_executemany( sentry_init, - capture_events, capture_items, - span_streaming, ): sentry_init( integrations=[DjangoIntegration(db_transaction_spans=True)], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") - - with sentry_sdk.traces.start_span(name="custom parent"): - from django.db import connection, transaction - - cursor = connection.cursor() - - query = """INSERT INTO auth_user ( - password, - is_superuser, - username, - first_name, - last_name, - email, - is_staff, - is_active, - date_joined -) -VALUES ('password', false, %s, %s, %s, %s, false, true, %s);""" - - query_list = ( - ( - "user1", - "John", - "Doe", - "user1@example.com", - datetime(1970, 1, 1), - ), - ( - "user2", - "Max", - "Mustermann", - "user2@example.com", - datetime(1970, 1, 1), - ), - ) + items = capture_items("span") - transaction.set_autocommit(False) - cursor.executemany(query, query_list) - transaction.rollback() - transaction.set_autocommit(True) - - sentry_sdk.flush() - spans = [item.payload for item in items] - - # Ensure operation is rolled back - assert not User.objects.exists() - - assert spans[2]["attributes"]["sentry.origin"] == "manual" - assert spans[0]["attributes"]["sentry.origin"] == "auto.db.django" - - rollback_spans = [ - span - for span in spans - if span["attributes"].get(SPANDATA.DB_OPERATION_NAME) - == SPANNAME.DB_ROLLBACK - ] - assert len(rollback_spans) == 1 - rollback_span = rollback_spans[0] - - assert rollback_span["attributes"]["sentry.origin"] == "auto.db.django" - - # Verify other database attributes - assert rollback_span["attributes"].get(SPANDATA.DB_SYSTEM_NAME) == "sqlite" - conn_params = connection.get_connection_params() - assert rollback_span["attributes"].get(SPANDATA.DB_NAMESPACE) is not None - assert rollback_span["attributes"].get( - SPANDATA.DB_NAMESPACE - ) == conn_params.get("database") or conn_params.get("dbname") - - insert_spans = [ - span for span in spans if span["name"].startswith("INSERT INTO") - ] - else: - events = capture_events() - - with start_transaction(name="test_transaction"): - from django.db import connection, transaction + with sentry_sdk.start_span(name="custom parent"): + from django.db import connection, transaction - cursor = connection.cursor() + cursor = connection.cursor() - query = """INSERT INTO auth_user ( + query = """INSERT INTO auth_user ( password, - is_superuser, - username, - first_name, - last_name, - email, - is_staff, - is_active, - date_joined -) -VALUES ('password', false, %s, %s, %s, %s, false, true, %s);""" - - query_list = ( - ( - "user1", - "John", - "Doe", - "user1@example.com", - datetime(1970, 1, 1), - ), - ( - "user2", - "Max", - "Mustermann", - "user2@example.com", - datetime(1970, 1, 1), - ), - ) + is_superuser, + username, + first_name, + last_name, + email, + is_staff, + is_active, + date_joined +) +VALUES ('password', false, %s, %s, %s, %s, false, true, %s);""" - transaction.set_autocommit(False) - cursor.executemany(query, query_list) - transaction.rollback() - transaction.set_autocommit(True) + query_list = ( + ( + "user1", + "John", + "Doe", + "user1@example.com", + datetime(1970, 1, 1), + ), + ( + "user2", + "Max", + "Mustermann", + "user2@example.com", + datetime(1970, 1, 1), + ), + ) - (event,) = events + transaction.set_autocommit(False) + cursor.executemany(query, query_list) + transaction.rollback() + transaction.set_autocommit(True) - # Ensure operation is rolled back - assert not User.objects.exists() + sentry_sdk.flush() + spans = [item.payload for item in items] - assert event["contexts"]["trace"]["origin"] == "manual" - assert event["spans"][0]["origin"] == "auto.db.django" + # Ensure operation is rolled back + assert not User.objects.exists() - rollback_spans = [ - span - for span in event["spans"] - if span["data"].get(SPANDATA.DB_OPERATION) == SPANNAME.DB_ROLLBACK - ] - assert len(rollback_spans) == 1 - rollback_span = rollback_spans[0] + assert spans[2]["attributes"]["sentry.origin"] == "manual" + assert spans[0]["attributes"]["sentry.origin"] == "auto.db.django" - assert rollback_span["origin"] == "auto.db.django" + rollback_spans = [ + span + for span in spans + if span["attributes"].get(SPANDATA.DB_OPERATION_NAME) == SPANNAME.DB_ROLLBACK + ] + assert len(rollback_spans) == 1 + rollback_span = rollback_spans[0] - # Verify other database attributes - assert rollback_span["data"].get(SPANDATA.DB_SYSTEM) == "sqlite" - conn_params = connection.get_connection_params() - assert rollback_span["data"].get(SPANDATA.DB_NAME) is not None - assert rollback_span["data"].get(SPANDATA.DB_NAME) == conn_params.get( - "database" - ) or conn_params.get("dbname") + assert rollback_span["attributes"]["sentry.origin"] == "auto.db.django" - insert_spans = [ - span - for span in event["spans"] - if span["description"].startswith("INSERT INTO") - ] + # Verify other database attributes + assert rollback_span["attributes"].get(SPANDATA.DB_SYSTEM_NAME) == "sqlite" + conn_params = connection.get_connection_params() + assert rollback_span["attributes"].get(SPANDATA.DB_NAMESPACE) is not None + assert rollback_span["attributes"].get(SPANDATA.DB_NAMESPACE) == conn_params.get( + "database" + ) or conn_params.get("dbname") + + insert_spans = [span for span in spans if span["name"].startswith("INSERT INTO")] # Verify queries and rollback statements are siblings for insert_span in insert_spans: @@ -1064,18 +576,14 @@ def test_db_no_autocommit_rollback_executemany( @pytest.mark.forked @pytest_mark_django_db_decorator(transaction=True) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_db_atomic_execute( sentry_init, client, - capture_events, capture_items, - span_streaming, ): sentry_init( integrations=[DjangoIntegration(db_transaction_spans=True)], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) if "postgres" not in connections: @@ -1084,89 +592,44 @@ def test_db_atomic_execute( # trigger Django to open a new connection by marking the existing one as None. connections["postgres"].connection = None - if span_streaming: - items = capture_items("span") - - client.get(reverse("postgres_insert_orm_atomic")) - - sentry_sdk.flush() - spans = [item.payload for item in items] - - # Ensure operation is persisted - assert User.objects.using("postgres").exists() + items = capture_items("span") - assert spans[5]["attributes"]["sentry.origin"] == "auto.http.django" + client.get(reverse("postgres_insert_orm_atomic")) - commit_spans = [ - span - for span in spans - if span["attributes"].get(SPANDATA.DB_OPERATION_NAME) == SPANNAME.DB_COMMIT - ] + sentry_sdk.flush() + spans = [item.payload for item in items] - assert len(commit_spans) == 1 - commit_span = commit_spans[0] + # Ensure operation is persisted + assert User.objects.using("postgres").exists() - assert commit_span["attributes"]["sentry.origin"] == "auto.db.django" + assert spans[5]["attributes"]["sentry.origin"] == "auto.http.django" - # Verify other database attributes - assert commit_span["attributes"].get(SPANDATA.DB_SYSTEM_NAME) == "postgresql" - conn_params = connections["postgres"].get_connection_params() - assert commit_span["attributes"].get(SPANDATA.DB_NAMESPACE) is not None - assert commit_span["attributes"].get(SPANDATA.DB_NAMESPACE) == conn_params.get( - "database" - ) or conn_params.get("dbname") - assert commit_span["attributes"].get(SPANDATA.SERVER_ADDRESS) == os.environ.get( - "SENTRY_PYTHON_TEST_POSTGRES_HOST", "localhost" - ) - assert commit_span["attributes"].get(SPANDATA.SERVER_PORT) == os.environ.get( - "SENTRY_PYTHON_TEST_POSTGRES_PORT", "5432" - ) - - insert_spans = [ - span for span in spans if span["name"].startswith("INSERT INTO") - ] - else: - events = capture_events() - - client.get(reverse("postgres_insert_orm_atomic")) - - (event,) = events - - # Ensure operation is persisted - assert User.objects.using("postgres").exists() - - assert event["contexts"]["trace"]["origin"] == "auto.http.django" - - commit_spans = [ - span - for span in event["spans"] - if span["data"].get(SPANDATA.DB_OPERATION) == SPANNAME.DB_COMMIT - ] + commit_spans = [ + span + for span in spans + if span["attributes"].get(SPANDATA.DB_OPERATION_NAME) == SPANNAME.DB_COMMIT + ] - assert len(commit_spans) == 1 - commit_span = commit_spans[0] + assert len(commit_spans) == 1 + commit_span = commit_spans[0] - assert commit_span["origin"] == "auto.db.django" + assert commit_span["attributes"]["sentry.origin"] == "auto.db.django" - # Verify other database attributes - assert commit_span["data"].get(SPANDATA.DB_SYSTEM) == "postgresql" - conn_params = connections["postgres"].get_connection_params() - assert commit_span["data"].get(SPANDATA.DB_NAME) is not None - assert commit_span["data"].get(SPANDATA.DB_NAME) == conn_params.get( - "database" - ) or conn_params.get("dbname") - assert commit_span["data"].get(SPANDATA.SERVER_ADDRESS) == os.environ.get( - "SENTRY_PYTHON_TEST_POSTGRES_HOST", "localhost" - ) - assert commit_span["data"].get(SPANDATA.SERVER_PORT) == os.environ.get( - "SENTRY_PYTHON_TEST_POSTGRES_PORT", "5432" - ) + # Verify other database attributes + assert commit_span["attributes"].get(SPANDATA.DB_SYSTEM_NAME) == "postgresql" + conn_params = connections["postgres"].get_connection_params() + assert commit_span["attributes"].get(SPANDATA.DB_NAMESPACE) is not None + assert commit_span["attributes"].get(SPANDATA.DB_NAMESPACE) == conn_params.get( + "database" + ) or conn_params.get("dbname") + assert commit_span["attributes"].get(SPANDATA.SERVER_ADDRESS) == os.environ.get( + "SENTRY_PYTHON_TEST_POSTGRES_HOST", "localhost" + ) + assert commit_span["attributes"].get(SPANDATA.SERVER_PORT) == os.environ.get( + "SENTRY_PYTHON_TEST_POSTGRES_PORT", "5432" + ) - insert_spans = [ - span - for span in event["spans"] - if span["description"].startswith("INSERT INTO") - ] + insert_spans = [span for span in spans if span["name"].startswith("INSERT INTO")] assert len(insert_spans) == 1 insert_span = insert_spans[0] @@ -1176,98 +639,24 @@ def test_db_atomic_execute( @pytest.mark.forked @pytest_mark_django_db_decorator(transaction=True) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_db_atomic_executemany( sentry_init, - capture_events, capture_items, - span_streaming, ): sentry_init( integrations=[DjangoIntegration(db_transaction_spans=True)], send_default_pii=True, traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") - - with sentry_sdk.traces.start_span(name="custom parent"): - from django.db import connection, transaction - - with transaction.atomic(): - cursor = connection.cursor() - - query = """INSERT INTO auth_user ( - password, - is_superuser, - username, - first_name, - last_name, - email, - is_staff, - is_active, - date_joined -) -VALUES ('password', false, %s, %s, %s, %s, false, true, %s);""" - - query_list = ( - ( - "user1", - "John", - "Doe", - "user1@example.com", - datetime(1970, 1, 1), - ), - ( - "user2", - "Max", - "Mustermann", - "user2@example.com", - datetime(1970, 1, 1), - ), - ) - cursor.executemany(query, query_list) - - sentry_sdk.flush() - spans = [item.payload for item in items] + items = capture_items("span") - # Ensure operation is persisted - assert User.objects.exists() + with sentry_sdk.start_span(name="custom parent"): + from django.db import connection, transaction - assert spans[3]["attributes"]["sentry.origin"] == "manual" - - commit_spans = [ - span - for span in spans - if span["attributes"].get(SPANDATA.DB_OPERATION_NAME) == SPANNAME.DB_COMMIT - ] - assert len(commit_spans) == 1 - commit_span = commit_spans[0] - - assert commit_span["attributes"]["sentry.origin"] == "auto.db.django" - - # Verify other database attributes - assert commit_span["attributes"].get(SPANDATA.DB_SYSTEM_NAME) == "sqlite" - conn_params = connection.get_connection_params() - assert commit_span["attributes"].get(SPANDATA.DB_NAMESPACE) is not None - assert commit_span["attributes"].get(SPANDATA.DB_NAMESPACE) == conn_params.get( - "database" - ) or conn_params.get("dbname") - - insert_spans = [ - span for span in spans if span["name"].startswith("INSERT INTO") - ] - else: - events = capture_events() - - with start_transaction(name="test_transaction"): - from django.db import connection, transaction - - with transaction.atomic(): - cursor = connection.cursor() + with transaction.atomic(): + cursor = connection.cursor() - query = """INSERT INTO auth_user ( + query = """INSERT INTO auth_user ( password, is_superuser, username, @@ -1280,54 +669,51 @@ def test_db_atomic_executemany( ) VALUES ('password', false, %s, %s, %s, %s, false, true, %s);""" - query_list = ( - ( - "user1", - "John", - "Doe", - "user1@example.com", - datetime(1970, 1, 1), - ), - ( - "user2", - "Max", - "Mustermann", - "user2@example.com", - datetime(1970, 1, 1), - ), - ) - cursor.executemany(query, query_list) + query_list = ( + ( + "user1", + "John", + "Doe", + "user1@example.com", + datetime(1970, 1, 1), + ), + ( + "user2", + "Max", + "Mustermann", + "user2@example.com", + datetime(1970, 1, 1), + ), + ) + cursor.executemany(query, query_list) - (event,) = events + sentry_sdk.flush() + spans = [item.payload for item in items] - # Ensure operation is persisted - assert User.objects.exists() + # Ensure operation is persisted + assert User.objects.exists() - assert event["contexts"]["trace"]["origin"] == "manual" + assert spans[3]["attributes"]["sentry.origin"] == "manual" - commit_spans = [ - span - for span in event["spans"] - if span["data"].get(SPANDATA.DB_OPERATION) == SPANNAME.DB_COMMIT - ] - assert len(commit_spans) == 1 - commit_span = commit_spans[0] + commit_spans = [ + span + for span in spans + if span["attributes"].get(SPANDATA.DB_OPERATION_NAME) == SPANNAME.DB_COMMIT + ] + assert len(commit_spans) == 1 + commit_span = commit_spans[0] - assert commit_span["origin"] == "auto.db.django" + assert commit_span["attributes"]["sentry.origin"] == "auto.db.django" - # Verify other database attributes - assert commit_span["data"].get(SPANDATA.DB_SYSTEM) == "sqlite" - conn_params = connection.get_connection_params() - assert commit_span["data"].get(SPANDATA.DB_NAME) is not None - assert commit_span["data"].get(SPANDATA.DB_NAME) == conn_params.get( - "database" - ) or conn_params.get("dbname") + # Verify other database attributes + assert commit_span["attributes"].get(SPANDATA.DB_SYSTEM_NAME) == "sqlite" + conn_params = connection.get_connection_params() + assert commit_span["attributes"].get(SPANDATA.DB_NAMESPACE) is not None + assert commit_span["attributes"].get(SPANDATA.DB_NAMESPACE) == conn_params.get( + "database" + ) or conn_params.get("dbname") - insert_spans = [ - span - for span in event["spans"] - if span["description"].startswith("INSERT INTO") - ] + insert_spans = [span for span in spans if span["name"].startswith("INSERT INTO")] # Verify queries and commit statements are siblings for insert_span in insert_spans: @@ -1336,19 +722,15 @@ def test_db_atomic_executemany( @pytest.mark.forked @pytest_mark_django_db_decorator(transaction=True) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_db_atomic_rollback_execute( sentry_init, client, - capture_events, capture_items, - span_streaming, ): sentry_init( integrations=[DjangoIntegration(db_transaction_spans=True)], send_default_pii=True, traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) if "postgres" not in connections: @@ -1357,90 +739,44 @@ def test_db_atomic_rollback_execute( # trigger Django to open a new connection by marking the existing one as None. connections["postgres"].connection = None - if span_streaming: - items = capture_items("span") - - client.get(reverse("postgres_insert_orm_atomic_rollback")) - - sentry_sdk.flush() - spans = [item.payload for item in items] - - # Ensure operation is rolled back - assert not User.objects.using("postgres").exists() + items = capture_items("span") - assert spans[5]["attributes"]["sentry.origin"] == "auto.http.django" + client.get(reverse("postgres_insert_orm_atomic_rollback")) - rollback_spans = [ - span - for span in spans - if span["attributes"].get(SPANDATA.DB_OPERATION_NAME) - == SPANNAME.DB_ROLLBACK - ] + sentry_sdk.flush() + spans = [item.payload for item in items] - assert len(rollback_spans) == 1 - rollback_span = rollback_spans[0] + # Ensure operation is rolled back + assert not User.objects.using("postgres").exists() - assert rollback_span["attributes"]["sentry.origin"] == "auto.db.django" + assert spans[5]["attributes"]["sentry.origin"] == "auto.http.django" - # Verify other database attributes - assert rollback_span["attributes"].get(SPANDATA.DB_SYSTEM_NAME) == "postgresql" - conn_params = connections["postgres"].get_connection_params() - assert rollback_span["attributes"].get(SPANDATA.DB_NAMESPACE) is not None - assert rollback_span["attributes"].get( - SPANDATA.DB_NAMESPACE - ) == conn_params.get("database") or conn_params.get("dbname") - assert rollback_span["attributes"].get( - SPANDATA.SERVER_ADDRESS - ) == os.environ.get("SENTRY_PYTHON_TEST_POSTGRES_HOST", "localhost") - assert rollback_span["attributes"].get(SPANDATA.SERVER_PORT) == os.environ.get( - "SENTRY_PYTHON_TEST_POSTGRES_PORT", "5432" - ) - - insert_spans = [ - span for span in spans if span["name"].startswith("INSERT INTO") - ] - else: - events = capture_events() - - client.get(reverse("postgres_insert_orm_atomic_rollback")) - - (event,) = events + rollback_spans = [ + span + for span in spans + if span["attributes"].get(SPANDATA.DB_OPERATION_NAME) == SPANNAME.DB_ROLLBACK + ] - # Ensure operation is rolled back - assert not User.objects.using("postgres").exists() + assert len(rollback_spans) == 1 + rollback_span = rollback_spans[0] - assert event["contexts"]["trace"]["origin"] == "auto.http.django" + assert rollback_span["attributes"]["sentry.origin"] == "auto.db.django" - rollback_spans = [ - span - for span in event["spans"] - if span["data"].get(SPANDATA.DB_OPERATION) == SPANNAME.DB_ROLLBACK - ] - - assert len(rollback_spans) == 1 - rollback_span = rollback_spans[0] - - assert rollback_span["origin"] == "auto.db.django" - - # Verify other database attributes - assert rollback_span["data"].get(SPANDATA.DB_SYSTEM) == "postgresql" - conn_params = connections["postgres"].get_connection_params() - assert rollback_span["data"].get(SPANDATA.DB_NAME) is not None - assert rollback_span["data"].get(SPANDATA.DB_NAME) == conn_params.get( - "database" - ) or conn_params.get("dbname") - assert rollback_span["data"].get(SPANDATA.SERVER_ADDRESS) == os.environ.get( - "SENTRY_PYTHON_TEST_POSTGRES_HOST", "localhost" - ) - assert rollback_span["data"].get(SPANDATA.SERVER_PORT) == os.environ.get( - "SENTRY_PYTHON_TEST_POSTGRES_PORT", "5432" - ) + # Verify other database attributes + assert rollback_span["attributes"].get(SPANDATA.DB_SYSTEM_NAME) == "postgresql" + conn_params = connections["postgres"].get_connection_params() + assert rollback_span["attributes"].get(SPANDATA.DB_NAMESPACE) is not None + assert rollback_span["attributes"].get(SPANDATA.DB_NAMESPACE) == conn_params.get( + "database" + ) or conn_params.get("dbname") + assert rollback_span["attributes"].get(SPANDATA.SERVER_ADDRESS) == os.environ.get( + "SENTRY_PYTHON_TEST_POSTGRES_HOST", "localhost" + ) + assert rollback_span["attributes"].get(SPANDATA.SERVER_PORT) == os.environ.get( + "SENTRY_PYTHON_TEST_POSTGRES_PORT", "5432" + ) - insert_spans = [ - span - for span in event["spans"] - if span["description"].startswith("INSERT INTO") - ] + insert_spans = [span for span in spans if span["name"].startswith("INSERT INTO")] assert len(insert_spans) == 1 insert_span = insert_spans[0] @@ -1451,101 +787,24 @@ def test_db_atomic_rollback_execute( @pytest.mark.forked @pytest_mark_django_db_decorator(transaction=True) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_db_atomic_rollback_executemany( sentry_init, - capture_events, capture_items, - span_streaming, ): sentry_init( integrations=[DjangoIntegration(db_transaction_spans=True)], send_default_pii=True, traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") - - with sentry_sdk.traces.start_span(name="custom parent"): - from django.db import connection, transaction - - with transaction.atomic(): - cursor = connection.cursor() - - query = """INSERT INTO auth_user ( - password, - is_superuser, - username, - first_name, - last_name, - email, - is_staff, - is_active, - date_joined -) -VALUES ('password', false, %s, %s, %s, %s, false, true, %s);""" - - query_list = ( - ( - "user1", - "John", - "Doe", - "user1@example.com", - datetime(1970, 1, 1), - ), - ( - "user2", - "Max", - "Mustermann", - "user2@example.com", - datetime(1970, 1, 1), - ), - ) - cursor.executemany(query, query_list) - transaction.set_rollback(True) - - sentry_sdk.flush() - spans = [item.payload for item in items] - - # Ensure operation is rolled back - assert not User.objects.exists() + items = capture_items("span") - assert spans[3]["attributes"]["sentry.origin"] == "manual" + with sentry_sdk.start_span(name="custom parent"): + from django.db import connection, transaction - rollback_spans = [ - span - for span in spans - if span["attributes"].get(SPANDATA.DB_OPERATION_NAME) - == SPANNAME.DB_ROLLBACK - ] - - assert len(rollback_spans) == 1 - rollback_span = rollback_spans[0] - - assert rollback_span["attributes"]["sentry.origin"] == "auto.db.django" - - # Verify other database attributes - assert rollback_span["attributes"].get(SPANDATA.DB_SYSTEM_NAME) == "sqlite" - conn_params = connection.get_connection_params() - assert rollback_span["attributes"].get(SPANDATA.DB_NAMESPACE) is not None - assert rollback_span["attributes"].get( - SPANDATA.DB_NAMESPACE - ) == conn_params.get("database") or conn_params.get("dbname") - - insert_spans = [ - span for span in spans if span["name"].startswith("INSERT INTO") - ] - else: - events = capture_events() - - with start_transaction(name="test_transaction"): - from django.db import connection, transaction - - with transaction.atomic(): - cursor = connection.cursor() + with transaction.atomic(): + cursor = connection.cursor() - query = """INSERT INTO auth_user ( + query = """INSERT INTO auth_user ( password, is_superuser, username, @@ -1558,56 +817,53 @@ def test_db_atomic_rollback_executemany( ) VALUES ('password', false, %s, %s, %s, %s, false, true, %s);""" - query_list = ( - ( - "user1", - "John", - "Doe", - "user1@example.com", - datetime(1970, 1, 1), - ), - ( - "user2", - "Max", - "Mustermann", - "user2@example.com", - datetime(1970, 1, 1), - ), - ) - cursor.executemany(query, query_list) - transaction.set_rollback(True) + query_list = ( + ( + "user1", + "John", + "Doe", + "user1@example.com", + datetime(1970, 1, 1), + ), + ( + "user2", + "Max", + "Mustermann", + "user2@example.com", + datetime(1970, 1, 1), + ), + ) + cursor.executemany(query, query_list) + transaction.set_rollback(True) - (event,) = events + sentry_sdk.flush() + spans = [item.payload for item in items] - # Ensure operation is rolled back - assert not User.objects.exists() + # Ensure operation is rolled back + assert not User.objects.exists() - assert event["contexts"]["trace"]["origin"] == "manual" + assert spans[3]["attributes"]["sentry.origin"] == "manual" - rollback_spans = [ - span - for span in event["spans"] - if span["data"].get(SPANDATA.DB_OPERATION) == SPANNAME.DB_ROLLBACK - ] + rollback_spans = [ + span + for span in spans + if span["attributes"].get(SPANDATA.DB_OPERATION_NAME) == SPANNAME.DB_ROLLBACK + ] - assert len(rollback_spans) == 1 - rollback_span = rollback_spans[0] + assert len(rollback_spans) == 1 + rollback_span = rollback_spans[0] - assert rollback_span["origin"] == "auto.db.django" + assert rollback_span["attributes"]["sentry.origin"] == "auto.db.django" - # Verify other database attributes - assert rollback_span["data"].get(SPANDATA.DB_SYSTEM) == "sqlite" - conn_params = connection.get_connection_params() - assert rollback_span["data"].get(SPANDATA.DB_NAME) is not None - assert rollback_span["data"].get(SPANDATA.DB_NAME) == conn_params.get( - "database" - ) or conn_params.get("dbname") + # Verify other database attributes + assert rollback_span["attributes"].get(SPANDATA.DB_SYSTEM_NAME) == "sqlite" + conn_params = connection.get_connection_params() + assert rollback_span["attributes"].get(SPANDATA.DB_NAMESPACE) is not None + assert rollback_span["attributes"].get(SPANDATA.DB_NAMESPACE) == conn_params.get( + "database" + ) or conn_params.get("dbname") - insert_spans = [ - span - for span in event["spans"] - if span["description"].startswith("INSERT INTO") - ] + insert_spans = [span for span in spans if span["name"].startswith("INSERT INTO")] # Verify queries and rollback statements are siblings for insert_span in insert_spans: @@ -1616,19 +872,15 @@ def test_db_atomic_rollback_executemany( @pytest.mark.forked @pytest_mark_django_db_decorator(transaction=True) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_db_atomic_execute_exception( sentry_init, client, - capture_events, capture_items, - span_streaming, ): sentry_init( integrations=[DjangoIntegration(db_transaction_spans=True)], send_default_pii=True, traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) if "postgres" not in connections: @@ -1637,90 +889,44 @@ def test_db_atomic_execute_exception( # trigger Django to open a new connection by marking the existing one as None. connections["postgres"].connection = None - if span_streaming: - items = capture_items("span") - - client.get(reverse("postgres_insert_orm_atomic_exception")) - - sentry_sdk.flush() - spans = [item.payload for item in items] - - # Ensure operation is rolled back - assert not User.objects.using("postgres").exists() + items = capture_items("span") - assert spans[5]["attributes"]["sentry.origin"] == "auto.http.django" + client.get(reverse("postgres_insert_orm_atomic_exception")) - rollback_spans = [ - span - for span in spans - if span["attributes"].get(SPANDATA.DB_OPERATION_NAME) - == SPANNAME.DB_ROLLBACK - ] + sentry_sdk.flush() + spans = [item.payload for item in items] - assert len(rollback_spans) == 1 - rollback_span = rollback_spans[0] + # Ensure operation is rolled back + assert not User.objects.using("postgres").exists() - assert rollback_span["attributes"]["sentry.origin"] == "auto.db.django" + assert spans[5]["attributes"]["sentry.origin"] == "auto.http.django" - # Verify other database attributes - assert rollback_span["attributes"].get(SPANDATA.DB_SYSTEM_NAME) == "postgresql" - conn_params = connections["postgres"].get_connection_params() - assert rollback_span["attributes"].get(SPANDATA.DB_NAMESPACE) is not None - assert rollback_span["attributes"].get( - SPANDATA.DB_NAMESPACE - ) == conn_params.get("database") or conn_params.get("dbname") - assert rollback_span["attributes"].get( - SPANDATA.SERVER_ADDRESS - ) == os.environ.get("SENTRY_PYTHON_TEST_POSTGRES_HOST", "localhost") - assert rollback_span["attributes"].get(SPANDATA.SERVER_PORT) == os.environ.get( - "SENTRY_PYTHON_TEST_POSTGRES_PORT", "5432" - ) - - insert_spans = [ - span for span in spans if span["name"].startswith("INSERT INTO") - ] - else: - events = capture_events() - - client.get(reverse("postgres_insert_orm_atomic_exception")) - - (event,) = events + rollback_spans = [ + span + for span in spans + if span["attributes"].get(SPANDATA.DB_OPERATION_NAME) == SPANNAME.DB_ROLLBACK + ] - # Ensure operation is rolled back - assert not User.objects.using("postgres").exists() + assert len(rollback_spans) == 1 + rollback_span = rollback_spans[0] - assert event["contexts"]["trace"]["origin"] == "auto.http.django" + assert rollback_span["attributes"]["sentry.origin"] == "auto.db.django" - rollback_spans = [ - span - for span in event["spans"] - if span["data"].get(SPANDATA.DB_OPERATION) == SPANNAME.DB_ROLLBACK - ] - - assert len(rollback_spans) == 1 - rollback_span = rollback_spans[0] - - assert rollback_span["origin"] == "auto.db.django" - - # Verify other database attributes - assert rollback_span["data"].get(SPANDATA.DB_SYSTEM) == "postgresql" - conn_params = connections["postgres"].get_connection_params() - assert rollback_span["data"].get(SPANDATA.DB_NAME) is not None - assert rollback_span["data"].get(SPANDATA.DB_NAME) == conn_params.get( - "database" - ) or conn_params.get("dbname") - assert rollback_span["data"].get(SPANDATA.SERVER_ADDRESS) == os.environ.get( - "SENTRY_PYTHON_TEST_POSTGRES_HOST", "localhost" - ) - assert rollback_span["data"].get(SPANDATA.SERVER_PORT) == os.environ.get( - "SENTRY_PYTHON_TEST_POSTGRES_PORT", "5432" - ) + # Verify other database attributes + assert rollback_span["attributes"].get(SPANDATA.DB_SYSTEM_NAME) == "postgresql" + conn_params = connections["postgres"].get_connection_params() + assert rollback_span["attributes"].get(SPANDATA.DB_NAMESPACE) is not None + assert rollback_span["attributes"].get(SPANDATA.DB_NAMESPACE) == conn_params.get( + "database" + ) or conn_params.get("dbname") + assert rollback_span["attributes"].get(SPANDATA.SERVER_ADDRESS) == os.environ.get( + "SENTRY_PYTHON_TEST_POSTGRES_HOST", "localhost" + ) + assert rollback_span["attributes"].get(SPANDATA.SERVER_PORT) == os.environ.get( + "SENTRY_PYTHON_TEST_POSTGRES_PORT", "5432" + ) - insert_spans = [ - span - for span in event["spans"] - if span["description"].startswith("INSERT INTO") - ] + insert_spans = [span for span in spans if span["name"].startswith("INSERT INTO")] assert len(insert_spans) == 1 insert_span = insert_spans[0] @@ -1730,30 +936,25 @@ def test_db_atomic_execute_exception( @pytest.mark.forked @pytest_mark_django_db_decorator(transaction=True) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_db_atomic_executemany_exception( sentry_init, - capture_events, capture_items, - span_streaming, ): sentry_init( integrations=[DjangoIntegration(db_transaction_spans=True)], send_default_pii=True, traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") + items = capture_items("span") - with sentry_sdk.traces.start_span(name="custom parent"): - from django.db import connection, transaction + with sentry_sdk.start_span(name="custom parent"): + from django.db import connection, transaction - try: - with transaction.atomic(): - cursor = connection.cursor() + try: + with transaction.atomic(): + cursor = connection.cursor() - query = """INSERT INTO auth_user ( + query = """INSERT INTO auth_user ( password, is_superuser, username, @@ -1766,131 +967,54 @@ def test_db_atomic_executemany_exception( ) VALUES ('password', false, %s, %s, %s, %s, false, true, %s);""" - query_list = ( - ( - "user1", - "John", - "Doe", - "user1@example.com", - datetime(1970, 1, 1), - ), - ( - "user2", - "Max", - "Mustermann", - "user2@example.com", - datetime(1970, 1, 1), - ), - ) - cursor.executemany(query, query_list) - 1 / 0 - except ZeroDivisionError: - pass - - sentry_sdk.flush() - spans = [item.payload for item in items] - - # Ensure operation is rolled back - assert not User.objects.exists() - - assert spans[3]["attributes"]["sentry.origin"] == "manual" - - rollback_spans = [ - span - for span in spans - if span["attributes"].get(SPANDATA.DB_OPERATION_NAME) - == SPANNAME.DB_ROLLBACK - ] - assert len(rollback_spans) == 1 - rollback_span = rollback_spans[0] - - assert rollback_span["attributes"]["sentry.origin"] == "auto.db.django" - - # Verify other database attributes - assert rollback_span["attributes"].get(SPANDATA.DB_SYSTEM_NAME) == "sqlite" - conn_params = connection.get_connection_params() - assert rollback_span["attributes"].get(SPANDATA.DB_NAMESPACE) is not None - assert rollback_span["attributes"].get( - SPANDATA.DB_NAMESPACE - ) == conn_params.get("database") or conn_params.get("dbname") - - insert_spans = [ - span for span in spans if span["name"].startswith("INSERT INTO") - ] - else: - events = capture_events() - - with start_transaction(name="test_transaction"): - from django.db import connection, transaction - - try: - with transaction.atomic(): - cursor = connection.cursor() - - query = """INSERT INTO auth_user ( - password, - is_superuser, - username, - first_name, - last_name, - email, - is_staff, - is_active, - date_joined -) -VALUES ('password', false, %s, %s, %s, %s, false, true, %s);""" + query_list = ( + ( + "user1", + "John", + "Doe", + "user1@example.com", + datetime(1970, 1, 1), + ), + ( + "user2", + "Max", + "Mustermann", + "user2@example.com", + datetime(1970, 1, 1), + ), + ) + cursor.executemany(query, query_list) + 1 / 0 + except ZeroDivisionError: + pass + + sentry_sdk.flush() + spans = [item.payload for item in items] + + # Ensure operation is rolled back + assert not User.objects.exists() + + assert spans[3]["attributes"]["sentry.origin"] == "manual" + + rollback_spans = [ + span + for span in spans + if span["attributes"].get(SPANDATA.DB_OPERATION_NAME) == SPANNAME.DB_ROLLBACK + ] + assert len(rollback_spans) == 1 + rollback_span = rollback_spans[0] + + assert rollback_span["attributes"]["sentry.origin"] == "auto.db.django" + + # Verify other database attributes + assert rollback_span["attributes"].get(SPANDATA.DB_SYSTEM_NAME) == "sqlite" + conn_params = connection.get_connection_params() + assert rollback_span["attributes"].get(SPANDATA.DB_NAMESPACE) is not None + assert rollback_span["attributes"].get(SPANDATA.DB_NAMESPACE) == conn_params.get( + "database" + ) or conn_params.get("dbname") - query_list = ( - ( - "user1", - "John", - "Doe", - "user1@example.com", - datetime(1970, 1, 1), - ), - ( - "user2", - "Max", - "Mustermann", - "user2@example.com", - datetime(1970, 1, 1), - ), - ) - cursor.executemany(query, query_list) - 1 / 0 - except ZeroDivisionError: - pass - - (event,) = events - - # Ensure operation is rolled back - assert not User.objects.exists() - - assert event["contexts"]["trace"]["origin"] == "manual" - - rollback_spans = [ - span - for span in event["spans"] - if span["data"].get(SPANDATA.DB_OPERATION) == SPANNAME.DB_ROLLBACK - ] - assert len(rollback_spans) == 1 - rollback_span = rollback_spans[0] - - assert rollback_span["origin"] == "auto.db.django" - - # Verify other database attributes - assert rollback_span["data"].get(SPANDATA.DB_SYSTEM) == "sqlite" - conn_params = connection.get_connection_params() - assert rollback_span["data"].get(SPANDATA.DB_NAME) is not None - assert rollback_span["data"].get(SPANDATA.DB_NAME) == conn_params.get( - "database" - ) or conn_params.get("dbname") - - insert_spans = [ - span - for span in event["spans"] - if span["description"].startswith("INSERT INTO") - ] + insert_spans = [span for span in spans if span["name"].startswith("INSERT INTO")] # Verify queries and rollback statements are siblings for insert_span in insert_spans: diff --git a/tests/integrations/django/test_transactions.py b/tests/integrations/django/test_resolver.py similarity index 88% rename from tests/integrations/django/test_transactions.py rename to tests/integrations/django/test_resolver.py index 6711043a47..5be661a058 100644 --- a/tests/integrations/django/test_transactions.py +++ b/tests/integrations/django/test_resolver.py @@ -68,10 +68,6 @@ def test_resolver_re_path_multiple_groups(): assert result == "/api/{project_id}/product/{pid}/" -@pytest.mark.skipif( - django.VERSION < (2, 0), - reason="Django>=2.0 required for patterns", -) def test_resolver_path_group(): url_conf = (path("api/v2//store/", lambda x: ""),) resolver = RavenResolver() @@ -79,10 +75,6 @@ def test_resolver_path_group(): assert result == "/api/v2/{project_id}/store/" -@pytest.mark.skipif( - django.VERSION < (2, 0), - reason="Django>=2.0 required for patterns", -) def test_resolver_path_multiple_groups(): url_conf = (path("api/v2//product/", lambda x: ""),) resolver = RavenResolver() @@ -90,10 +82,6 @@ def test_resolver_path_multiple_groups(): assert result == "/api/v2/{project_id}/product/{pid}" -@pytest.mark.skipif( - django.VERSION < (2, 0), - reason="Django>=2.0 required for patterns", -) @pytest.mark.skipif( django.VERSION > (5, 1), reason="get_converter removed in 5.1", @@ -130,10 +118,6 @@ class CustomPathConverter(PathConverter): assert result == "/api/v3/{my_path}" -@pytest.mark.skipif( - django.VERSION < (2, 0), - reason="Django>=2.0 required for patterns", -) def test_resolver_path_no_converter(): url_conf = (path("api/v4/", lambda x: ""),) resolver = RavenResolver() @@ -141,10 +125,6 @@ def test_resolver_path_no_converter(): assert result == "/api/v4/{project_id}" -@pytest.mark.skipif( - django.VERSION < (2, 0), - reason="Django>=2.0 required for path patterns", -) def test_resolver_path_with_i18n(): url_conf = (path(pgettext_lazy("url", "pgettext"), lambda x: ""),) resolver = RavenResolver() diff --git a/tests/integrations/django/test_tasks.py b/tests/integrations/django/test_tasks.py index 674ef53f0e..f080d7872c 100644 --- a/tests/integrations/django/test_tasks.py +++ b/tests/integrations/django/test_tasks.py @@ -1,8 +1,11 @@ +import logging + import pytest import sentry_sdk from sentry_sdk.consts import OP from sentry_sdk.integrations.django import DjangoIntegration +from sentry_sdk.integrations.logging import LoggingIntegration try: from django.tasks import task @@ -51,60 +54,35 @@ def task_two(): not HAS_DJANGO_TASKS, reason="Django tasks are only available in Django 6.0+", ) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_task_span_is_created( sentry_init, - capture_events, capture_items, immediate_backend, - span_streaming, ): """Test that the queue.submit.django span is created when a task is enqueued.""" sentry_init( integrations=[DjangoIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") - - with sentry_sdk.traces.start_span(name="custom parent"): - simple_task.enqueue() - - sentry_sdk.flush() - spans = [item.payload for item in items] - - queue_submit_spans = [ - span - for span in spans - if span["attributes"].get("sentry.op") == OP.QUEUE_SUBMIT_DJANGO - ] - assert len(queue_submit_spans) == 1 - assert ( - queue_submit_spans[0]["name"] - == "tests.integrations.django.test_tasks.simple_task" - ) - assert ( - queue_submit_spans[0]["attributes"]["sentry.origin"] == "auto.http.django" - ) - else: - events = capture_events() - - with sentry_sdk.start_transaction(name="test_transaction"): - simple_task.enqueue() - - (event,) = events - assert event["type"] == "transaction" - - queue_submit_spans = [ - span for span in event["spans"] if span["op"] == OP.QUEUE_SUBMIT_DJANGO - ] - assert len(queue_submit_spans) == 1 - assert ( - queue_submit_spans[0]["description"] - == "tests.integrations.django.test_tasks.simple_task" - ) - assert queue_submit_spans[0]["origin"] == "auto.http.django" + items = capture_items("span") + + with sentry_sdk.start_span(name="custom parent"): + simple_task.enqueue() + + sentry_sdk.flush() + spans = [item.payload for item in items] + + queue_submit_spans = [ + span + for span in spans + if span["attributes"].get("sentry.op") == OP.QUEUE_SUBMIT_DJANGO + ] + assert len(queue_submit_spans) == 1 + assert ( + queue_submit_spans[0]["name"] + == "tests.integrations.django.test_tasks.simple_task" + ) + assert queue_submit_spans[0]["attributes"]["sentry.origin"] == "auto.http.django" @pytest.mark.skipif( @@ -128,179 +106,108 @@ def test_task_enqueue_returns_result(sentry_init, immediate_backend): not HAS_DJANGO_TASKS, reason="Django tasks are only available in Django 6.0+", ) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_task_enqueue_with_kwargs( sentry_init, immediate_backend, - capture_events, capture_items, - span_streaming, ): """Test that task enqueuing works correctly with keyword arguments.""" sentry_init( integrations=[DjangoIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") - - with sentry_sdk.traces.start_span(name="custom parent"): - result = greet.enqueue(name="World", greeting="Hi") - - assert result.return_value == "Hi, World!" - - sentry_sdk.flush() - spans = [item.payload for item in items] - - queue_submit_spans = [ - span - for span in spans - if span["attributes"].get("sentry.op") == OP.QUEUE_SUBMIT_DJANGO - ] - assert len(queue_submit_spans) == 1 - assert ( - queue_submit_spans[0]["name"] - == "tests.integrations.django.test_tasks.greet" - ) - else: - events = capture_events() - - with sentry_sdk.start_transaction(name="test_transaction"): - result = greet.enqueue(name="World", greeting="Hi") - - assert result.return_value == "Hi, World!" - - (event,) = events - queue_submit_spans = [ - span for span in event["spans"] if span["op"] == OP.QUEUE_SUBMIT_DJANGO - ] - assert len(queue_submit_spans) == 1 - assert ( - queue_submit_spans[0]["description"] - == "tests.integrations.django.test_tasks.greet" - ) + items = capture_items("span") + + with sentry_sdk.start_span(name="custom parent"): + result = greet.enqueue(name="World", greeting="Hi") + + assert result.return_value == "Hi, World!" + + sentry_sdk.flush() + spans = [item.payload for item in items] + + queue_submit_spans = [ + span + for span in spans + if span["attributes"].get("sentry.op") == OP.QUEUE_SUBMIT_DJANGO + ] + assert len(queue_submit_spans) == 1 + assert queue_submit_spans[0]["name"] == "tests.integrations.django.test_tasks.greet" @pytest.mark.skipif( not HAS_DJANGO_TASKS, reason="Django tasks are only available in Django 6.0+", ) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_task_error_reporting( sentry_init, immediate_backend, - capture_events, capture_items, - span_streaming, ): """Test that errors in tasks are correctly reported and don't break the span.""" sentry_init( - integrations=[DjangoIntegration()], + integrations=[ + DjangoIntegration(), + LoggingIntegration(event_level=logging.ERROR), + ], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") - - with sentry_sdk.traces.start_span(name="custom parent"): - result = failing_task.enqueue() - - with pytest.raises(ValueError, match="Task failed"): - _ = result.return_value + items = capture_items("span") - sentry_sdk.flush() - spans = [item.payload for item in items] + with sentry_sdk.start_span(name="custom parent"): + result = failing_task.enqueue() - queue_submit_spans = [ - span - for span in spans - if span["attributes"].get("sentry.op") == OP.QUEUE_SUBMIT_DJANGO - ] + with pytest.raises(ValueError, match="Task failed"): + _ = result.return_value - assert len(queue_submit_spans) == 1 - assert ( - queue_submit_spans[0]["name"] - == "tests.integrations.django.test_tasks.failing_task" - ) - else: - events = capture_events() + sentry_sdk.flush() + spans = [item.payload for item in items] - with sentry_sdk.start_transaction(name="test_transaction"): - result = failing_task.enqueue() + queue_submit_spans = [ + span + for span in spans + if span["attributes"].get("sentry.op") == OP.QUEUE_SUBMIT_DJANGO + ] - with pytest.raises(ValueError, match="Task failed"): - _ = result.return_value - - assert len(events) == 2 - transaction_event = events[-1] - assert transaction_event["type"] == "transaction" - - queue_submit_spans = [ - span - for span in transaction_event["spans"] - if span["op"] == OP.QUEUE_SUBMIT_DJANGO - ] - - assert len(queue_submit_spans) == 1 - assert ( - queue_submit_spans[0]["description"] - == "tests.integrations.django.test_tasks.failing_task" - ) + assert len(queue_submit_spans) == 1 + assert ( + queue_submit_spans[0]["name"] + == "tests.integrations.django.test_tasks.failing_task" + ) @pytest.mark.skipif( not HAS_DJANGO_TASKS, reason="Django tasks are only available in Django 6.0+", ) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_multiple_task_enqueues_create_multiple_spans( sentry_init, - capture_events, capture_items, immediate_backend, - span_streaming, ): """Test that enqueueing multiple tasks creates multiple spans.""" sentry_init( integrations=[DjangoIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") - - with sentry_sdk.traces.start_span(name="custom parent"): - task_one.enqueue() - task_two.enqueue() - task_one.enqueue() - - sentry_sdk.flush() - spans = [item.payload for item in items] - - queue_submit_spans = [ - span - for span in spans - if span["attributes"].get("sentry.op") == OP.QUEUE_SUBMIT_DJANGO - ] - assert len(queue_submit_spans) == 3 - - span_names = [span["name"] for span in queue_submit_spans] - else: - events = capture_events() - - with sentry_sdk.start_transaction(name="test_transaction"): - task_one.enqueue() - task_two.enqueue() - task_one.enqueue() - - (event,) = events - queue_submit_spans = [ - span for span in event["spans"] if span["op"] == OP.QUEUE_SUBMIT_DJANGO - ] - assert len(queue_submit_spans) == 3 - - span_names = [span["description"] for span in queue_submit_spans] + items = capture_items("span") + + with sentry_sdk.start_span(name="custom parent"): + task_one.enqueue() + task_two.enqueue() + task_one.enqueue() + + sentry_sdk.flush() + spans = [item.payload for item in items] + + queue_submit_spans = [ + span + for span in spans + if span["attributes"].get("sentry.op") == OP.QUEUE_SUBMIT_DJANGO + ] + assert len(queue_submit_spans) == 3 + + span_names = [span["name"] for span in queue_submit_spans] assert span_names.count("tests.integrations.django.test_tasks.task_one") == 2 assert span_names.count("tests.integrations.django.test_tasks.task_two") == 1 diff --git a/tests/integrations/dramatiq/test_dramatiq.py b/tests/integrations/dramatiq/test_dramatiq.py index 6f889e5d9b..31577cd621 100644 --- a/tests/integrations/dramatiq/test_dramatiq.py +++ b/tests/integrations/dramatiq/test_dramatiq.py @@ -6,13 +6,11 @@ from dramatiq.middleware import Middleware, SkipMessage import sentry_sdk -from sentry_sdk import start_transaction -from sentry_sdk.consts import SPANDATA, SPANSTATUS +from sentry_sdk.consts import SPANDATA from sentry_sdk.integrations.dramatiq import DramatiqIntegration -from sentry_sdk.integrations.logging import ignore_logger -from sentry_sdk.tracing import Transaction, TransactionSource +from sentry_sdk.integrations.logging import ignore_logger_for_events -ignore_logger("dramatiq.worker.WorkerThread") +ignore_logger_for_events("dramatiq.worker.WorkerThread") @pytest.fixture(scope="function") @@ -70,46 +68,34 @@ def dummy_actor(x, y): @pytest.mark.parametrize( - "broker,expected_span_status,fail_fast,span_streaming", + "broker,expected_span_status,fail_fast", [ - ({"traces_sample_rate": 1.0}, SPANSTATUS.INTERNAL_ERROR, False, False), - ({"traces_sample_rate": 1.0}, SPANSTATUS.OK, False, False), - ({"traces_sample_rate": 1.0}, SPANSTATUS.INTERNAL_ERROR, True, False), - ({"traces_sample_rate": 1.0}, SPANSTATUS.OK, True, False), ( { "traces_sample_rate": 1.0, - "trace_lifecycle": "stream", }, - SPANSTATUS.INTERNAL_ERROR, + "error", False, - True, ), ( { "traces_sample_rate": 1.0, - "trace_lifecycle": "stream", }, - SPANSTATUS.OK, + "ok", False, - True, ), ( { "traces_sample_rate": 1.0, - "trace_lifecycle": "stream", }, - SPANSTATUS.INTERNAL_ERROR, - True, + "error", True, ), ( { "traces_sample_rate": 1.0, - "trace_lifecycle": "stream", }, - SPANSTATUS.OK, - True, + "ok", True, ), ], @@ -118,10 +104,6 @@ def dummy_actor(x, y): "success", "error_fail_fast", "success_fail_fast", - "error_stream", - "success_stream", - "error_fail_fast_stream", - "success_fail_fast_stream", ], indirect=["broker"], ) @@ -132,14 +114,10 @@ def test_task_transaction( capture_items, expected_span_status, fail_fast, - span_streaming, ): - task_fails = expected_span_status == SPANSTATUS.INTERNAL_ERROR + task_fails = expected_span_status == "error" - if span_streaming: - items = capture_items("event", "span") - else: - events = capture_events() + items = capture_items("event", "span") @dramatiq.actor(max_retries=0) def dummy_actor(x, y): @@ -147,7 +125,7 @@ def dummy_actor(x, y): dummy_actor.send(1, int(not task_fails)) - if expected_span_status == SPANSTATUS.INTERNAL_ERROR and fail_fast: + if expected_span_status == "error" and fail_fast: with pytest.raises(ZeroDivisionError): broker.join(dummy_actor.queue_name, fail_fast=fail_fast) else: @@ -156,99 +134,57 @@ def dummy_actor(x, y): worker.join() sentry_sdk.flush() - if span_streaming: - if task_fails: - error_item, segment_item = items - error_event = error_item.payload - exception = error_event["exception"]["values"][0] - assert exception["type"] == "ZeroDivisionError" - assert exception["mechanism"]["type"] == DramatiqIntegration.identifier - else: - (segment_item,) = items - - segment = segment_item.payload - assert segment_item.type == "span" - assert segment["name"] == "dummy_actor" - assert segment["is_segment"] is True - assert segment["attributes"]["sentry.op"] == "queue.task.dramatiq" - assert segment["attributes"]["sentry.segment.name.source"] == "task" - assert ( - segment["attributes"][SPANDATA.MESSAGING_DESTINATION_NAME] - == dummy_actor.queue_name - ) - assert segment["status"] == ("error" if task_fails else "ok") + if task_fails: + error_item, segment_item = items + error_event = error_item.payload + exception = error_event["exception"]["values"][0] + assert exception["type"] == "ZeroDivisionError" + assert exception["mechanism"]["type"] == DramatiqIntegration.identifier else: - if task_fails: - error_event = events.pop(0) - exception = error_event["exception"]["values"][0] - assert exception["type"] == "ZeroDivisionError" - assert exception["mechanism"]["type"] == DramatiqIntegration.identifier - - (event,) = events - assert event["type"] == "transaction" - assert event["transaction"] == "dummy_actor" - assert event["transaction_info"] == {"source": TransactionSource.TASK} - assert ( - event["contexts"]["trace"]["data"][SPANDATA.MESSAGING_DESTINATION_NAME] - == dummy_actor.queue_name - ) - assert event["contexts"]["trace"]["status"] == expected_span_status + (segment_item,) = items + + segment = segment_item.payload + assert segment_item.type == "span" + assert segment["name"] == "dummy_actor" + assert segment["is_segment"] is True + assert segment["attributes"]["sentry.op"] == "queue.task.dramatiq" + assert segment["attributes"]["sentry.segment.name.source"] == "task" + assert ( + segment["attributes"][SPANDATA.MESSAGING_DESTINATION_NAME] + == dummy_actor.queue_name + ) + assert segment["status"] == ("error" if task_fails else "ok") @pytest.mark.parametrize( - "broker,span_streaming", + "broker", [ - ({"traces_sample_rate": 1.0}, False), - ( - { - "traces_sample_rate": 1.0, - "trace_lifecycle": "stream", - }, - True, - ), + { + "traces_sample_rate": 1.0, + }, ], - ids=["static", "stream"], indirect=["broker"], ) -def test_dramatiq_propagate_trace( - broker, worker, capture_events, capture_items, span_streaming -): - if span_streaming: - items = capture_items("span") +def test_dramatiq_propagate_trace(broker, worker, capture_items): + items = capture_items("span") - with sentry_sdk.traces.start_span(name="outer") as outer_span: - - @dramatiq.actor(max_retries=0) - def propagated_trace_task(): - pass - - propagated_trace_task.send() - broker.join(propagated_trace_task.queue_name) - worker.join() - - sentry_sdk.flush() - - inner_segment, outer_segment = [i.payload for i in items] - assert inner_segment["name"] == "propagated_trace_task" - assert inner_segment["attributes"]["sentry.op"] == "queue.task.dramatiq" - assert inner_segment["trace_id"] == outer_span.trace_id - assert outer_segment["name"] == "outer" - else: - events = capture_events() + with sentry_sdk.start_span(name="outer") as outer_span: @dramatiq.actor(max_retries=0) def propagated_trace_task(): pass - with start_transaction() as outer_transaction: - propagated_trace_task.send() - broker.join(propagated_trace_task.queue_name) - worker.join() + propagated_trace_task.send() + broker.join(propagated_trace_task.queue_name) + worker.join() + + sentry_sdk.flush() - assert ( - events[0]["transaction"] == "propagated_trace_task" - ) # the "inner" transaction - assert events[0]["contexts"]["trace"]["trace_id"] == outer_transaction.trace_id + inner_segment, outer_segment = [i.payload for i in items] + assert inner_segment["name"] == "propagated_trace_task" + assert inner_segment["attributes"]["sentry.op"] == "queue.task.dramatiq" + assert inner_segment["trace_id"] == outer_span.trace_id + assert outer_segment["name"] == "outer" @pytest.mark.parametrize( @@ -578,37 +514,27 @@ def dummy_actor(): @pytest.mark.parametrize( - "broker,span_streaming", + "broker", [ - ({"traces_sample_rate": 1.0}, False), - ( - { - "traces_sample_rate": 1.0, - "trace_lifecycle": "stream", - }, - True, - ), + { + "traces_sample_rate": 1.0, + }, ], - ids=["static", "stream"], indirect=["broker"], ) def test_that_skip_message_cleans_up_scope_and_transaction( - broker, worker, capture_events, capture_items, span_streaming + broker, worker, capture_items ): captured_spans: list = [] class SkipMessageMiddleware(Middleware): def before_process_message(self, broker, message): - if span_streaming: - captured_spans.append(sentry_sdk.get_current_span()) - else: - captured_spans.append(sentry_sdk.get_current_scope().transaction) + captured_spans.append(sentry_sdk.get_current_span()) raise SkipMessage() broker.add_middleware(SkipMessageMiddleware()) - if span_streaming: - items = capture_items("span") + items = capture_items("span") @dramatiq.actor(max_retries=0) def skipped_actor(): ... @@ -618,12 +544,7 @@ def skipped_actor(): ... broker.join(skipped_actor.queue_name) worker.join() - if span_streaming: - sentry_sdk.flush() - (segment_payload,) = [i.payload for i in items] - assert segment_payload["name"] == "skipped_actor" - assert segment_payload["end_timestamp"] is not None - else: - (transaction,) = captured_spans - assert isinstance(transaction, Transaction) - assert transaction.timestamp is not None + sentry_sdk.flush() + (segment_payload,) = [i.payload for i in items] + assert segment_payload["name"] == "skipped_actor" + assert segment_payload["end_timestamp"] is not None diff --git a/tests/integrations/falcon/test_falcon.py b/tests/integrations/falcon/test_falcon.py index 79765bc537..027684b181 100644 --- a/tests/integrations/falcon/test_falcon.py +++ b/tests/integrations/falcon/test_falcon.py @@ -8,7 +8,6 @@ from sentry_sdk.consts import SPANDATA from sentry_sdk.integrations.falcon import FalconIntegration from sentry_sdk.integrations.logging import LoggingIntegration -from sentry_sdk.utils import parse_version try: import falcon.asgi @@ -18,9 +17,6 @@ import falcon.inspect # We only need this module for the ASGI test -FALCON_VERSION = parse_version(falcon.__version__) - - @pytest.fixture def make_app(sentry_init): def inner(): @@ -65,34 +61,23 @@ def inner(): return inner -@pytest.mark.parametrize("span_streaming", [True, False]) def test_has_context( sentry_init, - capture_events, capture_items, make_client, - span_streaming, ): sentry_init( integrations=[FalconIntegration()], - trace_lifecycle="stream" if span_streaming else "static", ) client = make_client() - if span_streaming: - items = capture_items("event") + items = capture_items("event") - response = client.simulate_get("/message") - assert response.status == falcon.HTTP_200 - - (event,) = (item.payload for item in items) - else: - events = capture_events() + response = client.simulate_get("/message") + assert response.status == falcon.HTTP_200 - response = client.simulate_get("/message") - assert response.status == falcon.HTTP_200 + (event,) = (item.payload for item in items) - (event,) = events assert event["transaction"] == "/message" # Falcon URI template assert "data" not in event["request"] assert event["request"]["url"] == "http://falconframework.org/message" @@ -107,50 +92,35 @@ def test_has_context( ("/message/123456", "path", "/message/123456", "url"), ], ) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_transaction_style( sentry_init, make_client, - capture_events, capture_items, url, transaction_style, expected_transaction, expected_source, - span_streaming, ): integration = FalconIntegration(transaction_style=transaction_style) sentry_init( integrations=[integration], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) client = make_client() - if span_streaming: - items = capture_items("event") - items = capture_items("event", "span") + items = capture_items("event", "span") - response = client.simulate_get(url) - assert response.status == falcon.HTTP_200 + response = client.simulate_get(url) + assert response.status == falcon.HTTP_200 - (event,) = (item.payload for item in items if item.type == "event") + (event,) = (item.payload for item in items if item.type == "event") - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - spans = [span for span in spans if span["name"] == expected_transaction] - assert len(spans) == 1 - assert spans[0]["attributes"]["sentry.segment.name.source"] == expected_source - else: - events = capture_events() - - response = client.simulate_get(url) - assert response.status == falcon.HTTP_200 - - (event, transaction) = events + sentry_sdk.flush() - assert transaction["transaction"] == expected_transaction - assert transaction["transaction_info"] == {"source": expected_source} + spans = [item.payload for item in items if item.type == "span"] + spans = [span for span in spans if span["name"] == expected_transaction] + assert len(spans) == 1 + assert spans[0]["attributes"]["sentry.segment.name.source"] == expected_source assert event["transaction"] == expected_transaction assert event["transaction_info"] == {"source": expected_source} @@ -164,7 +134,6 @@ def test_http_route( sentry_init( integrations=[FalconIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", ) client = make_client() @@ -177,17 +146,13 @@ def test_http_route( assert segment["attributes"][SPANDATA.HTTP_ROUTE] == "/message/{message_id:int}" -@pytest.mark.parametrize("span_streaming", [True, False]) def test_unhandled_errors( sentry_init, capture_exceptions, - capture_events, capture_items, - span_streaming, ): sentry_init( integrations=[FalconIntegration()], - trace_lifecycle="stream" if span_streaming else "static", ) class Resource: @@ -200,45 +165,29 @@ def on_get(self, req, resp): client = falcon.testing.TestClient(app) exceptions = capture_exceptions() - if span_streaming: - items = capture_items("event") + items = capture_items("event") - try: - client.simulate_get("/") - except ZeroDivisionError: - pass - - (exc,) = exceptions - assert isinstance(exc, ZeroDivisionError) - - (event,) = (item.payload for item in items) - else: - events = capture_events() + try: + client.simulate_get("/") + except ZeroDivisionError: + pass - try: - client.simulate_get("/") - except ZeroDivisionError: - pass + (exc,) = exceptions + assert isinstance(exc, ZeroDivisionError) - (exc,) = exceptions - assert isinstance(exc, ZeroDivisionError) + (event,) = (item.payload for item in items) - (event,) = events assert event["exception"]["values"][0]["mechanism"]["type"] == "falcon" assert " by zero" in event["exception"]["values"][0]["value"] -@pytest.mark.parametrize("span_streaming", [True, False]) def test_raised_5xx_errors( sentry_init, capture_exceptions, - capture_events, capture_items, - span_streaming, ): sentry_init( integrations=[FalconIntegration()], - trace_lifecycle="stream" if span_streaming else "static", ) class Resource: @@ -251,39 +200,26 @@ def on_get(self, req, resp): client = falcon.testing.TestClient(app) exceptions = capture_exceptions() - if span_streaming: - items = capture_items("event") + items = capture_items("event") - client.simulate_get("/") - - (exc,) = exceptions - assert isinstance(exc, falcon.HTTPError) - - (event,) = (item.payload for item in items) - else: - events = capture_events() + client.simulate_get("/") - client.simulate_get("/") + (exc,) = exceptions + assert isinstance(exc, falcon.HTTPError) - (exc,) = exceptions - assert isinstance(exc, falcon.HTTPError) + (event,) = (item.payload for item in items) - (event,) = events assert event["exception"]["values"][0]["mechanism"]["type"] == "falcon" assert event["exception"]["values"][0]["type"] == "HTTPError" -@pytest.mark.parametrize("span_streaming", [True, False]) def test_raised_4xx_errors( sentry_init, capture_exceptions, - capture_events, capture_items, - span_streaming, ): sentry_init( integrations=[FalconIntegration()], - trace_lifecycle="stream" if span_streaming else "static", ) class Resource: @@ -294,10 +230,7 @@ def on_get(self, req, resp): app.add_route("/", Resource()) exceptions = capture_exceptions() - if span_streaming: - events = capture_items("event") - else: - events = capture_events() + events = capture_items("event") client = falcon.testing.TestClient(app) client.simulate_get("/") @@ -306,13 +239,10 @@ def on_get(self, req, resp): assert len(events) == 0 -@pytest.mark.parametrize("span_streaming", [True, False]) def test_http_status( sentry_init, capture_exceptions, - capture_events, capture_items, - span_streaming, ): """ This just demonstrates, that if Falcon raises a HTTPStatus with code 500 @@ -320,7 +250,6 @@ def test_http_status( """ sentry_init( integrations=[FalconIntegration()], - trace_lifecycle="stream" if span_streaming else "static", ) class Resource: @@ -333,33 +262,24 @@ def on_get(self, req, resp): client = falcon.testing.TestClient(app) exceptions = capture_exceptions() - if span_streaming: - events = capture_items("event") + events = capture_items("event") - client.simulate_get("/") - else: - events = capture_events() - - client.simulate_get("/") + client.simulate_get("/") assert len(exceptions) == 0 assert len(events) == 0 @pytest.mark.parametrize("max_value_length", [1024, None]) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_falcon_large_json_request( sentry_init, - capture_events, capture_items, max_value_length, - span_streaming, ): sentry_init( integrations=[FalconIntegration()], max_request_body_size="always", max_value_length=max_value_length, - trace_lifecycle="stream" if span_streaming else "static", ) data = {"foo": {"bar": "a" * (1034)}} @@ -375,20 +295,12 @@ def on_post(self, req, resp): client = falcon.testing.TestClient(app) - if span_streaming: - items = capture_items("event") - - response = client.simulate_post("/", json=data) - assert response.status == falcon.HTTP_200 + items = capture_items("event") - (event,) = (item.payload for item in items) - else: - events = capture_events() + response = client.simulate_post("/", json=data) + assert response.status == falcon.HTTP_200 - response = client.simulate_post("/", json=data) - assert response.status == falcon.HTTP_200 - - (event,) = events + (event,) = (item.payload for item in items) if max_value_length: assert event["_meta"]["request"]["data"]["foo"]["bar"] == { "": { @@ -402,17 +314,13 @@ def on_post(self, req, resp): @pytest.mark.parametrize("data", [{}, []], ids=["empty-dict", "empty-list"]) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_falcon_empty_json_request( sentry_init, - capture_events, capture_items, data, - span_streaming, ): sentry_init( integrations=[FalconIntegration()], - trace_lifecycle="stream" if span_streaming else "static", ) class Resource: @@ -426,33 +334,21 @@ def on_post(self, req, resp): client = falcon.testing.TestClient(app) - if span_streaming: - items = capture_items("event") - - response = client.simulate_post("/", json=data) - assert response.status == falcon.HTTP_200 - - (event,) = (item.payload for item in items) - else: - events = capture_events() + items = capture_items("event") - response = client.simulate_post("/", json=data) - assert response.status == falcon.HTTP_200 + response = client.simulate_post("/", json=data) + assert response.status == falcon.HTTP_200 - (event,) = events + (event,) = (item.payload for item in items) assert event["request"]["data"] == data -@pytest.mark.parametrize("span_streaming", [True, False]) def test_falcon_raw_data_request( sentry_init, - capture_events, capture_items, - span_streaming, ): sentry_init( integrations=[FalconIntegration()], - trace_lifecycle="stream" if span_streaming else "static", ) class Resource: @@ -465,34 +361,22 @@ def on_post(self, req, resp): client = falcon.testing.TestClient(app) - if span_streaming: - items = capture_items("event") - - response = client.simulate_post("/", body="hi") - assert response.status == falcon.HTTP_200 - - (event,) = (item.payload for item in items) - else: - events = capture_events() + items = capture_items("event") - response = client.simulate_post("/", body="hi") - assert response.status == falcon.HTTP_200 + response = client.simulate_post("/", body="hi") + assert response.status == falcon.HTTP_200 - (event,) = events + (event,) = (item.payload for item in items) assert event["request"]["headers"]["Content-Length"] == "2" assert event["request"]["data"] == "" -@pytest.mark.parametrize("span_streaming", [True, False]) def test_logging( sentry_init, - capture_events, capture_items, - span_streaming, ): sentry_init( integrations=[FalconIntegration(), LoggingIntegration(event_level="ERROR")], - trace_lifecycle="stream" if span_streaming else "static", ) logger = logging.getLogger() @@ -508,18 +392,11 @@ def on_get(self, req, resp): client = falcon.testing.TestClient(app) - if span_streaming: - items = capture_items("event") + items = capture_items("event") - client.simulate_get("/") - - (event,) = (item.payload for item in items) - else: - events = capture_events() - - client.simulate_get("/") + client.simulate_get("/") - (event,) = events + (event,) = (item.payload for item in items) assert event["level"] == "error" @@ -546,16 +423,12 @@ def http500_handler(ex, req, resp, params): assert response.json == {"message": "Sentry error."} -@pytest.mark.parametrize("span_streaming", [True, False]) def test_error_in_errorhandler( sentry_init, - capture_events, capture_items, - span_streaming, ): sentry_init( integrations=[FalconIntegration()], - trace_lifecycle="stream" if span_streaming else "static", ) app = falcon.API() @@ -572,36 +445,24 @@ def http500_handler(ex, req, resp, params): app.add_error_handler(Exception, http500_handler) client = falcon.testing.TestClient(app) - if span_streaming: - items = capture_items("event") - - with pytest.raises(ZeroDivisionError): - client.simulate_get("/") + items = capture_items("event") - (event,) = (item.payload for item in items) - else: - events = capture_events() - - with pytest.raises(ZeroDivisionError): - client.simulate_get("/") + with pytest.raises(ZeroDivisionError): + client.simulate_get("/") - (event,) = events + (event,) = (item.payload for item in items) last_ex_values = event["exception"]["values"][-1] assert last_ex_values["type"] == "ZeroDivisionError" assert last_ex_values["stacktrace"]["frames"][-1]["vars"]["ex"] == "ValueError()" -@pytest.mark.parametrize("span_streaming", [True, False]) def test_bad_request_not_captured( sentry_init, - capture_events, capture_items, - span_streaming, ): sentry_init( integrations=[FalconIntegration()], - trace_lifecycle="stream" if span_streaming else "static", ) app = falcon.API() @@ -614,26 +475,19 @@ def on_get(self, req, resp): client = falcon.testing.TestClient(app) - if span_streaming: - events = capture_items("event") - else: - events = capture_events() + events = capture_items("event") client.simulate_get("/") assert not events -@pytest.mark.parametrize("span_streaming", [True, False]) def test_does_not_leak_scope( sentry_init, - capture_events, capture_items, - span_streaming, ): sentry_init( integrations=[FalconIntegration()], - trace_lifecycle="stream" if span_streaming else "static", ) app = falcon.API() @@ -654,10 +508,7 @@ def generator(): client = falcon.testing.TestClient(app) - if span_streaming: - events = capture_items("event") - else: - events = capture_events() + events = capture_items("event") sentry_sdk.get_isolation_scope().set_tag("request_data", False) @@ -669,11 +520,7 @@ def generator(): assert not sentry_sdk.get_isolation_scope()._tags["request_data"] -@pytest.mark.skipif( - not hasattr(falcon, "asgi"), reason="This Falcon version lacks ASGI support." -) -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_falcon_not_breaking_asgi(sentry_init, span_streaming): +def test_falcon_not_breaking_asgi(sentry_init): """ This test simply verifies that the Falcon integration does not break ASGI Falcon apps. @@ -683,7 +530,6 @@ def test_falcon_not_breaking_asgi(sentry_init, span_streaming): """ sentry_init( integrations=[FalconIntegration()], - trace_lifecycle="stream" if span_streaming else "static", ) asgi_app = falcon.asgi.App() @@ -694,17 +540,10 @@ def test_falcon_not_breaking_asgi(sentry_init, span_streaming): pytest.fail("Falcon integration causing errors in ASGI apps.") -@pytest.mark.skipif( - (FALCON_VERSION or ()) < (3,), - reason="The Sentry Falcon integration only supports custom error handlers on Falcon 3+", -) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_falcon_custom_error_handler( sentry_init, make_app, - capture_events, capture_items, - span_streaming, ): """ When a custom error handler handles what otherwise would have resulted in a 5xx error, @@ -712,59 +551,41 @@ def test_falcon_custom_error_handler( """ sentry_init( integrations=[FalconIntegration()], - trace_lifecycle="stream" if span_streaming else "static", ) app = make_app() client = falcon.testing.TestClient(app) - if span_streaming: - events = capture_items("event") - else: - events = capture_events() + events = capture_items("event") client.simulate_get("/custom-error") assert len(events) == 0 -@pytest.mark.parametrize("span_streaming", [True, False]) def test_span_origin( sentry_init, - capture_events, capture_items, make_client, - span_streaming, ): sentry_init( integrations=[FalconIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) client = make_client() - if span_streaming: - items = capture_items("span") - - client.simulate_get("/message") - - sentry_sdk.flush() - spans = [item.payload for item in items] - - assert spans[0]["attributes"]["sentry.origin"] == "auto.http.falcon" - else: - events = capture_events() + items = capture_items("span") - client.simulate_get("/message") + client.simulate_get("/message") - (_, event) = events + sentry_sdk.flush() + spans = [item.payload for item in items] - assert event["contexts"]["trace"]["origin"] == "auto.http.falcon" + assert spans[0]["attributes"]["sentry.origin"] == "auto.http.falcon" -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_falcon_request_media(sentry_init, span_streaming): +def test_falcon_request_media(sentry_init): # test_passed stores whether the test has passed. test_passed = False @@ -792,7 +613,6 @@ def on_post(self, req, _): sentry_init( integrations=[FalconIntegration()], - trace_lifecycle="stream" if span_streaming else "static", ) try: diff --git a/tests/integrations/fastapi/test_fastapi.py b/tests/integrations/fastapi/test_fastapi.py index a79b915eef..0439326881 100644 --- a/tests/integrations/fastapi/test_fastapi.py +++ b/tests/integrations/fastapi/test_fastapi.py @@ -4,7 +4,6 @@ import os import threading import warnings -from unittest import mock import fastapi import pytest @@ -28,6 +27,7 @@ from sentry_sdk.feature_flags import add_feature_flag from sentry_sdk.integrations.asgi import SentryAsgiMiddleware from sentry_sdk.integrations.fastapi import FastApiIntegration +from sentry_sdk.integrations.logging import LoggingIntegration from sentry_sdk.integrations.starlette import StarletteIntegration from sentry_sdk.utils import parse_version @@ -57,7 +57,6 @@ ) from tests.integrations.conftest import parametrize_test_configurable_status_codes -from tests.integrations.starlette import test_starlette def fastapi_app_factory(): @@ -126,238 +125,142 @@ async def body_form( @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) -async def test_request_info_json_body( - sentry_init, capture_events, capture_items, span_streaming -): +async def test_request_info_json_body(sentry_init, capture_items): sentry_init( traces_sample_rate=1.0, send_default_pii=True, integrations=[StarletteIntegration()], - trace_lifecycle="stream" if span_streaming else "static", ) app = fastapi_app_factory() client = TestClient(app) - if span_streaming: - items = capture_items("event", "span") - - client.post( - "/body/json", - json=BODY_JSON, - headers={ - "cookie": "yummy_cookie=choco; tasty_cookie=strawberry", - }, - ) - - (event,) = (item.payload for item in items if item.type == "event") - assert event["request"]["cookies"] == { - "tasty_cookie": "strawberry", - "yummy_cookie": "choco", - } - assert event["request"]["data"] == BODY_JSON - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - server_span = next( - span for span in spans if span["attributes"]["sentry.op"] == "http.server" - ) + items = capture_items("event", "span") - assert json.loads( - server_span["attributes"][SPANDATA.HTTP_REQUEST_BODY_DATA] - ) == {"some": "json", "for": "testing", "nested": {"numbers": 123}} - else: - events = capture_events() - - client.post( - "/body/json", - json=BODY_JSON, - headers={ - "cookie": "yummy_cookie=choco; tasty_cookie=strawberry", - }, - ) + client.post( + "/body/json", + json=BODY_JSON, + headers={ + "cookie": "yummy_cookie=choco; tasty_cookie=strawberry", + }, + ) - (event, transaction_event) = events + (event,) = (item.payload for item in items if item.type == "event") + assert event["request"]["cookies"] == { + "tasty_cookie": "strawberry", + "yummy_cookie": "choco", + } + assert event["request"]["data"] == BODY_JSON - assert event["request"]["cookies"] == { - "tasty_cookie": "strawberry", - "yummy_cookie": "choco", - } - assert event["request"]["data"] == BODY_JSON + sentry_sdk.flush() + spans = [item.payload for item in items if item.type == "span"] + server_span = next( + span for span in spans if span["attributes"]["sentry.op"] == "http.server" + ) - assert transaction_event["request"]["cookies"] == { - "tasty_cookie": "strawberry", - "yummy_cookie": "choco", - } - assert transaction_event["request"]["data"] == BODY_JSON + assert json.loads(server_span["attributes"][SPANDATA.HTTP_REQUEST_BODY_DATA]) == { + "some": "json", + "for": "testing", + "nested": {"numbers": 123}, + } @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) -async def test_formdata_request_body( - sentry_init, capture_events, capture_items, span_streaming -): +async def test_formdata_request_body(sentry_init, capture_items): sentry_init( traces_sample_rate=1.0, send_default_pii=True, max_request_body_size="always", integrations=[StarletteIntegration()], - trace_lifecycle="stream" if span_streaming else "static", ) app = fastapi_app_factory() client = TestClient(app) - if span_streaming: - items = capture_items("event", "span") + items = capture_items("event", "span") - client.post( - "/body/form", - data=BODY_FORM.encode("utf-8"), - headers={ - "content-type": "multipart/form-data; boundary=fd721ef49ea403a6", - }, - ) - - (event,) = (item.payload for item in items if item.type == "event") - assert event["request"]["data"].keys() == PARSED_FORM.keys() - assert event["request"]["data"]["username"] == PARSED_FORM["username"] - assert event["request"]["data"]["password"] == "[Filtered]" - assert event["request"]["data"]["photo"] == "" - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - server_span = next( - span for span in spans if span["attributes"]["sentry.op"] == "http.server" - ) + client.post( + "/body/form", + data=BODY_FORM.encode("utf-8"), + headers={ + "content-type": "multipart/form-data; boundary=fd721ef49ea403a6", + }, + ) - # Going forward, the sanitization of data will need to happen within the `before_send_span` hooks - # See https://sentry.slack.com/archives/C09RR0KD2N7/p1776951331206129?thread_ts=1776951227.440659&cid=C09RR0KD2N7 - parsed_form_attribute = json.loads( - server_span["attributes"][SPANDATA.HTTP_REQUEST_BODY_DATA] - ) - assert parsed_form_attribute.keys() == PARSED_FORM.keys() - assert parsed_form_attribute["username"] == PARSED_FORM["username"] - assert parsed_form_attribute["password"] == "hello123" - assert parsed_form_attribute["photo"] == "[Unparsable]" - else: - events = capture_events() - - client.post( - "/body/form", - data=BODY_FORM.encode("utf-8"), - headers={ - "content-type": "multipart/form-data; boundary=fd721ef49ea403a6", - }, - ) + (event,) = (item.payload for item in items if item.type == "event") + assert event["request"]["data"].keys() == PARSED_FORM.keys() + assert event["request"]["data"]["username"] == PARSED_FORM["username"] + assert event["request"]["data"]["password"] == "[Filtered]" + assert event["request"]["data"]["photo"] == "" - (event, transaction_event) = events - assert event["request"]["data"].keys() == PARSED_FORM.keys() - assert event["request"]["data"]["username"] == PARSED_FORM["username"] - assert event["request"]["data"]["password"] == "[Filtered]" - assert event["request"]["data"]["photo"] == "" - assert event["_meta"]["request"]["data"]["photo"] == { - "": {"rem": [["!raw", "x"]]} - } + sentry_sdk.flush() + spans = [item.payload for item in items if item.type == "span"] + server_span = next( + span for span in spans if span["attributes"]["sentry.op"] == "http.server" + ) - assert transaction_event["request"]["data"].keys() == PARSED_FORM.keys() - assert ( - transaction_event["request"]["data"]["username"] == PARSED_FORM["username"] - ) - assert transaction_event["request"]["data"]["password"] == "[Filtered]" - assert transaction_event["request"]["data"]["photo"] == "" - assert transaction_event["_meta"]["request"]["data"]["photo"] == { - "": {"rem": [["!raw", "x"]]} - } + # Going forward, the sanitization of data will need to happen within the `before_send_span` hooks + # See https://sentry.slack.com/archives/C09RR0KD2N7/p1776951331206129?thread_ts=1776951227.440659&cid=C09RR0KD2N7 + parsed_form_attribute = json.loads( + server_span["attributes"][SPANDATA.HTTP_REQUEST_BODY_DATA] + ) + assert parsed_form_attribute.keys() == PARSED_FORM.keys() + assert parsed_form_attribute["username"] == PARSED_FORM["username"] + assert parsed_form_attribute["password"] == "hello123" + assert parsed_form_attribute["photo"] == "[Unparsable]" @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) -async def test_request_body_too_big( - sentry_init, capture_events, capture_items, span_streaming -): +async def test_request_body_too_big(sentry_init, capture_items): sentry_init( traces_sample_rate=1.0, send_default_pii=True, integrations=[StarletteIntegration()], - trace_lifecycle="stream" if span_streaming else "static", ) app = fastapi_app_factory() client = TestClient(app) - if span_streaming: - items = capture_items("event", "span") + items = capture_items("event", "span") - client.post( - "/body/form", - data=BODY_FORM.encode("utf-8"), - headers={ - "content-type": "multipart/form-data; boundary=fd721ef49ea403a6", - "cookie": "yummy_cookie=choco; tasty_cookie=strawberry", - }, - ) - - (event,) = (item.payload for item in items if item.type == "event") - assert event["request"]["cookies"] == { - "tasty_cookie": "strawberry", - "yummy_cookie": "choco", - } - # Because request is too big only the AnnotatedValue is extracted. - assert event["_meta"]["request"]["data"] == {"": {"rem": [["!config", "x"]]}} - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - server_span = next( - span for span in spans if span["attributes"]["sentry.op"] == "http.server" - ) + client.post( + "/body/form", + data=BODY_FORM.encode("utf-8"), + headers={ + "content-type": "multipart/form-data; boundary=fd721ef49ea403a6", + "cookie": "yummy_cookie=choco; tasty_cookie=strawberry", + }, + ) - # Because request is too big only the AnnotatedValue is extracted. - assert ( - server_span["attributes"][SPANDATA.HTTP_REQUEST_BODY_DATA] - == "[Exceeds maximum size]" - ) - else: - events = capture_events() - - client.post( - "/body/form", - data=BODY_FORM.encode("utf-8"), - headers={ - "content-type": "multipart/form-data; boundary=fd721ef49ea403a6", - "cookie": "yummy_cookie=choco; tasty_cookie=strawberry", - }, - ) + (event,) = (item.payload for item in items if item.type == "event") + assert event["request"]["cookies"] == { + "tasty_cookie": "strawberry", + "yummy_cookie": "choco", + } + # Because request is too big only the AnnotatedValue is extracted. + assert event["_meta"]["request"]["data"] == {"": {"rem": [["!config", "x"]]}} - (event, transaction_event) = events - assert event["request"]["cookies"] == { - "tasty_cookie": "strawberry", - "yummy_cookie": "choco", - } - # Because request is too big only the AnnotatedValue is extracted. - assert event["_meta"]["request"]["data"] == {"": {"rem": [["!config", "x"]]}} + sentry_sdk.flush() + spans = [item.payload for item in items if item.type == "span"] + server_span = next( + span for span in spans if span["attributes"]["sentry.op"] == "http.server" + ) - assert transaction_event["request"]["cookies"] == { - "tasty_cookie": "strawberry", - "yummy_cookie": "choco", - } - # Because request is too big only the AnnotatedValue is extracted. - assert transaction_event["_meta"]["request"]["data"] == { - "": {"rem": [["!config", "x"]]} - } + # Because request is too big only the AnnotatedValue is extracted. + assert ( + server_span["attributes"][SPANDATA.HTTP_REQUEST_BODY_DATA] + == "[Exceeds maximum size]" + ) @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) async def test_formdata_request_body_data_collection_http_bodies_empty( - sentry_init, capture_events, capture_items, span_streaming + sentry_init, capture_items ): sentry_init( traces_sample_rate=1.0, max_request_body_size="always", integrations=[StarletteIntegration()], - trace_lifecycle="stream" if span_streaming else "static", data_collection={"http_bodies": []}, ) @@ -366,31 +269,22 @@ async def test_formdata_request_body_data_collection_http_bodies_empty( headers = {"content-type": "multipart/form-data; boundary=fd721ef49ea403a6"} - if span_streaming: - items = capture_items("event", "span") - - client.post("/body/form", data=BODY_FORM.encode("utf-8"), headers=headers) - - (event,) = (item.payload for item in items if item.type == "event") - assert "data" not in event["request"] + items = capture_items("event", "span") - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - server_span = next( - span for span in spans if span["attributes"]["sentry.op"] == "http.server" - ) - assert SPANDATA.HTTP_REQUEST_BODY_DATA not in server_span["attributes"] - else: - events = capture_events() + client.post("/body/form", data=BODY_FORM.encode("utf-8"), headers=headers) - client.post("/body/form", data=BODY_FORM.encode("utf-8"), headers=headers) + (event,) = (item.payload for item in items if item.type == "event") + assert "data" not in event["request"] - (event, _) = events - assert "data" not in event["request"] + sentry_sdk.flush() + spans = [item.payload for item in items if item.type == "span"] + server_span = next( + span for span in spans if span["attributes"]["sentry.op"] == "http.server" + ) + assert SPANDATA.HTTP_REQUEST_BODY_DATA not in server_span["attributes"] @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) @pytest.mark.parametrize( "data_collection, expect_body", [ @@ -408,62 +302,44 @@ async def test_formdata_request_body_data_collection_http_bodies_empty( ) async def test_request_body_data_collection( sentry_init, - capture_events, capture_items, - span_streaming, data_collection, expect_body, ): sentry_init( traces_sample_rate=1.0, integrations=[StarletteIntegration()], - trace_lifecycle="stream" if span_streaming else "static", data_collection=data_collection, ) app = fastapi_app_factory() client = TestClient(app) - if span_streaming: - items = capture_items("event", "span") + items = capture_items("event", "span") - client.post("/body/json", json=BODY_JSON) + client.post("/body/json", json=BODY_JSON) - (event,) = (item.payload for item in items if item.type == "event") + (event,) = (item.payload for item in items if item.type == "event") - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - server_span = next( - span for span in spans if span["attributes"]["sentry.op"] == "http.server" - ) + sentry_sdk.flush() + spans = [item.payload for item in items if item.type == "span"] + server_span = next( + span for span in spans if span["attributes"]["sentry.op"] == "http.server" + ) - if expect_body: - assert event["request"]["data"] == BODY_JSON - assert ( - json.loads(server_span["attributes"][SPANDATA.HTTP_REQUEST_BODY_DATA]) - == BODY_JSON - ) - else: - assert "data" not in event["request"] - assert SPANDATA.HTTP_REQUEST_BODY_DATA not in server_span["attributes"] + if expect_body: + assert event["request"]["data"] == BODY_JSON + assert ( + json.loads(server_span["attributes"][SPANDATA.HTTP_REQUEST_BODY_DATA]) + == BODY_JSON + ) else: - events = capture_events() - - client.post("/body/json", json=BODY_JSON) - - (event, _) = events - - if expect_body: - assert event["request"]["data"] == BODY_JSON - else: - assert "data" not in event["request"] + assert "data" not in event["request"] + assert SPANDATA.HTTP_REQUEST_BODY_DATA not in server_span["attributes"] @pytest.mark.asyncio async def test_response(sentry_init, capture_events): - # FastAPI is heavily based on Starlette so we also need - # to enable StarletteIntegration. - # In the future this will be auto enabled. sentry_init( integrations=[StarletteIntegration(), FastApiIntegration()], traces_sample_rate=1.0, @@ -479,11 +355,11 @@ async def test_response(sentry_init, capture_events): assert response.json() == {"message": "Hi"} - assert len(events) == 2 + assert len(events) == 1 - (message_event, transaction_event) = events + (message_event,) = events assert message_event["message"] == "Hi" - assert transaction_event["transaction"] == "/message" + assert message_event["transaction"] == "/message" @pytest.mark.parametrize( @@ -570,50 +446,11 @@ def test_legacy_setup( @pytest.mark.parametrize("endpoint", ["/sync/thread_ids", "/async/thread_ids"]) -@mock.patch("sentry_sdk.profiler.transaction_profiler.PROFILE_MINIMUM_SAMPLES", 0) -def test_active_thread_id(sentry_init, capture_envelopes, teardown_profiling, endpoint): - sentry_init( - traces_sample_rate=1.0, - profiles_sample_rate=1.0, - ) - app = fastapi_app_factory() - asgi_app = SentryAsgiMiddleware(app) - - envelopes = capture_envelopes() - - client = TestClient(asgi_app) - response = client.get(endpoint) - assert response.status_code == 200 - - data = json.loads(response.content) - - envelopes = [envelope for envelope in envelopes] - assert len(envelopes) == 1 - - profiles = [item for item in envelopes[0].items if item.type == "profile"] - assert len(profiles) == 1 - - for item in profiles: - transactions = item.payload.json["transactions"] - assert len(transactions) == 1 - assert str(data["active"]) == transactions[0]["active_thread_id"] - - transactions = [item for item in envelopes[0].items if item.type == "transaction"] - assert len(transactions) == 1 - - for item in transactions: - transaction = item.payload.json - trace_context = transaction["contexts"]["trace"] - assert str(data["active"]) == trace_context["data"]["thread.id"] - - -@pytest.mark.parametrize("endpoint", ["/sync/thread_ids", "/async/thread_ids"]) -def test_active_thread_id_span_streaming(sentry_init, capture_items, endpoint): +def test_active_thread_id(sentry_init, capture_items, endpoint): sentry_init( auto_enabling_integrations=False, # Ensure httpx is not auto-enabled; its legacy start_span interferes with streaming mode integrations=[StarletteIntegration(), FastApiIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", ) app = fastapi_app_factory() @@ -632,22 +469,23 @@ def test_active_thread_id_span_streaming(sentry_init, capture_items, endpoint): assert str(data["active"]) == segments[0]["attributes"]["thread.id"] -@pytest.mark.parametrize("span_streaming", [True, False]) @pytest.mark.asyncio -async def test_original_request_not_scrubbed( - sentry_init, capture_events, span_streaming -): +async def test_original_request_not_scrubbed(sentry_init, capture_events): sentry_init( auto_enabling_integrations=False, # Ensure httpx is not auto-enabled; its legacy start_span interferes with streaming mode - integrations=[StarletteIntegration(), FastApiIntegration()], + integrations=[ + StarletteIntegration(), + FastApiIntegration(), + LoggingIntegration(event_level=logging.ERROR), + ], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) app = FastAPI() @app.post("/error") async def _error(request: Request): + await request.json() logging.critical("Oh no!") assert request.headers["Authorization"] == "Bearer ohno" assert request.headers["Proxy-Authorization"] == "Basic ohno" @@ -673,102 +511,6 @@ async def _error(request: Request): assert event["request"]["headers"]["proxy-authorization"] == "[Filtered]" -def test_response_status_code_ok_in_transaction_context(sentry_init, capture_envelopes): - """ - Tests that the response status code is added to the transaction "response" context. - """ - sentry_init( - integrations=[StarletteIntegration(), FastApiIntegration()], - traces_sample_rate=1.0, - release="demo-release", - ) - - envelopes = capture_envelopes() - - app = fastapi_app_factory() - - client = TestClient(app) - client.get("/message") - - (_, transaction_envelope) = envelopes - transaction = transaction_envelope.get_transaction_event() - - assert transaction["type"] == "transaction" - assert len(transaction["contexts"]) > 0 - assert "response" in transaction["contexts"].keys(), ( - "Response context not found in transaction" - ) - assert transaction["contexts"]["response"]["status_code"] == 200 - - -def test_response_status_code_error_in_transaction_context( - sentry_init, - capture_envelopes, -): - """ - Tests that the response status code is added to the transaction "response" context. - """ - sentry_init( - integrations=[StarletteIntegration(), FastApiIntegration()], - traces_sample_rate=1.0, - release="demo-release", - ) - - envelopes = capture_envelopes() - - app = fastapi_app_factory() - - client = TestClient(app) - with pytest.raises(ZeroDivisionError): - client.get("/error") - - ( - _, - _, - transaction_envelope, - ) = envelopes - transaction = transaction_envelope.get_transaction_event() - - assert transaction["type"] == "transaction" - assert len(transaction["contexts"]) > 0 - assert "response" in transaction["contexts"].keys(), ( - "Response context not found in transaction" - ) - assert transaction["contexts"]["response"]["status_code"] == 500 - - -def test_response_status_code_not_found_in_transaction_context( - sentry_init, - capture_envelopes, -): - """ - Tests that the response status code is added to the transaction "response" context. - """ - sentry_init( - integrations=[StarletteIntegration(), FastApiIntegration()], - traces_sample_rate=1.0, - release="demo-release", - ) - - envelopes = capture_envelopes() - - app = fastapi_app_factory() - - client = TestClient(app) - client.get("/non-existing-route-123") - - (transaction_envelope,) = envelopes - transaction = transaction_envelope.get_transaction_event() - - assert transaction["type"] == "transaction" - assert len(transaction["contexts"]) > 0 - assert "response" in transaction["contexts"].keys(), ( - "Response context not found in transaction" - ) - assert transaction["contexts"]["response"]["status_code"] == 404 - - -@pytest.mark.parametrize("span_streaming", [True, False]) @pytest.mark.parametrize( "request_url,transaction_style,expected_transaction_name,expected_transaction_source", [ @@ -792,9 +534,7 @@ def test_transaction_name( transaction_style, expected_transaction_name, expected_transaction_source, - capture_envelopes, capture_items, - span_streaming, ): """ Tests that the transaction name is something meaningful. @@ -806,46 +546,29 @@ def test_transaction_name( FastApiIntegration(transaction_style=transaction_style), ], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") - else: - envelopes = capture_envelopes() + items = capture_items("span") app = fastapi_app_factory() client = TestClient(app) client.get(request_url) - if span_streaming: - sentry_sdk.flush() - segments = [item.payload for item in items if item.payload.get("is_segment")] - assert len(segments) == 1 - segment = segments[0] - assert segment["name"] == expected_transaction_name - assert ( - segment["attributes"]["sentry.segment.name.source"] - == expected_transaction_source - ) - else: - (_, transaction_envelope) = envelopes - transaction_event = transaction_envelope.get_transaction_event() - - assert transaction_event["transaction"] == expected_transaction_name - assert ( - transaction_event["transaction_info"]["source"] - == expected_transaction_source - ) + sentry_sdk.flush() + segments = [item.payload for item in items if item.payload.get("is_segment")] + assert len(segments) == 1 + segment = segments[0] + assert segment["name"] == expected_transaction_name + assert ( + segment["attributes"]["sentry.segment.name.source"] + == expected_transaction_source + ) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_http_route_with_prefix( sentry_init, - capture_envelopes, capture_items, - span_streaming, ): sentry_init( auto_enabling_integrations=False, @@ -854,13 +577,9 @@ def test_http_route_with_prefix( FastApiIntegration(transaction_style="url"), ], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") - else: - envelopes = capture_envelopes() + items = capture_items("span") app = FastAPI() router = APIRouter() @@ -874,19 +593,13 @@ async def get_user(user_id: int): client = TestClient(app) client.get("/api/users/123") - if span_streaming: - sentry_sdk.flush() - segments = [item.payload for item in items if item.payload.get("is_segment")] - assert len(segments) == 1 - segment = segments[0] - assert segment["name"] == "/api/users/{user_id}" - assert segment["attributes"]["sentry.segment.name.source"] == "route" - assert segment["attributes"]["http.route"] == "/api/users/{user_id}" - else: - (transaction_envelope,) = envelopes - transaction_event = transaction_envelope.get_transaction_event() - assert transaction_event["transaction"] == "/api/users/{user_id}" - assert transaction_event["transaction_info"]["source"] == "route" + sentry_sdk.flush() + segments = [item.payload for item in items if item.payload.get("is_segment")] + assert len(segments) == 1 + segment = segments[0] + assert segment["name"] == "/api/users/{user_id}" + assert segment["attributes"]["sentry.segment.name.source"] == "route" + assert segment["attributes"]["http.route"] == "/api/users/{user_id}" def test_route_endpoint_equal_dependant_call(sentry_init): @@ -986,7 +699,7 @@ def test_transaction_name_in_middleware( transaction_style, expected_transaction_name, expected_transaction_source, - capture_envelopes, + capture_items, ): """ Tests that the transaction name is something meaningful. @@ -1004,7 +717,7 @@ def test_transaction_name_in_middleware( traces_sample_rate=1.0, ) - envelopes = capture_envelopes() + items = capture_items("span") app = fastapi_app_factory() @@ -1018,70 +731,27 @@ def test_transaction_name_in_middleware( client = TestClient(app) client.get(request_url) - (transaction_envelope,) = envelopes - transaction_event = transaction_envelope.get_transaction_event() - - assert transaction_event["contexts"]["response"]["status_code"] == 400 - assert transaction_event["transaction"] == expected_transaction_name + sentry_sdk.flush() + segments = [item.payload for item in items if item.payload.get("is_segment")] + assert len(segments) == 1 + segment = segments[0] + assert segment["name"] == expected_transaction_name assert ( - transaction_event["transaction_info"]["source"] == expected_transaction_source + segment["attributes"]["sentry.segment.name.source"] + == expected_transaction_source ) -@test_starlette.parametrize_test_configurable_status_codes_deprecated -def test_configurable_status_codes_deprecated( - sentry_init, - capture_events, - failed_request_status_codes, - status_code, - expected_error, -): - with pytest.warns(DeprecationWarning): - starlette_integration = StarletteIntegration( - failed_request_status_codes=failed_request_status_codes - ) - - with pytest.warns(DeprecationWarning): - fast_api_integration = FastApiIntegration( - failed_request_status_codes=failed_request_status_codes - ) - - sentry_init( - integrations=[ - starlette_integration, - fast_api_integration, - ] - ) - - events = capture_events() - - app = FastAPI() - - @app.get("/error") - async def _error(): - raise HTTPException(status_code) - - client = TestClient(app) - client.get("/error") - - if expected_error: - assert len(events) == 1 - else: - assert not events - - @pytest.mark.skipif( FASTAPI_VERSION < (0, 80), reason="Requires FastAPI >= 0.80, because earlier versions do not support HTTP 'HEAD' requests", ) -def test_transaction_http_method_default(sentry_init, capture_events): +def test_transaction_http_method_default(sentry_init, capture_items): """ - By default OPTIONS and HEAD requests do not create a transaction. + By default OPTIONS and HEAD requests do not create a span. """ - # FastAPI is heavily based on Starlette so we also need - # to enable StarletteIntegration. - # In the future this will be auto enabled. sentry_init( + auto_enabling_integrations=False, traces_sample_rate=1.0, integrations=[ StarletteIntegration(), @@ -1091,29 +761,26 @@ def test_transaction_http_method_default(sentry_init, capture_events): app = fastapi_app_factory() - events = capture_events() + items = capture_items("span") client = TestClient(app) client.get("/nomessage") client.options("/nomessage") client.head("/nomessage") - assert len(events) == 1 - - (event,) = events - - assert event["request"]["method"] == "GET" + sentry_sdk.flush() + segments = [item.payload for item in items if item.payload.get("is_segment")] + assert len(segments) == 1 + assert segments[0]["attributes"]["http.request.method"] == "GET" @pytest.mark.skipif( FASTAPI_VERSION < (0, 80), reason="Requires FastAPI >= 0.80, because earlier versions do not support HTTP 'HEAD' requests", ) -def test_transaction_http_method_custom(sentry_init, capture_events): - # FastAPI is heavily based on Starlette so we also need - # to enable StarletteIntegration. - # In the future this will be auto enabled. +def test_transaction_http_method_custom(sentry_init, capture_items): sentry_init( + auto_enabling_integrations=False, traces_sample_rate=1.0, integrations=[ StarletteIntegration( @@ -1133,59 +800,47 @@ def test_transaction_http_method_custom(sentry_init, capture_events): app = fastapi_app_factory() - events = capture_events() + items = capture_items("span") client = TestClient(app) client.get("/nomessage") client.options("/nomessage") client.head("/nomessage") - assert len(events) == 2 - - (event1, event2) = events + sentry_sdk.flush() + segments = [item.payload for item in items if item.payload.get("is_segment")] + assert len(segments) == 2 - assert event1["request"]["method"] == "OPTIONS" - assert event2["request"]["method"] == "HEAD" + assert segments[0]["attributes"]["http.request.method"] == "OPTIONS" + assert segments[1]["attributes"]["http.request.method"] == "HEAD" -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_request_url(sentry_init, capture_events, capture_items, span_streaming): +def test_request_url(sentry_init, capture_items): sentry_init( traces_sample_rate=1.0, send_default_pii=True, integrations=[ StarletteIntegration(), ], - trace_lifecycle="stream" if span_streaming else "static", ) starlette_app = fastapi_app_factory() client = TestClient(starlette_app) - if span_streaming: - items = capture_items("span") - - client.get("/root/nomessage") - sentry_sdk.flush() - spans = [item.payload for item in items] - - (server_span,) = ( - span - for span in spans - if span["attributes"].get("sentry.op") == "http.server" - ) - assert server_span["attributes"][SPANDATA.URL_FULL] == ( - "http://testserver/root/nomessage" - ) - assert server_span["attributes"][SPANDATA.URL_PATH] == "/root/nomessage" - else: - events = capture_events() + items = capture_items("span") - client.get("/root/nomessage") + client.get("/root/nomessage") + sentry_sdk.flush() + spans = [item.payload for item in items] - (event,) = events - assert event["request"]["url"] == "http://testserver/root/nomessage" + (server_span,) = ( + span for span in spans if span["attributes"].get("sentry.op") == "http.server" + ) + assert server_span["attributes"][SPANDATA.URL_FULL] == ( + "http://testserver/root/nomessage" + ) + assert server_span["attributes"][SPANDATA.URL_PATH] == "/root/nomessage" @parametrize_test_configurable_status_codes @@ -1222,7 +877,7 @@ async def _error(): @pytest.mark.parametrize("transaction_style", ["endpoint", "url"]) -def test_app_host(sentry_init, capture_events, transaction_style): +def test_app_host(sentry_init, capture_items, transaction_style): sentry_init( traces_sample_rate=1.0, integrations=[ @@ -1240,20 +895,20 @@ async def subapp_route(): app.host("subapp", subapp) - events = capture_events() + items = capture_items("span") client = TestClient(app) client.get("/subapp", headers={"Host": "subapp"}) - assert len(events) == 1 - - (event,) = events - assert "transaction" in event + sentry_sdk.flush() + segments = [item.payload for item in items if item.payload.get("is_segment")] + assert len(segments) == 1 + segment = segments[0] if transaction_style == "url": - assert event["transaction"] == "/subapp" + assert segment["name"] == "/subapp" else: - assert event["transaction"].endswith("subapp_route") + assert segment["name"].endswith("subapp_route") @pytest.mark.asyncio diff --git a/tests/integrations/fastmcp/test_fastmcp.py b/tests/integrations/fastmcp/test_fastmcp.py index 6b2dc3c643..10699de562 100644 --- a/tests/integrations/fastmcp/test_fastmcp.py +++ b/tests/integrations/fastmcp/test_fastmcp.py @@ -11,7 +11,7 @@ - Span creation when tools/prompts/resources are called through MCP protocol - Span data accuracy (operation, name, origin, etc.) - Error capture and instrumentation -- PII and include_prompts flag behavior +- PII flag behavior - Request context data extraction - Transport detection (stdio, http, sse) @@ -23,13 +23,13 @@ import asyncio import json +import logging from unittest import mock -import anyio import pytest import sentry_sdk -from sentry_sdk.utils import package_version, parse_version +from sentry_sdk.integrations.logging import LoggingIntegration try: from unittest.mock import AsyncMock @@ -40,10 +40,8 @@ async def __call__(self, *args, **kwargs): return super(AsyncMock, self).__call__(*args, **kwargs) -from mcp.server.sse import SseServerTransport from mcp.server.streamable_http_manager import StreamableHTTPSessionManager -from sentry_sdk import start_transaction from sentry_sdk.consts import OP, SPANDATA from sentry_sdk.integrations.mcp import MCPIntegration @@ -54,8 +52,7 @@ async def __call__(self, *args, **kwargs): from starlette.applications import Starlette -from starlette.responses import Response -from starlette.routing import Mount, Route +from starlette.routing import Mount # Try to import both FastMCP implementations try: @@ -89,15 +86,6 @@ async def __call__(self, *args, **kwargs): GetPromptRequest = None ReadResourceRequest = None -MCP_PACKAGE_VERSION = package_version("mcp") - -try: - from fastmcp import __version__ - - FASTMCP_VERSION = parse_version(__version__) -except ImportError: - FASTMCP_VERSION = None - # Collect available FastMCP implementations for parametrization fastmcp_implementations = [] fastmcp_ids = [] @@ -279,26 +267,21 @@ def reset_request_ctx(): @pytest.mark.asyncio @pytest.mark.parametrize("FastMCP", fastmcp_implementations, ids=fastmcp_ids) @pytest.mark.parametrize( - "send_default_pii, include_prompts", - [(True, True), (True, False), (False, True), (False, False)], + "send_default_pii", + [True, False], ) -@pytest.mark.parametrize("span_streaming", [True, False]) async def test_fastmcp_tool_sync( sentry_init, - capture_events, capture_items, FastMCP, send_default_pii, - include_prompts, stdio, - span_streaming, ): """Test that FastMCP synchronous tool handlers create proper spans""" sentry_init( - integrations=[MCPIntegration(include_prompts=include_prompts)], + integrations=[MCPIntegration()], traces_sample_rate=1.0, send_default_pii=send_default_pii, - trace_lifecycle="stream" if span_streaming else "static", ) mcp = FastMCP("Test Server") @@ -308,99 +291,54 @@ def add_numbers(a: int, b: int) -> dict: """Add two numbers together""" return {"result": a + b, "operation": "addition"} - if span_streaming: - items = capture_items("span") - - with sentry_sdk.traces.start_span(name="custom parent"): - # Call through MCP protocol to trigger instrumentation - await stdio( - mcp._mcp_server, - method="tools/call", - params={ - "name": "add_numbers", - "arguments": {"a": 10, "b": 5}, - }, - request_id="req-123", - ) - - sentry_sdk.flush() - spans = [item.payload for item in items] - assert len(spans) == 2 - - # Verify span structure - span = spans[0] - assert span["attributes"]["sentry.op"] == OP.MCP_SERVER - assert span["attributes"]["sentry.origin"] == "auto.ai.mcp" - assert span["name"] == "tools/call add_numbers" - assert span["attributes"][SPANDATA.MCP_TOOL_NAME] == "add_numbers" - assert span["attributes"][SPANDATA.MCP_METHOD_NAME] == "tools/call" - assert span["attributes"][SPANDATA.MCP_TRANSPORT] == "stdio" - assert span["attributes"][SPANDATA.MCP_REQUEST_ID] == "req-123" + items = capture_items("span") + + # Call through MCP protocol to trigger instrumentation + await stdio( + mcp._mcp_server, + method="tools/call", + params={ + "name": "add_numbers", + "arguments": {"a": 10, "b": 5}, + }, + request_id="req-123", + ) - # Check PII-sensitive data - if send_default_pii and include_prompts: - assert SPANDATA.MCP_TOOL_RESULT_CONTENT in span["attributes"] - else: - assert SPANDATA.MCP_TOOL_RESULT_CONTENT not in span["attributes"] + sentry_sdk.flush() + spans = [item.payload for item in items] + assert len(spans) == 1 + + # Verify span structure + span = spans[0] + assert span["attributes"]["sentry.op"] == OP.MCP_SERVER + assert span["attributes"]["sentry.origin"] == "auto.ai.mcp" + assert span["name"] == "tools/call add_numbers" + assert span["attributes"][SPANDATA.MCP_TOOL_NAME] == "add_numbers" + assert span["attributes"][SPANDATA.MCP_METHOD_NAME] == "tools/call" + assert span["attributes"][SPANDATA.MCP_TRANSPORT] == "stdio" + assert span["attributes"][SPANDATA.MCP_REQUEST_ID] == "req-123" + + # Check PII-sensitive data + if send_default_pii: + assert SPANDATA.MCP_TOOL_RESULT_CONTENT in span["attributes"] else: - events = capture_events() - with start_transaction(name="fastmcp tx"): - # Call through MCP protocol to trigger instrumentation - await stdio( - mcp._mcp_server, - method="tools/call", - params={ - "name": "add_numbers", - "arguments": {"a": 10, "b": 5}, - }, - request_id="req-123", - ) - - (tx,) = events - assert tx["type"] == "transaction" - assert len(tx["spans"]) == 1 - - # Verify span structure - span = tx["spans"][0] - assert span["op"] == OP.MCP_SERVER - assert span["origin"] == "auto.ai.mcp" - assert span["description"] == "tools/call add_numbers" - assert span["data"][SPANDATA.MCP_TOOL_NAME] == "add_numbers" - assert span["data"][SPANDATA.MCP_METHOD_NAME] == "tools/call" - assert span["data"][SPANDATA.MCP_TRANSPORT] == "stdio" - assert span["data"][SPANDATA.MCP_REQUEST_ID] == "req-123" - - # Check PII-sensitive data - if send_default_pii and include_prompts: - assert SPANDATA.MCP_TOOL_RESULT_CONTENT in span["data"] - else: - assert SPANDATA.MCP_TOOL_RESULT_CONTENT not in span["data"] + assert SPANDATA.MCP_TOOL_RESULT_CONTENT not in span["attributes"] @pytest.mark.parametrize("FastMCP", fastmcp_implementations, ids=fastmcp_ids) @pytest.mark.asyncio @pytest.mark.parametrize( - "send_default_pii, include_prompts", - [(True, True), (True, False), (False, True), (False, False)], + "send_default_pii", + [True, False], ) -@pytest.mark.parametrize("span_streaming", [True, False]) async def test_fastmcp_tool_async( - sentry_init, - capture_events, - capture_items, - FastMCP, - send_default_pii, - include_prompts, - json_rpc, - select_transactions_with_mcp_spans, - span_streaming, + sentry_init, capture_items, FastMCP, send_default_pii, json_rpc ): """Test that FastMCP async tool handlers create proper spans""" sentry_init( - integrations=[MCPIntegration(include_prompts=include_prompts)], + integrations=[MCPIntegration()], traces_sample_rate=1.0, send_default_pii=send_default_pii, - trace_lifecycle="stream" if span_streaming else "static", ) mcp = FastMCP("Test Server") @@ -422,106 +360,63 @@ async def multiply_numbers(x: int, y: int) -> dict: """Multiply two numbers together""" return {"result": x * y, "operation": "multiplication"} - if span_streaming: - items = capture_items("span") - - session_id, result = json_rpc( - app, - method="tools/call", - params={ - "name": "multiply_numbers", - "arguments": {"x": 7, "y": 6}, - }, - request_id="req-456", - ) - - assert json.loads(result.json()["result"]["content"][0]["text"]) == { - "result": 42, - "operation": "multiplication", - } - - sentry_sdk.flush() - spans = [item.payload for item in items] - spans = [ - span - for span in spans - if span["attributes"].get("mcp.method.name") == "tools/call" - ] - assert len(spans) == 1 - span = spans[0] + items = capture_items("span") - assert span["attributes"]["sentry.op"] == OP.MCP_SERVER - assert span["attributes"]["sentry.origin"] == "auto.ai.mcp" - assert span["name"] == "tools/call multiply_numbers" - assert span["attributes"][SPANDATA.MCP_TOOL_NAME] == "multiply_numbers" - assert span["attributes"][SPANDATA.MCP_METHOD_NAME] == "tools/call" - assert span["attributes"][SPANDATA.MCP_TRANSPORT] == "http" - assert span["attributes"][SPANDATA.MCP_REQUEST_ID] == "req-456" - assert span["attributes"][SPANDATA.MCP_SESSION_ID] == session_id + session_id, result = json_rpc( + app, + method="tools/call", + params={ + "name": "multiply_numbers", + "arguments": {"x": 7, "y": 6}, + }, + request_id="req-456", + ) - # Check PII-sensitive data - if send_default_pii and include_prompts: - assert SPANDATA.MCP_TOOL_RESULT_CONTENT in span["attributes"] - else: - assert SPANDATA.MCP_TOOL_RESULT_CONTENT not in span["attributes"] + assert json.loads(result.json()["result"]["content"][0]["text"]) == { + "result": 42, + "operation": "multiplication", + } + + sentry_sdk.flush() + spans = [item.payload for item in items] + spans = [ + span + for span in spans + if span["attributes"].get("mcp.method.name") == "tools/call" + ] + assert len(spans) == 1 + span = spans[0] + + assert span["attributes"]["sentry.op"] == OP.MCP_SERVER + assert span["attributes"]["sentry.origin"] == "auto.ai.mcp" + assert span["name"] == "tools/call multiply_numbers" + assert span["attributes"][SPANDATA.MCP_TOOL_NAME] == "multiply_numbers" + assert span["attributes"][SPANDATA.MCP_METHOD_NAME] == "tools/call" + assert span["attributes"][SPANDATA.MCP_TRANSPORT] == "http" + assert span["attributes"][SPANDATA.MCP_REQUEST_ID] == "req-456" + assert span["attributes"][SPANDATA.MCP_SESSION_ID] == session_id + + # Check PII-sensitive data + if send_default_pii: + assert SPANDATA.MCP_TOOL_RESULT_CONTENT in span["attributes"] else: - events = capture_events() - - session_id, result = json_rpc( - app, - method="tools/call", - params={ - "name": "multiply_numbers", - "arguments": {"x": 7, "y": 6}, - }, - request_id="req-456", - ) - - assert json.loads(result.json()["result"]["content"][0]["text"]) == { - "result": 42, - "operation": "multiplication", - } - - transactions = select_transactions_with_mcp_spans( - events, method_name="tools/call" - ) - assert len(transactions) == 1 - tx = transactions[0] - assert len(tx["spans"]) == 1 - span = tx["spans"][0] - - assert span["op"] == OP.MCP_SERVER - assert span["origin"] == "auto.ai.mcp" - assert span["description"] == "tools/call multiply_numbers" - assert span["data"][SPANDATA.MCP_TOOL_NAME] == "multiply_numbers" - assert span["data"][SPANDATA.MCP_METHOD_NAME] == "tools/call" - assert span["data"][SPANDATA.MCP_TRANSPORT] == "http" - assert span["data"][SPANDATA.MCP_REQUEST_ID] == "req-456" - assert span["data"][SPANDATA.MCP_SESSION_ID] == session_id - - # Check PII-sensitive data - if send_default_pii and include_prompts: - assert SPANDATA.MCP_TOOL_RESULT_CONTENT in span["data"] - else: - assert SPANDATA.MCP_TOOL_RESULT_CONTENT not in span["data"] + assert SPANDATA.MCP_TOOL_RESULT_CONTENT not in span["attributes"] @pytest.mark.asyncio @pytest.mark.parametrize("FastMCP", fastmcp_implementations, ids=fastmcp_ids) -@pytest.mark.parametrize("span_streaming", [True, False]) async def test_fastmcp_tool_with_error( sentry_init, - capture_events, capture_items, FastMCP, stdio, - span_streaming, ): """Test that FastMCP tool handler errors are captured properly""" + # TODO: This test doesn't capture errors via the MCP integration, but rather + # via logging. Might be worth another look if that's intended. sentry_init( - integrations=[MCPIntegration()], + integrations=[MCPIntegration(), LoggingIntegration(event_level=logging.ERROR)], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) mcp = FastMCP("Test Server") @@ -531,232 +426,46 @@ def failing_tool(value: int) -> int: """A tool that always fails""" raise ValueError("Tool execution failed") - if span_streaming: - items = capture_items("event", "span") - with sentry_sdk.traces.start_span(name="custom parent"): - await stdio( - mcp._mcp_server, - method="tools/call", - params={ - "name": "failing_tool", - "arguments": {"value": 42}, - }, - request_id="req-error", - ) - - sentry_sdk.flush() - # Check span was created - spans = [item.payload for item in items if item.type == "span"] - tool_spans = [ - s for s in spans if s["attributes"].get("sentry.op") == OP.MCP_SERVER - ] - - assert len(tool_spans) == 1 - - # Check error event was captured - events = [item.payload for item in items if item.type == "event"] - error_events = [e for e in events if e.get("level") == "error"] - assert len(error_events) >= 1 - error_event = error_events[0] - assert error_event["exception"]["values"][0]["type"] == "ValueError" - assert error_event["exception"]["values"][0]["value"] == "Tool execution failed" - else: - events = capture_events() - with start_transaction(name="fastmcp tx"): - await stdio( - mcp._mcp_server, - method="tools/call", - params={ - "name": "failing_tool", - "arguments": {"value": 42}, - }, - request_id="req-error", - ) - - # Should have transaction and error events - assert len(events) >= 1 - - # Check span was created - tx = [e for e in events if e.get("type") == "transaction"][0] - tool_spans = [s for s in tx["spans"] if s["op"] == OP.MCP_SERVER] - - assert len(tool_spans) == 1 - - # Check error event was captured - error_events = [e for e in events if e.get("level") == "error"] - assert len(error_events) >= 1 - error_event = error_events[0] - assert error_event["exception"]["values"][0]["type"] == "ValueError" - assert error_event["exception"]["values"][0]["value"] == "Tool execution failed" - - -@pytest.mark.asyncio -@pytest.mark.parametrize("FastMCP", fastmcp_implementations, ids=fastmcp_ids) -@pytest.mark.parametrize("span_streaming", [True, False]) -async def test_fastmcp_multiple_tools( - sentry_init, - capture_events, - capture_items, - FastMCP, - stdio, - span_streaming, -): - """Test that multiple FastMCP tool calls create multiple spans""" - sentry_init( - integrations=[MCPIntegration()], - traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", + items = capture_items("event", "span") + await stdio( + mcp._mcp_server, + method="tools/call", + params={ + "name": "failing_tool", + "arguments": {"value": 42}, + }, + request_id="req-error", ) - mcp = FastMCP("Test Server") - - @mcp.tool() - def tool_one(x: int) -> int: - """First tool""" - return x * 2 - - @mcp.tool() - def tool_two(y: int) -> int: - """Second tool""" - return y + 10 + sentry_sdk.flush() + # Check span was created + spans = [item.payload for item in items if item.type == "span"] + tool_spans = [s for s in spans if s["attributes"].get("sentry.op") == OP.MCP_SERVER] - @mcp.tool() - def tool_three(z: int) -> int: - """Third tool""" - return z - 5 + assert len(tool_spans) == 1 - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="custom parent"): - result1 = await stdio( - mcp._mcp_server, - method="tools/call", - params={ - "name": "tool_one", - "arguments": {"x": 5}, - }, - request_id="req-multi", - ) - - result2 = await stdio( - mcp._mcp_server, - method="tools/call", - params={ - "name": "tool_two", - "arguments": { - "y": int( - result1.message.result["content"][0]["text"] - if MCP_PACKAGE_VERSION is not None - and MCP_PACKAGE_VERSION >= (2,) - else result1.message.root.result["content"][0]["text"] - ) - }, - }, - request_id="req-multi", - ) - - await stdio( - mcp._mcp_server, - method="tools/call", - params={ - "name": "tool_three", - "arguments": { - "z": int( - result2.message.result["content"][0]["text"] - if MCP_PACKAGE_VERSION is not None - and MCP_PACKAGE_VERSION >= (2,) - else result2.message.root.result["content"][0]["text"] - ) - }, - }, - request_id="req-multi", - ) - - sentry_sdk.flush() - # Verify three spans were created - spans = [item.payload for item in items] - tool_spans = [ - s for s in spans if s["attributes"].get("sentry.op") == OP.MCP_SERVER - ] - assert len(tool_spans) == 3 - assert tool_spans[0]["attributes"][SPANDATA.MCP_TOOL_NAME] == "tool_one" - assert tool_spans[1]["attributes"][SPANDATA.MCP_TOOL_NAME] == "tool_two" - assert tool_spans[2]["attributes"][SPANDATA.MCP_TOOL_NAME] == "tool_three" - else: - events = capture_events() - with start_transaction(name="fastmcp tx"): - result1 = await stdio( - mcp._mcp_server, - method="tools/call", - params={ - "name": "tool_one", - "arguments": {"x": 5}, - }, - request_id="req-multi", - ) - - result2 = await stdio( - mcp._mcp_server, - method="tools/call", - params={ - "name": "tool_two", - "arguments": { - "y": int( - result1.message.result["content"][0]["text"] - if MCP_PACKAGE_VERSION is not None - and MCP_PACKAGE_VERSION >= (2,) - else result1.message.root.result["content"][0]["text"] - ) - }, - }, - request_id="req-multi", - ) - - await stdio( - mcp._mcp_server, - method="tools/call", - params={ - "name": "tool_three", - "arguments": { - "z": int( - result2.message.result["content"][0]["text"] - if MCP_PACKAGE_VERSION is not None - and MCP_PACKAGE_VERSION >= (2,) - else result2.message.root.result["content"][0]["text"] - ) - }, - }, - request_id="req-multi", - ) - - (tx,) = events - assert tx["type"] == "transaction" - - # Verify three spans were created - tool_spans = [s for s in tx["spans"] if s["op"] == OP.MCP_SERVER] - assert len(tool_spans) == 3 - assert tool_spans[0]["data"][SPANDATA.MCP_TOOL_NAME] == "tool_one" - assert tool_spans[1]["data"][SPANDATA.MCP_TOOL_NAME] == "tool_two" - assert tool_spans[2]["data"][SPANDATA.MCP_TOOL_NAME] == "tool_three" + # Check error event was captured + events = [item.payload for item in items if item.type == "event"] + error_events = [e for e in events if e.get("level") == "error"] + assert len(error_events) >= 1 + error_event = error_events[0] + assert error_event["exception"]["values"][0]["type"] == "ValueError" + assert error_event["exception"]["values"][0]["value"] == "Tool execution failed" @pytest.mark.asyncio @pytest.mark.parametrize("FastMCP", fastmcp_implementations, ids=fastmcp_ids) -@pytest.mark.parametrize("span_streaming", [True, False]) async def test_fastmcp_tool_with_complex_return( sentry_init, - capture_events, capture_items, FastMCP, stdio, - span_streaming, ): """Test FastMCP tool with complex nested return value""" sentry_init( - integrations=[MCPIntegration(include_prompts=True)], + integrations=[MCPIntegration()], traces_sample_rate=1.0, send_default_pii=True, - trace_lifecycle="stream" if span_streaming else "static", ) mcp = FastMCP("Test Server") @@ -771,53 +480,25 @@ def get_user_data(user_id: int) -> dict: "tags": ["admin", "verified"], } - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="custom parent"): - await stdio( - mcp._mcp_server, - method="tools/call", - params={ - "name": "get_user_data", - "arguments": {"user_id": 123}, - }, - request_id="req-complex", - ) - - sentry_sdk.flush() - # Verify span was created with complex data - spans = [item.payload for item in items] - tool_spans = [ - s for s in spans if s["attributes"].get("sentry.op") == OP.MCP_SERVER - ] - assert len(tool_spans) == 1 - assert tool_spans[0]["attributes"]["sentry.op"] == OP.MCP_SERVER - assert tool_spans[0]["attributes"][SPANDATA.MCP_TOOL_NAME] == "get_user_data" - # Complex return value should be captured since include_prompts=True and send_default_pii=True - assert SPANDATA.MCP_TOOL_RESULT_CONTENT in tool_spans[0]["attributes"] - else: - events = capture_events() - with start_transaction(name="fastmcp tx"): - await stdio( - mcp._mcp_server, - method="tools/call", - params={ - "name": "get_user_data", - "arguments": {"user_id": 123}, - }, - request_id="req-complex", - ) - - (tx,) = events - assert tx["type"] == "transaction" + items = capture_items("span") + await stdio( + mcp._mcp_server, + method="tools/call", + params={ + "name": "get_user_data", + "arguments": {"user_id": 123}, + }, + request_id="req-complex", + ) - # Verify span was created with complex data - tool_spans = [s for s in tx["spans"] if s["op"] == OP.MCP_SERVER] - assert len(tool_spans) == 1 - assert tool_spans[0]["op"] == OP.MCP_SERVER - assert tool_spans[0]["data"][SPANDATA.MCP_TOOL_NAME] == "get_user_data" - # Complex return value should be captured since include_prompts=True and send_default_pii=True - assert SPANDATA.MCP_TOOL_RESULT_CONTENT in tool_spans[0]["data"] + sentry_sdk.flush() + # Verify span was created with complex data + spans = [item.payload for item in items] + tool_spans = [s for s in spans if s["attributes"].get("sentry.op") == OP.MCP_SERVER] + assert len(tool_spans) == 1 + assert tool_spans[0]["attributes"]["sentry.op"] == OP.MCP_SERVER + assert tool_spans[0]["attributes"][SPANDATA.MCP_TOOL_NAME] == "get_user_data" + assert SPANDATA.MCP_TOOL_RESULT_CONTENT in tool_spans[0]["attributes"] # ============================================================================= @@ -828,26 +509,21 @@ def get_user_data(user_id: int) -> dict: @pytest.mark.asyncio @pytest.mark.parametrize("FastMCP", fastmcp_implementations, ids=fastmcp_ids) @pytest.mark.parametrize( - "send_default_pii, include_prompts", - [(True, True), (False, False)], + "send_default_pii", + [True, False], ) -@pytest.mark.parametrize("span_streaming", [True, False]) async def test_fastmcp_prompt_sync( sentry_init, - capture_events, capture_items, FastMCP, send_default_pii, - include_prompts, stdio, - span_streaming, ): """Test that FastMCP synchronous prompt handlers create proper spans""" sentry_init( - integrations=[MCPIntegration(include_prompts=include_prompts)], + integrations=[MCPIntegration()], traces_sample_rate=1.0, send_default_pii=send_default_pii, - trace_lifecycle="stream" if span_streaming else "static", ) mcp = FastMCP("Test Server") @@ -858,107 +534,66 @@ async def test_fastmcp_prompt_sync( @mcp.prompt() def code_help_prompt(language: str): """Get help for a programming language""" - message = { - "role": "user", - "content": { - "type": "text", - "text": f"Tell me about {language}", - }, - } - - if FASTMCP_VERSION is not None and FASTMCP_VERSION >= (3,): - message = Message(message) + message = Message( + { + "role": "user", + "content": { + "type": "text", + "text": f"Tell me about {language}", + }, + } + ) return [message] - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="custom parent"): - await stdio( - mcp._mcp_server, - method="prompts/get", - params={ - "name": "code_help_prompt", - "arguments": {"language": "python"}, - }, - request_id="req-prompt", - ) - - sentry_sdk.flush() - # Verify prompt span was created - spans = [item.payload for item in items] - prompt_spans = [ - s for s in spans if s["attributes"].get("sentry.op") == OP.MCP_SERVER - ] - assert len(prompt_spans) == 1 - span = prompt_spans[0] - assert span["attributes"]["sentry.origin"] == "auto.ai.mcp" - assert span["name"] == "prompts/get code_help_prompt" - assert span["attributes"][SPANDATA.MCP_PROMPT_NAME] == "code_help_prompt" - - # Check PII-sensitive data - if send_default_pii and include_prompts: - assert SPANDATA.MCP_PROMPT_RESULT_MESSAGE_CONTENT in span["attributes"] - else: - assert ( - SPANDATA.MCP_PROMPT_RESULT_MESSAGE_CONTENT not in span["attributes"] - ) - else: - events = capture_events() - with start_transaction(name="fastmcp tx"): - await stdio( - mcp._mcp_server, - method="prompts/get", - params={ - "name": "code_help_prompt", - "arguments": {"language": "python"}, - }, - request_id="req-prompt", - ) - - (tx,) = events - assert tx["type"] == "transaction" + items = capture_items("span") + with sentry_sdk.start_span(name="custom parent"): + await stdio( + mcp._mcp_server, + method="prompts/get", + params={ + "name": "code_help_prompt", + "arguments": {"language": "python"}, + }, + request_id="req-prompt", + ) - # Verify prompt span was created - prompt_spans = [s for s in tx["spans"] if s["op"] == OP.MCP_SERVER] - assert len(prompt_spans) == 1 - span = prompt_spans[0] - assert span["origin"] == "auto.ai.mcp" - assert span["description"] == "prompts/get code_help_prompt" - assert span["data"][SPANDATA.MCP_PROMPT_NAME] == "code_help_prompt" + sentry_sdk.flush() + # Verify prompt span was created + spans = [item.payload for item in items] + prompt_spans = [ + s for s in spans if s["attributes"].get("sentry.op") == OP.MCP_SERVER + ] + assert len(prompt_spans) == 1 + span = prompt_spans[0] + assert span["attributes"]["sentry.origin"] == "auto.ai.mcp" + assert span["name"] == "prompts/get code_help_prompt" + assert span["attributes"][SPANDATA.MCP_PROMPT_NAME] == "code_help_prompt" - # Check PII-sensitive data - if send_default_pii and include_prompts: - assert SPANDATA.MCP_PROMPT_RESULT_MESSAGE_CONTENT in span["data"] - else: - assert SPANDATA.MCP_PROMPT_RESULT_MESSAGE_CONTENT not in span["data"] + # Check PII-sensitive data + if send_default_pii: + assert SPANDATA.MCP_PROMPT_RESULT_MESSAGE_CONTENT in span["attributes"] + else: + assert SPANDATA.MCP_PROMPT_RESULT_MESSAGE_CONTENT not in span["attributes"] # ============================================================================= -# Resource Handler Tests (if supported) +# Resource Handler Tests # ============================================================================= -@pytest.mark.skipif( - HAS_STANDALONE_FASTMCP and (FASTMCP_VERSION is None or FASTMCP_VERSION < (0, 4, 1)), - reason="Resource URI templates not supported before fastmcp 0.4.1", -) @pytest.mark.asyncio @pytest.mark.parametrize("FastMCP", fastmcp_implementations, ids=fastmcp_ids) -@pytest.mark.parametrize("span_streaming", [True, False]) async def test_fastmcp_resource_sync( sentry_init, - capture_events, capture_items, FastMCP, stdio, - span_streaming, ): """Test that FastMCP synchronous resource handlers create proper spans""" sentry_init( integrations=[MCPIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) mcp = FastMCP("Test Server") @@ -971,90 +606,42 @@ def read_file(path: str): """Read a file resource""" return "file contents" - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="custom parent"): - try: - await stdio( - mcp._mcp_server, - method="resources/read", - params={ - "uri": "file:///test.txt", - }, - request_id="req-resource", - ) - except ValueError as e: - # Older FastMCP versions may not support this URI pattern - if "Unknown resource" in str(e): - pytest.skip( - f"Resource URI not supported in this FastMCP version: {e}" - ) - raise - - sentry_sdk.flush() - # Verify resource span was created - spans = [item.payload for item in items] - resource_spans = [ - s for s in spans if s["attributes"].get("sentry.op") == OP.MCP_SERVER - ] - assert len(resource_spans) == 1 - span = resource_spans[0] - assert span["attributes"]["sentry.origin"] == "auto.ai.mcp" - assert span["name"] == "resources/read file:///test.txt" - assert span["attributes"][SPANDATA.MCP_RESOURCE_PROTOCOL] == "file" - else: - events = capture_events() - with start_transaction(name="fastmcp tx"): - try: - await stdio( - mcp._mcp_server, - method="resources/read", - params={ - "uri": "file:///test.txt", - }, - request_id="req-resource", - ) - except ValueError as e: - # Older FastMCP versions may not support this URI pattern - if "Unknown resource" in str(e): - pytest.skip( - f"Resource URI not supported in this FastMCP version: {e}" - ) - raise - - (tx,) = events - assert tx["type"] == "transaction" - - # Verify resource span was created - resource_spans = [s for s in tx["spans"] if s["op"] == OP.MCP_SERVER] - assert len(resource_spans) == 1 - span = resource_spans[0] - assert span["origin"] == "auto.ai.mcp" - assert span["description"] == "resources/read file:///test.txt" - assert span["data"][SPANDATA.MCP_RESOURCE_PROTOCOL] == "file" - - -@pytest.mark.skipif( - HAS_STANDALONE_FASTMCP and (FASTMCP_VERSION is None or FASTMCP_VERSION < (0, 4, 1)), - reason="Resource URI templates not supported before fastmcp 0.4.1", -) + items = capture_items("span") + try: + await stdio( + mcp._mcp_server, + method="resources/read", + params={ + "uri": "file:///test.txt", + }, + request_id="req-resource", + ) + except ValueError as e: + # Older FastMCP versions may not support this URI pattern + if "Unknown resource" in str(e): + pytest.skip(f"Resource URI not supported in this FastMCP version: {e}") + raise + + sentry_sdk.flush() + # Verify resource span was created + spans = [item.payload for item in items] + resource_spans = [ + s for s in spans if s["attributes"].get("sentry.op") == OP.MCP_SERVER + ] + assert len(resource_spans) == 1 + span = resource_spans[0] + assert span["attributes"]["sentry.origin"] == "auto.ai.mcp" + assert span["name"] == "resources/read file:///test.txt" + assert span["attributes"][SPANDATA.MCP_RESOURCE_PROTOCOL] == "file" + + @pytest.mark.parametrize("FastMCP", fastmcp_implementations, ids=fastmcp_ids) @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) -async def test_fastmcp_resource_async( - sentry_init, - capture_events, - capture_items, - FastMCP, - json_rpc, - select_transactions_with_mcp_spans, - span_streaming, -): +async def test_fastmcp_resource_async(sentry_init, capture_items, FastMCP, json_rpc): """Test that FastMCP async resource handlers create proper spans""" sentry_init( integrations=[MCPIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) mcp = FastMCP("Test Server") @@ -1073,78 +660,42 @@ async def test_fastmcp_resource_async( # Try to register an async resource handler if hasattr(mcp, "resource"): - if span_streaming: - items = capture_items("span") - - @mcp.resource("https://example.com/{resource}") - async def read_url(resource: str): - """Read a URL resource""" - return "resource data" - - _, result = json_rpc( - app, - method="resources/read", - params={ - "uri": "https://example.com/resource", - }, - request_id="req-async-resource", - ) - # Older FastMCP versions may not support this URI pattern - if ( - "error" in result.json() - and "Unknown resource" in result.json()["error"]["message"] - ): - pytest.skip("Resource URI not supported in this FastMCP version.") - return - - assert "resource data" in result.json()["result"]["contents"][0]["text"] - - sentry_sdk.flush() - spans = [item.payload for item in items] - spans = [ - span - for span in spans - if span["attributes"].get("mcp.method.name") == "resources/read" - ] - assert len(spans) == 1 - span = spans[0] - - assert span["attributes"][SPANDATA.MCP_RESOURCE_PROTOCOL] == "https" - else: - events = capture_events() + items = capture_items("span") - @mcp.resource("https://example.com/{resource}") - async def read_url(resource: str): - """Read a URL resource""" - return "resource data" + @mcp.resource("https://example.com/{resource}") + async def read_url(resource: str): + """Read a URL resource""" + return "resource data" - _, result = json_rpc( - app, - method="resources/read", - params={ - "uri": "https://example.com/resource", - }, - request_id="req-async-resource", - ) - # Older FastMCP versions may not support this URI pattern - if ( - "error" in result.json() - and "Unknown resource" in result.json()["error"]["message"] - ): - pytest.skip("Resource URI not supported in this FastMCP version.") - return + _, result = json_rpc( + app, + method="resources/read", + params={ + "uri": "https://example.com/resource", + }, + request_id="req-async-resource", + ) + # Older FastMCP versions may not support this URI pattern + if ( + "error" in result.json() + and "Unknown resource" in result.json()["error"]["message"] + ): + pytest.skip("Resource URI not supported in this FastMCP version.") + return - assert "resource data" in result.json()["result"]["contents"][0]["text"] + assert "resource data" in result.json()["result"]["contents"][0]["text"] - transactions = select_transactions_with_mcp_spans( - events, method_name="resources/read" - ) - assert len(transactions) == 1 - tx = transactions[0] - assert len(tx["spans"]) == 1 - span = tx["spans"][0] + sentry_sdk.flush() + spans = [item.payload for item in items] + spans = [ + span + for span in spans + if span["attributes"].get("mcp.method.name") == "resources/read" + ] + assert len(spans) == 1 + span = spans[0] - assert span["data"][SPANDATA.MCP_RESOURCE_PROTOCOL] == "https" + assert span["attributes"][SPANDATA.MCP_RESOURCE_PROTOCOL] == "https" # ============================================================================= @@ -1154,20 +705,16 @@ async def read_url(resource: str): @pytest.mark.asyncio @pytest.mark.parametrize("FastMCP", fastmcp_implementations, ids=fastmcp_ids) -@pytest.mark.parametrize("span_streaming", [True, False]) async def test_fastmcp_span_origin( sentry_init, - capture_events, capture_items, FastMCP, stdio, - span_streaming, ): """Test that FastMCP span origin is set correctly""" sentry_init( integrations=[MCPIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) mcp = FastMCP("Test Server") @@ -1177,51 +724,25 @@ def test_tool(value: int) -> int: """Test tool for origin checking""" return value * 2 - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="custom parent"): - await stdio( - mcp._mcp_server, - method="tools/call", - params={ - "name": "test_tool", - "arguments": {"value": 21}, - }, - request_id="req-origin", - ) - - sentry_sdk.flush() - - spans = [item.payload for item in items] - assert spans[-1]["attributes"]["sentry.origin"] == "manual" - - # Verify MCP span has correct origin - mcp_spans = [ - s for s in spans if s["attributes"].get("sentry.op") == OP.MCP_SERVER - ] - assert len(mcp_spans) == 1 - assert mcp_spans[0]["attributes"]["sentry.origin"] == "auto.ai.mcp" - else: - events = capture_events() - with start_transaction(name="fastmcp tx"): - await stdio( - mcp._mcp_server, - method="tools/call", - params={ - "name": "test_tool", - "arguments": {"value": 21}, - }, - request_id="req-origin", - ) + items = capture_items("span") + await stdio( + mcp._mcp_server, + method="tools/call", + params={ + "name": "test_tool", + "arguments": {"value": 21}, + }, + request_id="req-origin", + ) - (tx,) = events + sentry_sdk.flush() - assert tx["contexts"]["trace"]["origin"] == "manual" + spans = [item.payload for item in items] - # Verify MCP span has correct origin - mcp_spans = [s for s in tx["spans"] if s["op"] == OP.MCP_SERVER] - assert len(mcp_spans) == 1 - assert mcp_spans[0]["origin"] == "auto.ai.mcp" + # Verify MCP span has correct origin + mcp_spans = [s for s in spans if s["attributes"].get("sentry.op") == OP.MCP_SERVER] + assert len(mcp_spans) == 1 + assert mcp_spans[0]["attributes"]["sentry.origin"] == "auto.ai.mcp" # ============================================================================= @@ -1229,151 +750,12 @@ def test_tool(value: int) -> int: # ============================================================================= -@pytest.mark.asyncio -@pytest.mark.parametrize("FastMCP", fastmcp_implementations, ids=fastmcp_ids) -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.skipif( - StandaloneFastMCP and (FASTMCP_VERSION is not None and FASTMCP_VERSION >= (4,)), - reason="SSE tracing not (yet) supported in v4.", -) -async def test_fastmcp_sse_transport( - sentry_init, - capture_events, - capture_items, - FastMCP, - json_rpc_sse, - span_streaming, -): - """Test that FastMCP correctly detects SSE transport""" - sentry_init( - integrations=[MCPIntegration()], - traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", - ) - - mcp = FastMCP("Test Server") - sse = SseServerTransport("/messages/") - - sse_connection_closed = asyncio.Event() - - async def handle_sse(request): - async with sse.connect_sse( - request.scope, request.receive, request._send - ) as streams: - async with anyio.create_task_group() as tg: - - async def run_server(): - await mcp._mcp_server.run( - streams[0], - streams[1], - mcp._mcp_server.create_initialization_options(), - ) - - tg.start_soon(run_server) - - sse_connection_closed.set() - return Response() - - app = Starlette( - routes=[ - Route("/sse", endpoint=handle_sse, methods=["GET"]), - Mount("/messages/", app=sse.handle_post_message), - ], - ) - - @mcp.tool() - def sse_tool(value: str) -> dict: - """Tool for SSE transport test""" - return {"message": f"Received: {value}"} - - keep_sse_alive = asyncio.Event() - - if span_streaming: - items = capture_items("span") - - app_task, _, result = await json_rpc_sse( - app, - method="tools/call", - params={ - "name": "sse_tool", - "arguments": {"value": "hello"}, - }, - request_id="req-sse", - keep_sse_alive=keep_sse_alive, - ) - - await sse_connection_closed.wait() - await app_task - - assert json.loads(result["result"]["content"][0]["text"]) == { - "message": "Received: hello" - } - - sentry_sdk.flush() - # Find MCP spans - spans = [item.payload for item in items] - mcp_spans = [ - s for s in spans if s["attributes"].get("sentry.op") == OP.MCP_SERVER - ] - - assert len(mcp_spans) >= 1 - span = mcp_spans[0] - # Check that SSE transport is detected - assert span["attributes"].get(SPANDATA.MCP_TRANSPORT) == "sse" - else: - events = capture_events() - - app_task, _, result = await json_rpc_sse( - app, - method="tools/call", - params={ - "name": "sse_tool", - "arguments": {"value": "hello"}, - }, - request_id="req-sse", - keep_sse_alive=keep_sse_alive, - ) - - await sse_connection_closed.wait() - await app_task - - assert json.loads(result["result"]["content"][0]["text"]) == { - "message": "Received: hello" - } - - transactions = [ - event - for event in events - if event["type"] == "transaction" and event["transaction"] == "/sse" - ] - assert len(transactions) == 1 - tx = transactions[0] - - # Find MCP spans - mcp_spans = [s for s in tx["spans"] if s["op"] == OP.MCP_SERVER] - - assert len(mcp_spans) >= 1 - span = mcp_spans[0] - # Check that SSE transport is detected - assert span["data"].get(SPANDATA.MCP_TRANSPORT) == "sse" - - @pytest.mark.parametrize("FastMCP", fastmcp_implementations, ids=fastmcp_ids) -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_fastmcp_http_transport( - sentry_init, - capture_events, - capture_items, - FastMCP, - json_rpc, - select_transactions_with_mcp_spans, - span_streaming, -): +def test_fastmcp_http_transport(sentry_init, capture_items, FastMCP, json_rpc): """Test that FastMCP correctly detects HTTP transport""" sentry_init( integrations=[MCPIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) mcp = FastMCP("Test Server") @@ -1395,80 +777,48 @@ def http_tool(data: str) -> dict: """Tool for HTTP transport test""" return {"processed": data.upper()} - if span_streaming: - items = capture_items("span") + items = capture_items("span") - _, result = json_rpc( - app, - method="tools/call", - params={ - "name": "http_tool", - "arguments": {"data": "test"}, - }, - request_id="req-http", - ) - - assert json.loads(result.json()["result"]["content"][0]["text"]) == { - "processed": "TEST" - } - - sentry_sdk.flush() - spans = [item.payload for item in items] - spans = [ - span - for span in spans - if span["attributes"].get("mcp.method.name") == "tools/call" - ] - assert len(spans) == 1 - span = spans[0] - - # Check that HTTP transport is detected - assert span["attributes"].get(SPANDATA.MCP_TRANSPORT) == "http" - else: - events = capture_events() - - _, result = json_rpc( - app, - method="tools/call", - params={ - "name": "http_tool", - "arguments": {"data": "test"}, - }, - request_id="req-http", - ) + _, result = json_rpc( + app, + method="tools/call", + params={ + "name": "http_tool", + "arguments": {"data": "test"}, + }, + request_id="req-http", + ) - assert json.loads(result.json()["result"]["content"][0]["text"]) == { - "processed": "TEST" - } + assert json.loads(result.json()["result"]["content"][0]["text"]) == { + "processed": "TEST" + } - transactions = select_transactions_with_mcp_spans( - events, method_name="tools/call" - ) - assert len(transactions) == 1 - tx = transactions[0] - assert len(tx["spans"]) == 1 - span = tx["spans"][0] + sentry_sdk.flush() + spans = [item.payload for item in items] + spans = [ + span + for span in spans + if span["attributes"].get("mcp.method.name") == "tools/call" + ] + assert len(spans) == 1 + span = spans[0] - # Check that HTTP transport is detected - assert span["data"].get(SPANDATA.MCP_TRANSPORT) == "http" + # Check that HTTP transport is detected + assert span["attributes"].get(SPANDATA.MCP_TRANSPORT) == "http" @pytest.mark.asyncio @pytest.mark.parametrize("FastMCP", fastmcp_implementations, ids=fastmcp_ids) -@pytest.mark.parametrize("span_streaming", [True, False]) async def test_fastmcp_stdio_transport( sentry_init, - capture_events, capture_items, FastMCP, stdio, - span_streaming, ): """Test that FastMCP correctly detects stdio transport""" sentry_init( integrations=[MCPIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) mcp = FastMCP("Test Server") @@ -1478,146 +828,24 @@ def stdio_tool(n: int) -> dict: """Tool for stdio transport test""" return {"squared": n * n} - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="custom parent"): - await stdio( - mcp._mcp_server, - method="tools/call", - params={ - "name": "stdio_tool", - "arguments": {"n": 7}, - }, - request_id="req-stdio", - ) - - sentry_sdk.flush() - # Find MCP spans - spans = [item.payload for item in items] - mcp_spans = [ - s for s in spans if s["attributes"].get("sentry.op") == OP.MCP_SERVER - ] - - assert len(mcp_spans) >= 1 - span = mcp_spans[0] - # Check that stdio transport is detected - - assert span["attributes"].get(SPANDATA.MCP_TRANSPORT) == "stdio" - else: - events = capture_events() - with start_transaction(name="fastmcp tx"): - await stdio( - mcp._mcp_server, - method="tools/call", - params={ - "name": "stdio_tool", - "arguments": {"n": 7}, - }, - request_id="req-stdio", - ) - - (tx,) = events - - # Find MCP spans - mcp_spans = [s for s in tx["spans"] if s["op"] == OP.MCP_SERVER] - - assert len(mcp_spans) >= 1 - span = mcp_spans[0] - # Check that stdio transport is detected - - assert span["data"].get(SPANDATA.MCP_TRANSPORT) == "stdio" - - -@pytest.mark.asyncio -@pytest.mark.parametrize("FastMCP", fastmcp_implementations, ids=fastmcp_ids) -@pytest.mark.parametrize("span_streaming", [True, False]) -async def test_fastmcp_mixed_sync_async_tools( - sentry_init, - capture_events, - capture_items, - FastMCP, - stdio, - span_streaming, -): - """Test mixing sync and async tools in FastMCP""" - sentry_init( - integrations=[MCPIntegration()], - traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", + items = capture_items("span") + await stdio( + mcp._mcp_server, + method="tools/call", + params={ + "name": "stdio_tool", + "arguments": {"n": 7}, + }, + request_id="req-stdio", ) - mcp = FastMCP("Test Server") - - @mcp.tool() - def sync_add(a: int, b: int) -> int: - """Sync addition""" - return a + b - - @mcp.tool() - async def async_multiply(x: int, y: int) -> int: - """Async multiplication""" - return x * y - - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="custom parent"): - # Use async version for both since we're in an async context - await stdio( - mcp._mcp_server, - method="tools/call", - params={ - "name": "sync_add", - "arguments": {"a": 3, "b": 4}, - }, - request_id="req-mixed", - ) - await stdio( - mcp._mcp_server, - method="tools/call", - params={ - "name": "async_multiply", - "arguments": {"x": 5, "y": 6}, - }, - request_id="req-mixed", - ) - - sentry_sdk.flush() - # Verify both sync and async tool spans were created - spans = [item.payload for item in items] - mcp_spans = [ - s for s in spans if s["attributes"].get("sentry.op") == OP.MCP_SERVER - ] - assert len(mcp_spans) == 2 - assert mcp_spans[0]["attributes"][SPANDATA.MCP_TOOL_NAME] == "sync_add" - assert mcp_spans[1]["attributes"][SPANDATA.MCP_TOOL_NAME] == "async_multiply" - else: - events = capture_events() - with start_transaction(name="fastmcp tx"): - # Use async version for both since we're in an async context - await stdio( - mcp._mcp_server, - method="tools/call", - params={ - "name": "sync_add", - "arguments": {"a": 3, "b": 4}, - }, - request_id="req-mixed", - ) - await stdio( - mcp._mcp_server, - method="tools/call", - params={ - "name": "async_multiply", - "arguments": {"x": 5, "y": 6}, - }, - request_id="req-mixed", - ) + sentry_sdk.flush() + # Find MCP spans + spans = [item.payload for item in items] + mcp_spans = [s for s in spans if s["attributes"].get("sentry.op") == OP.MCP_SERVER] - (tx,) = events - assert tx["type"] == "transaction" + assert len(mcp_spans) >= 1 + span = mcp_spans[0] + # Check that stdio transport is detected - # Verify both sync and async tool spans were created - mcp_spans = [s for s in tx["spans"] if s["op"] == OP.MCP_SERVER] - assert len(mcp_spans) == 2 - assert mcp_spans[0]["data"][SPANDATA.MCP_TOOL_NAME] == "sync_add" - assert mcp_spans[1]["data"][SPANDATA.MCP_TOOL_NAME] == "async_multiply" + assert span["attributes"].get(SPANDATA.MCP_TRANSPORT) == "stdio" diff --git a/tests/integrations/flask/test_flask.py b/tests/integrations/flask/test_flask.py index fa84780fd9..53898543e5 100644 --- a/tests/integrations/flask/test_flask.py +++ b/tests/integrations/flask/test_flask.py @@ -20,7 +20,7 @@ try: from werkzeug.wrappers.request import UnsupportedMediaType except ImportError: - UnsupportedMediaType = None + from werkzeug.exceptions import BadRequest as UnsupportedMediaType import sentry_sdk import sentry_sdk.integrations.flask as flask_sentry @@ -90,7 +90,6 @@ def test_has_context(sentry_init, app, capture_events): assert event["request"]["url"] == "http://localhost/message" -@pytest.mark.parametrize("span_streaming", [True, False]) @pytest.mark.parametrize( "url,transaction_style,expected_transaction,expected_source", [ @@ -109,36 +108,27 @@ def test_transaction_or_segment_style( transaction_style, expected_transaction, expected_source, - span_streaming, ): sentry_init( integrations=[ flask_sentry.FlaskIntegration(transaction_style=transaction_style) ], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") - else: - events = capture_events() + items = capture_items("span") client = app.test_client() response = client.get(url) assert response.status_code == 200 - if span_streaming: - sentry_sdk.flush() - spans = [i.payload for i in items] - assert len(spans) == 1 - (segment,) = spans - assert segment["name"] == expected_transaction - assert segment["attributes"]["sentry.segment.name.source"] == expected_source - else: - (_, event) = events - assert event["transaction"] == expected_transaction - assert event["transaction_info"] == {"source": expected_source} + sentry_sdk.flush() + + spans = [i.payload for i in items] + assert len(spans) == 1 + (segment,) = spans + assert segment["name"] == expected_transaction + assert segment["attributes"]["sentry.segment.name.source"] == expected_source def test_http_route( @@ -149,7 +139,6 @@ def test_http_route( sentry_init( integrations=[flask_sentry.FlaskIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", ) items = capture_items("span") @@ -246,7 +235,6 @@ def test_flask_login_partially_configured( assert event.get("user", {}).get("id") is None -@pytest.mark.parametrize("span_streaming", [True, False]) @pytest.mark.parametrize("send_default_pii", [True, False]) @pytest.mark.parametrize("user_id", [None, "42", 3]) def test_flask_login_configured( @@ -258,17 +246,12 @@ def test_flask_login_configured( capture_items, monkeypatch, integration_enabled_params, - span_streaming, ): - if span_streaming: - sentry_init( - integrations=[flask_sentry.FlaskIntegration()], - send_default_pii=send_default_pii, - traces_sample_rate=1.0, - trace_lifecycle="stream", - ) - else: - sentry_init(send_default_pii=send_default_pii, **integration_enabled_params) + sentry_init( + integrations=[flask_sentry.FlaskIntegration()], + send_default_pii=send_default_pii, + traces_sample_rate=1.0, + ) class User: is_authenticated = is_active = True @@ -290,34 +273,23 @@ def login(): login_user(User()) return "ok" - if span_streaming: - items = capture_items("event", "span") - else: - events = capture_events() + items = capture_items("event", "span") client = app.test_client() assert client.get("/login").status_code == 200 assert client.get("/message").status_code == 200 - if span_streaming: - sentry_sdk.flush() - spans = [i.payload for i in items if i.type == "span"] - segment = next(s for s in spans if s["name"] == "hi") + sentry_sdk.flush() - if send_default_pii and user_id is not None: - assert segment["attributes"]["user.id"] == str(user_id) - assert segment["attributes"]["user.email"] == "user@example.com" - assert segment["attributes"]["user.name"] == "testuser" - else: - assert "user.id" not in segment.get("attributes", {}) + spans = [i.payload for i in items if i.type == "span"] + segment = next(s for s in spans if s["name"] == "hi") + + if send_default_pii and user_id is not None: + assert segment["attributes"]["user.id"] == str(user_id) + assert segment["attributes"]["user.email"] == "user@example.com" + assert segment["attributes"]["user.name"] == "testuser" else: - (event,) = events - if user_id is None or not send_default_pii: - assert event.get("user", {}).get("id") is None - else: - assert event["user"]["id"] == str(user_id) - assert event["user"]["email"] == "user@example.com" - assert event["user"]["username"] == "testuser" + assert "user.id" not in segment.get("attributes", {}) @pytest.mark.parametrize("max_value_length", [1024, None]) @@ -359,7 +331,10 @@ def index(): def test_flask_session_tracking(sentry_init, capture_envelopes, app): sentry_init( - integrations=[flask_sentry.FlaskIntegration()], + integrations=[ + flask_sentry.FlaskIntegration(), + LoggingIntegration(level=None, event_level=logging.ERROR), + ], release="demo-release", ) @@ -462,43 +437,6 @@ def index(): assert len(event["request"]["data"]["foo"]) == 1034 -def test_flask_formdata_request_appear_transaction_body( - sentry_init, capture_events, app -): - """ - Test that ensures that transaction request data contains body, even if no exception was raised - """ - sentry_init(integrations=[flask_sentry.FlaskIntegration()], traces_sample_rate=1.0) - - data = {"username": "sentry-user", "age": "26"} - - @app.route("/", methods=["POST"]) - def index(): - assert request.form["username"] == data["username"] - assert request.form["age"] == data["age"] - assert not request.get_data() - try: - assert not request.get_json() - except UnsupportedMediaType: - # flask/werkzeug 3 - pass - set_tag("view", "yes") - capture_message("hi") - return "ok" - - events = capture_events() - - client = app.test_client() - response = client.post("/", data=data) - assert response.status_code == 200 - - event, transaction_event = events - - assert "request" in transaction_event - assert "data" in transaction_event["request"] - assert transaction_event["request"]["data"] == data - - @pytest.mark.parametrize("input_char", ["a", b"a"]) def test_flask_too_large_raw_request(sentry_init, input_char, capture_events, app): sentry_init( @@ -837,14 +775,15 @@ def zerodivision(e): assert not events -@pytest.mark.parametrize("span_streaming", [True, False]) def test_tracing_success( - sentry_init, capture_events, capture_items, app, span_streaming + sentry_init, + capture_events, + capture_items, + app, ): sentry_init( traces_sample_rate=1.0, integrations=[flask_sentry.FlaskIntegration()], - trace_lifecycle="stream" if span_streaming else "static", ) @app.before_request @@ -857,61 +796,39 @@ def hi_tx(): capture_message("hi") return "ok" - if span_streaming: - items = capture_items("event", "span") - else: - events = capture_events() + items = capture_items("event", "span") with app.test_client() as client: response = client.get("/message_tx") assert response.status_code == 200 - if span_streaming: - sentry_sdk.flush() - spans = [i.payload for i in items if i.type == "span"] - message_events = [i.payload for i in items if i.type == "event"] - - assert len(spans) == 1 - assert len(message_events) == 1 - - (segment,) = spans - (message_event,) = message_events + sentry_sdk.flush() + spans = [i.payload for i in items if i.type == "span"] + message_events = [i.payload for i in items if i.type == "event"] - assert segment["name"] == "hi_tx" - assert segment["status"] == SpanStatus.OK - assert segment["attributes"]["sentry.origin"] == "auto.http.flask" + assert len(spans) == 1 + assert len(message_events) == 1 - assert message_event["message"] == "hi" - assert message_event["transaction"] == "hi_tx" - assert message_event["tags"]["view"] == "yes" - assert message_event["tags"]["before_request"] == "yes" - else: - message_event, transaction_event = events + (segment,) = spans + (message_event,) = message_events - assert transaction_event["type"] == "transaction" - assert transaction_event["transaction"] == "hi_tx" - assert transaction_event["contexts"]["trace"]["status"] == "ok" - assert transaction_event["tags"]["view"] == "yes" - assert transaction_event["tags"]["before_request"] == "yes" + assert segment["name"] == "hi_tx" + assert segment["status"] == SpanStatus.OK + assert segment["attributes"]["sentry.origin"] == "auto.http.flask" - assert message_event["message"] == "hi" - assert message_event["transaction"] == "hi_tx" - assert message_event["tags"]["view"] == "yes" - assert message_event["tags"]["before_request"] == "yes" + assert message_event["message"] == "hi" + assert message_event["transaction"] == "hi_tx" + assert message_event["tags"]["view"] == "yes" + assert message_event["tags"]["before_request"] == "yes" -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_tracing_error(sentry_init, capture_events, capture_items, app, span_streaming): +def test_tracing_error(sentry_init, capture_events, capture_items, app): sentry_init( traces_sample_rate=1.0, integrations=[flask_sentry.FlaskIntegration()], - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("event", "span") - else: - events = capture_events() + items = capture_items("event", "span") @app.route("/error") def error(): @@ -922,33 +839,23 @@ def error(): response = client.get("/error") assert response.status_code == 500 - if span_streaming: - sentry_sdk.flush() - spans = [i.payload for i in items if i.type == "span"] - error_events = [i.payload for i in items if i.type == "event"] - - assert len(spans) == 1 - assert len(error_events) == 1 + sentry_sdk.flush() - (segment,) = spans - (error_event,) = error_events + spans = [i.payload for i in items if i.type == "span"] + error_events = [i.payload for i in items if i.type == "event"] - assert segment["name"] == "error" - assert segment["status"] == SpanStatus.ERROR + assert len(spans) == 1 + assert len(error_events) == 1 - assert error_event["transaction"] == "error" - (exception,) = error_event["exception"]["values"] - assert exception["type"] == "ZeroDivisionError" - else: - error_event, transaction_event = events + (segment,) = spans + (error_event,) = error_events - assert transaction_event["type"] == "transaction" - assert transaction_event["transaction"] == "error" - assert transaction_event["contexts"]["trace"]["status"] == "internal_error" + assert segment["name"] == "error" + assert segment["status"] == SpanStatus.ERROR - assert error_event["transaction"] == "error" - (exception,) = error_event["exception"]["values"] - assert exception["type"] == "ZeroDivisionError" + assert error_event["transaction"] == "error" + (exception,) = error_event["exception"]["values"] + assert exception["type"] == "ZeroDivisionError" def test_error_has_trace_context_if_tracing_disabled(sentry_init, capture_events, app): @@ -1038,7 +945,12 @@ def index(): def test_request_not_modified_by_reference(sentry_init, capture_events, app): - sentry_init(integrations=[flask_sentry.FlaskIntegration()]) + sentry_init( + integrations=[ + flask_sentry.FlaskIntegration(), + LoggingIntegration(event_level=logging.ERROR), + ] + ) @app.route("/", methods=["POST"]) def index(): @@ -1067,98 +979,30 @@ def index(): assert event["request"]["headers"]["Proxy-Authorization"] == "[Filtered]" -def test_response_status_code_ok_in_transaction_context( - sentry_init, capture_envelopes, app -): - """ - Tests that the response status code is added to the transaction context. - This also works for when there is an Exception during the request, but somehow the test flask app doesn't seem to trigger that. - """ +def test_span_origin(sentry_init, app, capture_events, capture_items): sentry_init( integrations=[flask_sentry.FlaskIntegration()], traces_sample_rate=1.0, - release="demo-release", ) - envelopes = capture_envelopes() + items = capture_items("span") client = app.test_client() client.get("/message") - sentry_sdk.get_client().flush() - - (_, transaction_envelope, _) = envelopes - transaction = transaction_envelope.get_transaction_event() - - assert transaction["type"] == "transaction" - assert len(transaction["contexts"]) > 0 - assert "response" in transaction["contexts"].keys(), ( - "Response context not found in transaction" - ) - assert transaction["contexts"]["response"]["status_code"] == 200 - - -def test_response_status_code_not_found_in_transaction_context( - sentry_init, capture_envelopes, app -): - sentry_init( - integrations=[flask_sentry.FlaskIntegration()], - traces_sample_rate=1.0, - release="demo-release", - ) - - envelopes = capture_envelopes() - - client = app.test_client() - client.get("/not-existing-route") - - sentry_sdk.get_client().flush() - - (transaction_envelope, _) = envelopes - transaction = transaction_envelope.get_transaction_event() - - assert transaction["type"] == "transaction" - assert len(transaction["contexts"]) > 0 - assert "response" in transaction["contexts"].keys(), ( - "Response context not found in transaction" - ) - assert transaction["contexts"]["response"]["status_code"] == 404 - - -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_span_origin(sentry_init, app, capture_events, capture_items, span_streaming): - sentry_init( - integrations=[flask_sentry.FlaskIntegration()], - traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", - ) - - if span_streaming: - items = capture_items("span") - else: - events = capture_events() - - client = app.test_client() - client.get("/message") + sentry_sdk.flush() - if span_streaming: - sentry_sdk.flush() - spans = [i.payload for i in items] - assert len(spans) == 1 - (segment,) = spans - assert segment["attributes"]["sentry.origin"] == "auto.http.flask" - else: - (_, event) = events - assert event["contexts"]["trace"]["origin"] == "auto.http.flask" + spans = [i.payload for i in items] + assert len(spans) == 1 + (segment,) = spans + assert segment["attributes"]["sentry.origin"] == "auto.http.flask" -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_transaction_or_segment_http_method_default( +def test_segment_http_method_default( sentry_init, app, capture_events, capture_items, - span_streaming, ): """ By default OPTIONS and HEAD requests do not create a transaction or segment. @@ -1166,13 +1010,9 @@ def test_transaction_or_segment_http_method_default( sentry_init( traces_sample_rate=1.0, integrations=[flask_sentry.FlaskIntegration()], - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") - else: - events = capture_events() + items = capture_items("span") client = app.test_client() response = client.get("/nomessage") @@ -1184,25 +1024,19 @@ def test_transaction_or_segment_http_method_default( response = client.head("/nomessage") assert response.status_code == 200 - if span_streaming: - sentry_sdk.flush() - spans = [i.payload for i in items] - assert len(spans) == 1 - (segment,) = spans - assert segment["attributes"]["http.request.method"] == "GET" - else: - (event,) = events - assert len(events) == 1 - assert event["request"]["method"] == "GET" + sentry_sdk.flush() + spans = [i.payload for i in items] + assert len(spans) == 1 + (segment,) = spans + assert segment["attributes"]["http.request.method"] == "GET" -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_transaction_or_segment_http_method_custom( + +def test_segment_http_method_custom( sentry_init, app, capture_events, capture_items, - span_streaming, ): """ Configure FlaskIntegration to ONLY capture OPTIONS and HEAD requests. @@ -1217,13 +1051,9 @@ def test_transaction_or_segment_http_method_custom( ) # capitalization does not matter ) # case does not matter ], - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") - else: - events = capture_events() + items = capture_items("span") client = app.test_client() response = client.get("/nomessage") @@ -1232,32 +1062,21 @@ def test_transaction_or_segment_http_method_custom( response = client.options("/nomessage") assert response.status_code == 200 - if span_streaming: - sentry_sdk.flush() - spans = [i.payload for i in items] - (options_segment,) = spans - assert options_segment["attributes"]["http.request.method"] == "OPTIONS" - - response = client.head("/nomessage") - assert response.status_code == 200 + sentry_sdk.flush() - sentry_sdk.flush() - spans = [i.payload for i in items] - assert len(spans) == 2 - (_, head_segment) = spans + spans = [i.payload for i in items] + (options_segment,) = spans + assert options_segment["attributes"]["http.request.method"] == "OPTIONS" - assert head_segment["attributes"]["http.request.method"] == "HEAD" - else: - (event1,) = events - assert event1["request"]["method"] == "OPTIONS" - - response = client.head("/nomessage") - assert response.status_code == 200 + response = client.head("/nomessage") + assert response.status_code == 200 - assert len(events) == 2 - (_, event2) = events + sentry_sdk.flush() + spans = [i.payload for i in items] + assert len(spans) == 2 + (_, head_segment) = spans - assert event2["request"]["method"] == "HEAD" + assert head_segment["attributes"]["http.request.method"] == "HEAD" @pytest.mark.parametrize( @@ -1365,7 +1184,6 @@ def test_span_http_query_data_collection( sentry_init( integrations=[flask_sentry.FlaskIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", **init_kwargs, ) monkeypatch.setattr(flask_sentry, "flask_login", None) @@ -1423,7 +1241,6 @@ def test_user_info_span_attributes_data_collection( sentry_init( integrations=[flask_sentry.FlaskIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", **init_kwargs, ) # This test is about user IP collection, not flask_login. Disable @@ -1554,7 +1371,6 @@ def test_flask_login_user_identity_span_attributes_data_collection( sentry_init( integrations=[flask_sentry.FlaskIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", **init_kwargs, ) @@ -1679,34 +1495,6 @@ def index(): assert "data" not in event.get("_meta", {}).get("request", {}) -def test_flask_transaction_request_body_data_collection( - sentry_init, capture_events, app, monkeypatch -): - sentry_init( - integrations=[flask_sentry.FlaskIntegration()], - traces_sample_rate=1.0, - data_collection={"http_bodies": []}, - ) - monkeypatch.setattr(flask_sentry, "flask_login", None) - - data = {"username": "sentry-user", "age": "26"} - - @app.route("/", methods=["POST"]) - def index(): - capture_message("hi") - return "ok" - - events = capture_events() - - client = app.test_client() - response = client.post("/", content_type="application/json", data=data) - assert response.status_code == 200 - - event, transaction_event = events - assert "data" not in event["request"] - assert "data" not in transaction_event["request"] - - def test_flask_oversized_request_body_not_annotated_data_collection( sentry_init, capture_events, app, monkeypatch ): diff --git a/tests/integrations/gcp/test_gcp.py b/tests/integrations/gcp/test_gcp.py index d779295cc1..be2cd13aaf 100644 --- a/tests/integrations/gcp/test_gcp.py +++ b/tests/integrations/gcp/test_gcp.py @@ -231,75 +231,13 @@ def cloud_function(functionhandler, event): (exception,) = envelope_items[0]["exception"]["values"] assert exception["type"] == "ServerlessTimeoutWarning" - assert ( - exception["value"] - == "WARNING : Function is expected to get timed out. Configured timeout duration = 3 seconds." - ) + assert exception["value"] == "WARNING: Function is about to time out." assert exception["mechanism"]["type"] == "threading" assert not exception["mechanism"]["handled"] assert envelope_items[0]["tags"]["cloud_function"] == "true" -def test_performance_no_error(run_cloud_function): - envelope_items, _, _ = run_cloud_function( - dedent( - """ - functionhandler = None - event = {} - def cloud_function(functionhandler, event): - return "test_string" - """ - ) - + FUNCTIONS_PRELUDE - + dedent( - """ - init_sdk(traces_sample_rate=1.0) - gcp_functions.worker_v1.FunctionHandler.invoke_user_function(functionhandler, event) - """ - ) - ) - - assert envelope_items[0]["type"] == "transaction" - assert envelope_items[0]["contexts"]["trace"]["op"] == "function.gcp" - assert envelope_items[0]["transaction"].startswith("Google Cloud function") - assert envelope_items[0]["transaction_info"] == {"source": "component"} - assert envelope_items[0]["transaction"] in envelope_items[0]["request"]["url"] - - -def test_performance_error(run_cloud_function): - envelope_items, _, _ = run_cloud_function( - dedent( - """ - functionhandler = None - event = {} - def cloud_function(functionhandler, event): - raise Exception("something went wrong") - """ - ) - + FUNCTIONS_PRELUDE - + dedent( - """ - init_sdk(traces_sample_rate=1.0) - gcp_functions.worker_v1.FunctionHandler.invoke_user_function(functionhandler, event) - """ - ) - ) - - assert envelope_items[0]["level"] == "error" - (exception,) = envelope_items[0]["exception"]["values"] - - assert exception["type"] == "Exception" - assert exception["value"] == "something went wrong" - assert exception["mechanism"]["type"] == "gcp" - assert not exception["mechanism"]["handled"] - - assert envelope_items[1]["type"] == "transaction" - assert envelope_items[1]["contexts"]["trace"]["op"] == "function.gcp" - assert envelope_items[1]["transaction"].startswith("Google Cloud function") - assert envelope_items[1]["transaction"] in envelope_items[0]["request"]["url"] - - def test_traces_sampler_gets_correct_values_in_sampling_context( run_cloud_function, DictionaryContaining, # noqa:N803 @@ -382,9 +320,9 @@ def _safe_is_equal(x, y): def test_error_has_new_trace_context_performance_enabled(run_cloud_function): """ - Check if an 'trace' context is added to errros and transactions when performance monitoring is enabled. + Check if a 'trace' context is added to errors and spans when performance monitoring is enabled. """ - envelope_items, _, _ = run_cloud_function( + envelope_items, _, span_items = run_cloud_function( dedent( """ functionhandler = None @@ -403,7 +341,7 @@ def cloud_function(functionhandler, event): """ ) ) - (msg_event, error_event, transaction_event) = envelope_items + (msg_event, error_event) = envelope_items assert "trace" in msg_event["contexts"] assert "trace_id" in msg_event["contexts"]["trace"] @@ -411,13 +349,13 @@ def cloud_function(functionhandler, event): assert "trace" in error_event["contexts"] assert "trace_id" in error_event["contexts"]["trace"] - assert "trace" in transaction_event["contexts"] - assert "trace_id" in transaction_event["contexts"]["trace"] + assert len(span_items) == 1 + segment_span = span_items[0] assert ( msg_event["contexts"]["trace"]["trace_id"] == error_event["contexts"]["trace"]["trace_id"] - == transaction_event["contexts"]["trace"]["trace_id"] + == segment_span["trace_id"] ) @@ -459,59 +397,6 @@ def cloud_function(functionhandler, event): ) -def test_error_has_existing_trace_context_performance_enabled(run_cloud_function): - """ - Check if an 'trace' context is added to errros and transactions - from the incoming 'sentry-trace' header when performance monitoring is enabled. - """ - trace_id = "471a43a4192642f0b136d5159a501701" - parent_span_id = "6e8f22c393e68f19" - parent_sampled = 1 - sentry_trace_header = "{}-{}-{}".format(trace_id, parent_span_id, parent_sampled) - - envelope_items, _, _ = run_cloud_function( - dedent( - """ - functionhandler = None - - from collections import namedtuple - GCPEvent = namedtuple("GCPEvent", ["headers"]) - event = GCPEvent(headers={"sentry-trace": "%s"}) - - def cloud_function(functionhandler, event): - sentry_sdk.capture_message("hi") - x = 3/0 - return "3" - """ - % sentry_trace_header - ) - + FUNCTIONS_PRELUDE - + dedent( - """ - init_sdk(traces_sample_rate=1.0) - gcp_functions.worker_v1.FunctionHandler.invoke_user_function(functionhandler, event) - """ - ) - ) - (msg_event, error_event, transaction_event) = envelope_items - - assert "trace" in msg_event["contexts"] - assert "trace_id" in msg_event["contexts"]["trace"] - - assert "trace" in error_event["contexts"] - assert "trace_id" in error_event["contexts"]["trace"] - - assert "trace" in transaction_event["contexts"] - assert "trace_id" in transaction_event["contexts"]["trace"] - - assert ( - msg_event["contexts"]["trace"]["trace_id"] - == error_event["contexts"]["trace"]["trace_id"] - == transaction_event["contexts"]["trace"]["trace_id"] - == "471a43a4192642f0b136d5159a501701" - ) - - def test_error_has_existing_trace_context_performance_disabled(run_cloud_function): """ Check if an 'trace' context is added to errros and transactions @@ -562,7 +447,7 @@ def cloud_function(functionhandler, event): def test_span_origin(run_cloud_function): - events, _, _ = run_cloud_function( + _, _, span_items = run_cloud_function( dedent( """ functionhandler = None @@ -580,12 +465,11 @@ def cloud_function(functionhandler, event): ) ) - (event,) = events - - assert event["contexts"]["trace"]["origin"] == "auto.function.gcp" + assert len(span_items) == 1 + assert span_items[0]["attributes"]["sentry.origin"] == "auto.function.gcp" -def test_span_streaming_no_error(run_cloud_function): +def test_performance_no_error(run_cloud_function): _, _, span_items = run_cloud_function( dedent( """ @@ -598,7 +482,7 @@ def cloud_function(functionhandler, event): + FUNCTIONS_PRELUDE + dedent( """ - init_sdk(traces_sample_rate=1.0, trace_lifecycle="stream") + init_sdk(traces_sample_rate=1.0) gcp_functions.worker_v1.FunctionHandler.invoke_user_function(functionhandler, event) """ ) @@ -619,7 +503,7 @@ def cloud_function(functionhandler, event): assert segment_span["attributes"]["faas.entry_point"] == "cloud_function" -def test_span_streaming_error(run_cloud_function): +def test_performance_error(run_cloud_function): envelope_items, _, span_items = run_cloud_function( dedent( """ @@ -632,7 +516,7 @@ def cloud_function(functionhandler, event): + FUNCTIONS_PRELUDE + dedent( """ - init_sdk(traces_sample_rate=1.0, trace_lifecycle="stream") + init_sdk(traces_sample_rate=1.0) gcp_functions.worker_v1.FunctionHandler.invoke_user_function(functionhandler, event) """ ) @@ -660,7 +544,7 @@ def cloud_function(functionhandler, event): assert segment_span["status"] == SpanStatus.ERROR -def test_span_streaming_existing_trace_context(run_cloud_function): +def test_existing_trace_context(run_cloud_function): trace_id = "471a43a4192642f0b136d5159a501701" parent_span_id = "6e8f22c393e68f19" parent_sampled = 1 @@ -684,7 +568,7 @@ def cloud_function(functionhandler, event): + FUNCTIONS_PRELUDE + dedent( """ - init_sdk(traces_sample_rate=1.0, trace_lifecycle="stream") + init_sdk(traces_sample_rate=1.0) gcp_functions.worker_v1.FunctionHandler.invoke_user_function(functionhandler, event) """ ) @@ -708,7 +592,7 @@ def cloud_function(functionhandler, event): assert segment_span["attributes"]["faas.entry_point"] == "cloud_function" -def test_span_streaming_request_attributes(run_cloud_function): +def test_request_attributes(run_cloud_function): _, _, span_items = run_cloud_function( dedent( """ @@ -729,7 +613,7 @@ def cloud_function(functionhandler, event): + FUNCTIONS_PRELUDE + dedent( """ - init_sdk(traces_sample_rate=1.0, send_default_pii=True, trace_lifecycle="stream") + init_sdk(traces_sample_rate=1.0, send_default_pii=True) gcp_functions.worker_v1.FunctionHandler.invoke_user_function(functionhandler, event) """ ) @@ -749,7 +633,7 @@ def cloud_function(functionhandler, event): assert attrs["faas.entry_point"] == "cloud_function" -def test_span_streaming_no_query_string_without_pii(run_cloud_function): +def test_no_query_string_without_pii(run_cloud_function): _, _, span_items = run_cloud_function( dedent( """ @@ -770,7 +654,7 @@ def cloud_function(functionhandler, event): + FUNCTIONS_PRELUDE + dedent( """ - init_sdk(traces_sample_rate=1.0, send_default_pii=False, trace_lifecycle="stream") + init_sdk(traces_sample_rate=1.0, send_default_pii=False) gcp_functions.worker_v1.FunctionHandler.invoke_user_function(functionhandler, event) """ ) @@ -866,53 +750,7 @@ def _build_init_kwargs(send_default_pii, data_collection): "send_default_pii, data_collection, expected_event, expected_span", _QUERY_STRING_DATA_COLLECTION_CASES, ) -def test_query_string_data_collection_event_processor( - run_cloud_function, - send_default_pii, - data_collection, - expected_event, - expected_span, -): - init_kwargs = _build_init_kwargs(send_default_pii, data_collection) - envelope_items, _, _ = run_cloud_function( - dedent( - """ - functionhandler = None - - from collections import namedtuple - GCPEvent = namedtuple("GCPEvent", ["headers", "method", "query_string"]) - event = GCPEvent( - headers={}, - method="GET", - query_string=b"toy=tennisball&color=red&auth=secret", - ) - - def cloud_function(functionhandler, event): - raise Exception("something went wrong") - """ - ) - + FUNCTIONS_PRELUDE - + dedent( - """ - init_sdk(%s) - gcp_functions.worker_v1.FunctionHandler.invoke_user_function(functionhandler, event) - """ - % init_kwargs - ) - ) - - request = envelope_items[0]["request"] - if expected_event is None: - assert "query_string" not in request - else: - assert request["query_string"] == expected_event - - -@pytest.mark.parametrize( - "send_default_pii, data_collection, expected_event, expected_span", - _QUERY_STRING_DATA_COLLECTION_CASES, -) -def test_query_string_data_collection_span_streaming( +def test_query_string_data_collection( run_cloud_function, send_default_pii, data_collection, @@ -940,7 +778,7 @@ def cloud_function(functionhandler, event): + FUNCTIONS_PRELUDE + dedent( """ - init_sdk(traces_sample_rate=1.0, trace_lifecycle="stream", %s) + init_sdk(traces_sample_rate=1.0, %s) gcp_functions.worker_v1.FunctionHandler.invoke_user_function(functionhandler, event) """ % init_kwargs diff --git a/tests/integrations/google_genai/test_google_genai.py b/tests/integrations/google_genai/test_google_genai.py index 444333e45f..f2d7d82479 100644 --- a/tests/integrations/google_genai/test_google_genai.py +++ b/tests/integrations/google_genai/test_google_genai.py @@ -7,7 +7,6 @@ from google.genai.types import Content, Part import sentry_sdk -from sentry_sdk import start_transaction from sentry_sdk._types import BLOB_DATA_SUBSTITUTE from sentry_sdk.consts import OP, SPANDATA from sentry_sdk.integrations.google_genai import GoogleGenAIIntegration @@ -115,230 +114,90 @@ def create_test_config( return genai_types.GenerateContentConfig(**config_dict) -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize( - "send_default_pii, include_prompts", - [ - (True, True), - (True, False), - (False, True), - (False, False), - ], + "send_default_pii", + [True, False], ) def test_nonstreaming_generate_content( sentry_init, - capture_events, capture_items, send_default_pii, - include_prompts, mock_genai_client, - stream_gen_ai_spans, - span_streaming, ): sentry_init( - integrations=[GoogleGenAIIntegration(include_prompts=include_prompts)], + integrations=[GoogleGenAIIntegration()], traces_sample_rate=1.0, send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) # Mock the HTTP response at the _api_client.request() level mock_http_response = create_mock_http_response(EXAMPLE_API_RESPONSE_JSON) + items = capture_items("span") - if span_streaming: - items = capture_items("transaction", "span") - - with mock.patch.object( - mock_genai_client._api_client, - "request", - return_value=mock_http_response, - ), sentry_sdk.traces.start_span(name="google_genai"): - config = create_test_config(temperature=0.7, max_output_tokens=100) - mock_genai_client.models.generate_content( - model="gemini-1.5-flash", - contents=[ - "Message demonstrating the absence of truncation.", - "Tell me a joke", - ], - config=config, - ) - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert len(spans) == 2 - assert spans[1]["name"] == "google_genai" - chat_span = next(item.payload for item in items if item.type == "span") - - # Check chat span - assert chat_span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - assert chat_span["name"] == "chat gemini-1.5-flash" - assert chat_span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert chat_span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "gcp.gemini" - assert ( - chat_span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "gemini-1.5-flash" + with mock.patch.object( + mock_genai_client._api_client, + "request", + return_value=mock_http_response, + ): + config = create_test_config(temperature=0.7, max_output_tokens=100) + mock_genai_client.models.generate_content( + model="gemini-1.5-flash", + contents=[ + "Message demonstrating the absence of truncation.", + "Tell me a joke", + ], + config=config, ) - if send_default_pii and include_prompts: - assert json.loads( - chat_span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - ) == [ - { - "role": "user", - "content": [ - { - "type": "text", - "text": "Message demonstrating the absence of truncation.", - }, - { - "type": "text", - "text": "Tell me a joke", - }, - ], - } - ] - - # Response text is stored as a JSON array - response_text = chat_span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] - - # Parse the JSON array - response_texts = json.loads(response_text) - assert response_texts == ["Hello! How can I help you today?"] - else: - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in chat_span["attributes"] - - # Check token usage - assert chat_span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - # Output tokens now include reasoning tokens: candidates_token_count (20) + thoughts_token_count (3) = 23 - assert chat_span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 23 - assert chat_span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 - assert chat_span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHED] == 5 - assert ( - chat_span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS_REASONING] == 3 - ) - elif stream_gen_ai_spans: - items = capture_items("transaction", "span") - - with mock.patch.object( - mock_genai_client._api_client, - "request", - return_value=mock_http_response, - ), start_transaction(name="google_genai"): - config = create_test_config(temperature=0.7, max_output_tokens=100) - mock_genai_client.models.generate_content( - model="gemini-1.5-flash", - contents=[ - "Message demonstrating the absence of truncation.", - "Tell me a joke", + sentry_sdk.flush() + spans = [item.payload for item in items] + assert len(spans) == 1 + chat_span = next(item.payload for item in items if item.type == "span") + + # Check chat span + assert chat_span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT + assert chat_span["name"] == "chat gemini-1.5-flash" + assert chat_span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" + assert chat_span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "gcp.gemini" + assert chat_span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "gemini-1.5-flash" + + if send_default_pii: + assert json.loads( + chat_span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] + ) == [ + { + "role": "user", + "content": [ + { + "type": "text", + "text": "Message demonstrating the absence of truncation.", + }, + { + "type": "text", + "text": "Tell me a joke", + }, ], - config=config, - ) + } + ] - (event,) = (item.payload for item in items if item.type == "transaction") - assert event["transaction"] == "google_genai" - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert len(spans) == 1 - sentry_sdk.flush() - chat_span = next(item.payload for item in items if item.type == "span") - - # Check chat span - assert chat_span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - assert chat_span["name"] == "chat gemini-1.5-flash" - assert chat_span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert chat_span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "gcp.gemini" - assert ( - chat_span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "gemini-1.5-flash" - ) + # Response text is stored as a JSON array + response_text = chat_span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] - if send_default_pii and include_prompts: - assert json.loads( - chat_span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - ) == [ - { - "role": "user", - "content": [ - { - "type": "text", - "text": "Message demonstrating the absence of truncation.", - }, - { - "type": "text", - "text": "Tell me a joke", - }, - ], - } - ] - - # Response text is stored as a JSON array - response_text = chat_span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] - - # Parse the JSON array - response_texts = json.loads(response_text) - assert response_texts == ["Hello! How can I help you today?"] - else: - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in chat_span["attributes"] - - # Check token usage - assert chat_span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - # Output tokens now include reasoning tokens: candidates_token_count (20) + thoughts_token_count (3) = 23 - assert chat_span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 23 - assert chat_span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 - assert chat_span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHED] == 5 - assert ( - chat_span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS_REASONING] == 3 - ) + # Parse the JSON array + response_texts = json.loads(response_text) + assert response_texts == ["Hello! How can I help you today?"] else: - events = capture_events() - - with mock.patch.object( - mock_genai_client._api_client, - "request", - return_value=mock_http_response, - ), start_transaction(name="google_genai"): - config = create_test_config(temperature=0.7, max_output_tokens=100) - mock_genai_client.models.generate_content( - model="gemini-1.5-flash", contents="Tell me a joke", config=config - ) + assert SPANDATA.GEN_AI_RESPONSE_TEXT not in chat_span["attributes"] + + # Check token usage + assert chat_span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 + # Output tokens now include reasoning tokens: candidates_token_count (20) + thoughts_token_count (3) = 23 + assert chat_span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 23 + assert chat_span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 + assert chat_span["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] == 5 + assert chat_span["attributes"][SPANDATA.GEN_AI_USAGE_REASONING_OUTPUT_TOKENS] == 3 + - assert len(events) == 1 - (event,) = events - - assert event["type"] == "transaction" - assert event["transaction"] == "google_genai" - - assert len(event["spans"]) == 1 - chat_span = event["spans"][0] - - # Check chat span - assert chat_span["op"] == OP.GEN_AI_CHAT - assert chat_span["description"] == "chat gemini-1.5-flash" - assert chat_span["data"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert chat_span["data"][SPANDATA.GEN_AI_SYSTEM] == "gcp.gemini" - assert chat_span["data"][SPANDATA.GEN_AI_REQUEST_MODEL] == "gemini-1.5-flash" - - if send_default_pii and include_prompts: - # Response text is stored as a JSON array - response_text = chat_span["data"][SPANDATA.GEN_AI_RESPONSE_TEXT] - # Parse the JSON array - response_texts = json.loads(response_text) - assert response_texts == ["Hello! How can I help you today?"] - else: - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in chat_span["data"] - - # Check token usage - assert chat_span["data"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - # Output tokens now include reasoning tokens: candidates_token_count (20) + thoughts_token_count (3) = 23 - assert chat_span["data"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 23 - assert chat_span["data"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 - assert chat_span["data"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHED] == 5 - assert chat_span["data"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS_REASONING] == 3 - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize("generate_content_config", (False, True)) @pytest.mark.parametrize( "system_instructions,expected_texts", @@ -369,108 +228,62 @@ def test_nonstreaming_generate_content( ) def test_generate_content_with_system_instruction( sentry_init, - capture_events, capture_items, mock_genai_client, generate_content_config, system_instructions, expected_texts, - stream_gen_ai_spans, - span_streaming, ): sentry_init( - integrations=[GoogleGenAIIntegration(include_prompts=True)], + integrations=[GoogleGenAIIntegration()], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) mock_http_response = create_mock_http_response(EXAMPLE_API_RESPONSE_JSON) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with mock.patch.object( - mock_genai_client._api_client, "request", return_value=mock_http_response - ), start_transaction(name="google_genai"): - config = { - "system_instruction": system_instructions, - "temperature": 0.5, - } - - if generate_content_config: - config = create_test_config(**config) - - mock_genai_client.models.generate_content( - model="gemini-1.5-flash", - contents="What is 2+2?", - config=config, - ) - - sentry_sdk.flush() - invoke_span = next(item.payload for item in items) + with mock.patch.object( + mock_genai_client._api_client, "request", return_value=mock_http_response + ): + config = { + "system_instruction": system_instructions, + "temperature": 0.5, + } - if expected_texts is None: - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in invoke_span["attributes"] - return + if generate_content_config: + config = create_test_config(**config) - # (PII is enabled and include_prompts is True in this test) - system_instructions = json.loads( - invoke_span["attributes"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS] + mock_genai_client.models.generate_content( + model="gemini-1.5-flash", + contents="What is 2+2?", + config=config, ) - else: - events = capture_events() - - with mock.patch.object( - mock_genai_client._api_client, "request", return_value=mock_http_response - ), start_transaction(name="google_genai"): - config = { - "system_instruction": system_instructions, - "temperature": 0.5, - } - - if generate_content_config: - config = create_test_config(**config) - mock_genai_client.models.generate_content( - model="gemini-1.5-flash", - contents="What is 2+2?", - config=config, - ) + sentry_sdk.flush() + invoke_span = next(item.payload for item in items) - (event,) = events - invoke_span = event["spans"][0] + if expected_texts is None: + assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in invoke_span["attributes"] + return - if expected_texts is None: - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in invoke_span["data"] - return - - # (PII is enabled and include_prompts is True in this test) - system_instructions = json.loads( - invoke_span["data"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS] - ) + system_instructions = json.loads( + invoke_span["attributes"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS] + ) assert system_instructions == [ {"type": "text", "content": text} for text in expected_texts ] -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_generate_content_with_tools( sentry_init, - capture_events, capture_items, mock_genai_client, - stream_gen_ai_spans, - span_streaming, ): sentry_init( integrations=[GoogleGenAIIntegration()], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) # Create a mock tool function @@ -515,57 +328,29 @@ def get_weather(location: str) -> str: } mock_http_response = create_mock_http_response(tool_response_json) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with mock.patch.object( - mock_genai_client._api_client, "request", return_value=mock_http_response - ), start_transaction(name="google_genai"): - config = create_test_config(tools=[get_weather, mock_tool]) - mock_genai_client.models.generate_content( - model="gemini-1.5-flash", contents="What's the weather?", config=config - ) - - sentry_sdk.flush() - invoke_span = next(item.payload for item in items) - - # Check that tools are recorded (data is serialized as a string) - tools_data_str = invoke_span["attributes"][ - SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS - ] - # Parse the JSON string to verify content - tools_data = json.loads(tools_data_str) - assert len(tools_data) == 2 - - # The order of tools may not be guaranteed, so sort by name and description for comparison - sorted_tools = sorted( - tools_data, key=lambda t: (t.get("name", ""), t.get("name", "")) + with mock.patch.object( + mock_genai_client._api_client, "request", return_value=mock_http_response + ): + config = create_test_config(tools=[get_weather, mock_tool]) + mock_genai_client.models.generate_content( + model="gemini-1.5-flash", contents="What's the weather?", config=config ) - else: - events = capture_events() - - with mock.patch.object( - mock_genai_client._api_client, "request", return_value=mock_http_response - ), start_transaction(name="google_genai"): - config = create_test_config(tools=[get_weather, mock_tool]) - mock_genai_client.models.generate_content( - model="gemini-1.5-flash", contents="What's the weather?", config=config - ) - (event,) = events - invoke_span = event["spans"][0] + sentry_sdk.flush() + invoke_span = next(item.payload for item in items) - # Check that tools are recorded (data is serialized as a string) - tools_data_str = invoke_span["data"][SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS] - # Parse the JSON string to verify content - tools_data = json.loads(tools_data_str) - assert len(tools_data) == 2 + # Check that tools are recorded (data is serialized as a string) + tools_data_str = invoke_span["attributes"][SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS] + # Parse the JSON string to verify content + tools_data = json.loads(tools_data_str) + assert len(tools_data) == 2 - # The order of tools may not be guaranteed, so sort by name and description for comparison - sorted_tools = sorted( - tools_data, key=lambda t: (t.get("name", ""), t.get("description", "")) - ) + # The order of tools may not be guaranteed, so sort by name and description for comparison + sorted_tools = sorted( + tools_data, key=lambda t: (t.get("name", ""), t.get("name", "")) + ) # The function tool assert sorted_tools[0]["name"] == "get_weather" @@ -576,21 +361,14 @@ def get_weather(location: str) -> str: assert sorted_tools[1]["description"] == "Get weather information (tool object)" -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_tool_execution( sentry_init, - capture_events, capture_items, - stream_gen_ai_spans, - span_streaming, ): sentry_init( - integrations=[GoogleGenAIIntegration(include_prompts=True)], + integrations=[GoogleGenAIIntegration()], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) # Create a mock tool function @@ -602,101 +380,50 @@ def get_weather(location: str) -> str: from sentry_sdk.integrations.google_genai.utils import wrapped_tool wrapped_weather = wrapped_tool(get_weather) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - # Execute the wrapped tool - with start_transaction(name="test_tool"): - result = wrapped_weather("San Francisco") - - assert result == "The weather in San Francisco is sunny" - - sentry_sdk.flush() - spans = [item.payload for item in items] - assert len(spans) == 1 - sentry_sdk.flush() - tool_span = next(item.payload for item in items) - - assert tool_span["attributes"]["sentry.op"] == OP.GEN_AI_EXECUTE_TOOL - assert tool_span["name"] == "execute_tool get_weather" - assert tool_span["attributes"][SPANDATA.GEN_AI_TOOL_NAME] == "get_weather" - assert ( - tool_span["attributes"][SPANDATA.GEN_AI_TOOL_DESCRIPTION] - == "Get the weather for a location" - ) - else: - events = capture_events() - - # Execute the wrapped tool - with start_transaction(name="test_tool"): - result = wrapped_weather("San Francisco") + # Execute the wrapped tool + result = wrapped_weather("San Francisco") - assert result == "The weather in San Francisco is sunny" + assert result == "The weather in San Francisco is sunny" - (event,) = events - assert len(event["spans"]) == 1 - tool_span = event["spans"][0] + sentry_sdk.flush() + spans = [item.payload for item in items] + assert len(spans) == 1 + sentry_sdk.flush() + tool_span = next(item.payload for item in items) - assert tool_span["op"] == OP.GEN_AI_EXECUTE_TOOL - assert tool_span["description"] == "execute_tool get_weather" - assert tool_span["data"][SPANDATA.GEN_AI_TOOL_NAME] == "get_weather" - assert ( - tool_span["data"][SPANDATA.GEN_AI_TOOL_DESCRIPTION] - == "Get the weather for a location" - ) + assert tool_span["attributes"]["sentry.op"] == OP.GEN_AI_EXECUTE_TOOL + assert tool_span["name"] == "execute_tool get_weather" + assert tool_span["attributes"][SPANDATA.GEN_AI_TOOL_NAME] == "get_weather" + assert ( + tool_span["attributes"][SPANDATA.GEN_AI_TOOL_DESCRIPTION] + == "Get the weather for a location" + ) -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_error_handling( sentry_init, - capture_events, capture_items, mock_genai_client, - stream_gen_ai_spans, - span_streaming, ): sentry_init( integrations=[GoogleGenAIIntegration()], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming or stream_gen_ai_spans: - items = capture_items("event") - - # Mock an error at the HTTP level - with mock.patch.object( - mock_genai_client._api_client, "request", side_effect=Exception("API Error") - ), start_transaction(name="google_genai"), pytest.raises( - Exception, match="API Error" - ): - mock_genai_client.models.generate_content( - model="gemini-1.5-flash", - contents="This will fail", - config=create_test_config(), - ) + items = capture_items("event") - (error_event,) = (item.payload for item in items) - else: - events = capture_events() - - # Mock an error at the HTTP level - with mock.patch.object( - mock_genai_client._api_client, "request", side_effect=Exception("API Error") - ), start_transaction(name="google_genai"), pytest.raises( - Exception, match="API Error" - ): - mock_genai_client.models.generate_content( - model="gemini-1.5-flash", - contents="This will fail", - config=create_test_config(), - ) + # Mock an error at the HTTP level + with mock.patch.object( + mock_genai_client._api_client, "request", side_effect=Exception("API Error") + ), pytest.raises(Exception, match="API Error"): + mock_genai_client.models.generate_content( + model="gemini-1.5-flash", + contents="This will fail", + config=create_test_config(), + ) - # Should have both transaction and error events - assert len(events) == 2 - error_event, transaction_event = events + (error_event,) = (item.payload for item in items) assert error_event["level"] == "error" assert error_event["exception"]["values"][0]["type"] == "Exception" @@ -704,23 +431,16 @@ def test_error_handling( assert error_event["exception"]["values"][0]["mechanism"]["type"] == "google_genai" -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_streaming_generate_content( sentry_init, - capture_events, capture_items, mock_genai_client, - stream_gen_ai_spans, - span_streaming, ): """Test streaming with generate_content_stream, verifying chunk accumulation.""" sentry_init( - integrations=[GoogleGenAIIntegration(include_prompts=True)], + integrations=[GoogleGenAIIntegration()], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) # Create streaming chunks - simulating a multi-chunk response @@ -784,230 +504,114 @@ def test_streaming_generate_content( # Create streaming mock responses stream_chunks = [chunk1_json, chunk2_json, chunk3_json] mock_stream = create_mock_streaming_responses(stream_chunks) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with mock.patch.object( - mock_genai_client._api_client, "request_streamed", return_value=mock_stream - ), start_transaction(name="google_genai"): - config = create_test_config() - stream = mock_genai_client.models.generate_content_stream( - model="gemini-1.5-flash", - contents=[ - "Message demonstrating the absence of truncation.", - "Stream me a response", - ], - config=config, - ) - - # Consume the stream (this is what users do with the integration wrapper) - collected_chunks = list(stream) - - # Verify we got all chunks - assert len(collected_chunks) == 3 - assert collected_chunks[0].candidates[0].content.parts[0].text == "Hello! " - assert collected_chunks[1].candidates[0].content.parts[0].text == "How can I " - assert ( - collected_chunks[2].candidates[0].content.parts[0].text == "help you today?" + with mock.patch.object( + mock_genai_client._api_client, "request_streamed", return_value=mock_stream + ): + config = create_test_config() + stream = mock_genai_client.models.generate_content_stream( + model="gemini-1.5-flash", + contents=[ + "Message demonstrating the absence of truncation.", + "Stream me a response", + ], + config=config, ) - sentry_sdk.flush() - spans = [item.payload for item in items] - assert len(spans) == 1 - sentry_sdk.flush() - chat_span = next(item.payload for item in items) - - assert json.loads( - chat_span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - ) == [ - { - "role": "user", - "content": [ - { - "type": "text", - "text": "Message demonstrating the absence of truncation.", - }, - { - "type": "text", - "text": "Stream me a response", - }, - ], - } - ] - - # Check that streaming flag is set on both spans - assert chat_span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True + # Consume the stream (this is what users do with the integration wrapper) + collected_chunks = list(stream) - # Verify accumulated response text (all chunks combined) - expected_full_text = "Hello! How can I help you today?" - # Response text is stored as a JSON string - chat_response_text = json.loads( - chat_span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] - ) + # Verify we got all chunks + assert len(collected_chunks) == 3 + assert collected_chunks[0].candidates[0].content.parts[0].text == "Hello! " + assert collected_chunks[1].candidates[0].content.parts[0].text == "How can I " + assert collected_chunks[2].candidates[0].content.parts[0].text == "help you today?" - assert chat_response_text == [expected_full_text] + sentry_sdk.flush() + spans = [item.payload for item in items] + assert len(spans) == 1 + sentry_sdk.flush() + chat_span = next(item.payload for item in items) - # Verify finish reasons (only the final chunk has a finish reason) - # When there's a single finish reason, it's stored as a plain string (not JSON) - assert SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS in chat_span["attributes"] - assert ( - chat_span["attributes"][SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS] == "STOP" - ) - assert chat_span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert chat_span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 10 - assert chat_span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 25 - assert chat_span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHED] == 5 - assert ( - chat_span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS_REASONING] == 3 - ) - - # Verify model name - assert ( - chat_span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "gemini-1.5-flash" - ) - else: - events = capture_events() - - with mock.patch.object( - mock_genai_client._api_client, "request_streamed", return_value=mock_stream - ), start_transaction(name="google_genai"): - config = create_test_config() - stream = mock_genai_client.models.generate_content_stream( - model="gemini-1.5-flash", contents="Stream me a response", config=config - ) - - # Consume the stream (this is what users do with the integration wrapper) - collected_chunks = list(stream) - - # Verify we got all chunks - assert len(collected_chunks) == 3 - assert collected_chunks[0].candidates[0].content.parts[0].text == "Hello! " - assert collected_chunks[1].candidates[0].content.parts[0].text == "How can I " - assert ( - collected_chunks[2].candidates[0].content.parts[0].text == "help you today?" - ) - - (event,) = events + assert json.loads(chat_span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) == [ + { + "role": "user", + "content": [ + { + "type": "text", + "text": "Message demonstrating the absence of truncation.", + }, + { + "type": "text", + "text": "Stream me a response", + }, + ], + } + ] - assert len(event["spans"]) == 1 - chat_span = event["spans"][0] + # Check that streaming flag is set on both spans + assert chat_span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True - # Check that streaming flag is set on both spans - assert chat_span["data"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True + # Verify accumulated response text (all chunks combined) + expected_full_text = "Hello! How can I help you today?" + # Response text is stored as a JSON string + chat_response_text = json.loads( + chat_span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] + ) - # Verify accumulated response text (all chunks combined) - expected_full_text = "Hello! How can I help you today?" - # Response text is stored as a JSON string - chat_response_text = json.loads( - chat_span["data"][SPANDATA.GEN_AI_RESPONSE_TEXT] - ) - assert chat_response_text == [expected_full_text] + assert chat_response_text == [expected_full_text] - # Verify finish reasons (only the final chunk has a finish reason) - # When there's a single finish reason, it's stored as a plain string (not JSON) - assert SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS in chat_span["data"] - assert chat_span["data"][SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS] == "STOP" - assert chat_span["data"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert chat_span["data"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 10 - assert chat_span["data"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 25 - assert chat_span["data"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHED] == 5 - assert chat_span["data"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS_REASONING] == 3 + # Verify finish reasons (only the final chunk has a finish reason) + # When there's a single finish reason, it's stored as a plain string (not JSON) + assert SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS in chat_span["attributes"] + assert chat_span["attributes"][SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS] == "STOP" + assert chat_span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 + assert chat_span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 10 + assert chat_span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 25 + assert chat_span["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] == 5 + assert chat_span["attributes"][SPANDATA.GEN_AI_USAGE_REASONING_OUTPUT_TOKENS] == 3 - # Verify model name - assert chat_span["data"][SPANDATA.GEN_AI_REQUEST_MODEL] == "gemini-1.5-flash" + # Verify model name + assert chat_span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "gemini-1.5-flash" -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_span_origin( sentry_init, - capture_events, capture_items, mock_genai_client, - stream_gen_ai_spans, - span_streaming, ): sentry_init( integrations=[GoogleGenAIIntegration()], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) mock_http_response = create_mock_http_response(EXAMPLE_API_RESPONSE_JSON) + items = capture_items("span") - if span_streaming: - items = capture_items("span", "transaction") - - with mock.patch.object( - mock_genai_client._api_client, "request", return_value=mock_http_response - ), sentry_sdk.traces.start_span(name="google_genai"): - config = create_test_config() - mock_genai_client.models.generate_content( - model="gemini-1.5-flash", contents="Test origin", config=config - ) - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - for span in spans: - if span["is_segment"] is True: - assert span["attributes"]["sentry.origin"] == "manual" - continue - - assert span["attributes"]["sentry.origin"] == "auto.ai.google_genai" - elif stream_gen_ai_spans: - items = capture_items("span", "transaction") - - with mock.patch.object( - mock_genai_client._api_client, "request", return_value=mock_http_response - ), start_transaction(name="google_genai"): - config = create_test_config() - mock_genai_client.models.generate_content( - model="gemini-1.5-flash", contents="Test origin", config=config - ) - - (event,) = (item.payload for item in items if item.type == "transaction") - assert event["contexts"]["trace"]["origin"] == "manual" - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - for span in spans: - assert span["attributes"]["sentry.origin"] == "auto.ai.google_genai" - else: - events = capture_events() - - with mock.patch.object( - mock_genai_client._api_client, "request", return_value=mock_http_response - ), start_transaction(name="google_genai"): - config = create_test_config() - mock_genai_client.models.generate_content( - model="gemini-1.5-flash", contents="Test origin", config=config - ) - - (event,) = events + with mock.patch.object( + mock_genai_client._api_client, "request", return_value=mock_http_response + ): + config = create_test_config() + mock_genai_client.models.generate_content( + model="gemini-1.5-flash", contents="Test origin", config=config + ) - assert event["contexts"]["trace"]["origin"] == "manual" - for span in event["spans"]: - assert span["origin"] == "auto.ai.google_genai" + sentry_sdk.flush() + spans = [item.payload for item in items] + for span in spans: + assert span["attributes"]["sentry.origin"] == "auto.ai.google_genai" -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_response_without_usage_metadata( sentry_init, - capture_events, capture_items, mock_genai_client, - stream_gen_ai_spans, - span_streaming, ): """Test handling of responses without usage metadata""" sentry_init( integrations=[GoogleGenAIIntegration()], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) # Response without usage metadata @@ -1024,62 +628,35 @@ def test_response_without_usage_metadata( } mock_http_response = create_mock_http_response(response_json) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with mock.patch.object( - mock_genai_client._api_client, "request", return_value=mock_http_response - ), start_transaction(name="google_genai"): - config = create_test_config() - mock_genai_client.models.generate_content( - model="gemini-1.5-flash", contents="Test", config=config - ) - - sentry_sdk.flush() - chat_span = next(item.payload for item in items) - - # Usage data should not be present - assert SPANDATA.GEN_AI_USAGE_INPUT_TOKENS not in chat_span["attributes"] - assert SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS not in chat_span["attributes"] - assert SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS not in chat_span["attributes"] - else: - events = capture_events() - - with mock.patch.object( - mock_genai_client._api_client, "request", return_value=mock_http_response - ), start_transaction(name="google_genai"): - config = create_test_config() - mock_genai_client.models.generate_content( - model="gemini-1.5-flash", contents="Test", config=config - ) + with mock.patch.object( + mock_genai_client._api_client, "request", return_value=mock_http_response + ): + config = create_test_config() + mock_genai_client.models.generate_content( + model="gemini-1.5-flash", contents="Test", config=config + ) - (event,) = events - chat_span = event["spans"][0] + sentry_sdk.flush() + chat_span = next(item.payload for item in items) - # Usage data should not be present - assert SPANDATA.GEN_AI_USAGE_INPUT_TOKENS not in chat_span["data"] - assert SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS not in chat_span["data"] - assert SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS not in chat_span["data"] + # Usage data should not be present + assert SPANDATA.GEN_AI_USAGE_INPUT_TOKENS not in chat_span["attributes"] + assert SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS not in chat_span["attributes"] + assert SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS not in chat_span["attributes"] -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_multiple_candidates( sentry_init, - capture_events, capture_items, mock_genai_client, - stream_gen_ai_spans, - span_streaming, ): """Test handling of multiple response candidates""" sentry_init( - integrations=[GoogleGenAIIntegration(include_prompts=True)], + integrations=[GoogleGenAIIntegration()], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) # Response with multiple candidates @@ -1108,231 +685,123 @@ def test_multiple_candidates( } mock_http_response = create_mock_http_response(multi_candidate_json) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with mock.patch.object( - mock_genai_client._api_client, "request", return_value=mock_http_response - ), start_transaction(name="google_genai"): - config = create_test_config() - mock_genai_client.models.generate_content( - model="gemini-1.5-flash", contents="Generate multiple", config=config - ) - - sentry_sdk.flush() - chat_span = next(item.payload for item in items) - - # Should capture all responses - # Response text is stored as a JSON string when there are multiple responses - response_text = chat_span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] - - if isinstance(response_text, str) and response_text.startswith("["): - # It's a JSON array - response_list = json.loads(response_text) - assert response_list == ["Response 1", "Response 2"] - else: - # It's concatenated - assert response_text == "Response 1\nResponse 2" - - # Finish reasons are serialized as JSON - finish_reasons = json.loads( - chat_span["attributes"][SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS] + with mock.patch.object( + mock_genai_client._api_client, "request", return_value=mock_http_response + ): + config = create_test_config() + mock_genai_client.models.generate_content( + model="gemini-1.5-flash", contents="Generate multiple", config=config ) - else: - events = capture_events() - - with mock.patch.object( - mock_genai_client._api_client, "request", return_value=mock_http_response - ), start_transaction(name="google_genai"): - config = create_test_config() - mock_genai_client.models.generate_content( - model="gemini-1.5-flash", contents="Generate multiple", config=config - ) - (event,) = events - chat_span = event["spans"][0] + sentry_sdk.flush() + chat_span = next(item.payload for item in items) - # Should capture all responses - # Response text is stored as a JSON string when there are multiple responses - response_text = chat_span["data"][SPANDATA.GEN_AI_RESPONSE_TEXT] + # Should capture all responses + # Response text is stored as a JSON string when there are multiple responses + response_text = chat_span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] - if isinstance(response_text, str) and response_text.startswith("["): - # It's a JSON array - response_list = json.loads(response_text) - assert response_list == ["Response 1", "Response 2"] - else: - # It's concatenated - assert response_text == "Response 1\nResponse 2" + if isinstance(response_text, str) and response_text.startswith("["): + # It's a JSON array + response_list = json.loads(response_text) + assert response_list == ["Response 1", "Response 2"] + else: + # It's concatenated + assert response_text == "Response 1\nResponse 2" - # Finish reasons are serialized as JSON - finish_reasons = json.loads( - chat_span["data"][SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS] - ) + # Finish reasons are serialized as JSON + finish_reasons = json.loads( + chat_span["attributes"][SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS] + ) assert finish_reasons == ["STOP", "MAX_TOKENS"] -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_all_configuration_parameters( sentry_init, - capture_events, capture_items, mock_genai_client, - stream_gen_ai_spans, - span_streaming, ): """Test that all configuration parameters are properly recorded""" sentry_init( integrations=[GoogleGenAIIntegration()], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) mock_http_response = create_mock_http_response(EXAMPLE_API_RESPONSE_JSON) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with mock.patch.object( - mock_genai_client._api_client, "request", return_value=mock_http_response - ), start_transaction(name="google_genai"): - config = create_test_config( - temperature=0.8, - top_p=0.95, - top_k=40, - max_output_tokens=2048, - presence_penalty=0.1, - frequency_penalty=0.2, - seed=12345, - ) - mock_genai_client.models.generate_content( - model="gemini-1.5-flash", contents="Test all params", config=config - ) - - sentry_sdk.flush() - invoke_span = next(item.payload for item in items) - - # Check all parameters are recorded - assert invoke_span["attributes"][SPANDATA.GEN_AI_REQUEST_TEMPERATURE] == 0.8 - assert invoke_span["attributes"][SPANDATA.GEN_AI_REQUEST_TOP_P] == 0.95 - assert invoke_span["attributes"][SPANDATA.GEN_AI_REQUEST_TOP_K] == 40 - assert invoke_span["attributes"][SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 2048 - assert ( - invoke_span["attributes"][SPANDATA.GEN_AI_REQUEST_PRESENCE_PENALTY] == 0.1 + with mock.patch.object( + mock_genai_client._api_client, "request", return_value=mock_http_response + ): + config = create_test_config( + temperature=0.8, + top_p=0.95, + top_k=40, + max_output_tokens=2048, + presence_penalty=0.1, + frequency_penalty=0.2, + seed=12345, ) - assert ( - invoke_span["attributes"][SPANDATA.GEN_AI_REQUEST_FREQUENCY_PENALTY] == 0.2 + mock_genai_client.models.generate_content( + model="gemini-1.5-flash", contents="Test all params", config=config ) - assert invoke_span["attributes"][SPANDATA.GEN_AI_REQUEST_SEED] == 12345 - else: - events = capture_events() - - with mock.patch.object( - mock_genai_client._api_client, "request", return_value=mock_http_response - ), start_transaction(name="google_genai"): - config = create_test_config( - temperature=0.8, - top_p=0.95, - top_k=40, - max_output_tokens=2048, - presence_penalty=0.1, - frequency_penalty=0.2, - seed=12345, - ) - mock_genai_client.models.generate_content( - model="gemini-1.5-flash", contents="Test all params", config=config - ) - (event,) = events - invoke_span = event["spans"][0] + sentry_sdk.flush() + invoke_span = next(item.payload for item in items) - # Check all parameters are recorded - assert invoke_span["data"][SPANDATA.GEN_AI_REQUEST_TEMPERATURE] == 0.8 - assert invoke_span["data"][SPANDATA.GEN_AI_REQUEST_TOP_P] == 0.95 - assert invoke_span["data"][SPANDATA.GEN_AI_REQUEST_TOP_K] == 40 - assert invoke_span["data"][SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 2048 - assert invoke_span["data"][SPANDATA.GEN_AI_REQUEST_PRESENCE_PENALTY] == 0.1 - assert invoke_span["data"][SPANDATA.GEN_AI_REQUEST_FREQUENCY_PENALTY] == 0.2 - assert invoke_span["data"][SPANDATA.GEN_AI_REQUEST_SEED] == 12345 + # Check all parameters are recorded + assert invoke_span["attributes"][SPANDATA.GEN_AI_REQUEST_TEMPERATURE] == 0.8 + assert invoke_span["attributes"][SPANDATA.GEN_AI_REQUEST_TOP_P] == 0.95 + assert invoke_span["attributes"][SPANDATA.GEN_AI_REQUEST_TOP_K] == 40 + assert invoke_span["attributes"][SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 2048 + assert invoke_span["attributes"][SPANDATA.GEN_AI_REQUEST_PRESENCE_PENALTY] == 0.1 + assert invoke_span["attributes"][SPANDATA.GEN_AI_REQUEST_FREQUENCY_PENALTY] == 0.2 + assert invoke_span["attributes"][SPANDATA.GEN_AI_REQUEST_SEED] == 12345 -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_empty_response( sentry_init, - capture_events, capture_items, mock_genai_client, - stream_gen_ai_spans, - span_streaming, ): """Test handling of minimal response with no content""" sentry_init( integrations=[GoogleGenAIIntegration()], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) # Minimal response with empty candidates array minimal_response_json = {"candidates": []} mock_http_response = create_mock_http_response(minimal_response_json) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with mock.patch.object( - mock_genai_client._api_client, "request", return_value=mock_http_response - ), start_transaction(name="google_genai"): - response = mock_genai_client.models.generate_content( - model="gemini-1.5-flash", contents="Test", config=create_test_config() - ) - - # Response will have an empty candidates list - assert response is not None - assert len(response.candidates) == 0 - - # Should still create spans even with empty candidates - sentry_sdk.flush() - spans = [item.payload for item in items] - assert len(spans) == 1 - else: - events = capture_events() - - with mock.patch.object( - mock_genai_client._api_client, "request", return_value=mock_http_response - ), start_transaction(name="google_genai"): - response = mock_genai_client.models.generate_content( - model="gemini-1.5-flash", contents="Test", config=create_test_config() - ) + with mock.patch.object( + mock_genai_client._api_client, "request", return_value=mock_http_response + ): + response = mock_genai_client.models.generate_content( + model="gemini-1.5-flash", contents="Test", config=create_test_config() + ) - # Response will have an empty candidates list - assert response is not None - assert len(response.candidates) == 0 + # Response will have an empty candidates list + assert response is not None + assert len(response.candidates) == 0 - (event,) = events - # Should still create spans even with empty candidates - assert len(event["spans"]) == 1 + # Should still create spans even with empty candidates + sentry_sdk.flush() + spans = [item.payload for item in items] + assert len(spans) == 1 -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_response_with_different_id_fields( sentry_init, - capture_events, capture_items, mock_genai_client, - stream_gen_ai_spans, - span_streaming, ): """Test handling of different response ID field names""" sentry_init( integrations=[GoogleGenAIIntegration()], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) # Response with response_id and model_version @@ -1351,42 +820,23 @@ def test_response_with_different_id_fields( } mock_http_response = create_mock_http_response(response_json) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with mock.patch.object( - mock_genai_client._api_client, "request", return_value=mock_http_response - ), start_transaction(name="google_genai"): - mock_genai_client.models.generate_content( - model="gemini-1.5-flash", contents="Test", config=create_test_config() - ) - - sentry_sdk.flush() - chat_span = next(item.payload for item in items) - - assert chat_span["attributes"][SPANDATA.GEN_AI_RESPONSE_ID] == "resp-456" - assert ( - chat_span["attributes"][SPANDATA.GEN_AI_RESPONSE_MODEL] - == "gemini-1.5-flash-001" + with mock.patch.object( + mock_genai_client._api_client, "request", return_value=mock_http_response + ): + mock_genai_client.models.generate_content( + model="gemini-1.5-flash", contents="Test", config=create_test_config() ) - else: - events = capture_events() - with mock.patch.object( - mock_genai_client._api_client, "request", return_value=mock_http_response - ), start_transaction(name="google_genai"): - mock_genai_client.models.generate_content( - model="gemini-1.5-flash", contents="Test", config=create_test_config() - ) - - (event,) = events - chat_span = event["spans"][0] + sentry_sdk.flush() + chat_span = next(item.payload for item in items) - assert chat_span["data"][SPANDATA.GEN_AI_RESPONSE_ID] == "resp-456" - assert ( - chat_span["data"][SPANDATA.GEN_AI_RESPONSE_MODEL] == "gemini-1.5-flash-001" - ) + assert chat_span["attributes"][SPANDATA.GEN_AI_RESPONSE_ID] == "resp-456" + assert ( + chat_span["attributes"][SPANDATA.GEN_AI_RESPONSE_MODEL] + == "gemini-1.5-flash-001" + ) def test_tool_with_async_function(sentry_init): @@ -1410,78 +860,47 @@ async def async_tool(param: str) -> str: assert hasattr(wrapped_async_tool, "__wrapped__") # Should preserve original -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_contents_as_none( sentry_init, - capture_events, capture_items, mock_genai_client, - stream_gen_ai_spans, - span_streaming, ): """Test handling when contents parameter is None""" sentry_init( - integrations=[GoogleGenAIIntegration(include_prompts=True)], + integrations=[GoogleGenAIIntegration()], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) mock_http_response = create_mock_http_response(EXAMPLE_API_RESPONSE_JSON) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with mock.patch.object( - mock_genai_client._api_client, "request", return_value=mock_http_response - ), start_transaction(name="google_genai"): - mock_genai_client.models.generate_content( - model="gemini-1.5-flash", contents=None, config=create_test_config() - ) - - sentry_sdk.flush() - invoke_span = next(item.payload for item in items) - - # Should handle None contents gracefully - messages = invoke_span["attributes"].get(SPANDATA.GEN_AI_REQUEST_MESSAGES, []) - else: - events = capture_events() - - with mock.patch.object( - mock_genai_client._api_client, "request", return_value=mock_http_response - ), start_transaction(name="google_genai"): - mock_genai_client.models.generate_content( - model="gemini-1.5-flash", contents=None, config=create_test_config() - ) + with mock.patch.object( + mock_genai_client._api_client, "request", return_value=mock_http_response + ): + mock_genai_client.models.generate_content( + model="gemini-1.5-flash", contents=None, config=create_test_config() + ) - (event,) = events - invoke_span = event["spans"][0] + sentry_sdk.flush() + invoke_span = next(item.payload for item in items) - # Should handle None contents gracefully - messages = invoke_span["data"].get(SPANDATA.GEN_AI_REQUEST_MESSAGES, []) + # Should handle None contents gracefully + messages = invoke_span["attributes"].get(SPANDATA.GEN_AI_REQUEST_MESSAGES, []) # Should only have system message if any, not user message assert all(msg["role"] != "user" or msg["content"] is not None for msg in messages) -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_tool_calls_extraction( sentry_init, - capture_events, capture_items, mock_genai_client, - stream_gen_ai_spans, - span_streaming, ): """Test extraction of tool/function calls from response""" sentry_init( integrations=[GoogleGenAIIntegration()], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) # Response with function calls @@ -1520,49 +939,27 @@ def test_tool_calls_extraction( } mock_http_response = create_mock_http_response(function_call_response_json) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with mock.patch.object( - mock_genai_client._api_client, "request", return_value=mock_http_response - ), start_transaction(name="google_genai"): - mock_genai_client.models.generate_content( - model="gemini-1.5-flash", - contents="What's the weather and time?", - config=create_test_config(), - ) - - sentry_sdk.flush() - chat_span = next(item.payload for item in items) # The chat span - - # Check that tool calls are extracted and stored - assert SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS in chat_span["attributes"] - - # Parse the JSON string to verify content - tool_calls = json.loads( - chat_span["attributes"][SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS] + with mock.patch.object( + mock_genai_client._api_client, "request", return_value=mock_http_response + ): + mock_genai_client.models.generate_content( + model="gemini-1.5-flash", + contents="What's the weather and time?", + config=create_test_config(), ) - else: - events = capture_events() - - with mock.patch.object( - mock_genai_client._api_client, "request", return_value=mock_http_response - ), start_transaction(name="google_genai"): - mock_genai_client.models.generate_content( - model="gemini-1.5-flash", - contents="What's the weather and time?", - config=create_test_config(), - ) - (event,) = events - chat_span = event["spans"][0] # The chat span + sentry_sdk.flush() + chat_span = next(item.payload for item in items) # The chat span - # Check that tool calls are extracted and stored - assert SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS in chat_span["data"] + # Check that tool calls are extracted and stored + assert SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS in chat_span["attributes"] - # Parse the JSON string to verify content - tool_calls = json.loads(chat_span["data"][SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS]) + # Parse the JSON string to verify content + tool_calls = json.loads( + chat_span["attributes"][SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS] + ) assert len(tool_calls) == 2 @@ -1582,51 +979,6 @@ def test_tool_calls_extraction( assert json.loads(tool_calls[1]["arguments"]) == {"timezone": "PST"} -def test_google_genai_message_truncation( - sentry_init, capture_events, mock_genai_client -): - """Test that large messages are truncated properly in Google GenAI integration.""" - sentry_init( - integrations=[GoogleGenAIIntegration(include_prompts=True)], - traces_sample_rate=1.0, - send_default_pii=True, - stream_gen_ai_spans=False, - ) - events = capture_events() - - large_content = ( - "This is a very long message that will exceed our size limits. " * 1000 - ) - small_content = "This is a small user message" - - mock_http_response = create_mock_http_response(EXAMPLE_API_RESPONSE_JSON) - - with mock.patch.object( - mock_genai_client._api_client, "request", return_value=mock_http_response - ): - with start_transaction(name="google_genai"): - mock_genai_client.models.generate_content( - model="gemini-1.5-flash", - contents=[large_content, small_content], - config=create_test_config(), - ) - - (event,) = events - invoke_span = event["spans"][0] - assert SPANDATA.GEN_AI_REQUEST_MESSAGES in invoke_span["data"] - - messages_data = invoke_span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - assert isinstance(messages_data, str) - - parsed_messages = json.loads(messages_data) - assert isinstance(parsed_messages, list) - assert len(parsed_messages) == 1 - assert parsed_messages[0]["role"] == "user" - - # What "small content" becomes because the large message used the entire character limit - assert "..." in parsed_messages[0]["content"][1]["text"] - - # Sample embed content API response JSON EXAMPLE_EMBED_RESPONSE_JSON = { "embeddings": [ @@ -1651,207 +1003,82 @@ def test_google_genai_message_truncation( } -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize( - "send_default_pii, include_prompts", - [ - (True, True), - (True, False), - (False, True), - (False, False), - ], + "send_default_pii", + [True, False], ) def test_embed_content( sentry_init, - capture_events, capture_items, send_default_pii, - include_prompts, mock_genai_client, - stream_gen_ai_spans, - span_streaming, ): sentry_init( - integrations=[GoogleGenAIIntegration(include_prompts=include_prompts)], + integrations=[GoogleGenAIIntegration()], traces_sample_rate=1.0, send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) # Mock the HTTP response at the _api_client.request() level mock_http_response = create_mock_http_response(EXAMPLE_EMBED_RESPONSE_JSON) + items = capture_items("span") - if span_streaming: - items = capture_items("transaction", "span") - - with mock.patch.object( - mock_genai_client._api_client, - "request", - return_value=mock_http_response, - ), sentry_sdk.traces.start_span(name="google_genai_embeddings"): - mock_genai_client.models.embed_content( - model="text-embedding-004", - contents=[ - "What is your name?", - "What is your favorite color?", - ], - ) - - # Should have 1 span for embeddings - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert len(spans) == 2 - assert spans[1]["name"] == "google_genai_embeddings" - (embed_span, _) = spans - - # Check embeddings span - assert embed_span["attributes"]["sentry.op"] == OP.GEN_AI_EMBEDDINGS - assert embed_span["name"] == "embeddings text-embedding-004" - assert embed_span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "embeddings" - assert embed_span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "gcp.gemini" - assert ( - embed_span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] - == "text-embedding-004" - ) - - # Check input texts if PII is allowed - if send_default_pii and include_prompts: - input_texts = json.loads( - embed_span["attributes"][SPANDATA.GEN_AI_EMBEDDINGS_INPUT] - ) - assert input_texts == [ + with mock.patch.object( + mock_genai_client._api_client, + "request", + return_value=mock_http_response, + ): + mock_genai_client.models.embed_content( + model="text-embedding-004", + contents=[ "What is your name?", "What is your favorite color?", - ] - else: - assert SPANDATA.GEN_AI_EMBEDDINGS_INPUT not in embed_span["attributes"] - - # Check usage data (sum of token counts from statistics: 10 + 15 = 25) - # Note: Only available in newer versions with ContentEmbeddingStatistics - if SPANDATA.GEN_AI_USAGE_INPUT_TOKENS in embed_span["attributes"]: - assert embed_span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 25 - elif stream_gen_ai_spans: - items = capture_items("transaction", "span") - - with mock.patch.object( - mock_genai_client._api_client, - "request", - return_value=mock_http_response, - ), start_transaction(name="google_genai_embeddings"): - mock_genai_client.models.embed_content( - model="text-embedding-004", - contents=[ - "What is your name?", - "What is your favorite color?", - ], - ) - - (event,) = (item.payload for item in items if item.type == "transaction") + ], + ) - assert event["transaction"] == "google_genai_embeddings" + # Should have 1 span for embeddings + sentry_sdk.flush() + spans = [item.payload for item in items] + assert len(spans) == 1 + (embed_span,) = spans - # Should have 1 span for embeddings - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert len(spans) == 1 - (embed_span,) = spans + # Check embeddings span + assert embed_span["attributes"]["sentry.op"] == OP.GEN_AI_EMBEDDINGS + assert embed_span["name"] == "embeddings text-embedding-004" + assert embed_span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "embeddings" + assert embed_span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "gcp.gemini" + assert ( + embed_span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "text-embedding-004" + ) - # Check embeddings span - assert embed_span["attributes"]["sentry.op"] == OP.GEN_AI_EMBEDDINGS - assert embed_span["name"] == "embeddings text-embedding-004" - assert embed_span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "embeddings" - assert embed_span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "gcp.gemini" - assert ( - embed_span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] - == "text-embedding-004" + # Check input texts if PII is allowed + if send_default_pii: + input_texts = json.loads( + embed_span["attributes"][SPANDATA.GEN_AI_EMBEDDINGS_INPUT] ) - - # Check input texts if PII is allowed - if send_default_pii and include_prompts: - input_texts = json.loads( - embed_span["attributes"][SPANDATA.GEN_AI_EMBEDDINGS_INPUT] - ) - assert input_texts == [ - "What is your name?", - "What is your favorite color?", - ] - else: - assert SPANDATA.GEN_AI_EMBEDDINGS_INPUT not in embed_span["attributes"] - - # Check usage data (sum of token counts from statistics: 10 + 15 = 25) - # Note: Only available in newer versions with ContentEmbeddingStatistics - if SPANDATA.GEN_AI_USAGE_INPUT_TOKENS in embed_span["attributes"]: - assert embed_span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 25 + assert input_texts == [ + "What is your name?", + "What is your favorite color?", + ] else: - events = capture_events() - - with mock.patch.object( - mock_genai_client._api_client, - "request", - return_value=mock_http_response, - ), start_transaction(name="google_genai_embeddings"): - mock_genai_client.models.embed_content( - model="text-embedding-004", - contents=[ - "What is your name?", - "What is your favorite color?", - ], - ) - - assert len(events) == 1 - (event,) = events + assert SPANDATA.GEN_AI_EMBEDDINGS_INPUT not in embed_span["attributes"] - assert event["type"] == "transaction" - assert event["transaction"] == "google_genai_embeddings" - - # Should have 1 span for embeddings - assert len(event["spans"]) == 1 - (embed_span,) = event["spans"] - - # Check embeddings span - assert embed_span["op"] == OP.GEN_AI_EMBEDDINGS - assert embed_span["description"] == "embeddings text-embedding-004" - assert embed_span["data"][SPANDATA.GEN_AI_OPERATION_NAME] == "embeddings" - assert embed_span["data"][SPANDATA.GEN_AI_SYSTEM] == "gcp.gemini" - assert embed_span["data"][SPANDATA.GEN_AI_REQUEST_MODEL] == "text-embedding-004" - - # Check input texts if PII is allowed - if send_default_pii and include_prompts: - input_texts = json.loads( - embed_span["data"][SPANDATA.GEN_AI_EMBEDDINGS_INPUT] - ) - assert input_texts == [ - "What is your name?", - "What is your favorite color?", - ] - else: - assert SPANDATA.GEN_AI_EMBEDDINGS_INPUT not in embed_span["data"] + # Check usage data (sum of token counts from statistics: 10 + 15 = 25) + # Note: Only available in newer versions with ContentEmbeddingStatistics + if SPANDATA.GEN_AI_USAGE_INPUT_TOKENS in embed_span["attributes"]: + assert embed_span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 25 - # Check usage data (sum of token counts from statistics: 10 + 15 = 25) - # Note: Only available in newer versions with ContentEmbeddingStatistics - if SPANDATA.GEN_AI_USAGE_INPUT_TOKENS in embed_span["data"]: - assert embed_span["data"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 25 - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_embed_content_string_input( sentry_init, - capture_events, capture_items, mock_genai_client, - stream_gen_ai_spans, - span_streaming, ): """Test embed_content with a single string instead of list.""" sentry_init( - integrations=[GoogleGenAIIntegration(include_prompts=True)], + integrations=[GoogleGenAIIntegration()], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) # Mock response with single embedding @@ -1870,108 +1097,54 @@ def test_embed_content_string_input( }, } mock_http_response = create_mock_http_response(single_embed_response) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with mock.patch.object( - mock_genai_client._api_client, "request", return_value=mock_http_response - ), start_transaction(name="google_genai_embeddings"): - mock_genai_client.models.embed_content( - model="text-embedding-004", - contents="Single text input", - ) - - sentry_sdk.flush() - spans = [item.payload for item in items] - (embed_span,) = spans - - # Check that single string is handled correctly - input_texts = json.loads( - embed_span["attributes"][SPANDATA.GEN_AI_EMBEDDINGS_INPUT] + with mock.patch.object( + mock_genai_client._api_client, "request", return_value=mock_http_response + ): + mock_genai_client.models.embed_content( + model="text-embedding-004", + contents="Single text input", ) - assert input_texts == ["Single text input"] - # Should use token_count from statistics (5), not billable_character_count (10) - # Note: Only available in newer versions with ContentEmbeddingStatistics - if SPANDATA.GEN_AI_USAGE_INPUT_TOKENS in embed_span["attributes"]: - assert embed_span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 5 - else: - events = capture_events() - - with mock.patch.object( - mock_genai_client._api_client, "request", return_value=mock_http_response - ), start_transaction(name="google_genai_embeddings"): - mock_genai_client.models.embed_content( - model="text-embedding-004", - contents="Single text input", - ) + sentry_sdk.flush() + spans = [item.payload for item in items] + (embed_span,) = spans - (event,) = events - (embed_span,) = event["spans"] + # Check that single string is handled correctly + input_texts = json.loads(embed_span["attributes"][SPANDATA.GEN_AI_EMBEDDINGS_INPUT]) - # Check that single string is handled correctly - input_texts = json.loads(embed_span["data"][SPANDATA.GEN_AI_EMBEDDINGS_INPUT]) - assert input_texts == ["Single text input"] - # Should use token_count from statistics (5), not billable_character_count (10) - # Note: Only available in newer versions with ContentEmbeddingStatistics - if SPANDATA.GEN_AI_USAGE_INPUT_TOKENS in embed_span["data"]: - assert embed_span["data"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 5 + assert input_texts == ["Single text input"] + # Should use token_count from statistics (5), not billable_character_count (10) + # Note: Only available in newer versions with ContentEmbeddingStatistics + if SPANDATA.GEN_AI_USAGE_INPUT_TOKENS in embed_span["attributes"]: + assert embed_span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 5 -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_embed_content_error_handling( sentry_init, - capture_events, capture_items, mock_genai_client, - stream_gen_ai_spans, - span_streaming, ): """Test error handling in embed_content.""" sentry_init( integrations=[GoogleGenAIIntegration()], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming or stream_gen_ai_spans: - items = capture_items("event") - - # Mock an error at the HTTP level - with mock.patch.object( - mock_genai_client._api_client, - "request", - side_effect=Exception("Embedding API Error"), - ), start_transaction(name="google_genai_embeddings"), pytest.raises( - Exception, match="Embedding API Error" - ): - mock_genai_client.models.embed_content( - model="text-embedding-004", - contents=["This will fail"], - ) + items = capture_items("event") - (error_event,) = (item.payload for item in items) - else: - events = capture_events() - - # Mock an error at the HTTP level - with mock.patch.object( - mock_genai_client._api_client, - "request", - side_effect=Exception("Embedding API Error"), - ), start_transaction(name="google_genai_embeddings"), pytest.raises( - Exception, match="Embedding API Error" - ): - mock_genai_client.models.embed_content( - model="text-embedding-004", - contents=["This will fail"], - ) + # Mock an error at the HTTP level + with mock.patch.object( + mock_genai_client._api_client, + "request", + side_effect=Exception("Embedding API Error"), + ), pytest.raises(Exception, match="Embedding API Error"): + mock_genai_client.models.embed_content( + model="text-embedding-004", + contents=["This will fail"], + ) - # Should have both transaction and error events - assert len(events) == 2 - error_event, _ = events + (error_event,) = (item.payload for item in items) assert error_event["level"] == "error" assert error_event["exception"]["values"][0]["type"] == "Exception" @@ -1979,22 +1152,15 @@ def test_embed_content_error_handling( assert error_event["exception"]["values"][0]["mechanism"]["type"] == "google_genai" -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_embed_content_without_statistics( sentry_init, - capture_events, capture_items, mock_genai_client, - stream_gen_ai_spans, - span_streaming, ): """Test embed_content response without statistics (older package versions).""" sentry_init( integrations=[GoogleGenAIIntegration()], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) # Response without statistics (typical for older google-genai versions) @@ -2010,320 +1176,131 @@ def test_embed_content_without_statistics( ], } mock_http_response = create_mock_http_response(old_version_response) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with mock.patch.object( - mock_genai_client._api_client, "request", return_value=mock_http_response - ), start_transaction(name="google_genai_embeddings"): - mock_genai_client.models.embed_content( - model="text-embedding-004", - contents=["Test without statistics", "Another test"], - ) - - sentry_sdk.flush() - spans = [item.payload for item in items] - (embed_span,) = spans - - # No usage tokens since there are no statistics in older versions - # This is expected and the integration should handle it gracefully - assert SPANDATA.GEN_AI_USAGE_INPUT_TOKENS not in embed_span["attributes"] - else: - events = capture_events() - - with mock.patch.object( - mock_genai_client._api_client, "request", return_value=mock_http_response - ), start_transaction(name="google_genai_embeddings"): - mock_genai_client.models.embed_content( - model="text-embedding-004", - contents=["Test without statistics", "Another test"], - ) + with mock.patch.object( + mock_genai_client._api_client, "request", return_value=mock_http_response + ): + mock_genai_client.models.embed_content( + model="text-embedding-004", + contents=["Test without statistics", "Another test"], + ) - (event,) = events - (embed_span,) = event["spans"] + sentry_sdk.flush() + spans = [item.payload for item in items] + (embed_span,) = spans - # No usage tokens since there are no statistics in older versions - # This is expected and the integration should handle it gracefully - assert SPANDATA.GEN_AI_USAGE_INPUT_TOKENS not in embed_span["data"] + # No usage tokens since there are no statistics in older versions + # This is expected and the integration should handle it gracefully + assert SPANDATA.GEN_AI_USAGE_INPUT_TOKENS not in embed_span["attributes"] -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_embed_content_span_origin( sentry_init, - capture_events, capture_items, mock_genai_client, - stream_gen_ai_spans, - span_streaming, ): """Test that embed_content spans have correct origin.""" sentry_init( integrations=[GoogleGenAIIntegration()], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) mock_http_response = create_mock_http_response(EXAMPLE_EMBED_RESPONSE_JSON) - if span_streaming: - items = capture_items("transaction", "span") - with mock.patch.object( - mock_genai_client._api_client, "request", return_value=mock_http_response - ), sentry_sdk.traces.start_span(name="google_genai_embeddings"): - mock_genai_client.models.embed_content( - model="text-embedding-004", - contents=["Test origin"], - ) - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - for span in spans: - if span["is_segment"] is True: - assert span["attributes"]["sentry.origin"] == "manual" - continue - - assert span["attributes"]["sentry.origin"] == "auto.ai.google_genai" - elif stream_gen_ai_spans: - items = capture_items("transaction", "span") - with mock.patch.object( - mock_genai_client._api_client, "request", return_value=mock_http_response - ), start_transaction(name="google_genai_embeddings"): - mock_genai_client.models.embed_content( - model="text-embedding-004", - contents=["Test origin"], - ) - - (event,) = (item.payload for item in items if item.type == "transaction") - assert event["contexts"]["trace"]["origin"] == "manual" - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - for span in spans: - assert span["attributes"]["sentry.origin"] == "auto.ai.google_genai" - else: - events = capture_events() - with mock.patch.object( - mock_genai_client._api_client, "request", return_value=mock_http_response - ), start_transaction(name="google_genai_embeddings"): - mock_genai_client.models.embed_content( - model="text-embedding-004", - contents=["Test origin"], - ) - - (event,) = events + items = capture_items("span") + with mock.patch.object( + mock_genai_client._api_client, "request", return_value=mock_http_response + ): + mock_genai_client.models.embed_content( + model="text-embedding-004", + contents=["Test origin"], + ) - assert event["contexts"]["trace"]["origin"] == "manual" - for span in event["spans"]: - assert span["origin"] == "auto.ai.google_genai" + sentry_sdk.flush() + spans = [item.payload for item in items] + for span in spans: + assert span["attributes"]["sentry.origin"] == "auto.ai.google_genai" -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio @pytest.mark.parametrize( - "send_default_pii, include_prompts", - [ - (True, True), - (True, False), - (False, True), - (False, False), - ], + "send_default_pii", + [True, False], ) async def test_async_embed_content( sentry_init, - capture_events, capture_items, send_default_pii, - include_prompts, mock_genai_client, - stream_gen_ai_spans, - span_streaming, ): """Test async embed_content method.""" sentry_init( - integrations=[GoogleGenAIIntegration(include_prompts=include_prompts)], + integrations=[GoogleGenAIIntegration()], traces_sample_rate=1.0, send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) # Mock the async HTTP response mock_http_response = create_mock_http_response(EXAMPLE_EMBED_RESPONSE_JSON) + items = capture_items("span") - if span_streaming: - items = capture_items("transaction", "span") - - with mock.patch.object( - mock_genai_client._api_client, - "async_request", - return_value=mock_http_response, - ), sentry_sdk.traces.start_span(name="google_genai_embeddings_async"): - await mock_genai_client.aio.models.embed_content( - model="text-embedding-004", - contents=[ - "What is your name?", - "What is your favorite color?", - ], - ) - - # Should have 1 span for embeddings - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert len(spans) == 2 - assert spans[1]["name"] == "google_genai_embeddings_async" - (embed_span, _) = spans - - # Check embeddings span - assert embed_span["attributes"]["sentry.op"] == OP.GEN_AI_EMBEDDINGS - assert embed_span["name"] == "embeddings text-embedding-004" - assert embed_span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "embeddings" - assert embed_span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "gcp.gemini" - assert ( - embed_span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] - == "text-embedding-004" - ) - - # Check input texts if PII is allowed - if send_default_pii and include_prompts: - input_texts = json.loads( - embed_span["attributes"][SPANDATA.GEN_AI_EMBEDDINGS_INPUT] - ) - assert input_texts == [ + with mock.patch.object( + mock_genai_client._api_client, + "async_request", + return_value=mock_http_response, + ): + await mock_genai_client.aio.models.embed_content( + model="text-embedding-004", + contents=[ "What is your name?", "What is your favorite color?", - ] - else: - assert SPANDATA.GEN_AI_EMBEDDINGS_INPUT not in embed_span["attributes"] - - # Check usage data (sum of token counts from statistics: 10 + 15 = 25) - # Note: Only available in newer versions with ContentEmbeddingStatistics - if SPANDATA.GEN_AI_USAGE_INPUT_TOKENS in embed_span["attributes"]: - assert embed_span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 25 - elif stream_gen_ai_spans: - items = capture_items("transaction", "span") - - with mock.patch.object( - mock_genai_client._api_client, - "async_request", - return_value=mock_http_response, - ), start_transaction(name="google_genai_embeddings_async"): - await mock_genai_client.aio.models.embed_content( - model="text-embedding-004", - contents=[ - "What is your name?", - "What is your favorite color?", - ], - ) - - (event,) = (item.payload for item in items if item.type == "transaction") + ], + ) - assert event["transaction"] == "google_genai_embeddings_async" + # Should have 1 span for embeddings + sentry_sdk.flush() + spans = [item.payload for item in items] + assert len(spans) == 1 + (embed_span,) = spans - # Should have 1 span for embeddings - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert len(spans) == 1 - (embed_span,) = spans + # Check embeddings span + assert embed_span["attributes"]["sentry.op"] == OP.GEN_AI_EMBEDDINGS + assert embed_span["name"] == "embeddings text-embedding-004" + assert embed_span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "embeddings" + assert embed_span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "gcp.gemini" + assert ( + embed_span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "text-embedding-004" + ) - # Check embeddings span - assert embed_span["attributes"]["sentry.op"] == OP.GEN_AI_EMBEDDINGS - assert embed_span["name"] == "embeddings text-embedding-004" - assert embed_span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "embeddings" - assert embed_span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "gcp.gemini" - assert ( - embed_span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] - == "text-embedding-004" + # Check input texts if PII is allowed + if send_default_pii: + input_texts = json.loads( + embed_span["attributes"][SPANDATA.GEN_AI_EMBEDDINGS_INPUT] ) - - # Check input texts if PII is allowed - if send_default_pii and include_prompts: - input_texts = json.loads( - embed_span["attributes"][SPANDATA.GEN_AI_EMBEDDINGS_INPUT] - ) - assert input_texts == [ - "What is your name?", - "What is your favorite color?", - ] - else: - assert SPANDATA.GEN_AI_EMBEDDINGS_INPUT not in embed_span["attributes"] - - # Check usage data (sum of token counts from statistics: 10 + 15 = 25) - # Note: Only available in newer versions with ContentEmbeddingStatistics - if SPANDATA.GEN_AI_USAGE_INPUT_TOKENS in embed_span["attributes"]: - assert embed_span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 25 + assert input_texts == [ + "What is your name?", + "What is your favorite color?", + ] else: - events = capture_events() - - with mock.patch.object( - mock_genai_client._api_client, - "async_request", - return_value=mock_http_response, - ), start_transaction(name="google_genai_embeddings_async"): - await mock_genai_client.aio.models.embed_content( - model="text-embedding-004", - contents=[ - "What is your name?", - "What is your favorite color?", - ], - ) - - assert len(events) == 1 - (event,) = events - - assert event["type"] == "transaction" - - assert event["transaction"] == "google_genai_embeddings_async" - - # Should have 1 span for embeddings - assert len(event["spans"]) == 1 - (embed_span,) = event["spans"] + assert SPANDATA.GEN_AI_EMBEDDINGS_INPUT not in embed_span["attributes"] - # Check embeddings span - assert embed_span["op"] == OP.GEN_AI_EMBEDDINGS - assert embed_span["description"] == "embeddings text-embedding-004" - assert embed_span["data"][SPANDATA.GEN_AI_OPERATION_NAME] == "embeddings" - assert embed_span["data"][SPANDATA.GEN_AI_SYSTEM] == "gcp.gemini" - assert embed_span["data"][SPANDATA.GEN_AI_REQUEST_MODEL] == "text-embedding-004" + # Check usage data (sum of token counts from statistics: 10 + 15 = 25) + # Note: Only available in newer versions with ContentEmbeddingStatistics + if SPANDATA.GEN_AI_USAGE_INPUT_TOKENS in embed_span["attributes"]: + assert embed_span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 25 - # Check input texts if PII is allowed - if send_default_pii and include_prompts: - input_texts = json.loads( - embed_span["data"][SPANDATA.GEN_AI_EMBEDDINGS_INPUT] - ) - assert input_texts == [ - "What is your name?", - "What is your favorite color?", - ] - else: - assert SPANDATA.GEN_AI_EMBEDDINGS_INPUT not in embed_span["data"] - - # Check usage data (sum of token counts from statistics: 10 + 15 = 25) - # Note: Only available in newer versions with ContentEmbeddingStatistics - if SPANDATA.GEN_AI_USAGE_INPUT_TOKENS in embed_span["data"]: - assert embed_span["data"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 25 - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio async def test_async_embed_content_string_input( sentry_init, - capture_events, capture_items, mock_genai_client, - stream_gen_ai_spans, - span_streaming, ): """Test async embed_content with a single string instead of list.""" sentry_init( - integrations=[GoogleGenAIIntegration(include_prompts=True)], + integrations=[GoogleGenAIIntegration()], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) # Mock response with single embedding @@ -2342,113 +1319,56 @@ async def test_async_embed_content_string_input( }, } mock_http_response = create_mock_http_response(single_embed_response) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with mock.patch.object( - mock_genai_client._api_client, - "async_request", - return_value=mock_http_response, - ), start_transaction(name="google_genai_embeddings_async"): - await mock_genai_client.aio.models.embed_content( - model="text-embedding-004", - contents="Single text input", - ) - - sentry_sdk.flush() - spans = [item.payload for item in items] - (embed_span,) = spans - - # Check that single string is handled correctly - input_texts = json.loads( - embed_span["attributes"][SPANDATA.GEN_AI_EMBEDDINGS_INPUT] + with mock.patch.object( + mock_genai_client._api_client, + "async_request", + return_value=mock_http_response, + ): + await mock_genai_client.aio.models.embed_content( + model="text-embedding-004", + contents="Single text input", ) - assert input_texts == ["Single text input"] - # Should use token_count from statistics (5), not billable_character_count (10) - # Note: Only available in newer versions with ContentEmbeddingStatistics - if SPANDATA.GEN_AI_USAGE_INPUT_TOKENS in embed_span["attributes"]: - assert embed_span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 5 - else: - events = capture_events() - - with mock.patch.object( - mock_genai_client._api_client, - "async_request", - return_value=mock_http_response, - ), start_transaction(name="google_genai_embeddings_async"): - await mock_genai_client.aio.models.embed_content( - model="text-embedding-004", - contents="Single text input", - ) - (event,) = events - (embed_span,) = event["spans"] + sentry_sdk.flush() + spans = [item.payload for item in items] + (embed_span,) = spans - # Check that single string is handled correctly - input_texts = json.loads(embed_span["data"][SPANDATA.GEN_AI_EMBEDDINGS_INPUT]) - assert input_texts == ["Single text input"] - # Should use token_count from statistics (5), not billable_character_count (10) - # Note: Only available in newer versions with ContentEmbeddingStatistics - if SPANDATA.GEN_AI_USAGE_INPUT_TOKENS in embed_span["data"]: - assert embed_span["data"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 5 + # Check that single string is handled correctly + input_texts = json.loads(embed_span["attributes"][SPANDATA.GEN_AI_EMBEDDINGS_INPUT]) + assert input_texts == ["Single text input"] + # Should use token_count from statistics (5), not billable_character_count (10) + # Note: Only available in newer versions with ContentEmbeddingStatistics + if SPANDATA.GEN_AI_USAGE_INPUT_TOKENS in embed_span["attributes"]: + assert embed_span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 5 -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio async def test_async_embed_content_error_handling( sentry_init, - capture_events, capture_items, mock_genai_client, - stream_gen_ai_spans, - span_streaming, ): """Test error handling in async embed_content.""" sentry_init( integrations=[GoogleGenAIIntegration()], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) + items = capture_items("event") - if span_streaming or stream_gen_ai_spans: - items = capture_items("event") - - # Mock an error at the HTTP level - with mock.patch.object( - mock_genai_client._api_client, - "async_request", - side_effect=Exception("Async Embedding API Error"), - ), start_transaction(name="google_genai_embeddings_async"), pytest.raises( - Exception, match="Async Embedding API Error" - ): - await mock_genai_client.aio.models.embed_content( - model="text-embedding-004", - contents=["This will fail"], - ) - - (error_event,) = (item.payload for item in items) - else: - events = capture_events() - - # Mock an error at the HTTP level - with mock.patch.object( - mock_genai_client._api_client, - "async_request", - side_effect=Exception("Async Embedding API Error"), - ), start_transaction(name="google_genai_embeddings_async"), pytest.raises( - Exception, match="Async Embedding API Error" - ): - await mock_genai_client.aio.models.embed_content( - model="text-embedding-004", - contents=["This will fail"], - ) + # Mock an error at the HTTP level + with mock.patch.object( + mock_genai_client._api_client, + "async_request", + side_effect=Exception("Async Embedding API Error"), + ), pytest.raises(Exception, match="Async Embedding API Error"): + await mock_genai_client.aio.models.embed_content( + model="text-embedding-004", + contents=["This will fail"], + ) - # Should have both transaction and error events - assert len(events) == 2 - error_event, _ = events + (error_event,) = (item.payload for item in items) assert error_event["level"] == "error" assert error_event["exception"]["values"][0]["type"] == "Exception" @@ -2456,23 +1376,16 @@ async def test_async_embed_content_error_handling( assert error_event["exception"]["values"][0]["mechanism"]["type"] == "google_genai" -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio async def test_async_embed_content_without_statistics( sentry_init, - capture_events, capture_items, mock_genai_client, - stream_gen_ai_spans, - span_streaming, ): """Test async embed_content response without statistics (older package versions).""" sentry_init( integrations=[GoogleGenAIIntegration()], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) # Response without statistics (typical for older google-genai versions) @@ -2488,149 +1401,69 @@ async def test_async_embed_content_without_statistics( ], } mock_http_response = create_mock_http_response(old_version_response) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with mock.patch.object( - mock_genai_client._api_client, - "async_request", - return_value=mock_http_response, - ), start_transaction(name="google_genai_embeddings_async"): - await mock_genai_client.aio.models.embed_content( - model="text-embedding-004", - contents=["Test without statistics", "Another test"], - ) - - sentry_sdk.flush() - spans = [item.payload for item in items] - (embed_span,) = spans - - # No usage tokens since there are no statistics in older versions - # This is expected and the integration should handle it gracefully - assert SPANDATA.GEN_AI_USAGE_INPUT_TOKENS not in embed_span["attributes"] - else: - events = capture_events() - - with mock.patch.object( - mock_genai_client._api_client, - "async_request", - return_value=mock_http_response, - ), start_transaction(name="google_genai_embeddings_async"): - await mock_genai_client.aio.models.embed_content( - model="text-embedding-004", - contents=["Test without statistics", "Another test"], - ) + with mock.patch.object( + mock_genai_client._api_client, + "async_request", + return_value=mock_http_response, + ): + await mock_genai_client.aio.models.embed_content( + model="text-embedding-004", + contents=["Test without statistics", "Another test"], + ) - (event,) = events - (embed_span,) = event["spans"] + sentry_sdk.flush() + spans = [item.payload for item in items] + (embed_span,) = spans - # No usage tokens since there are no statistics in older versions - # This is expected and the integration should handle it gracefully - assert SPANDATA.GEN_AI_USAGE_INPUT_TOKENS not in embed_span["data"] + # No usage tokens since there are no statistics in older versions + # This is expected and the integration should handle it gracefully + assert SPANDATA.GEN_AI_USAGE_INPUT_TOKENS not in embed_span["attributes"] -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio async def test_async_embed_content_span_origin( sentry_init, - capture_events, capture_items, mock_genai_client, - stream_gen_ai_spans, - span_streaming, ): """Test that async embed_content spans have correct origin.""" sentry_init( integrations=[GoogleGenAIIntegration()], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) mock_http_response = create_mock_http_response(EXAMPLE_EMBED_RESPONSE_JSON) + items = capture_items("span") - if span_streaming: - items = capture_items("transaction", "span") - - with mock.patch.object( - mock_genai_client._api_client, - "async_request", - return_value=mock_http_response, - ), sentry_sdk.traces.start_span(name="google_genai_embeddings_async"): - await mock_genai_client.aio.models.embed_content( - model="text-embedding-004", - contents=["Test origin"], - ) - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - for span in spans: - if span["is_segment"] is True: - assert span["attributes"]["sentry.origin"] == "manual" - continue - - assert span["attributes"]["sentry.origin"] == "auto.ai.google_genai" - - elif stream_gen_ai_spans: - items = capture_items("transaction", "span") - - with mock.patch.object( - mock_genai_client._api_client, - "async_request", - return_value=mock_http_response, - ), start_transaction(name="google_genai_embeddings_async"): - await mock_genai_client.aio.models.embed_content( - model="text-embedding-004", - contents=["Test origin"], - ) - - (event,) = [item.payload for item in items if item.type == "transaction"] - assert event["contexts"]["trace"]["origin"] == "manual" - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - for span in spans: - assert span["attributes"]["sentry.origin"] == "auto.ai.google_genai" - else: - events = capture_events() - - with mock.patch.object( - mock_genai_client._api_client, - "async_request", - return_value=mock_http_response, - ), start_transaction(name="google_genai_embeddings_async"): - await mock_genai_client.aio.models.embed_content( - model="text-embedding-004", - contents=["Test origin"], - ) - - (event,) = events + with mock.patch.object( + mock_genai_client._api_client, + "async_request", + return_value=mock_http_response, + ): + await mock_genai_client.aio.models.embed_content( + model="text-embedding-004", + contents=["Test origin"], + ) - assert event["contexts"]["trace"]["origin"] == "manual" - for span in event["spans"]: - assert span["origin"] == "auto.ai.google_genai" + sentry_sdk.flush() + spans = [item.payload for item in items] + for span in spans: + assert span["attributes"]["sentry.origin"] == "auto.ai.google_genai" # Integration tests for generate_content with different input message formats -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_generate_content_with_content_object( sentry_init, - capture_events, capture_items, mock_genai_client, - stream_gen_ai_spans, - span_streaming, ): """Test generate_content with Content object input.""" sentry_init( - integrations=[GoogleGenAIIntegration(include_prompts=True)], + integrations=[GoogleGenAIIntegration()], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) mock_http_response = create_mock_http_response(EXAMPLE_API_RESPONSE_JSON) @@ -2639,37 +1472,19 @@ def test_generate_content_with_content_object( content = genai_types.Content( role="user", parts=[genai_types.Part(text="Hello from Content object")] ) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with mock.patch.object( - mock_genai_client._api_client, "request", return_value=mock_http_response - ), start_transaction(name="google_genai"): - mock_genai_client.models.generate_content( - model="gemini-1.5-flash", contents=content, config=create_test_config() - ) - - sentry_sdk.flush() - invoke_span = next(item.payload for item in items) - - messages = json.loads( - invoke_span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] + with mock.patch.object( + mock_genai_client._api_client, "request", return_value=mock_http_response + ): + mock_genai_client.models.generate_content( + model="gemini-1.5-flash", contents=content, config=create_test_config() ) - else: - events = capture_events() - - with mock.patch.object( - mock_genai_client._api_client, "request", return_value=mock_http_response - ), start_transaction(name="google_genai"): - mock_genai_client.models.generate_content( - model="gemini-1.5-flash", contents=content, config=create_test_config() - ) - (event,) = events - invoke_span = event["spans"][0] + sentry_sdk.flush() + invoke_span = next(item.payload for item in items) - messages = json.loads(invoke_span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) + messages = json.loads(invoke_span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) assert len(messages) == 1 assert messages[0]["role"] == "user" @@ -2678,60 +1493,35 @@ def test_generate_content_with_content_object( ] -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_generate_content_with_dict_format( sentry_init, - capture_events, capture_items, mock_genai_client, - stream_gen_ai_spans, - span_streaming, ): """Test generate_content with dict format input (ContentDict).""" sentry_init( - integrations=[GoogleGenAIIntegration(include_prompts=True)], + integrations=[GoogleGenAIIntegration()], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) mock_http_response = create_mock_http_response(EXAMPLE_API_RESPONSE_JSON) # Dict format content contents = {"role": "user", "parts": [{"text": "Hello from dict format"}]} + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with mock.patch.object( - mock_genai_client._api_client, "request", return_value=mock_http_response - ), start_transaction(name="google_genai"): - mock_genai_client.models.generate_content( - model="gemini-1.5-flash", contents=contents, config=create_test_config() - ) - - sentry_sdk.flush() - invoke_span = next(item.payload for item in items) - - messages = json.loads( - invoke_span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] + with mock.patch.object( + mock_genai_client._api_client, "request", return_value=mock_http_response + ): + mock_genai_client.models.generate_content( + model="gemini-1.5-flash", contents=contents, config=create_test_config() ) - else: - events = capture_events() - - with mock.patch.object( - mock_genai_client._api_client, "request", return_value=mock_http_response - ), start_transaction(name="google_genai"): - mock_genai_client.models.generate_content( - model="gemini-1.5-flash", contents=contents, config=create_test_config() - ) - (event,) = events - invoke_span = event["spans"][0] + sentry_sdk.flush() + invoke_span = next(item.payload for item in items) - messages = json.loads(invoke_span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) + messages = json.loads(invoke_span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) assert len(messages) == 1 assert messages[0]["role"] == "user" @@ -2740,23 +1530,16 @@ def test_generate_content_with_dict_format( ] -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_generate_content_with_file_data( sentry_init, - capture_events, capture_items, mock_genai_client, - stream_gen_ai_spans, - span_streaming, ): """Test generate_content with file_data (external file reference).""" sentry_init( - integrations=[GoogleGenAIIntegration(include_prompts=True)], + integrations=[GoogleGenAIIntegration()], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) mock_http_response = create_mock_http_response(EXAMPLE_API_RESPONSE_JSON) @@ -2772,37 +1555,19 @@ def test_generate_content_with_file_data( genai_types.Part(file_data=file_data), ], ) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with mock.patch.object( - mock_genai_client._api_client, "request", return_value=mock_http_response - ), start_transaction(name="google_genai"): - mock_genai_client.models.generate_content( - model="gemini-1.5-flash", contents=content, config=create_test_config() - ) - - sentry_sdk.flush() - invoke_span = next(item.payload for item in items) - - messages = json.loads( - invoke_span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] + with mock.patch.object( + mock_genai_client._api_client, "request", return_value=mock_http_response + ): + mock_genai_client.models.generate_content( + model="gemini-1.5-flash", contents=content, config=create_test_config() ) - else: - events = capture_events() - - with mock.patch.object( - mock_genai_client._api_client, "request", return_value=mock_http_response - ), start_transaction(name="google_genai"): - mock_genai_client.models.generate_content( - model="gemini-1.5-flash", contents=content, config=create_test_config() - ) - (event,) = events - invoke_span = event["spans"][0] + sentry_sdk.flush() + invoke_span = next(item.payload for item in items) - messages = json.loads(invoke_span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) + messages = json.loads(invoke_span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) assert len(messages) == 1 assert messages[0]["role"] == "user" @@ -2817,23 +1582,16 @@ def test_generate_content_with_file_data( assert messages[0]["content"][1]["uri"] == "gs://bucket/image.jpg" -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_generate_content_with_inline_data( sentry_init, - capture_events, capture_items, mock_genai_client, - stream_gen_ai_spans, - span_streaming, ): """Test generate_content with inline_data (binary data).""" sentry_init( - integrations=[GoogleGenAIIntegration(include_prompts=True)], + integrations=[GoogleGenAIIntegration()], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) mock_http_response = create_mock_http_response(EXAMPLE_API_RESPONSE_JSON) @@ -2848,37 +1606,19 @@ def test_generate_content_with_inline_data( genai_types.Part(inline_data=blob), ], ) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with mock.patch.object( - mock_genai_client._api_client, "request", return_value=mock_http_response - ), start_transaction(name="google_genai"): - mock_genai_client.models.generate_content( - model="gemini-1.5-flash", contents=content, config=create_test_config() - ) - - sentry_sdk.flush() - invoke_span = next(item.payload for item in items) - - messages = json.loads( - invoke_span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] + with mock.patch.object( + mock_genai_client._api_client, "request", return_value=mock_http_response + ): + mock_genai_client.models.generate_content( + model="gemini-1.5-flash", contents=content, config=create_test_config() ) - else: - events = capture_events() - - with mock.patch.object( - mock_genai_client._api_client, "request", return_value=mock_http_response - ), start_transaction(name="google_genai"): - mock_genai_client.models.generate_content( - model="gemini-1.5-flash", contents=content, config=create_test_config() - ) - (event,) = events - invoke_span = event["spans"][0] + sentry_sdk.flush() + invoke_span = next(item.payload for item in items) - messages = json.loads(invoke_span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) + messages = json.loads(invoke_span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) assert len(messages) == 1 assert messages[0]["role"] == "user" @@ -2891,16 +1631,14 @@ def test_generate_content_with_inline_data( def test_generate_content_with_function_response( - sentry_init, capture_events, mock_genai_client + sentry_init, capture_items, mock_genai_client ): """Test generate_content with function_response (tool result).""" sentry_init( - integrations=[GoogleGenAIIntegration(include_prompts=True)], + integrations=[GoogleGenAIIntegration()], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=False, ) - events = capture_events() mock_http_response = create_mock_http_response(EXAMPLE_API_RESPONSE_JSON) @@ -2926,37 +1664,39 @@ def test_generate_content_with_function_response( ), ] + items = capture_items("span") + with mock.patch.object( mock_genai_client._api_client, "request", return_value=mock_http_response ): - with start_transaction(name="google_genai"): - mock_genai_client.models.generate_content( - model="gemini-1.5-flash", contents=contents, config=create_test_config() - ) + mock_genai_client.models.generate_content( + model="gemini-1.5-flash", contents=contents, config=create_test_config() + ) - (event,) = events - invoke_span = event["spans"][0] + sentry_sdk.flush() + spans = [item.payload for item in items] + invoke_span = spans[0] - messages = json.loads(invoke_span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) - assert len(messages) == 1 + messages = json.loads(invoke_span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) + assert len(messages) == 2 # First message is user message - assert messages[0]["role"] == "tool" - assert messages[0]["content"]["toolCallId"] == "call_123" - assert messages[0]["content"]["toolName"] == "get_weather" - assert messages[0]["content"]["output"] == "Sunny, 72F" + assert messages[1]["role"] == "tool" + assert messages[1]["content"]["toolCallId"] == "call_123" + assert messages[1]["content"]["toolName"] == "get_weather" + assert messages[1]["content"]["output"] == "Sunny, 72F" def test_generate_content_with_mixed_string_and_content( - sentry_init, capture_events, mock_genai_client + sentry_init, + capture_items, + mock_genai_client, ): """Test generate_content with mixed string and Content objects in list.""" sentry_init( - integrations=[GoogleGenAIIntegration(include_prompts=True)], + integrations=[GoogleGenAIIntegration()], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=False, ) - events = capture_events() mock_http_response = create_mock_http_response(EXAMPLE_API_RESPONSE_JSON) @@ -2973,78 +1713,55 @@ def test_generate_content_with_mixed_string_and_content( ), ] + items = capture_items("span") + with mock.patch.object( mock_genai_client._api_client, "request", return_value=mock_http_response ): - with start_transaction(name="google_genai"): - mock_genai_client.models.generate_content( - model="gemini-1.5-flash", contents=contents, config=create_test_config() - ) + mock_genai_client.models.generate_content( + model="gemini-1.5-flash", contents=contents, config=create_test_config() + ) - (event,) = events - invoke_span = event["spans"][0] + sentry_sdk.flush() + spans = [item.payload for item in items] + invoke_span = spans[0] - messages = json.loads(invoke_span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) - assert len(messages) == 1 + messages = json.loads(invoke_span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) + assert len(messages) == 3 # User message - assert messages[0]["role"] == "user" - assert messages[0]["content"] == [{"text": "Tell me a joke", "type": "text"}] + assert messages[2]["role"] == "user" + assert messages[2]["content"] == [{"text": "Tell me a joke", "type": "text"}] -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_generate_content_with_part_object_directly( sentry_init, - capture_events, capture_items, mock_genai_client, - stream_gen_ai_spans, - span_streaming, ): """Test generate_content with Part object directly (not wrapped in Content).""" sentry_init( - integrations=[GoogleGenAIIntegration(include_prompts=True)], + integrations=[GoogleGenAIIntegration()], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) mock_http_response = create_mock_http_response(EXAMPLE_API_RESPONSE_JSON) # Part object directly part = genai_types.Part(text="Direct Part object") + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with mock.patch.object( - mock_genai_client._api_client, "request", return_value=mock_http_response - ), start_transaction(name="google_genai"): - mock_genai_client.models.generate_content( - model="gemini-1.5-flash", contents=part, config=create_test_config() - ) - - sentry_sdk.flush() - invoke_span = next(item.payload for item in items) - - messages = json.loads( - invoke_span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] + with mock.patch.object( + mock_genai_client._api_client, "request", return_value=mock_http_response + ): + mock_genai_client.models.generate_content( + model="gemini-1.5-flash", contents=part, config=create_test_config() ) - else: - events = capture_events() - - with mock.patch.object( - mock_genai_client._api_client, "request", return_value=mock_http_response - ), start_transaction(name="google_genai"): - mock_genai_client.models.generate_content( - model="gemini-1.5-flash", contents=part, config=create_test_config() - ) - (event,) = events - invoke_span = event["spans"][0] + sentry_sdk.flush() + invoke_span = next(item.payload for item in items) - messages = json.loads(invoke_span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) + messages = json.loads(invoke_span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) assert len(messages) == 1 assert messages[0]["role"] == "user" @@ -3052,7 +1769,7 @@ def test_generate_content_with_part_object_directly( def test_generate_content_with_list_of_dicts( - sentry_init, capture_events, mock_genai_client + sentry_init, capture_items, mock_genai_client ): """ Test generate_content with list of dict format inputs. @@ -3062,12 +1779,10 @@ def test_generate_content_with_list_of_dicts( would be present. """ sentry_init( - integrations=[GoogleGenAIIntegration(include_prompts=True)], + integrations=[GoogleGenAIIntegration()], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=False, ) - events = capture_events() mock_http_response = create_mock_http_response(EXAMPLE_API_RESPONSE_JSON) @@ -3078,40 +1793,35 @@ def test_generate_content_with_list_of_dicts( {"role": "user", "parts": [{"text": "Second user message"}]}, ] + items = capture_items("span") + with mock.patch.object( mock_genai_client._api_client, "request", return_value=mock_http_response ): - with start_transaction(name="google_genai"): - mock_genai_client.models.generate_content( - model="gemini-1.5-flash", contents=contents, config=create_test_config() - ) + mock_genai_client.models.generate_content( + model="gemini-1.5-flash", contents=contents, config=create_test_config() + ) - (event,) = events - invoke_span = event["spans"][0] + sentry_sdk.flush() + spans = [item.payload for item in items] + invoke_span = spans[0] - messages = json.loads(invoke_span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) - assert len(messages) == 1 - assert messages[0]["role"] == "user" - assert messages[0]["content"] == [{"text": "Second user message", "type": "text"}] + messages = json.loads(invoke_span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) + assert len(messages) == 3 + assert messages[2]["role"] == "user" + assert messages[2]["content"] == [{"text": "Second user message", "type": "text"}] -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_generate_content_with_dict_inline_data( sentry_init, - capture_events, capture_items, mock_genai_client, - stream_gen_ai_spans, - span_streaming, ): """Test generate_content with dict format containing inline_data.""" sentry_init( - integrations=[GoogleGenAIIntegration(include_prompts=True)], + integrations=[GoogleGenAIIntegration()], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) mock_http_response = create_mock_http_response(EXAMPLE_API_RESPONSE_JSON) @@ -3124,37 +1834,19 @@ def test_generate_content_with_dict_inline_data( {"inline_data": {"data": b"fake_binary_data", "mime_type": "image/gif"}}, ], } + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with mock.patch.object( - mock_genai_client._api_client, "request", return_value=mock_http_response - ), start_transaction(name="google_genai"): - mock_genai_client.models.generate_content( - model="gemini-1.5-flash", contents=contents, config=create_test_config() - ) - - sentry_sdk.flush() - invoke_span = next(item.payload for item in items) - - messages = json.loads( - invoke_span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] + with mock.patch.object( + mock_genai_client._api_client, "request", return_value=mock_http_response + ): + mock_genai_client.models.generate_content( + model="gemini-1.5-flash", contents=contents, config=create_test_config() ) - else: - events = capture_events() - - with mock.patch.object( - mock_genai_client._api_client, "request", return_value=mock_http_response - ), start_transaction(name="google_genai"): - mock_genai_client.models.generate_content( - model="gemini-1.5-flash", contents=contents, config=create_test_config() - ) - (event,) = events - invoke_span = event["spans"][0] + sentry_sdk.flush() + invoke_span = next(item.payload for item in items) - messages = json.loads(invoke_span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) + messages = json.loads(invoke_span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) assert len(messages) == 1 assert messages[0]["role"] == "user" @@ -3168,22 +1860,15 @@ def test_generate_content_with_dict_inline_data( assert messages[0]["content"][1]["content"] == BLOB_DATA_SUBSTITUTE -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_generate_content_without_parts_property_inline_data( sentry_init, - capture_events, capture_items, mock_genai_client, - stream_gen_ai_spans, - span_streaming, ): sentry_init( - integrations=[GoogleGenAIIntegration(include_prompts=True)], + integrations=[GoogleGenAIIntegration()], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) mock_http_response = create_mock_http_response(EXAMPLE_API_RESPONSE_JSON) @@ -3192,37 +1877,19 @@ def test_generate_content_without_parts_property_inline_data( {"text": "What's in this image?"}, {"inline_data": {"data": b"fake_binary_data", "mime_type": "image/gif"}}, ] + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with mock.patch.object( - mock_genai_client._api_client, "request", return_value=mock_http_response - ), start_transaction(name="google_genai"): - mock_genai_client.models.generate_content( - model="gemini-1.5-flash", contents=contents, config=create_test_config() - ) - - sentry_sdk.flush() - invoke_span = next(item.payload for item in items) - - messages = json.loads( - invoke_span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] + with mock.patch.object( + mock_genai_client._api_client, "request", return_value=mock_http_response + ): + mock_genai_client.models.generate_content( + model="gemini-1.5-flash", contents=contents, config=create_test_config() ) - else: - events = capture_events() - - with mock.patch.object( - mock_genai_client._api_client, "request", return_value=mock_http_response - ), start_transaction(name="google_genai"): - mock_genai_client.models.generate_content( - model="gemini-1.5-flash", contents=contents, config=create_test_config() - ) - (event,) = events - invoke_span = event["spans"][0] + sentry_sdk.flush() + invoke_span = next(item.payload for item in items) - messages = json.loads(invoke_span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) + messages = json.loads(invoke_span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) assert len(messages) == 1 @@ -3238,22 +1905,15 @@ def test_generate_content_without_parts_property_inline_data( assert messages[0]["content"][1]["inline_data"]["mime_type"] == "image/gif" -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_generate_content_without_parts_property_inline_data_and_binary_data_within_string( sentry_init, - capture_events, capture_items, mock_genai_client, - stream_gen_ai_spans, - span_streaming, ): sentry_init( - integrations=[GoogleGenAIIntegration(include_prompts=True)], + integrations=[GoogleGenAIIntegration()], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) mock_http_response = create_mock_http_response(EXAMPLE_API_RESPONSE_JSON) @@ -3267,37 +1927,19 @@ def test_generate_content_without_parts_property_inline_data_and_binary_data_wit } }, ] + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with mock.patch.object( - mock_genai_client._api_client, "request", return_value=mock_http_response - ), start_transaction(name="google_genai"): - mock_genai_client.models.generate_content( - model="gemini-1.5-flash", contents=contents, config=create_test_config() - ) - - sentry_sdk.flush() - invoke_span = next(item.payload for item in items) - - messages = json.loads( - invoke_span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] + with mock.patch.object( + mock_genai_client._api_client, "request", return_value=mock_http_response + ): + mock_genai_client.models.generate_content( + model="gemini-1.5-flash", contents=contents, config=create_test_config() ) - else: - events = capture_events() - - with mock.patch.object( - mock_genai_client._api_client, "request", return_value=mock_http_response - ), start_transaction(name="google_genai"): - mock_genai_client.models.generate_content( - model="gemini-1.5-flash", contents=contents, config=create_test_config() - ) - (event,) = events - invoke_span = event["spans"][0] + sentry_sdk.flush() + invoke_span = next(item.payload for item in items) - messages = json.loads(invoke_span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) + messages = json.loads(invoke_span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) assert len(messages) == 1 assert messages[0]["role"] == "user" @@ -3650,15 +2292,12 @@ def __init__(self): } -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize( - "data_collection,send_default_pii,include_prompts,expected_present,expected_absent", + "data_collection,send_default_pii,expected_present,expected_absent", [ pytest.param( {"gen_ai": {"inputs": True, "outputs": True}}, False, - False, [ SPANDATA.GEN_AI_REQUEST_MESSAGES, SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS, @@ -3670,7 +2309,6 @@ def __init__(self): pytest.param( {"gen_ai": {"inputs": False, "outputs": False}}, True, - True, [], [ SPANDATA.GEN_AI_REQUEST_MESSAGES, @@ -3682,7 +2320,6 @@ def __init__(self): pytest.param( {"gen_ai": {"inputs": True, "outputs": False}}, False, - False, [ SPANDATA.GEN_AI_REQUEST_MESSAGES, SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS, @@ -3695,7 +2332,6 @@ def __init__(self): pytest.param( {"gen_ai": {"inputs": False, "outputs": True}}, False, - False, [ SPANDATA.GEN_AI_RESPONSE_TEXT, ], @@ -3708,7 +2344,6 @@ def __init__(self): pytest.param( {"gen_ai": {}}, False, - False, [ SPANDATA.GEN_AI_REQUEST_MESSAGES, SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS, @@ -3720,19 +2355,17 @@ def __init__(self): pytest.param( None, True, - True, [ SPANDATA.GEN_AI_REQUEST_MESSAGES, SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS, SPANDATA.GEN_AI_RESPONSE_TEXT, ], [], - id="no-gen-ai-config-legacy-pii-and-include-prompts-enabled", + id="no-gen-ai-config-legacy-pii", ), pytest.param( None, False, - True, [], [ SPANDATA.GEN_AI_REQUEST_MESSAGES, @@ -3745,23 +2378,17 @@ def __init__(self): ) def test_generate_content_data_collection( sentry_init, - capture_events, capture_items, mock_genai_client, data_collection, send_default_pii, - include_prompts, expected_present, expected_absent, - stream_gen_ai_spans, - span_streaming, ): sentry_init_kwargs = dict( - integrations=[GoogleGenAIIntegration(include_prompts=include_prompts)], + integrations=[GoogleGenAIIntegration()], traces_sample_rate=1.0, send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) if data_collection is not None: sentry_init_kwargs["data_collection"] = data_collection @@ -3769,12 +2396,11 @@ def test_generate_content_data_collection( sentry_init(**sentry_init_kwargs) mock_http_response = create_mock_http_response(EXAMPLE_API_RESPONSE_JSON) - streamed = span_streaming or stream_gen_ai_spans - captured = capture_items("span") if streamed else capture_events() + captured = capture_items("span") with mock.patch.object( mock_genai_client._api_client, "request", return_value=mock_http_response - ), start_transaction(name="google_genai"): + ): mock_genai_client.models.generate_content( model="gemini-1.5-flash", contents="Tell me a joke", @@ -3785,17 +2411,10 @@ def test_generate_content_data_collection( ), ) - if streamed: - sentry_sdk.flush() - spans = [item.payload for item in captured if item.type == "span"] - (span,) = [ - s for s in spans if s["attributes"].get("sentry.op") == OP.GEN_AI_CHAT - ] - span_data = span["attributes"] - else: - (event,) = captured - (span,) = [s for s in event["spans"] if s["op"] == OP.GEN_AI_CHAT] - span_data = span["data"] + sentry_sdk.flush() + spans = [item.payload for item in captured if item.type == "span"] + (span,) = [s for s in spans if s["attributes"].get("sentry.op") == OP.GEN_AI_CHAT] + span_data = span["attributes"] for key in expected_present: assert key in span_data, f"{key} should have been collected" @@ -3805,7 +2424,7 @@ def test_generate_content_data_collection( assert key not in span_data, f"{key} should not have been collected" # Data collection never gates non-PII attributes - assert span_data[SPANDATA.GEN_AI_SYSTEM] == "gcp.gemini" + assert span_data[SPANDATA.GEN_AI_PROVIDER_NAME] == "gcp.gemini" assert span_data[SPANDATA.GEN_AI_REQUEST_MODEL] == "gemini-1.5-flash" assert span_data[SPANDATA.GEN_AI_REQUEST_TEMPERATURE] == 0.7 assert span_data[SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 100 @@ -3815,8 +2434,6 @@ def test_generate_content_data_collection( assert span_data[SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS] == "STOP" -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize("send_default_pii", [True, False]) @pytest.mark.parametrize( "data_collection,expected_present,expected_absent", @@ -3873,22 +2490,17 @@ def test_generate_content_data_collection( ) def test_generate_content_data_collection_tools( sentry_init, - capture_events, capture_items, mock_genai_client, data_collection, send_default_pii, expected_present, expected_absent, - stream_gen_ai_spans, - span_streaming, ): sentry_init_kwargs = dict( - integrations=[GoogleGenAIIntegration(include_prompts=False)], + integrations=[GoogleGenAIIntegration()], traces_sample_rate=1.0, send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) if data_collection is not None: sentry_init_kwargs["data_collection"] = data_collection @@ -3933,29 +2545,21 @@ def test_generate_content_data_collection_tools( } ) - streamed = span_streaming or stream_gen_ai_spans - captured = capture_items("span") if streamed else capture_events() + captured = capture_items("span") with mock.patch.object( mock_genai_client._api_client, "request", return_value=mock_http_response - ), start_transaction(name="google_genai"): + ): mock_genai_client.models.generate_content( model="gemini-1.5-flash", contents="What's the weather?", config=create_test_config(tools=[weather_tool]), ) - if streamed: - sentry_sdk.flush() - spans = [item.payload for item in captured if item.type == "span"] - (span,) = [ - s for s in spans if s["attributes"].get("sentry.op") == OP.GEN_AI_CHAT - ] - span_data = span["attributes"] - else: - (event,) = captured - (span,) = [s for s in event["spans"] if s["op"] == OP.GEN_AI_CHAT] - span_data = span["data"] + sentry_sdk.flush() + spans = [item.payload for item in captured if item.type == "span"] + (span,) = [s for s in spans if s["attributes"].get("sentry.op") == OP.GEN_AI_CHAT] + span_data = span["attributes"] for key in expected_present: assert key in span_data, f"{key} should have been collected" @@ -3973,15 +2577,12 @@ def test_generate_content_data_collection_tools( assert json.loads(tool_calls[0]["arguments"]) == {"location": "San Francisco"} -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize( - "data_collection,send_default_pii,include_prompts,expected_present,expected_absent", + "data_collection,send_default_pii,expected_present,expected_absent", [ pytest.param( {"gen_ai": {"inputs": True, "outputs": True}}, False, - False, [ SPANDATA.GEN_AI_REQUEST_MESSAGES, SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS, @@ -3993,7 +2594,6 @@ def test_generate_content_data_collection_tools( pytest.param( {"gen_ai": {"inputs": False, "outputs": False}}, True, - True, [], [ SPANDATA.GEN_AI_REQUEST_MESSAGES, @@ -4005,7 +2605,6 @@ def test_generate_content_data_collection_tools( pytest.param( {"gen_ai": {"inputs": True, "outputs": False}}, False, - False, [ SPANDATA.GEN_AI_REQUEST_MESSAGES, SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS, @@ -4018,7 +2617,6 @@ def test_generate_content_data_collection_tools( pytest.param( {"gen_ai": {"inputs": False, "outputs": True}}, False, - False, [ SPANDATA.GEN_AI_RESPONSE_TEXT, ], @@ -4031,7 +2629,6 @@ def test_generate_content_data_collection_tools( pytest.param( {"gen_ai": {}}, False, - False, [ SPANDATA.GEN_AI_REQUEST_MESSAGES, SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS, @@ -4043,19 +2640,17 @@ def test_generate_content_data_collection_tools( pytest.param( None, True, - True, [ SPANDATA.GEN_AI_REQUEST_MESSAGES, SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS, SPANDATA.GEN_AI_RESPONSE_TEXT, ], [], - id="no-gen-ai-config-legacy-pii-and-include-prompts-enabled", + id="no-gen-ai-config-legacy-pii", ), pytest.param( None, False, - True, [], [ SPANDATA.GEN_AI_REQUEST_MESSAGES, @@ -4068,23 +2663,17 @@ def test_generate_content_data_collection_tools( ) def test_streaming_generate_content_data_collection( sentry_init, - capture_events, capture_items, mock_genai_client, data_collection, send_default_pii, - include_prompts, expected_present, expected_absent, - stream_gen_ai_spans, - span_streaming, ): sentry_init_kwargs = dict( - integrations=[GoogleGenAIIntegration(include_prompts=include_prompts)], + integrations=[GoogleGenAIIntegration()], traces_sample_rate=1.0, send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) if data_collection is not None: sentry_init_kwargs["data_collection"] = data_collection @@ -4128,12 +2717,11 @@ def test_streaming_generate_content_data_collection( ] ) - streamed = span_streaming or stream_gen_ai_spans - captured = capture_items("span") if streamed else capture_events() + captured = capture_items("span") with mock.patch.object( mock_genai_client._api_client, "request_streamed", return_value=mock_stream - ), start_transaction(name="google_genai"): + ): stream = mock_genai_client.models.generate_content_stream( model="gemini-1.5-flash", contents="Tell me a joke", @@ -4143,17 +2731,10 @@ def test_streaming_generate_content_data_collection( ) list(stream) - if streamed: - sentry_sdk.flush() - spans = [item.payload for item in captured if item.type == "span"] - (span,) = [ - s for s in spans if s["attributes"].get("sentry.op") == OP.GEN_AI_CHAT - ] - span_data = span["attributes"] - else: - (event,) = captured - (span,) = [s for s in event["spans"] if s["op"] == OP.GEN_AI_CHAT] - span_data = span["data"] + sentry_sdk.flush() + spans = [item.payload for item in captured if item.type == "span"] + (span,) = [s for s in spans if s["attributes"].get("sentry.op") == OP.GEN_AI_CHAT] + span_data = span["attributes"] for key in expected_present: assert key in span_data, f"{key} should have been collected" @@ -4169,8 +2750,6 @@ def test_streaming_generate_content_data_collection( assert span_data[SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 25 -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize("send_default_pii", [True, False]) @pytest.mark.parametrize( "data_collection,expected_present,expected_absent", @@ -4227,22 +2806,17 @@ def test_streaming_generate_content_data_collection( ) def test_streaming_generate_content_data_collection_tools( sentry_init, - capture_events, capture_items, mock_genai_client, data_collection, send_default_pii, expected_present, expected_absent, - stream_gen_ai_spans, - span_streaming, ): sentry_init_kwargs = dict( - integrations=[GoogleGenAIIntegration(include_prompts=False)], + integrations=[GoogleGenAIIntegration()], traces_sample_rate=1.0, send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) if data_collection is not None: sentry_init_kwargs["data_collection"] = data_collection @@ -4292,12 +2866,11 @@ def test_streaming_generate_content_data_collection_tools( ] ) - streamed = span_streaming or stream_gen_ai_spans - captured = capture_items("span") if streamed else capture_events() + captured = capture_items("span") with mock.patch.object( mock_genai_client._api_client, "request_streamed", return_value=mock_stream - ), start_transaction(name="google_genai"): + ): stream = mock_genai_client.models.generate_content_stream( model="gemini-1.5-flash", contents="What's the weather?", @@ -4305,17 +2878,10 @@ def test_streaming_generate_content_data_collection_tools( ) list(stream) - if streamed: - sentry_sdk.flush() - spans = [item.payload for item in captured if item.type == "span"] - (span,) = [ - s for s in spans if s["attributes"].get("sentry.op") == OP.GEN_AI_CHAT - ] - span_data = span["attributes"] - else: - (event,) = captured - (span,) = [s for s in event["spans"] if s["op"] == OP.GEN_AI_CHAT] - span_data = span["data"] + sentry_sdk.flush() + spans = [item.payload for item in captured if item.type == "span"] + (span,) = [s for s in spans if s["attributes"].get("sentry.op") == OP.GEN_AI_CHAT] + span_data = span["attributes"] for key in expected_present: assert key in span_data, f"{key} should have been collected" @@ -4332,15 +2898,12 @@ def test_streaming_generate_content_data_collection_tools( assert [tool_call["name"] for tool_call in tool_calls] == ["get_weather"] -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize( - "data_collection,send_default_pii,include_prompts,expected_present,expected_absent", + "data_collection,send_default_pii,expected_present,expected_absent", [ pytest.param( {"gen_ai": {"inputs": True, "outputs": True}}, False, - False, [ SPANDATA.GEN_AI_EMBEDDINGS_INPUT, ], @@ -4350,7 +2913,6 @@ def test_streaming_generate_content_data_collection_tools( pytest.param( {"gen_ai": {"inputs": False, "outputs": False}}, True, - True, [], [ SPANDATA.GEN_AI_EMBEDDINGS_INPUT, @@ -4360,7 +2922,6 @@ def test_streaming_generate_content_data_collection_tools( pytest.param( {"gen_ai": {"inputs": True, "outputs": False}}, False, - False, [ SPANDATA.GEN_AI_EMBEDDINGS_INPUT, ], @@ -4370,7 +2931,6 @@ def test_streaming_generate_content_data_collection_tools( pytest.param( {"gen_ai": {"inputs": False, "outputs": True}}, False, - False, [], [ SPANDATA.GEN_AI_EMBEDDINGS_INPUT, @@ -4380,7 +2940,6 @@ def test_streaming_generate_content_data_collection_tools( pytest.param( {"gen_ai": {}}, False, - False, [ SPANDATA.GEN_AI_EMBEDDINGS_INPUT, ], @@ -4390,17 +2949,15 @@ def test_streaming_generate_content_data_collection_tools( pytest.param( None, True, - True, [ SPANDATA.GEN_AI_EMBEDDINGS_INPUT, ], [], - id="no-gen-ai-config-legacy-pii-and-include-prompts-enabled", + id="no-gen-ai-config-legacy-pii", ), pytest.param( None, False, - True, [], [ SPANDATA.GEN_AI_EMBEDDINGS_INPUT, @@ -4411,23 +2968,17 @@ def test_streaming_generate_content_data_collection_tools( ) def test_embed_content_data_collection( sentry_init, - capture_events, capture_items, mock_genai_client, data_collection, send_default_pii, - include_prompts, expected_present, expected_absent, - stream_gen_ai_spans, - span_streaming, ): sentry_init_kwargs = dict( - integrations=[GoogleGenAIIntegration(include_prompts=include_prompts)], + integrations=[GoogleGenAIIntegration()], traces_sample_rate=1.0, send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) if data_collection is not None: sentry_init_kwargs["data_collection"] = data_collection @@ -4435,28 +2986,22 @@ def test_embed_content_data_collection( sentry_init(**sentry_init_kwargs) mock_http_response = create_mock_http_response(EXAMPLE_EMBED_RESPONSE_JSON) - streamed = span_streaming or stream_gen_ai_spans - captured = capture_items("span") if streamed else capture_events() + captured = capture_items("span") with mock.patch.object( mock_genai_client._api_client, "request", return_value=mock_http_response - ), start_transaction(name="google_genai_embeddings"): + ): mock_genai_client.models.embed_content( model="text-embedding-004", contents=["What is your name?", "What is your favorite color?"], ) - if streamed: - sentry_sdk.flush() - spans = [item.payload for item in captured if item.type == "span"] - (span,) = [ - s for s in spans if s["attributes"].get("sentry.op") == OP.GEN_AI_EMBEDDINGS - ] - span_data = span["attributes"] - else: - (event,) = captured - (span,) = [s for s in event["spans"] if s["op"] == OP.GEN_AI_EMBEDDINGS] - span_data = span["data"] + sentry_sdk.flush() + spans = [item.payload for item in captured if item.type == "span"] + (span,) = [ + s for s in spans if s["attributes"].get("sentry.op") == OP.GEN_AI_EMBEDDINGS + ] + span_data = span["attributes"] for key in expected_present: assert key in span_data, f"{key} should have been collected" @@ -4470,15 +3015,12 @@ def test_embed_content_data_collection( @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize( - "data_collection,send_default_pii,include_prompts,expected_present,expected_absent", + "data_collection,send_default_pii,expected_present,expected_absent", [ pytest.param( {"gen_ai": {"inputs": True, "outputs": True}}, False, - False, [ SPANDATA.GEN_AI_REQUEST_MESSAGES, SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS, @@ -4490,7 +3032,6 @@ def test_embed_content_data_collection( pytest.param( {"gen_ai": {"inputs": False, "outputs": False}}, True, - True, [], [ SPANDATA.GEN_AI_REQUEST_MESSAGES, @@ -4502,7 +3043,6 @@ def test_embed_content_data_collection( pytest.param( {"gen_ai": {"inputs": True, "outputs": False}}, False, - False, [ SPANDATA.GEN_AI_REQUEST_MESSAGES, SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS, @@ -4515,7 +3055,6 @@ def test_embed_content_data_collection( pytest.param( {"gen_ai": {"inputs": False, "outputs": True}}, False, - False, [ SPANDATA.GEN_AI_RESPONSE_TEXT, ], @@ -4528,7 +3067,6 @@ def test_embed_content_data_collection( pytest.param( {"gen_ai": {}}, False, - False, [ SPANDATA.GEN_AI_REQUEST_MESSAGES, SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS, @@ -4540,19 +3078,17 @@ def test_embed_content_data_collection( pytest.param( None, True, - True, [ SPANDATA.GEN_AI_REQUEST_MESSAGES, SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS, SPANDATA.GEN_AI_RESPONSE_TEXT, ], [], - id="no-gen-ai-config-legacy-pii-and-include-prompts-enabled", + id="no-gen-ai-config-legacy-pii", ), pytest.param( None, False, - True, [], [ SPANDATA.GEN_AI_REQUEST_MESSAGES, @@ -4565,23 +3101,17 @@ def test_embed_content_data_collection( ) async def test_async_generate_content_data_collection( sentry_init, - capture_events, capture_items, mock_genai_client, data_collection, send_default_pii, - include_prompts, expected_present, expected_absent, - stream_gen_ai_spans, - span_streaming, ): sentry_init_kwargs = dict( - integrations=[GoogleGenAIIntegration(include_prompts=include_prompts)], + integrations=[GoogleGenAIIntegration()], traces_sample_rate=1.0, send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) if data_collection is not None: sentry_init_kwargs["data_collection"] = data_collection @@ -4589,12 +3119,11 @@ async def test_async_generate_content_data_collection( sentry_init(**sentry_init_kwargs) mock_http_response = create_mock_http_response(EXAMPLE_API_RESPONSE_JSON) - streamed = span_streaming or stream_gen_ai_spans - captured = capture_items("span") if streamed else capture_events() + captured = capture_items("span") with mock.patch.object( mock_genai_client._api_client, "async_request", return_value=mock_http_response - ), start_transaction(name="google_genai"): + ): await mock_genai_client.aio.models.generate_content( model="gemini-1.5-flash", contents="Tell me a joke", @@ -4603,17 +3132,10 @@ async def test_async_generate_content_data_collection( ), ) - if streamed: - sentry_sdk.flush() - spans = [item.payload for item in captured if item.type == "span"] - (span,) = [ - s for s in spans if s["attributes"].get("sentry.op") == OP.GEN_AI_CHAT - ] - span_data = span["attributes"] - else: - (event,) = captured - (span,) = [s for s in event["spans"] if s["op"] == OP.GEN_AI_CHAT] - span_data = span["data"] + sentry_sdk.flush() + spans = [item.payload for item in captured if item.type == "span"] + (span,) = [s for s in spans if s["attributes"].get("sentry.op") == OP.GEN_AI_CHAT] + span_data = span["attributes"] for key in expected_present: assert key in span_data, f"{key} should have been collected" @@ -4627,15 +3149,12 @@ async def test_async_generate_content_data_collection( @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize( - "data_collection,send_default_pii,include_prompts,expected_present,expected_absent", + "data_collection,send_default_pii,expected_present,expected_absent", [ pytest.param( {"gen_ai": {"inputs": True, "outputs": True}}, False, - False, [ SPANDATA.GEN_AI_EMBEDDINGS_INPUT, ], @@ -4645,7 +3164,6 @@ async def test_async_generate_content_data_collection( pytest.param( {"gen_ai": {"inputs": False, "outputs": False}}, True, - True, [], [ SPANDATA.GEN_AI_EMBEDDINGS_INPUT, @@ -4655,7 +3173,6 @@ async def test_async_generate_content_data_collection( pytest.param( {"gen_ai": {"inputs": True, "outputs": False}}, False, - False, [ SPANDATA.GEN_AI_EMBEDDINGS_INPUT, ], @@ -4665,7 +3182,6 @@ async def test_async_generate_content_data_collection( pytest.param( {"gen_ai": {"inputs": False, "outputs": True}}, False, - False, [], [ SPANDATA.GEN_AI_EMBEDDINGS_INPUT, @@ -4675,7 +3191,6 @@ async def test_async_generate_content_data_collection( pytest.param( {"gen_ai": {}}, False, - False, [ SPANDATA.GEN_AI_EMBEDDINGS_INPUT, ], @@ -4685,17 +3200,15 @@ async def test_async_generate_content_data_collection( pytest.param( None, True, - True, [ SPANDATA.GEN_AI_EMBEDDINGS_INPUT, ], [], - id="no-gen-ai-config-legacy-pii-and-include-prompts-enabled", + id="no-gen-ai-config-legacy-pii", ), pytest.param( None, False, - True, [], [ SPANDATA.GEN_AI_EMBEDDINGS_INPUT, @@ -4706,23 +3219,17 @@ async def test_async_generate_content_data_collection( ) async def test_async_embed_content_data_collection( sentry_init, - capture_events, capture_items, mock_genai_client, data_collection, send_default_pii, - include_prompts, expected_present, expected_absent, - stream_gen_ai_spans, - span_streaming, ): sentry_init_kwargs = dict( - integrations=[GoogleGenAIIntegration(include_prompts=include_prompts)], + integrations=[GoogleGenAIIntegration()], traces_sample_rate=1.0, send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) if data_collection is not None: sentry_init_kwargs["data_collection"] = data_collection @@ -4730,28 +3237,22 @@ async def test_async_embed_content_data_collection( sentry_init(**sentry_init_kwargs) mock_http_response = create_mock_http_response(EXAMPLE_EMBED_RESPONSE_JSON) - streamed = span_streaming or stream_gen_ai_spans - captured = capture_items("span") if streamed else capture_events() + captured = capture_items("span") with mock.patch.object( mock_genai_client._api_client, "async_request", return_value=mock_http_response - ), start_transaction(name="google_genai_embeddings"): + ): await mock_genai_client.aio.models.embed_content( model="text-embedding-004", contents=["What is your name?", "What is your favorite color?"], ) - if streamed: - sentry_sdk.flush() - spans = [item.payload for item in captured if item.type == "span"] - (span,) = [ - s for s in spans if s["attributes"].get("sentry.op") == OP.GEN_AI_EMBEDDINGS - ] - span_data = span["attributes"] - else: - (event,) = captured - (span,) = [s for s in event["spans"] if s["op"] == OP.GEN_AI_EMBEDDINGS] - span_data = span["data"] + sentry_sdk.flush() + spans = [item.payload for item in captured if item.type == "span"] + (span,) = [ + s for s in spans if s["attributes"].get("sentry.op") == OP.GEN_AI_EMBEDDINGS + ] + span_data = span["attributes"] for key in expected_present: assert key in span_data, f"{key} should have been collected" diff --git a/tests/integrations/graphene/test_graphene.py b/tests/integrations/graphene/test_graphene.py index 60f47463cb..022b5f2747 100644 --- a/tests/integrations/graphene/test_graphene.py +++ b/tests/integrations/graphene/test_graphene.py @@ -329,107 +329,6 @@ def graphql_server_sync(): [True, False], ) def test_graphql_span_holds_query_information( - sentry_init, capture_events, send_default_pii -): - sentry_init( - integrations=[GrapheneIntegration(), FlaskIntegration()], - traces_sample_rate=1.0, - default_integrations=False, - send_default_pii=send_default_pii, - ) - events = capture_events() - - schema = Schema(query=Query) - - sync_app = Flask(__name__) - - @sync_app.route("/graphql", methods=["POST"]) - def graphql_server_sync(): - data = request.get_json() - result = schema.execute(data["query"], operation_name=data.get("operationName")) - return jsonify(result.data), 200 - - query = { - "query": "query GreetingQuery { hello }", - "operationName": "GreetingQuery", - } - client = sync_app.test_client() - client.post("/graphql", json=query) - - assert len(events) == 1 - - (event,) = events - assert len(event["spans"]) == 1 - - (span,) = event["spans"] - assert span["op"] == OP.GRAPHQL_QUERY - assert span["description"] == query["operationName"] - assert span["data"]["graphql.operation.name"] == query["operationName"] - assert span["data"]["graphql.operation.type"] == "query" - - if send_default_pii is True: - assert span["data"]["graphql.document"] == query["query"] - else: - assert "graphql.document" not in span["data"] - - -@pytest.mark.parametrize( - "data_collection,send_default_pii,expect_document", - DATA_COLLECTION_GRAPHQL_DOCUMENTS_PARAMS, -) -def test_graphql_span_data_collection( - sentry_init, capture_events, data_collection, send_default_pii, expect_document -): - init_kwargs = { - "integrations": [GrapheneIntegration(), FlaskIntegration()], - "traces_sample_rate": 1.0, - "default_integrations": False, - "data_collection": data_collection, - } - if send_default_pii is not None: - init_kwargs["send_default_pii"] = send_default_pii - sentry_init(**init_kwargs) - events = capture_events() - - schema = Schema(query=Query) - - sync_app = Flask(__name__) - - @sync_app.route("/graphql", methods=["POST"]) - def graphql_server_sync(): - data = request.get_json() - result = schema.execute(data["query"], operation_name=data.get("operationName")) - return jsonify(result.data), 200 - - query = { - "query": "query GreetingQuery { hello }", - "operationName": "GreetingQuery", - } - client = sync_app.test_client() - client.post("/graphql", json=query) - - assert len(events) == 1 - - (event,) = events - assert len(event["spans"]) == 1 - - (span,) = event["spans"] - assert span["op"] == OP.GRAPHQL_QUERY - assert span["description"] == query["operationName"] - assert span["data"]["graphql.operation.name"] == query["operationName"] - assert span["data"]["graphql.operation.type"] == "query" - - if expect_document: - assert span["data"]["graphql.document"] == query["query"] - else: - assert "graphql.document" not in span["data"] - - -@pytest.mark.parametrize( - "send_default_pii", - [True, False], -) -def test_graphql_streamed_span_holds_query_information( sentry_init, capture_items, send_default_pii ): sentry_init( @@ -437,7 +336,6 @@ def test_graphql_streamed_span_holds_query_information( traces_sample_rate=1.0, default_integrations=False, send_default_pii=send_default_pii, - trace_lifecycle="stream", ) items = capture_items("span") @@ -486,14 +384,13 @@ def graphql_server_sync(): "data_collection,send_default_pii,expect_document", DATA_COLLECTION_GRAPHQL_DOCUMENTS_PARAMS, ) -def test_graphql_streamed_span_data_collection( +def test_graphql_span_data_collection( sentry_init, capture_items, data_collection, send_default_pii, expect_document ): init_kwargs = { "integrations": [GrapheneIntegration(), FlaskIntegration()], "traces_sample_rate": 1.0, "default_integrations": False, - "trace_lifecycle": "stream", "data_collection": data_collection, } if send_default_pii is not None: @@ -542,56 +439,12 @@ def graphql_server_sync(): assert graphql_span["parent_span_id"] == flask_segment["span_id"] -def test_breadcrumbs_hold_query_information_on_error(sentry_init, capture_events): - sentry_init( - integrations=[ - GrapheneIntegration(), - ], - default_integrations=False, - ) - events = capture_events() - - schema = Schema(query=Query) - - sync_app = Flask(__name__) - - @sync_app.route("/graphql", methods=["POST"]) - def graphql_server_sync(): - data = request.get_json() - result = schema.execute(data["query"], operation_name=data.get("operationName")) - return jsonify(result.data), 200 - - query = { - "query": "query ErrorQuery { goodbye }", - "operationName": "ErrorQuery", - } - client = sync_app.test_client() - client.post("/graphql", json=query) - - assert len(events) == 1 - - (event,) = events - assert len(event["breadcrumbs"]) == 1 - - breadcrumbs = event["breadcrumbs"]["values"] - assert len(breadcrumbs) == 1 - - (breadcrumb,) = breadcrumbs - assert breadcrumb["category"] == "graphql.operation" - assert breadcrumb["data"]["operation_name"] == query["operationName"] - assert breadcrumb["data"]["operation_type"] == "query" - assert breadcrumb["type"] == "default" - - -def test_breadcrumbs_hold_query_information_on_error_with_span_streaming( - sentry_init, capture_items -): +def test_breadcrumbs_hold_query_information_on_error(sentry_init, capture_items): sentry_init( integrations=[ GrapheneIntegration(), ], default_integrations=False, - trace_lifecycle="stream", ) items = capture_items("span", "event") diff --git a/tests/integrations/grpc/test_grpc.py b/tests/integrations/grpc/test_grpc.py index f50a2f62d1..5dc356f674 100644 --- a/tests/integrations/grpc/test_grpc.py +++ b/tests/integrations/grpc/test_grpc.py @@ -7,11 +7,9 @@ import pytest import sentry_sdk -from sentry_sdk import start_span, start_transaction from sentry_sdk.consts import OP from sentry_sdk.integrations.grpc import GRPCIntegration from sentry_sdk.integrations.grpc.client import ClientInterceptor -from sentry_sdk.tracing_utils import has_span_streaming_enabled from tests.conftest import ApproxDict from tests.integrations.grpc.grpc_test_service_pb2 import gRPCTestMessage from tests.integrations.grpc.grpc_test_service_pb2_grpc import ( @@ -54,72 +52,45 @@ def _tear_down(server: grpc.Server): @pytest.mark.forked -@pytest.mark.parametrize("span_streaming", [True, False]) def test_grpc_server_starts_transaction( sentry_init, - capture_events_forksafe, capture_items_forksafe, - span_streaming, ): sentry_init( traces_sample_rate=1.0, integrations=[GRPCIntegration()], - trace_lifecycle="stream" if span_streaming else "static", ) server, channel = _set_up() # Use the provided channel stub = gRPCTestServiceStub(channel) + items = capture_items_forksafe("span") - if span_streaming: - items = capture_items_forksafe("span") + stub.TestServe(gRPCTestMessage(text="test")) - stub.TestServe(gRPCTestMessage(text="test")) - - _tear_down(server=server) - - sentry_sdk.flush() - items.write_file.close() - items = items.read_event() - spans = [item["payload"] for item in items if item["type"] == "span"] - span = spans[0] - - assert spans[1]["attributes"]["sentry.segment.name.source"] == "custom" - assert spans[1]["attributes"]["sentry.op"] == OP.GRPC_SERVER - assert span["attributes"]["sentry.op"] == "test" - else: - events = capture_events_forksafe() - - stub.TestServe(gRPCTestMessage(text="test")) - - _tear_down(server=server) + _tear_down(server=server) - events.write_file.close() - event = events.read_event() - span = event["spans"][0] + sentry_sdk.flush() + items.write_file.close() + items = items.read_event() + spans = [item["payload"] for item in items if item["type"] == "span"] + span = spans[0] - assert event["type"] == "transaction" - assert event["transaction_info"] == { - "source": "custom", - } - assert event["contexts"]["trace"]["op"] == OP.GRPC_SERVER - assert span["op"] == "test" + assert spans[1]["attributes"]["sentry.segment.name.source"] == "custom" + assert spans[1]["attributes"]["sentry.op"] == OP.GRPC_SERVER + assert span["attributes"]["sentry.op"] == "test" @pytest.mark.forked -@pytest.mark.parametrize("span_streaming", [True, False]) def test_grpc_server_other_interceptors( sentry_init, - capture_events_forksafe, capture_items_forksafe, - span_streaming, ): """Ensure compatibility with additional server interceptors.""" sentry_init( traces_sample_rate=1.0, integrations=[GRPCIntegration()], - trace_lifecycle="stream" if span_streaming else "static", ) mock_intercept = lambda continuation, handler_call_details: continuation( @@ -132,302 +103,177 @@ def test_grpc_server_other_interceptors( # Use the provided channel stub = gRPCTestServiceStub(channel) + items = capture_items_forksafe("span") - if span_streaming: - items = capture_items_forksafe("span") - - stub.TestServe(gRPCTestMessage(text="test")) - - _tear_down(server=server) - - mock_interceptor.intercept_service.assert_called_once() - - sentry_sdk.flush() - items.write_file.close() - items = items.read_event() - spans = [item["payload"] for item in items if item["type"] == "span"] - span = spans[0] + stub.TestServe(gRPCTestMessage(text="test")) - assert spans[1]["attributes"]["sentry.segment.name.source"] == "custom" - assert spans[1]["attributes"]["sentry.op"] == OP.GRPC_SERVER - assert span["attributes"]["sentry.op"] == "test" - else: - events = capture_events_forksafe() - - stub.TestServe(gRPCTestMessage(text="test")) + _tear_down(server=server) - _tear_down(server=server) + mock_interceptor.intercept_service.assert_called_once() - mock_interceptor.intercept_service.assert_called_once() + sentry_sdk.flush() + items.write_file.close() + items = items.read_event() + spans = [item["payload"] for item in items if item["type"] == "span"] + span = spans[0] - events.write_file.close() - event = events.read_event() - span = event["spans"][0] - - assert event["type"] == "transaction" - assert event["transaction_info"] == { - "source": "custom", - } - assert event["contexts"]["trace"]["op"] == OP.GRPC_SERVER - assert span["op"] == "test" + assert spans[1]["attributes"]["sentry.segment.name.source"] == "custom" + assert spans[1]["attributes"]["sentry.op"] == OP.GRPC_SERVER + assert span["attributes"]["sentry.op"] == "test" @pytest.mark.forked -@pytest.mark.parametrize("span_streaming", [True, False]) def test_grpc_server_continues_transaction( sentry_init, - capture_events_forksafe, capture_items_forksafe, - span_streaming, ): sentry_init( traces_sample_rate=1.0, integrations=[GRPCIntegration()], - trace_lifecycle="stream" if span_streaming else "static", ) server, channel = _set_up() # Use the provided channel stub = gRPCTestServiceStub(channel) - - if span_streaming: - items = capture_items_forksafe("span") - - with sentry_sdk.traces.start_span(name="custom parent") as segment_span: - metadata = ( - ( - "baggage", - "sentry-trace_id={trace_id},sentry-environment=test," - "sentry-transaction=test-transaction,sentry-sample_rate=1.0".format( - trace_id=segment_span.trace_id - ), - ), - ( - "sentry-trace", - "{trace_id}-{parent_span_id}-{sampled}".format( - trace_id=segment_span.trace_id, - parent_span_id=segment_span.span_id, - sampled=1, - ), + items = capture_items_forksafe("span") + + with sentry_sdk.start_span(name="custom parent") as segment_span: + metadata = ( + ( + "baggage", + "sentry-trace_id={trace_id},sentry-environment=test," + "sentry-transaction=test-transaction,sentry-sample_rate=1.0".format( + trace_id=segment_span.trace_id ), - ) - - stub.TestServe(gRPCTestMessage(text="test"), metadata=metadata) - - _tear_down(server=server) - - sentry_sdk.flush() - items.write_file.close() - items = items.read_event() - spans = [item["payload"] for item in items if item["type"] == "span"] - span = spans[0] - - assert spans[1]["attributes"]["sentry.segment.name.source"] == "custom" - assert spans[1]["attributes"]["sentry.op"] == OP.GRPC_SERVER - assert spans[1]["trace_id"] == segment_span.trace_id - assert span["attributes"]["sentry.op"] == "test" - else: - events = capture_events_forksafe() - - with start_transaction() as transaction: - metadata = ( - ( - "baggage", - "sentry-trace_id={trace_id},sentry-environment=test," - "sentry-transaction=test-transaction,sentry-sample_rate=1.0".format( - trace_id=transaction.trace_id - ), + ), + ( + "sentry-trace", + "{trace_id}-{parent_span_id}-{sampled}".format( + trace_id=segment_span.trace_id, + parent_span_id=segment_span.span_id, + sampled=1, ), - ( - "sentry-trace", - "{trace_id}-{parent_span_id}-{sampled}".format( - trace_id=transaction.trace_id, - parent_span_id=transaction.span_id, - sampled=1, - ), - ), - ) + ), + ) - stub.TestServe(gRPCTestMessage(text="test"), metadata=metadata) + stub.TestServe(gRPCTestMessage(text="test"), metadata=metadata) - _tear_down(server=server) + _tear_down(server=server) - events.write_file.close() - event = events.read_event() - span = event["spans"][0] + sentry_sdk.flush() + items.write_file.close() + items = items.read_event() + spans = [item["payload"] for item in items if item["type"] == "span"] + span = spans[0] - assert event["type"] == "transaction" - assert event["transaction_info"] == { - "source": "custom", - } - assert event["contexts"]["trace"]["op"] == OP.GRPC_SERVER - assert event["contexts"]["trace"]["trace_id"] == transaction.trace_id - assert span["op"] == "test" + assert spans[1]["attributes"]["sentry.segment.name.source"] == "custom" + assert spans[1]["attributes"]["sentry.op"] == OP.GRPC_SERVER + assert spans[1]["trace_id"] == segment_span.trace_id + assert span["attributes"]["sentry.op"] == "test" @pytest.mark.forked -@pytest.mark.parametrize("span_streaming", [True, False]) def test_grpc_client_starts_span( sentry_init, - capture_events_forksafe, capture_items_forksafe, - span_streaming, ): sentry_init( traces_sample_rate=1.0, integrations=[GRPCIntegration()], - trace_lifecycle="stream" if span_streaming else "static", ) server, channel = _set_up() # Use the provided channel stub = gRPCTestServiceStub(channel) + items = capture_items_forksafe("span") - if span_streaming: - items = capture_items_forksafe("span") - - with sentry_sdk.traces.start_span(name="custom parent"): - stub.TestServe(gRPCTestMessage(text="test")) - - _tear_down(server=server) - - sentry_sdk.flush() - items.write_file.close() - items = items.read_event() - spans = [item["payload"] for item in items if item["type"] == "span"] - span = spans[2] - - assert len(spans) == 4 - assert span["attributes"]["sentry.op"] == OP.GRPC_CLIENT - assert ( - span["name"] - == "unary unary call to /grpc_test_server.gRPCTestService/TestServe" - ) - assert span["attributes"] == ApproxDict( - { - "rpc.method": "/grpc_test_server.gRPCTestService/TestServe", - "sentry.environment": mock.ANY, - "sentry.op": "grpc.client", - "sentry.origin": "auto.grpc.grpc", - "sentry.release": mock.ANY, - "sentry.sdk.name": "sentry.python", - "sentry.sdk.version": mock.ANY, - "sentry.segment.id": mock.ANY, - "sentry.segment.name": "custom parent", - "server.address": mock.ANY, - "thread.id": mock.ANY, - "thread.name": mock.ANY, - "rpc.response.status_code": "OK", - } - ) - else: - events = capture_events_forksafe() - - with start_transaction(): - stub.TestServe(gRPCTestMessage(text="test")) - - _tear_down(server=server) + with sentry_sdk.start_span(name="custom parent"): + stub.TestServe(gRPCTestMessage(text="test")) - events.write_file.close() - events.read_event() - local_transaction = events.read_event() - span = local_transaction["spans"][0] + _tear_down(server=server) - assert len(local_transaction["spans"]) == 1 - assert span["op"] == OP.GRPC_CLIENT - assert ( - span["description"] - == "unary unary call to /grpc_test_server.gRPCTestService/TestServe" - ) - assert span["data"] == ApproxDict( - { - "type": "unary unary", - "method": "/grpc_test_server.gRPCTestService/TestServe", - "code": "OK", - } - ) + sentry_sdk.flush() + items.write_file.close() + items = items.read_event() + spans = [item["payload"] for item in items if item["type"] == "span"] + span = spans[2] + + assert len(spans) == 4 + assert span["attributes"]["sentry.op"] == OP.GRPC_CLIENT + assert ( + span["name"] + == "unary unary call to /grpc_test_server.gRPCTestService/TestServe" + ) + assert span["attributes"] == ApproxDict( + { + "rpc.method": "/grpc_test_server.gRPCTestService/TestServe", + "sentry.environment": mock.ANY, + "sentry.op": "grpc.client", + "sentry.origin": "auto.grpc.grpc", + "sentry.release": mock.ANY, + "sentry.sdk.name": "sentry.python", + "sentry.sdk.version": mock.ANY, + "sentry.segment.id": mock.ANY, + "sentry.segment.name": "custom parent", + "server.address": mock.ANY, + "thread.id": mock.ANY, + "thread.name": mock.ANY, + "rpc.response.status_code": "OK", + } + ) @pytest.mark.forked -@pytest.mark.parametrize("span_streaming", [True, False]) def test_grpc_client_unary_stream_starts_span( sentry_init, - capture_events_forksafe, capture_items_forksafe, - span_streaming, ): sentry_init( traces_sample_rate=1.0, integrations=[GRPCIntegration()], - trace_lifecycle="stream" if span_streaming else "static", ) server, channel = _set_up() # Use the provided channel stub = gRPCTestServiceStub(channel) + items = capture_items_forksafe("span") - if span_streaming: - items = capture_items_forksafe("span") + with sentry_sdk.start_span(name="custom parent"): + [el for el in stub.TestUnaryStream(gRPCTestMessage(text="test"))] - with sentry_sdk.traces.start_span(name="custom parent"): - [el for el in stub.TestUnaryStream(gRPCTestMessage(text="test"))] - - _tear_down(server=server) - - sentry_sdk.flush() - items.write_file.close() - items = items.read_event() - spans = [item["payload"] for item in items if item["type"] == "span"] - span = spans[0] + _tear_down(server=server) - assert len(spans) == 2 - assert span["attributes"]["sentry.op"] == OP.GRPC_CLIENT - assert ( - span["name"] - == "unary stream call to /grpc_test_server.gRPCTestService/TestUnaryStream" - ) - assert span["attributes"] == ApproxDict( - { - "rpc.method": "/grpc_test_server.gRPCTestService/TestUnaryStream", - "sentry.environment": mock.ANY, - "sentry.op": "grpc.client", - "sentry.origin": "auto.grpc.grpc", - "sentry.release": mock.ANY, - "sentry.sdk.name": "sentry.python", - "sentry.sdk.version": mock.ANY, - "sentry.segment.id": mock.ANY, - "sentry.segment.name": "custom parent", - "server.address": mock.ANY, - "thread.id": mock.ANY, - "thread.name": mock.ANY, - } - ) - else: - events = capture_events_forksafe() - with start_transaction(): - [el for el in stub.TestUnaryStream(gRPCTestMessage(text="test"))] - - _tear_down(server=server) - - events.write_file.close() - local_transaction = events.read_event() - span = local_transaction["spans"][0] - - assert len(local_transaction["spans"]) == 1 - assert span["op"] == OP.GRPC_CLIENT - assert ( - span["description"] - == "unary stream call to /grpc_test_server.gRPCTestService/TestUnaryStream" - ) - assert span["data"] == ApproxDict( - { - "type": "unary stream", - "method": "/grpc_test_server.gRPCTestService/TestUnaryStream", - } - ) + sentry_sdk.flush() + items.write_file.close() + items = items.read_event() + spans = [item["payload"] for item in items if item["type"] == "span"] + span = spans[0] + + assert len(spans) == 2 + assert span["attributes"]["sentry.op"] == OP.GRPC_CLIENT + assert ( + span["name"] + == "unary stream call to /grpc_test_server.gRPCTestService/TestUnaryStream" + ) + assert span["attributes"] == ApproxDict( + { + "rpc.method": "/grpc_test_server.gRPCTestService/TestUnaryStream", + "sentry.environment": mock.ANY, + "sentry.op": "grpc.client", + "sentry.origin": "auto.grpc.grpc", + "sentry.release": mock.ANY, + "sentry.sdk.name": "sentry.python", + "sentry.sdk.version": mock.ANY, + "sentry.segment.id": mock.ANY, + "sentry.segment.name": "custom parent", + "server.address": mock.ANY, + "thread.id": mock.ANY, + "thread.name": mock.ANY, + } + ) # using unittest.mock.Mock not possible because grpc verifies @@ -441,18 +287,14 @@ def intercept_unary_unary(self, continuation, client_call_details, request): @pytest.mark.forked -@pytest.mark.parametrize("span_streaming", [True, False]) def test_grpc_client_other_interceptor( sentry_init, - capture_events_forksafe, capture_items_forksafe, - span_streaming, ): """Ensure compatibility with additional client interceptors.""" sentry_init( traces_sample_rate=1.0, integrations=[GRPCIntegration()], - trace_lifecycle="stream" if span_streaming else "static", ) server, channel = _set_up() @@ -460,88 +302,54 @@ def test_grpc_client_other_interceptor( # Intercept the channel channel = grpc.intercept_channel(channel, MockClientInterceptor()) stub = gRPCTestServiceStub(channel) + items = capture_items_forksafe("span") - if span_streaming: - items = capture_items_forksafe("span") - - with sentry_sdk.traces.start_span(name="custom parent"): - stub.TestServe(gRPCTestMessage(text="test")) - - _tear_down(server=server) - - assert MockClientInterceptor.call_counter == 1 - - sentry_sdk.flush() - items.write_file.close() - items = items.read_event() - spans = [item["payload"] for item in items if item["type"] == "span"] - span = spans[2] - - assert len(spans) == 4 - assert span["attributes"]["sentry.op"] == OP.GRPC_CLIENT - assert ( - span["name"] - == "unary unary call to /grpc_test_server.gRPCTestService/TestServe" - ) - assert span["attributes"] == ApproxDict( - { - "rpc.method": "/grpc_test_server.gRPCTestService/TestServe", - "sentry.environment": mock.ANY, - "sentry.op": "grpc.client", - "sentry.origin": "auto.grpc.grpc", - "sentry.release": mock.ANY, - "sentry.sdk.name": "sentry.python", - "sentry.sdk.version": mock.ANY, - "sentry.segment.id": mock.ANY, - "sentry.segment.name": "custom parent", - "server.address": mock.ANY, - "thread.id": mock.ANY, - "thread.name": mock.ANY, - "rpc.response.status_code": "OK", - } - ) - else: - events = capture_events_forksafe() - - with start_transaction(): - stub.TestServe(gRPCTestMessage(text="test")) + with sentry_sdk.start_span(name="custom parent"): + stub.TestServe(gRPCTestMessage(text="test")) - _tear_down(server=server) + _tear_down(server=server) - assert MockClientInterceptor.call_counter == 1 + assert MockClientInterceptor.call_counter == 1 - events.write_file.close() - events.read_event() - local_transaction = events.read_event() - span = local_transaction["spans"][0] + sentry_sdk.flush() + items.write_file.close() + items = items.read_event() + spans = [item["payload"] for item in items if item["type"] == "span"] + span = spans[2] - assert len(local_transaction["spans"]) == 1 - assert span["op"] == OP.GRPC_CLIENT - assert ( - span["description"] - == "unary unary call to /grpc_test_server.gRPCTestService/TestServe" - ) - assert span["data"] == ApproxDict( - { - "type": "unary unary", - "method": "/grpc_test_server.gRPCTestService/TestServe", - "code": "OK", - } - ) + assert len(spans) == 4 + assert span["attributes"]["sentry.op"] == OP.GRPC_CLIENT + assert ( + span["name"] + == "unary unary call to /grpc_test_server.gRPCTestService/TestServe" + ) + assert span["attributes"] == ApproxDict( + { + "rpc.method": "/grpc_test_server.gRPCTestService/TestServe", + "sentry.environment": mock.ANY, + "sentry.op": "grpc.client", + "sentry.origin": "auto.grpc.grpc", + "sentry.release": mock.ANY, + "sentry.sdk.name": "sentry.python", + "sentry.sdk.version": mock.ANY, + "sentry.segment.id": mock.ANY, + "sentry.segment.name": "custom parent", + "server.address": mock.ANY, + "thread.id": mock.ANY, + "thread.name": mock.ANY, + "rpc.response.status_code": "OK", + } + ) @pytest.mark.forked -@pytest.mark.parametrize("span_streaming", [True, False]) def test_prevent_dual_client_interceptor( sentry_init, - capture_events_forksafe, capture_items_forksafe, - span_streaming, ): sentry_init( traces_sample_rate=1.0, integrations=[GRPCIntegration()], - trace_lifecycle="stream" if span_streaming else "static", ) server, channel = _set_up() @@ -549,118 +357,71 @@ def test_prevent_dual_client_interceptor( # Intercept the channel channel = grpc.intercept_channel(channel, ClientInterceptor()) stub = gRPCTestServiceStub(channel) + items = capture_items_forksafe("span") - if span_streaming: - items = capture_items_forksafe("span") - - with sentry_sdk.traces.start_span(name="custom parent"): - stub.TestServe(gRPCTestMessage(text="test")) - - _tear_down(server=server) - - sentry_sdk.flush() - items.write_file.close() - items = items.read_event() - spans = [item["payload"] for item in items if item["type"] == "span"] - span = spans[2] - - assert len(spans) == 4 - assert span["attributes"]["sentry.op"] == OP.GRPC_CLIENT - assert ( - span["name"] - == "unary unary call to /grpc_test_server.gRPCTestService/TestServe" - ) - assert span["attributes"] == ApproxDict( - { - "rpc.method": "/grpc_test_server.gRPCTestService/TestServe", - "rpc.response.status_code": "OK", - } - ) - else: - events = capture_events_forksafe() - - with start_transaction(): - stub.TestServe(gRPCTestMessage(text="test")) - - _tear_down(server=server) + with sentry_sdk.start_span(name="custom parent"): + stub.TestServe(gRPCTestMessage(text="test")) - events.write_file.close() - events.read_event() - local_transaction = events.read_event() - span = local_transaction["spans"][0] + _tear_down(server=server) - assert len(local_transaction["spans"]) == 1 - assert span["op"] == OP.GRPC_CLIENT - assert ( - span["description"] - == "unary unary call to /grpc_test_server.gRPCTestService/TestServe" - ) - assert span["data"] == ApproxDict( - { - "type": "unary unary", - "method": "/grpc_test_server.gRPCTestService/TestServe", - "code": "OK", - } - ) + sentry_sdk.flush() + items.write_file.close() + items = items.read_event() + spans = [item["payload"] for item in items if item["type"] == "span"] + span = spans[2] + + assert len(spans) == 4 + assert span["attributes"]["sentry.op"] == OP.GRPC_CLIENT + assert ( + span["name"] + == "unary unary call to /grpc_test_server.gRPCTestService/TestServe" + ) + assert span["attributes"] == ApproxDict( + { + "rpc.method": "/grpc_test_server.gRPCTestService/TestServe", + "rpc.response.status_code": "OK", + } + ) @pytest.mark.forked -@pytest.mark.parametrize("span_streaming", [True, False]) def test_grpc_client_and_servers_interceptors_integration( sentry_init, - capture_events_forksafe, capture_items_forksafe, - span_streaming, ): sentry_init( traces_sample_rate=1.0, integrations=[GRPCIntegration()], - trace_lifecycle="stream" if span_streaming else "static", ) server, channel = _set_up() # Use the provided channel stub = gRPCTestServiceStub(channel) + items = capture_items_forksafe("span") - if span_streaming: - items = capture_items_forksafe("span") - - with sentry_sdk.traces.start_span(name="custom parent"): - stub.TestServe(gRPCTestMessage(text="test")) - - _tear_down(server=server) - - sentry_sdk.flush() - items.write_file.close() - items = items.read_event() - - spans = [item["payload"] for item in items if item["type"] == "span"] + with sentry_sdk.start_span(name="custom parent"): + stub.TestServe(gRPCTestMessage(text="test")) - assert spans[1]["is_segment"] is True - assert spans[3]["is_segment"] is True - assert spans[1]["trace_id"] == spans[3]["trace_id"] - else: - events = capture_events_forksafe() + _tear_down(server=server) - with start_transaction(): - stub.TestServe(gRPCTestMessage(text="test")) + sentry_sdk.flush() + items.write_file.close() + items = items.read_event() - _tear_down(server=server) + spans = [item["payload"] for item in items if item["type"] == "span"] - events.write_file.close() - server_transaction = events.read_event() - local_transaction = events.read_event() - - assert ( - server_transaction["contexts"]["trace"]["trace_id"] - == local_transaction["contexts"]["trace"]["trace_id"] - ) + assert spans[1]["is_segment"] is True + assert spans[3]["is_segment"] is True + assert spans[1]["trace_id"] == spans[3]["trace_id"] @pytest.mark.forked def test_stream_stream(sentry_init): - sentry_init(traces_sample_rate=1.0, integrations=[GRPCIntegration()]) + sentry_init( + traces_sample_rate=1.0, + integrations=[GRPCIntegration()], + ) server, channel = _set_up() # Use the provided channel @@ -678,7 +439,10 @@ def test_stream_unary(sentry_init): Test to verify stream-stream works. Tracing not supported for it yet. """ - sentry_init(traces_sample_rate=1.0, integrations=[GRPCIntegration()]) + sentry_init( + traces_sample_rate=1.0, + integrations=[GRPCIntegration()], + ) server, channel = _set_up() # Use the provided channel @@ -690,69 +454,39 @@ def test_stream_unary(sentry_init): @pytest.mark.forked -@pytest.mark.parametrize("span_streaming", [True, False]) def test_span_origin( sentry_init, - capture_events_forksafe, capture_items_forksafe, - span_streaming, ): sentry_init( traces_sample_rate=1.0, integrations=[GRPCIntegration()], - trace_lifecycle="stream" if span_streaming else "static", ) server, channel = _set_up() # Use the provided channel stub = gRPCTestServiceStub(channel) + items = capture_items_forksafe("span") - if span_streaming: - items = capture_items_forksafe("span") - - with sentry_sdk.traces.start_span(name="custom parent"): - stub.TestServe(gRPCTestMessage(text="test")) - - _tear_down(server=server) - - sentry_sdk.flush() - items.write_file.close() - items = items.read_event() - - spans = [item["payload"] for item in items if item["type"] == "span"] - - assert spans[1]["attributes"]["sentry.origin"] == "auto.grpc.grpc" - assert ( - spans[0]["attributes"]["sentry.origin"] == "auto.grpc.grpc.TestService" - ) # manually created in TestService, not the instrumentation - - assert spans[3]["attributes"]["sentry.origin"] == "manual" - assert spans[2]["attributes"]["sentry.origin"] == "auto.grpc.grpc" - else: - events = capture_events_forksafe() - - with start_transaction(name="custom_transaction"): - stub.TestServe(gRPCTestMessage(text="test")) + with sentry_sdk.start_span(name="custom parent"): + stub.TestServe(gRPCTestMessage(text="test")) - _tear_down(server=server) + _tear_down(server=server) - events.write_file.close() + sentry_sdk.flush() + items.write_file.close() + items = items.read_event() - transaction_from_integration = events.read_event() - custom_transaction = events.read_event() + spans = [item["payload"] for item in items if item["type"] == "span"] - assert ( - transaction_from_integration["contexts"]["trace"]["origin"] - == "auto.grpc.grpc" - ) - assert ( - transaction_from_integration["spans"][0]["origin"] - == "auto.grpc.grpc.TestService" - ) # manually created in TestService, not the instrumentation + assert spans[1]["attributes"]["sentry.origin"] == "auto.grpc.grpc" + assert ( + spans[0]["attributes"]["sentry.origin"] == "auto.grpc.grpc.TestService" + ) # manually created in TestService, not the instrumentation - assert custom_transaction["contexts"]["trace"]["origin"] == "manual" - assert custom_transaction["spans"][0]["origin"] == "auto.grpc.grpc" + assert spans[3]["attributes"]["sentry.origin"] == "manual" + assert spans[2]["attributes"]["sentry.origin"] == "auto.grpc.grpc" class TestService(gRPCTestServiceServicer): @@ -760,25 +494,14 @@ class TestService(gRPCTestServiceServicer): @staticmethod def TestServe(request, context): # noqa: N802 - client = sentry_sdk.get_client() - span_streaming = has_span_streaming_enabled(client.options) - - if span_streaming: - with sentry_sdk.traces.start_span( - name="test", - attributes={ - "sentry.op": "test", - "sentry.origin": "auto.grpc.grpc.TestService", - }, - ): - pass - else: - with start_span( - op="test", - name="test", - origin="auto.grpc.grpc.TestService", - ): - pass + with sentry_sdk.start_span( + name="test", + attributes={ + "sentry.op": "test", + "sentry.origin": "auto.grpc.grpc.TestService", + }, + ): + pass return gRPCTestMessage(text=request.text) diff --git a/tests/integrations/grpc/test_grpc_aio.py b/tests/integrations/grpc/test_grpc_aio.py index 217dc110d2..63911c7c80 100644 --- a/tests/integrations/grpc/test_grpc_aio.py +++ b/tests/integrations/grpc/test_grpc_aio.py @@ -7,10 +7,8 @@ import pytest_asyncio import sentry_sdk -from sentry_sdk import start_span, start_transaction from sentry_sdk.consts import OP from sentry_sdk.integrations.grpc import GRPCIntegration -from sentry_sdk.tracing_utils import has_span_streaming_enabled from tests.conftest import ApproxDict from tests.integrations.grpc.grpc_test_service_pb2 import gRPCTestMessage from tests.integrations.grpc.grpc_test_service_pb2_grpc import ( @@ -29,13 +27,12 @@ async def grpc_server_and_channel(sentry_init): channel: "Optional[grpc.aio.Channel]" = None server: "Optional[grpc.aio.Server]" = None - async def inner(span_streaming: bool): + async def inner(): nonlocal server, channel sentry_init( traces_sample_rate=1.0, integrations=[GRPCIntegration()], - trace_lifecycle="stream" if span_streaming else "static", ) # Create server @@ -66,213 +63,119 @@ async def inner(span_streaming: bool): @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) async def test_noop_for_unimplemented_method( sentry_init, - capture_events, capture_items, - span_streaming, ): sentry_init( traces_sample_rate=1.0, integrations=[GRPCIntegration()], - trace_lifecycle="stream" if span_streaming else "static", ) # Create empty server with no services server = grpc.aio.server() port = server.add_insecure_port("[::]:0") # Let gRPC choose a free port await asyncio.create_task(server.start()) + items = capture_items("span") - if span_streaming: - items = capture_items("span") - - try: - async with grpc.aio.insecure_channel( - f"localhost:{port}" # noqa: E231 - ) as channel: - stub = gRPCTestServiceStub(channel) - with pytest.raises(grpc.RpcError) as exc: - await stub.TestServe(gRPCTestMessage(text="test")) - assert exc.value.details() == "Method not found!" - finally: - await server.stop(None) - - sentry_sdk.flush() - spans = [item.payload for item in items] - assert len(spans) == 0 # No client span created without an active span. - else: - events = capture_events() - - try: - async with grpc.aio.insecure_channel( - f"localhost:{port}" # noqa: E231 - ) as channel: - stub = gRPCTestServiceStub(channel) - with pytest.raises(grpc.RpcError) as exc: - await stub.TestServe(gRPCTestMessage(text="test")) - assert exc.value.details() == "Method not found!" - finally: - await server.stop(None) + try: + async with grpc.aio.insecure_channel( + f"localhost:{port}" # noqa: E231 + ) as channel: + stub = gRPCTestServiceStub(channel) + with pytest.raises(grpc.RpcError) as exc: + await stub.TestServe(gRPCTestMessage(text="test")) + assert exc.value.details() == "Method not found!" + finally: + await server.stop(None) - assert not events + sentry_sdk.flush() + spans = [item.payload for item in items] + assert len(spans) == 0 # No client span created without an active span. @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) async def test_grpc_server_starts_transaction( grpc_server_and_channel, - capture_events, capture_items, - span_streaming, ): - _, channel = await grpc_server_and_channel(span_streaming) + _, channel = await grpc_server_and_channel() # Use the provided channel stub = gRPCTestServiceStub(channel) + items = capture_items("span") - if span_streaming: - items = capture_items("span") - - await stub.TestServe(gRPCTestMessage(text="test")) - - sentry_sdk.flush() - spans = [item.payload for item in items] - span = spans[0] - - assert spans[1]["attributes"]["sentry.segment.name.source"] == "custom" - assert spans[1]["attributes"]["sentry.op"] == OP.GRPC_SERVER - assert span["attributes"]["sentry.op"] == "test" - else: - events = capture_events() + await stub.TestServe(gRPCTestMessage(text="test")) - await stub.TestServe(gRPCTestMessage(text="test")) + sentry_sdk.flush() + spans = [item.payload for item in items] + span = spans[0] - (event,) = events - span = event["spans"][0] - - assert event["type"] == "transaction" - assert event["transaction_info"] == { - "source": "custom", - } - assert event["contexts"]["trace"]["op"] == OP.GRPC_SERVER - assert span["op"] == "test" + assert spans[1]["attributes"]["sentry.segment.name.source"] == "custom" + assert spans[1]["attributes"]["sentry.op"] == OP.GRPC_SERVER + assert span["attributes"]["sentry.op"] == "test" @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) async def test_grpc_server_continues_transaction( grpc_server_and_channel, - capture_events, capture_items, - span_streaming, ): - _, channel = await grpc_server_and_channel(span_streaming) + _, channel = await grpc_server_and_channel() # Use the provided channel stub = gRPCTestServiceStub(channel) - - if span_streaming: - items = capture_items("span") - - with sentry_sdk.traces.start_span(name="custom parent") as segment_span: - metadata = ( - ( - "baggage", - "sentry-trace_id={trace_id},sentry-environment=test," - "sentry-transaction=test-transaction,sentry-sample_rate=1.0".format( - trace_id=segment_span.trace_id - ), - ), - ( - "sentry-trace", - "{trace_id}-{parent_span_id}-{sampled}".format( - trace_id=segment_span.trace_id, - parent_span_id=segment_span.span_id, - sampled=1, - ), + items = capture_items("span") + + with sentry_sdk.start_span(name="custom parent") as segment_span: + metadata = ( + ( + "baggage", + "sentry-trace_id={trace_id},sentry-environment=test," + "sentry-transaction=test-transaction,sentry-sample_rate=1.0".format( + trace_id=segment_span.trace_id ), - ) - - await stub.TestServe(gRPCTestMessage(text="test"), metadata=metadata) - - sentry_sdk.flush() - spans = [item.payload for item in items] - span = spans[0] - - assert spans[1]["attributes"]["sentry.segment.name.source"] == "custom" - assert spans[1]["attributes"]["sentry.op"] == OP.GRPC_SERVER - assert spans[1]["trace_id"] == segment_span.trace_id - assert span["attributes"]["sentry.op"] == "test" - else: - events = capture_events() - - with sentry_sdk.start_transaction() as transaction: - metadata = ( - ( - "baggage", - "sentry-trace_id={trace_id},sentry-environment=test," - "sentry-transaction=test-transaction,sentry-sample_rate=1.0".format( - trace_id=transaction.trace_id - ), + ), + ( + "sentry-trace", + "{trace_id}-{parent_span_id}-{sampled}".format( + trace_id=segment_span.trace_id, + parent_span_id=segment_span.span_id, + sampled=1, ), - ( - "sentry-trace", - "{trace_id}-{parent_span_id}-{sampled}".format( - trace_id=transaction.trace_id, - parent_span_id=transaction.span_id, - sampled=1, - ), - ), - ) + ), + ) - await stub.TestServe(gRPCTestMessage(text="test"), metadata=metadata) + await stub.TestServe(gRPCTestMessage(text="test"), metadata=metadata) - (event, _) = events - span = event["spans"][0] + sentry_sdk.flush() + spans = [item.payload for item in items] + span = spans[0] - assert event["type"] == "transaction" - assert event["transaction_info"] == { - "source": "custom", - } - assert event["contexts"]["trace"]["op"] == OP.GRPC_SERVER - assert event["contexts"]["trace"]["trace_id"] == transaction.trace_id - assert span["op"] == "test" + assert spans[1]["attributes"]["sentry.segment.name.source"] == "custom" + assert spans[1]["attributes"]["sentry.op"] == OP.GRPC_SERVER + assert spans[1]["trace_id"] == segment_span.trace_id + assert span["attributes"]["sentry.op"] == "test" @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) async def test_grpc_server_exception( grpc_server_and_channel, - capture_events, capture_items, - span_streaming, ): - _, channel = await grpc_server_and_channel(span_streaming) + _, channel = await grpc_server_and_channel() # Use the provided channel stub = gRPCTestServiceStub(channel) + items = capture_items("event") - if span_streaming: - items = capture_items("event") - - try: - await stub.TestServe(gRPCTestMessage(text="exception")) - raise AssertionError() - except Exception: - pass - - (event,) = (item.payload for item in items) - else: - events = capture_events() - - try: - await stub.TestServe(gRPCTestMessage(text="exception")) - raise AssertionError() - except Exception: - pass + try: + await stub.TestServe(gRPCTestMessage(text="exception")) + raise AssertionError() + except Exception: + pass - (event, _) = events + (event,) = (item.payload for item in items) assert event["exception"]["values"][0]["type"] == "TestService.TestException" assert event["exception"]["values"][0]["value"] == "test" @@ -281,9 +184,9 @@ async def test_grpc_server_exception( @pytest.mark.asyncio -async def test_grpc_server_abort(grpc_server_and_channel, capture_events): - _, channel = await grpc_server_and_channel(False) - events = capture_events() +async def test_grpc_server_abort(grpc_server_and_channel, capture_items): + _, channel = await grpc_server_and_channel() + items = capture_items("span") # Use the provided channel stub = gRPCTestServiceStub(channel) @@ -296,154 +199,97 @@ async def test_grpc_server_abort(grpc_server_and_channel, capture_events): # Add a small delay to allow events to be collected await asyncio.sleep(0.1) - assert len(events) == 1 + assert len(items) >= 1 @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) async def test_grpc_client_starts_span( grpc_server_and_channel, - capture_events_forksafe, capture_items_forksafe, - span_streaming, ): - _, channel = await grpc_server_and_channel(span_streaming) + _, channel = await grpc_server_and_channel() # Use the provided channel stub = gRPCTestServiceStub(channel) + items = capture_items_forksafe("span") - if span_streaming: - items = capture_items_forksafe("span") - - with sentry_sdk.traces.start_span(name="custom parent") as span: - await stub.TestServe(gRPCTestMessage(text="test")) - - sentry_sdk.flush() - items.write_file.close() - items = items.read_event() - spans = [item["payload"] for item in items if item["type"] == "span"] - span = spans[2] + with sentry_sdk.start_span(name="custom parent") as span: + await stub.TestServe(gRPCTestMessage(text="test")) - assert len(spans) == 4 - assert span["attributes"]["sentry.op"] == OP.GRPC_CLIENT - assert ( - span["name"] - == "unary unary call to /grpc_test_server.gRPCTestService/TestServe" - ) - assert span["attributes"] == ApproxDict( - { - "rpc.method": "/grpc_test_server.gRPCTestService/TestServe", - "sentry.environment": mock.ANY, - "sentry.op": "grpc.client", - "sentry.origin": "auto.grpc.grpc", - "sentry.release": mock.ANY, - "sentry.sdk.name": "sentry.python", - "sentry.sdk.version": mock.ANY, - "sentry.segment.id": mock.ANY, - "sentry.segment.name": "custom parent", - "server.address": mock.ANY, - "thread.id": mock.ANY, - "thread.name": mock.ANY, - "rpc.response.status_code": "OK", - } - ) - else: - events = capture_events_forksafe() - - with start_transaction(): - await stub.TestServe(gRPCTestMessage(text="test")) - - events.write_file.close() - events.read_event() - local_transaction = events.read_event() - span = local_transaction["spans"][0] - - assert len(local_transaction["spans"]) == 1 - assert span["op"] == OP.GRPC_CLIENT - assert ( - span["description"] - == "unary unary call to /grpc_test_server.gRPCTestService/TestServe" - ) - assert span["data"] == ApproxDict( - { - "type": "unary unary", - "method": "/grpc_test_server.gRPCTestService/TestServe", - "code": "OK", - } - ) + sentry_sdk.flush() + items.write_file.close() + items = items.read_event() + spans = [item["payload"] for item in items if item["type"] == "span"] + span = spans[2] + + assert len(spans) == 4 + assert span["attributes"]["sentry.op"] == OP.GRPC_CLIENT + assert ( + span["name"] + == "unary unary call to /grpc_test_server.gRPCTestService/TestServe" + ) + assert span["attributes"] == ApproxDict( + { + "rpc.method": "/grpc_test_server.gRPCTestService/TestServe", + "sentry.environment": mock.ANY, + "sentry.op": "grpc.client", + "sentry.origin": "auto.grpc.grpc", + "sentry.release": mock.ANY, + "sentry.sdk.name": "sentry.python", + "sentry.sdk.version": mock.ANY, + "sentry.segment.id": mock.ANY, + "sentry.segment.name": "custom parent", + "server.address": mock.ANY, + "thread.id": mock.ANY, + "thread.name": mock.ANY, + "rpc.response.status_code": "OK", + } + ) @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) async def test_grpc_client_unary_stream_starts_span( grpc_server_and_channel, - capture_events_forksafe, capture_items_forksafe, - span_streaming, ): - _, channel = await grpc_server_and_channel(span_streaming) + _, channel = await grpc_server_and_channel() # Use the provided channel stub = gRPCTestServiceStub(channel) - - if span_streaming: - items = capture_items_forksafe("span") - - with sentry_sdk.traces.start_span(name="custom parent"): - response = stub.TestUnaryStream(gRPCTestMessage(text="test")) - [_ async for _ in response] - - sentry_sdk.flush() - items.write_file.close() - items = items.read_event() - spans = [item["payload"] for item in items if item["type"] == "span"] - span = spans[0] - - assert len(spans) == 2 - assert span["attributes"]["sentry.op"] == OP.GRPC_CLIENT - assert ( - span["name"] - == "unary stream call to /grpc_test_server.gRPCTestService/TestUnaryStream" - ) - assert span["attributes"] == ApproxDict( - { - "rpc.method": "/grpc_test_server.gRPCTestService/TestUnaryStream", - "sentry.environment": mock.ANY, - "sentry.op": "grpc.client", - "sentry.origin": "auto.grpc.grpc", - "sentry.release": mock.ANY, - "sentry.sdk.name": "sentry.python", - "sentry.sdk.version": mock.ANY, - "sentry.segment.id": mock.ANY, - "sentry.segment.name": "custom parent", - "server.address": mock.ANY, - "thread.id": mock.ANY, - "thread.name": mock.ANY, - } - ) - else: - events = capture_events_forksafe() - - with start_transaction(): - response = stub.TestUnaryStream(gRPCTestMessage(text="test")) - [_ async for _ in response] - - events.write_file.close() - local_transaction = events.read_event() - span = local_transaction["spans"][0] - - assert len(local_transaction["spans"]) == 1 - assert span["op"] == OP.GRPC_CLIENT - assert ( - span["description"] - == "unary stream call to /grpc_test_server.gRPCTestService/TestUnaryStream" - ) - assert span["data"] == ApproxDict( - { - "type": "unary stream", - "method": "/grpc_test_server.gRPCTestService/TestUnaryStream", - } - ) + items = capture_items_forksafe("span") + + with sentry_sdk.start_span(name="custom parent"): + response = stub.TestUnaryStream(gRPCTestMessage(text="test")) + [_ async for _ in response] + + sentry_sdk.flush() + items.write_file.close() + items = items.read_event() + spans = [item["payload"] for item in items if item["type"] == "span"] + span = spans[0] + + assert len(spans) == 2 + assert span["attributes"]["sentry.op"] == OP.GRPC_CLIENT + assert ( + span["name"] + == "unary stream call to /grpc_test_server.gRPCTestService/TestUnaryStream" + ) + assert span["attributes"] == ApproxDict( + { + "rpc.method": "/grpc_test_server.gRPCTestService/TestUnaryStream", + "sentry.environment": mock.ANY, + "sentry.op": "grpc.client", + "sentry.origin": "auto.grpc.grpc", + "sentry.release": mock.ANY, + "sentry.sdk.name": "sentry.python", + "sentry.sdk.version": mock.ANY, + "sentry.segment.id": mock.ANY, + "sentry.segment.name": "custom parent", + "server.address": mock.ANY, + "thread.id": mock.ANY, + "thread.name": mock.ANY, + } + ) @pytest.mark.asyncio @@ -452,7 +298,7 @@ async def test_stream_stream(grpc_server_and_channel): Test to verify stream-stream works. Tracing not supported for it yet. """ - _, channel = await grpc_server_and_channel(False) + _, channel = await grpc_server_and_channel() # Use the provided channel stub = gRPCTestServiceStub(channel) @@ -467,7 +313,7 @@ async def test_stream_unary(grpc_server_and_channel): Test to verify stream-stream works. Tracing not supported for it yet. """ - _, channel = await grpc_server_and_channel(False) + _, channel = await grpc_server_and_channel() # Use the provided channel stub = gRPCTestServiceStub(channel) @@ -476,59 +322,32 @@ async def test_stream_unary(grpc_server_and_channel): @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) async def test_span_origin( grpc_server_and_channel, - capture_events_forksafe, capture_items_forksafe, - span_streaming, ): - _, channel = await grpc_server_and_channel(span_streaming) + _, channel = await grpc_server_and_channel() # Use the provided channel stub = gRPCTestServiceStub(channel) + items = capture_items_forksafe("span") - if span_streaming: - items = capture_items_forksafe("span") - - with sentry_sdk.traces.start_span(name="custom parent"): - await stub.TestServe(gRPCTestMessage(text="test")) - - sentry_sdk.flush() - items.write_file.close() - items = items.read_event() - - spans = [item["payload"] for item in items if item["type"] == "span"] - - assert spans[1]["attributes"]["sentry.origin"] == "auto.grpc.grpc" - assert ( - spans[0]["attributes"]["sentry.origin"] == "auto.grpc.grpc.TestService.aio" - ) # manually created in TestService, not the instrumentation - - assert spans[3]["attributes"]["sentry.origin"] == "manual" - assert spans[2]["attributes"]["sentry.origin"] == "auto.grpc.grpc" - else: - events = capture_events_forksafe() - - with start_transaction(name="custom_transaction"): - await stub.TestServe(gRPCTestMessage(text="test")) + with sentry_sdk.start_span(name="custom parent"): + await stub.TestServe(gRPCTestMessage(text="test")) - events.write_file.close() + sentry_sdk.flush() + items.write_file.close() + items = items.read_event() - transaction_from_integration = events.read_event() - custom_transaction = events.read_event() + spans = [item["payload"] for item in items if item["type"] == "span"] - assert ( - transaction_from_integration["contexts"]["trace"]["origin"] - == "auto.grpc.grpc" - ) - assert ( - transaction_from_integration["spans"][0]["origin"] - == "auto.grpc.grpc.TestService.aio" - ) # manually created in TestService, not the instrumentation + assert spans[1]["attributes"]["sentry.origin"] == "auto.grpc.grpc" + assert ( + spans[0]["attributes"]["sentry.origin"] == "auto.grpc.grpc.TestService.aio" + ) # manually created in TestService, not the instrumentation - assert custom_transaction["contexts"]["trace"]["origin"] == "manual" - assert custom_transaction["spans"][0]["origin"] == "auto.grpc.grpc" + assert spans[3]["attributes"]["sentry.origin"] == "manual" + assert spans[2]["attributes"]["sentry.origin"] == "auto.grpc.grpc" class TestService(gRPCTestServiceServicer): @@ -540,25 +359,14 @@ def __init__(self): @classmethod async def TestServe(cls, request, context): # noqa: N802 - client = sentry_sdk.get_client() - span_streaming = has_span_streaming_enabled(client.options) - - if span_streaming: - with sentry_sdk.traces.start_span( - name="test", - attributes={ - "sentry.op": "test", - "sentry.origin": "auto.grpc.grpc.TestService.aio", - }, - ): - pass - else: - with start_span( - op="test", - name="test", - origin="auto.grpc.grpc.TestService.aio", - ): - pass + with sentry_sdk.start_span( + name="test", + attributes={ + "sentry.op": "test", + "sentry.origin": "auto.grpc.grpc.TestService.aio", + }, + ): + pass if request.text == "exception": raise cls.TestException() diff --git a/tests/integrations/httpx/test_httpx.py b/tests/integrations/httpx/test_httpx.py index 96e3dd001e..9c585fe8fe 100644 --- a/tests/integrations/httpx/test_httpx.py +++ b/tests/integrations/httpx/test_httpx.py @@ -5,54 +5,22 @@ import pytest import sentry_sdk -from sentry_sdk import capture_message, start_transaction +from sentry_sdk import capture_message from sentry_sdk.consts import MATCH_ALL, OP, SPANDATA from sentry_sdk.integrations.httpx import HttpxIntegration from tests.conftest import ApproxDict -def test_crumb_capture_and_hint_sync(sentry_init, capture_events, httpx_mock): - httpx_mock.add_response() - - def before_breadcrumb(crumb, hint): - crumb["data"]["extra"] = "foo" - return crumb - - sentry_init( - integrations=[HttpxIntegration()], - before_breadcrumb=before_breadcrumb, +def _get_http_client_span(items): + return next( + item.payload + for item in items + if item.payload.get("attributes", {}).get("sentry.op") == OP.HTTP_CLIENT ) - url = "http://example.com/" - - with start_transaction(): - events = capture_events() - - response = httpx.Client().get(url) - - assert response.status_code == 200 - capture_message("Testing!") - - (event,) = events - - crumb = event["breadcrumbs"]["values"][0] - assert crumb["type"] == "http" - assert crumb["category"] == "httplib" - assert crumb["data"] == ApproxDict( - { - "url": url, - SPANDATA.HTTP_METHOD: "GET", - SPANDATA.HTTP_FRAGMENT: "", - SPANDATA.HTTP_QUERY: "", - SPANDATA.HTTP_STATUS_CODE: 200, - "reason": "OK", - "extra": "foo", - } - ) - @pytest.mark.parametrize("send_default_pii", [True, False]) -def test_crumb_capture_and_hint_sync_span_streaming( +def test_crumb_capture_and_hint_sync( sentry_init, capture_events, httpx_mock, send_default_pii ): httpx_mock.add_response() @@ -64,13 +32,12 @@ def before_breadcrumb(crumb, hint): sentry_init( integrations=[HttpxIntegration()], before_breadcrumb=before_breadcrumb, - trace_lifecycle="stream", send_default_pii=send_default_pii, ) url = "http://example.com/" - with sentry_sdk.traces.start_span(name="segment"): + with sentry_sdk.start_span(name="segment"): events = capture_events() response = httpx.Client().get(url) @@ -107,47 +74,9 @@ def before_breadcrumb(crumb, hint): ) -@pytest.mark.asyncio -async def test_crumb_capture_and_hint_async(sentry_init, capture_events, httpx_mock): - httpx_mock.add_response() - - def before_breadcrumb(crumb, hint): - crumb["data"]["extra"] = "foo" - return crumb - - sentry_init(integrations=[HttpxIntegration()], before_breadcrumb=before_breadcrumb) - - url = "http://example.com/" - - with start_transaction(): - events = capture_events() - - response = await httpx.AsyncClient().get(url) - - assert response.status_code == 200 - capture_message("Testing!") - - (event,) = events - - crumb = event["breadcrumbs"]["values"][0] - assert crumb["type"] == "http" - assert crumb["category"] == "httplib" - assert crumb["data"] == ApproxDict( - { - "url": url, - SPANDATA.HTTP_METHOD: "GET", - SPANDATA.HTTP_FRAGMENT: "", - SPANDATA.HTTP_QUERY: "", - SPANDATA.HTTP_STATUS_CODE: 200, - "reason": "OK", - "extra": "foo", - } - ) - - @pytest.mark.asyncio @pytest.mark.parametrize("send_default_pii", [True, False]) -async def test_crumb_capture_and_hint_async_span_streaming( +async def test_crumb_capture_and_hint_async( sentry_init, capture_events, httpx_mock, send_default_pii ): httpx_mock.add_response() @@ -159,13 +88,12 @@ def before_breadcrumb(crumb, hint): sentry_init( integrations=[HttpxIntegration()], before_breadcrumb=before_breadcrumb, - trace_lifecycle="stream", send_default_pii=send_default_pii, ) url = "http://example.com/" - with sentry_sdk.traces.start_span(name="segment"): + with sentry_sdk.start_span(name="segment"): events = capture_events() response = await httpx.AsyncClient().get(url) @@ -217,42 +145,6 @@ def test_crumb_capture_without_span_sync(sentry_init, capture_events, httpx_mock assert response.status_code == 200 capture_message("Testing!") - (event,) = events - - crumb = event["breadcrumbs"]["values"][0] - assert crumb["type"] == "http" - assert crumb["category"] == "httplib" - assert crumb["data"] == ApproxDict( - { - "url": url, - SPANDATA.HTTP_METHOD: "GET", - SPANDATA.HTTP_FRAGMENT: "", - SPANDATA.HTTP_QUERY: "", - SPANDATA.HTTP_STATUS_CODE: 200, - "reason": "OK", - } - ) - - -def test_crumb_capture_without_span_sync_span_streaming( - sentry_init, capture_events, httpx_mock -): - httpx_mock.add_response() - - sentry_init( - integrations=[HttpxIntegration()], - trace_lifecycle="stream", - ) - - url = "http://example.com/" - - events = capture_events() - - response = httpx.Client().get(url) - - assert response.status_code == 200 - capture_message("Testing!") - sentry_sdk.flush() (event,) = events @@ -288,43 +180,6 @@ async def test_crumb_capture_without_span_async( assert response.status_code == 200 capture_message("Testing!") - (event,) = events - - crumb = event["breadcrumbs"]["values"][0] - assert crumb["type"] == "http" - assert crumb["category"] == "httplib" - assert crumb["data"] == ApproxDict( - { - "url": url, - SPANDATA.HTTP_METHOD: "GET", - SPANDATA.HTTP_FRAGMENT: "", - SPANDATA.HTTP_QUERY: "", - SPANDATA.HTTP_STATUS_CODE: 200, - "reason": "OK", - } - ) - - -@pytest.mark.asyncio -async def test_crumb_capture_without_span_async_span_streaming( - sentry_init, capture_events, httpx_mock -): - httpx_mock.add_response() - - sentry_init( - integrations=[HttpxIntegration()], - trace_lifecycle="stream", - ) - - url = "http://example.com/" - - events = capture_events() - - response = await httpx.AsyncClient().get(url) - - assert response.status_code == 200 - capture_message("Testing!") - sentry_sdk.flush() (event,) = events @@ -341,55 +196,6 @@ async def test_crumb_capture_without_span_async_span_streaming( ) -@pytest.mark.parametrize( - "status_code,level", - [ - (200, None), - (301, None), - (403, "warning"), - (405, "warning"), - (500, "error"), - ], -) -def test_crumb_capture_client_error_sync( - sentry_init, capture_events, httpx_mock, status_code, level -): - httpx_mock.add_response(status_code=status_code) - - sentry_init(integrations=[HttpxIntegration()]) - - url = "http://example.com/" - - with start_transaction(): - events = capture_events() - - response = httpx.Client().get(url) - - assert response.status_code == status_code - capture_message("Testing!") - - (event,) = events - - crumb = event["breadcrumbs"]["values"][0] - assert crumb["type"] == "http" - assert crumb["category"] == "httplib" - - if level is None: - assert "level" not in crumb - else: - assert crumb["level"] == level - - assert crumb["data"] == ApproxDict( - { - "url": url, - SPANDATA.HTTP_METHOD: "GET", - SPANDATA.HTTP_FRAGMENT: "", - SPANDATA.HTTP_QUERY: "", - SPANDATA.HTTP_STATUS_CODE: status_code, - } - ) - - @pytest.mark.parametrize( "status_code,level", [ @@ -401,20 +207,19 @@ def test_crumb_capture_client_error_sync( ], ) @pytest.mark.parametrize("send_default_pii", [True, False]) -def test_crumb_capture_client_error_sync_span_streaming( +def test_crumb_capture_client_error_sync( sentry_init, capture_events, httpx_mock, status_code, level, send_default_pii ): httpx_mock.add_response(status_code=status_code) sentry_init( integrations=[HttpxIntegration()], - trace_lifecycle="stream", send_default_pii=send_default_pii, ) url = "http://example.com/" - with sentry_sdk.traces.start_span(name="segment"): + with sentry_sdk.start_span(name="segment"): events = capture_events() response = httpx.Client().get(url) @@ -452,56 +257,6 @@ def test_crumb_capture_client_error_sync_span_streaming( ) -@pytest.mark.asyncio -@pytest.mark.parametrize( - "status_code,level", - [ - (200, None), - (301, None), - (403, "warning"), - (405, "warning"), - (500, "error"), - ], -) -async def test_crumb_capture_client_error_async( - sentry_init, capture_events, httpx_mock, status_code, level -): - httpx_mock.add_response(status_code=status_code) - - sentry_init(integrations=[HttpxIntegration()]) - - url = "http://example.com/" - - with start_transaction(): - events = capture_events() - - response = await httpx.AsyncClient().get(url) - - assert response.status_code == status_code - capture_message("Testing!") - - (event,) = events - - crumb = event["breadcrumbs"]["values"][0] - assert crumb["type"] == "http" - assert crumb["category"] == "httplib" - - if level is None: - assert "level" not in crumb - else: - assert crumb["level"] == level - - assert crumb["data"] == ApproxDict( - { - "url": url, - SPANDATA.HTTP_METHOD: "GET", - SPANDATA.HTTP_FRAGMENT: "", - SPANDATA.HTTP_QUERY: "", - SPANDATA.HTTP_STATUS_CODE: status_code, - } - ) - - @pytest.mark.asyncio @pytest.mark.parametrize( "status_code,level", @@ -514,20 +269,19 @@ async def test_crumb_capture_client_error_async( ], ) @pytest.mark.parametrize("send_default_pii", [True, False]) -async def test_crumb_capture_client_error_async_span_streaming( +async def test_crumb_capture_client_error_async( sentry_init, capture_events, httpx_mock, status_code, level, send_default_pii ): httpx_mock.add_response(status_code=status_code) sentry_init( integrations=[HttpxIntegration()], - trace_lifecycle="stream", send_default_pii=send_default_pii, ) url = "http://example.com/" - with sentry_sdk.traces.start_span(name="segment"): + with sentry_sdk.start_span(name="segment"): events = capture_events() response = await httpx.AsyncClient().get(url) @@ -538,921 +292,199 @@ async def test_crumb_capture_client_error_async_span_streaming( (event,) = events crumb = event["breadcrumbs"]["values"][0] - assert crumb["type"] == "http" - assert crumb["category"] == "httplib" - - if level is None: - assert "level" not in crumb - else: - assert crumb["level"] == level - - if send_default_pii: - assert crumb["data"] == ApproxDict( - { - "url": url, - SPANDATA.HTTP_METHOD: "GET", - SPANDATA.HTTP_FRAGMENT: "", - SPANDATA.HTTP_QUERY: "", - SPANDATA.HTTP_STATUS_CODE: status_code, - } - ) - else: - assert crumb["data"] == ApproxDict( - { - SPANDATA.HTTP_METHOD: "GET", - SPANDATA.HTTP_STATUS_CODE: status_code, - } - ) - - -def test_outgoing_trace_headers_legacy_sync(sentry_init, httpx_mock): - httpx_mock.add_response() - - sentry_init( - traces_sample_rate=1.0, - integrations=[HttpxIntegration()], - ) - - url = "http://example.com/" - - with start_transaction( - name="/interactions/other-dogs/new-dog", - op="greeting.sniff", - trace_id="01234567890123456789012345678901", - ) as transaction: - response = httpx.Client().get(url) - - request_span = transaction._span_recorder.spans[-1] - assert response.request.headers[ - "sentry-trace" - ] == "{trace_id}-{parent_span_id}-{sampled}".format( - trace_id=transaction.trace_id, - parent_span_id=request_span.span_id, - sampled=1, - ) - - -@pytest.mark.asyncio -async def test_outgoing_trace_headers_legacy_async(sentry_init, httpx_mock): - httpx_mock.add_response() - - sentry_init( - traces_sample_rate=1.0, - integrations=[HttpxIntegration()], - ) - - url = "http://example.com/" - - with start_transaction( - name="/interactions/other-dogs/new-dog", - op="greeting.sniff", - trace_id="01234567890123456789012345678901", - ) as transaction: - response = await httpx.AsyncClient().get(url) - - request_span = transaction._span_recorder.spans[-1] - assert response.request.headers[ - "sentry-trace" - ] == "{trace_id}-{parent_span_id}-{sampled}".format( - trace_id=transaction.trace_id, - parent_span_id=request_span.span_id, - sampled=1, - ) - - -def test_outgoing_trace_headers_append_to_baggage_legacy_sync( - sentry_init, - httpx_mock, -): - httpx_mock.add_response() - - sentry_init( - traces_sample_rate=1.0, - integrations=[HttpxIntegration()], - release="d08ebdb9309e1b004c6f52202de58a09c2268e42", - ) - - url = "http://example.com/" - - # patch random.randrange to return a predictable sample_rand value - with mock.patch("sentry_sdk.tracing_utils.Random.randrange", return_value=500000): - with start_transaction( - name="/interactions/other-dogs/new-dog", - op="greeting.sniff", - trace_id="01234567890123456789012345678901", - ) as transaction: - response = httpx.Client().get(url, headers={"baGGage": "custom=data"}) - - request_span = transaction._span_recorder.spans[-1] - assert response.request.headers[ - "sentry-trace" - ] == "{trace_id}-{parent_span_id}-{sampled}".format( - trace_id=transaction.trace_id, - parent_span_id=request_span.span_id, - sampled=1, - ) - assert ( - response.request.headers["baggage"] - == "custom=data,sentry-trace_id=01234567890123456789012345678901,sentry-sample_rand=0.500000,sentry-environment=production,sentry-release=d08ebdb9309e1b004c6f52202de58a09c2268e42,sentry-transaction=/interactions/other-dogs/new-dog,sentry-sample_rate=1.0,sentry-sampled=true" - ) - - -@pytest.mark.asyncio -async def test_outgoing_trace_headers_append_to_baggage_legacy_async( - sentry_init, - httpx_mock, -): - httpx_mock.add_response() - - sentry_init( - traces_sample_rate=1.0, - integrations=[HttpxIntegration()], - release="d08ebdb9309e1b004c6f52202de58a09c2268e42", - ) - - url = "http://example.com/" - - # patch random.randrange to return a predictable sample_rand value - with mock.patch("sentry_sdk.tracing_utils.Random.randrange", return_value=500000): - with start_transaction( - name="/interactions/other-dogs/new-dog", - op="greeting.sniff", - trace_id="01234567890123456789012345678901", - ) as transaction: - response = await httpx.AsyncClient().get( - url, headers={"baGGage": "custom=data"} - ) - - request_span = transaction._span_recorder.spans[-1] - assert response.request.headers[ - "sentry-trace" - ] == "{trace_id}-{parent_span_id}-{sampled}".format( - trace_id=transaction.trace_id, - parent_span_id=request_span.span_id, - sampled=1, - ) - assert ( - response.request.headers["baggage"] - == "custom=data,sentry-trace_id=01234567890123456789012345678901,sentry-sample_rand=0.500000,sentry-environment=production,sentry-release=d08ebdb9309e1b004c6f52202de58a09c2268e42,sentry-transaction=/interactions/other-dogs/new-dog,sentry-sample_rate=1.0,sentry-sampled=true" - ) - - -@pytest.mark.parametrize( - "trace_propagation_targets,url,trace_propagated", - [ - [ - None, - "https://example.com/", - False, - ], - [ - [], - "https://example.com/", - False, - ], - [ - [MATCH_ALL], - "https://example.com/", - True, - ], - [ - ["https://example.com/"], - "https://example.com/", - True, - ], - [ - ["https://example.com/"], - "https://example.com", - False, - ], - [ - ["https://example.com"], - "https://example.com", - True, - ], - [ - ["https://example.com", r"https?:\/\/[\w\-]+(\.[\w\-]+)+\.net"], - "https://example.net", - False, - ], - [ - ["https://example.com", r"https?:\/\/[\w\-]+(\.[\w\-]+)+\.net"], - "https://good.example.net", - True, - ], - [ - ["https://example.com", r"https?:\/\/[\w\-]+(\.[\w\-]+)+\.net"], - "https://good.example.net/some/thing", - True, - ], - ], -) -def test_option_trace_propagation_targets_sync( - sentry_init, - httpx_mock, - trace_propagation_targets, - url, - trace_propagated, -): - httpx_mock.add_response() - - sentry_init( - release="test", - trace_propagation_targets=trace_propagation_targets, - traces_sample_rate=1.0, - integrations=[HttpxIntegration()], - ) - - with sentry_sdk.start_transaction(): - httpx.Client().get(url) - - request_headers = httpx_mock.get_request().headers - - if trace_propagated: - assert "sentry-trace" in request_headers - else: - assert "sentry-trace" not in request_headers - - -@pytest.mark.asyncio -@pytest.mark.parametrize( - "trace_propagation_targets,url,trace_propagated", - [ - [ - None, - "https://example.com/", - False, - ], - [ - [], - "https://example.com/", - False, - ], - [ - [MATCH_ALL], - "https://example.com/", - True, - ], - [ - ["https://example.com/"], - "https://example.com/", - True, - ], - [ - ["https://example.com/"], - "https://example.com", - False, - ], - [ - ["https://example.com"], - "https://example.com", - True, - ], - [ - ["https://example.com", r"https?:\/\/[\w\-]+(\.[\w\-]+)+\.net"], - "https://example.net", - False, - ], - [ - ["https://example.com", r"https?:\/\/[\w\-]+(\.[\w\-]+)+\.net"], - "https://good.example.net", - True, - ], - [ - ["https://example.com", r"https?:\/\/[\w\-]+(\.[\w\-]+)+\.net"], - "https://good.example.net/some/thing", - True, - ], - ], -) -async def test_option_trace_propagation_targets_async( - sentry_init, - httpx_mock, - trace_propagation_targets, - url, - trace_propagated, -): - httpx_mock.add_response() - - sentry_init( - release="test", - trace_propagation_targets=trace_propagation_targets, - traces_sample_rate=1.0, - integrations=[HttpxIntegration()], - ) - - with sentry_sdk.start_transaction(): - await httpx.AsyncClient().get(url) - - request_headers = httpx_mock.get_request().headers - - if trace_propagated: - assert "sentry-trace" in request_headers - else: - assert "sentry-trace" not in request_headers - - -def test_do_not_propagate_outside_transaction(sentry_init, httpx_mock): - httpx_mock.add_response() - - sentry_init( - traces_sample_rate=1.0, - trace_propagation_targets=[MATCH_ALL], - integrations=[HttpxIntegration()], - ) - - httpx_client = httpx.Client() - httpx_client.get("http://example.com/") - - request_headers = httpx_mock.get_request().headers - assert "sentry-trace" not in request_headers - - -@pytest.mark.tests_internal_exceptions -def test_omit_url_data_if_parsing_fails(sentry_init, capture_events, httpx_mock): - httpx_mock.add_response() - - sentry_init(integrations=[HttpxIntegration()]) - - httpx_client = httpx.Client() - url = "http://example.com" - - events = capture_events() - with mock.patch( - "sentry_sdk.integrations.httpx.parse_url", - side_effect=ValueError, - ): - response = httpx_client.get(url) - - assert response.status_code == 200 - capture_message("Testing!") - - (event,) = events - assert event["breadcrumbs"]["values"][0]["data"] == ApproxDict( - { - SPANDATA.HTTP_METHOD: "GET", - SPANDATA.HTTP_STATUS_CODE: 200, - "reason": "OK", - # no url related data - } - ) - - assert "url" not in event["breadcrumbs"]["values"][0]["data"] - assert SPANDATA.HTTP_FRAGMENT not in event["breadcrumbs"]["values"][0]["data"] - assert SPANDATA.HTTP_QUERY not in event["breadcrumbs"]["values"][0]["data"] - - -def test_request_source_disabled_legacy_sync(sentry_init, capture_events, httpx_mock): - httpx_mock.add_response() - sentry_options = { - "integrations": [HttpxIntegration()], - "traces_sample_rate": 1.0, - "enable_http_request_source": False, - "http_request_source_threshold_ms": 0, - } - - sentry_init(**sentry_options) - - events = capture_events() - - url = "http://example.com/" - - with start_transaction(name="test_transaction"): - httpx.Client().get(url) - - (event,) = events - - span = event["spans"][-1] - assert span["description"].startswith("GET") - - data = span.get("data", {}) - - assert SPANDATA.CODE_LINENO not in data - assert SPANDATA.CODE_NAMESPACE not in data - assert SPANDATA.CODE_FILEPATH not in data - assert SPANDATA.CODE_FUNCTION not in data - - -@pytest.mark.asyncio -async def test_request_source_disabled_legacy_async( - sentry_init, capture_events, httpx_mock -): - httpx_mock.add_response() - sentry_options = { - "integrations": [HttpxIntegration()], - "traces_sample_rate": 1.0, - "enable_http_request_source": False, - "http_request_source_threshold_ms": 0, - } - - sentry_init(**sentry_options) - - events = capture_events() - - url = "http://example.com/" - - with start_transaction(name="test_transaction"): - await httpx.AsyncClient().get(url) - - (event,) = events - - span = event["spans"][-1] - assert span["description"].startswith("GET") - - data = span.get("data", {}) - - assert SPANDATA.CODE_LINENO not in data - assert SPANDATA.CODE_NAMESPACE not in data - assert SPANDATA.CODE_FILEPATH not in data - assert SPANDATA.CODE_FUNCTION not in data - - -@pytest.mark.parametrize("enable_http_request_source", [None, True]) -def test_request_source_enabled_legacy_sync( - sentry_init, - capture_events, - enable_http_request_source, - httpx_mock, -): - httpx_mock.add_response() - sentry_options = { - "integrations": [HttpxIntegration()], - "traces_sample_rate": 1.0, - "http_request_source_threshold_ms": 0, - } - if enable_http_request_source is not None: - sentry_options["enable_http_request_source"] = enable_http_request_source - - sentry_init(**sentry_options) - - events = capture_events() - - url = "http://example.com/" - - with start_transaction(name="test_transaction"): - httpx.Client().get(url) - - (event,) = events - - span = event["spans"][-1] - assert span["description"].startswith("GET") - - data = span.get("data", {}) - - assert SPANDATA.CODE_LINENO in data - assert SPANDATA.CODE_NAMESPACE in data - assert SPANDATA.CODE_FILEPATH in data - assert SPANDATA.CODE_FUNCTION in data - - -@pytest.mark.asyncio -@pytest.mark.parametrize("enable_http_request_source", [None, True]) -async def test_request_source_enabled_legacy_async( - sentry_init, - capture_events, - enable_http_request_source, - httpx_mock, -): - httpx_mock.add_response() - sentry_options = { - "integrations": [HttpxIntegration()], - "traces_sample_rate": 1.0, - "http_request_source_threshold_ms": 0, - } - if enable_http_request_source is not None: - sentry_options["enable_http_request_source"] = enable_http_request_source - - sentry_init(**sentry_options) - - events = capture_events() - - url = "http://example.com/" - - with start_transaction(name="test_transaction"): - await httpx.AsyncClient().get(url) - - (event,) = events - - span = event["spans"][-1] - assert span["description"].startswith("GET") - - data = span.get("data", {}) - - assert SPANDATA.CODE_LINENO in data - assert SPANDATA.CODE_NAMESPACE in data - assert SPANDATA.CODE_FILEPATH in data - assert SPANDATA.CODE_FUNCTION in data - - -def test_request_source_legacy_sync(sentry_init, capture_events, httpx_mock): - httpx_mock.add_response() - - sentry_init( - integrations=[HttpxIntegration()], - traces_sample_rate=1.0, - enable_http_request_source=True, - http_request_source_threshold_ms=0, - ) - - events = capture_events() - - url = "http://example.com/" - - with start_transaction(name="test_transaction"): - httpx.Client().get(url) - - (event,) = events - - span = event["spans"][-1] - assert span["description"].startswith("GET") - - data = span.get("data", {}) - - assert SPANDATA.CODE_LINENO in data - assert SPANDATA.CODE_NAMESPACE in data - assert SPANDATA.CODE_FILEPATH in data - assert SPANDATA.CODE_FUNCTION in data - - assert type(data.get(SPANDATA.CODE_LINENO)) == int - assert data.get(SPANDATA.CODE_LINENO) > 0 - assert data.get(SPANDATA.CODE_NAMESPACE) == "tests.integrations.httpx.test_httpx" - assert data.get(SPANDATA.CODE_FILEPATH).endswith( - "tests/integrations/httpx/test_httpx.py" - ) - - is_relative_path = data.get(SPANDATA.CODE_FILEPATH)[0] != os.sep - assert is_relative_path - - assert data.get(SPANDATA.CODE_FUNCTION) == "test_request_source_legacy_sync" - - -@pytest.mark.asyncio -async def test_request_source_legacy_async(sentry_init, capture_events, httpx_mock): - httpx_mock.add_response() - - sentry_init( - integrations=[HttpxIntegration()], - traces_sample_rate=1.0, - enable_http_request_source=True, - http_request_source_threshold_ms=0, - ) - - events = capture_events() - - url = "http://example.com/" - - with start_transaction(name="test_transaction"): - await httpx.AsyncClient().get(url) - - (event,) = events - - span = event["spans"][-1] - assert span["description"].startswith("GET") - - data = span.get("data", {}) - - assert SPANDATA.CODE_LINENO in data - assert SPANDATA.CODE_NAMESPACE in data - assert SPANDATA.CODE_FILEPATH in data - assert SPANDATA.CODE_FUNCTION in data - - assert type(data.get(SPANDATA.CODE_LINENO)) == int - assert data.get(SPANDATA.CODE_LINENO) > 0 - assert data.get(SPANDATA.CODE_NAMESPACE) == "tests.integrations.httpx.test_httpx" - assert data.get(SPANDATA.CODE_FILEPATH).endswith( - "tests/integrations/httpx/test_httpx.py" - ) - - is_relative_path = data.get(SPANDATA.CODE_FILEPATH)[0] != os.sep - assert is_relative_path - - assert data.get(SPANDATA.CODE_FUNCTION) == "test_request_source_legacy_async" - - -def test_request_source_with_module_in_search_path_legacy_sync( - sentry_init, capture_events, httpx_mock -): - """ - Test that request source is relative to the path of the module it ran in - """ - httpx_mock.add_response() - sentry_init( - integrations=[HttpxIntegration()], - traces_sample_rate=1.0, - enable_http_request_source=True, - http_request_source_threshold_ms=0, - ) - - events = capture_events() - - url = "http://example.com/" - - with start_transaction(name="test_transaction"): - from httpx_helpers.helpers import get_request_with_client - - get_request_with_client(httpx.Client(), url) - - (event,) = events - - span = event["spans"][-1] - assert span["description"].startswith("GET") - - data = span.get("data", {}) - - assert SPANDATA.CODE_LINENO in data - assert SPANDATA.CODE_NAMESPACE in data - assert SPANDATA.CODE_FILEPATH in data - assert SPANDATA.CODE_FUNCTION in data - - assert type(data.get(SPANDATA.CODE_LINENO)) == int - assert data.get(SPANDATA.CODE_LINENO) > 0 - assert data.get(SPANDATA.CODE_NAMESPACE) == "httpx_helpers.helpers" - assert data.get(SPANDATA.CODE_FILEPATH) == "httpx_helpers/helpers.py" - - is_relative_path = data.get(SPANDATA.CODE_FILEPATH)[0] != os.sep - assert is_relative_path - - assert data.get(SPANDATA.CODE_FUNCTION) == "get_request_with_client" - - -@pytest.mark.asyncio -async def test_request_source_with_module_in_search_path_legacy_async( - sentry_init, capture_events, httpx_mock -): - """ - Test that request source is relative to the path of the module it ran in - """ - httpx_mock.add_response() - sentry_init( - integrations=[HttpxIntegration()], - traces_sample_rate=1.0, - enable_http_request_source=True, - http_request_source_threshold_ms=0, - ) - - events = capture_events() - - url = "http://example.com/" - - with start_transaction(name="test_transaction"): - from httpx_helpers.helpers import async_get_request_with_client - - await async_get_request_with_client(httpx.AsyncClient(), url) - - (event,) = events - - span = event["spans"][-1] - assert span["description"].startswith("GET") - - data = span.get("data", {}) - - assert SPANDATA.CODE_LINENO in data - assert SPANDATA.CODE_NAMESPACE in data - assert SPANDATA.CODE_FILEPATH in data - assert SPANDATA.CODE_FUNCTION in data - - assert type(data.get(SPANDATA.CODE_LINENO)) == int - assert data.get(SPANDATA.CODE_LINENO) > 0 - assert data.get(SPANDATA.CODE_NAMESPACE) == "httpx_helpers.helpers" - assert data.get(SPANDATA.CODE_FILEPATH) == "httpx_helpers/helpers.py" - - is_relative_path = data.get(SPANDATA.CODE_FILEPATH)[0] != os.sep - assert is_relative_path - - assert data.get(SPANDATA.CODE_FUNCTION) == "async_get_request_with_client" - - -def test_no_request_source_if_duration_too_short_legacy_sync( - sentry_init, capture_events, httpx_mock -): - httpx_mock.add_response() - - sentry_init( - integrations=[HttpxIntegration()], - traces_sample_rate=1.0, - enable_http_request_source=True, - # Threshold so high no real request will ever exceed it - http_request_source_threshold_ms=9999999, - ) - - events = capture_events() - - url = "http://example.com/" - - with start_transaction(name="test_transaction"): - httpx.Client().get(url) - - (event,) = events - - span = event["spans"][-1] - assert span["description"].startswith("GET") - - data = span.get("data", {}) - - assert SPANDATA.CODE_LINENO not in data - assert SPANDATA.CODE_NAMESPACE not in data - assert SPANDATA.CODE_FILEPATH not in data - assert SPANDATA.CODE_FUNCTION not in data - - -@pytest.mark.asyncio -async def test_no_request_source_if_duration_too_short_legacy_async( - sentry_init, capture_events, httpx_mock -): - httpx_mock.add_response() - - sentry_init( - integrations=[HttpxIntegration()], - traces_sample_rate=1.0, - enable_http_request_source=True, - # Threshold so high no real request will ever exceed it - http_request_source_threshold_ms=9999999, - ) - - events = capture_events() - - url = "http://example.com/" - - with start_transaction(name="test_transaction"): - await httpx.AsyncClient().get(url) - - (event,) = events - - span = event["spans"][-1] - assert span["description"].startswith("GET") - - data = span.get("data", {}) - - assert SPANDATA.CODE_LINENO not in data - assert SPANDATA.CODE_NAMESPACE not in data - assert SPANDATA.CODE_FILEPATH not in data - assert SPANDATA.CODE_FUNCTION not in data - - -def test_request_source_if_duration_over_threshold_legacy_sync( - sentry_init, capture_events, httpx_mock -): - httpx_mock.add_response() - - sentry_init( - integrations=[HttpxIntegration()], - traces_sample_rate=1.0, - enable_http_request_source=True, - # Threshold is low so any request will exceed it - http_request_source_threshold_ms=0, - ) - - events = capture_events() - - url = "http://example.com/" - - with start_transaction(name="test_transaction"): - httpx.Client().get(url) - - (event,) = events - - span = event["spans"][-1] - assert span["description"].startswith("GET") - - data = span.get("data", {}) - - assert SPANDATA.CODE_LINENO in data - assert SPANDATA.CODE_NAMESPACE in data - assert SPANDATA.CODE_FILEPATH in data - assert SPANDATA.CODE_FUNCTION in data - - assert type(data.get(SPANDATA.CODE_LINENO)) == int - assert data.get(SPANDATA.CODE_LINENO) > 0 - assert data.get(SPANDATA.CODE_NAMESPACE) == "tests.integrations.httpx.test_httpx" - assert data.get(SPANDATA.CODE_FILEPATH).endswith( - "tests/integrations/httpx/test_httpx.py" - ) - - is_relative_path = data.get(SPANDATA.CODE_FILEPATH)[0] != os.sep - assert is_relative_path - - assert ( - data.get(SPANDATA.CODE_FUNCTION) - == "test_request_source_if_duration_over_threshold_legacy_sync" - ) - - -@pytest.mark.asyncio -async def test_request_source_if_duration_over_threshold_legacy_async( - sentry_init, capture_events, httpx_mock -): - httpx_mock.add_response() - - sentry_init( - integrations=[HttpxIntegration()], - traces_sample_rate=1.0, - enable_http_request_source=True, - # Threshold is low so any request will exceed it - http_request_source_threshold_ms=0, - ) - - events = capture_events() - - url = "http://example.com/" - - with start_transaction(name="test_transaction"): - await httpx.AsyncClient().get(url) - - (event,) = events - - span = event["spans"][-1] - assert span["description"].startswith("GET") - - data = span.get("data", {}) - - assert SPANDATA.CODE_LINENO in data - assert SPANDATA.CODE_NAMESPACE in data - assert SPANDATA.CODE_FILEPATH in data - assert SPANDATA.CODE_FUNCTION in data - - assert type(data.get(SPANDATA.CODE_LINENO)) == int - assert data.get(SPANDATA.CODE_LINENO) > 0 - assert data.get(SPANDATA.CODE_NAMESPACE) == "tests.integrations.httpx.test_httpx" - assert data.get(SPANDATA.CODE_FILEPATH).endswith( - "tests/integrations/httpx/test_httpx.py" - ) + assert crumb["type"] == "http" + assert crumb["category"] == "httplib" - is_relative_path = data.get(SPANDATA.CODE_FILEPATH)[0] != os.sep - assert is_relative_path + if level is None: + assert "level" not in crumb + else: + assert crumb["level"] == level - assert ( - data.get(SPANDATA.CODE_FUNCTION) - == "test_request_source_if_duration_over_threshold_legacy_async" - ) + if send_default_pii: + assert crumb["data"] == ApproxDict( + { + "url": url, + SPANDATA.HTTP_METHOD: "GET", + SPANDATA.HTTP_FRAGMENT: "", + SPANDATA.HTTP_QUERY: "", + SPANDATA.HTTP_STATUS_CODE: status_code, + } + ) + else: + assert crumb["data"] == ApproxDict( + { + SPANDATA.HTTP_METHOD: "GET", + SPANDATA.HTTP_STATUS_CODE: status_code, + } + ) -def test_span_origin_legacy_sync(sentry_init, capture_events, httpx_mock): +@pytest.mark.parametrize( + "trace_propagation_targets,url,trace_propagated", + [ + [ + None, + "https://example.com/", + False, + ], + [ + [], + "https://example.com/", + False, + ], + [ + [MATCH_ALL], + "https://example.com/", + True, + ], + [ + ["https://example.com/"], + "https://example.com/", + True, + ], + [ + ["https://example.com/"], + "https://example.com", + False, + ], + [ + ["https://example.com"], + "https://example.com", + True, + ], + [ + ["https://example.com", r"https?:\/\/[\w\-]+(\.[\w\-]+)+\.net"], + "https://example.net", + False, + ], + [ + ["https://example.com", r"https?:\/\/[\w\-]+(\.[\w\-]+)+\.net"], + "https://good.example.net", + True, + ], + [ + ["https://example.com", r"https?:\/\/[\w\-]+(\.[\w\-]+)+\.net"], + "https://good.example.net/some/thing", + True, + ], + ], +) +def test_option_trace_propagation_targets_sync( + sentry_init, + httpx_mock, + trace_propagation_targets, + url, + trace_propagated, +): httpx_mock.add_response() sentry_init( - integrations=[HttpxIntegration()], + release="test", + trace_propagation_targets=trace_propagation_targets, traces_sample_rate=1.0, + integrations=[HttpxIntegration()], ) - events = capture_events() - - url = "http://example.com/" - - with start_transaction(name="test_transaction"): - httpx.Client().get(url) + httpx.Client().get(url) - (event,) = events + request_headers = httpx_mock.get_request().headers - assert event["contexts"]["trace"]["origin"] == "manual" - assert event["spans"][0]["origin"] == "auto.http.httpx" + if trace_propagated: + assert "sentry-trace" in request_headers + else: + assert "sentry-trace" not in request_headers @pytest.mark.asyncio -async def test_span_origin_legacy_async(sentry_init, capture_events, httpx_mock): +@pytest.mark.parametrize( + "trace_propagation_targets,url,trace_propagated", + [ + [ + None, + "https://example.com/", + False, + ], + [ + [], + "https://example.com/", + False, + ], + [ + [MATCH_ALL], + "https://example.com/", + True, + ], + [ + ["https://example.com/"], + "https://example.com/", + True, + ], + [ + ["https://example.com/"], + "https://example.com", + False, + ], + [ + ["https://example.com"], + "https://example.com", + True, + ], + [ + ["https://example.com", r"https?:\/\/[\w\-]+(\.[\w\-]+)+\.net"], + "https://example.net", + False, + ], + [ + ["https://example.com", r"https?:\/\/[\w\-]+(\.[\w\-]+)+\.net"], + "https://good.example.net", + True, + ], + [ + ["https://example.com", r"https?:\/\/[\w\-]+(\.[\w\-]+)+\.net"], + "https://good.example.net/some/thing", + True, + ], + ], +) +async def test_option_trace_propagation_targets_async( + sentry_init, + httpx_mock, + trace_propagation_targets, + url, + trace_propagated, +): httpx_mock.add_response() sentry_init( - integrations=[HttpxIntegration()], + release="test", + trace_propagation_targets=trace_propagation_targets, traces_sample_rate=1.0, + integrations=[HttpxIntegration()], ) - events = capture_events() - - url = "http://example.com/" - - with start_transaction(name="test_transaction"): - await httpx.AsyncClient().get(url) - - (event,) = events - - assert event["contexts"]["trace"]["origin"] == "manual" - assert event["spans"][0]["origin"] == "auto.http.httpx" + await httpx.AsyncClient().get(url) + request_headers = httpx_mock.get_request().headers -def _get_http_client_span(items): - return next( - item.payload - for item in items - if item.payload.get("attributes", {}).get("sentry.op") == OP.HTTP_CLIENT - ) + if trace_propagated: + assert "sentry-trace" in request_headers + else: + assert "sentry-trace" not in request_headers -def test_outgoing_trace_headers_span_streaming_sync( - sentry_init, capture_items, httpx_mock -): +def test_outgoing_trace_headers_sync(sentry_init, capture_items, httpx_mock): httpx_mock.add_response() sentry_init( traces_sample_rate=1.0, integrations=[HttpxIntegration()], - trace_lifecycle="stream", ) url = "http://example.com/" items = capture_items("span") - with sentry_sdk.traces.start_span(name="test"): + with sentry_sdk.start_span(name="test"): response = httpx.Client().get(url) sentry_sdk.flush() @@ -1469,22 +501,19 @@ def test_outgoing_trace_headers_span_streaming_sync( @pytest.mark.asyncio -async def test_outgoing_trace_headers_span_streaming_async( - sentry_init, capture_items, httpx_mock -): +async def test_outgoing_trace_headers_async(sentry_init, capture_items, httpx_mock): httpx_mock.add_response() sentry_init( traces_sample_rate=1.0, integrations=[HttpxIntegration()], - trace_lifecycle="stream", ) url = "http://example.com/" items = capture_items("span") - with sentry_sdk.traces.start_span(name="test"): + with sentry_sdk.start_span(name="test"): response = await httpx.AsyncClient().get(url) sentry_sdk.flush() @@ -1500,7 +529,7 @@ async def test_outgoing_trace_headers_span_streaming_async( ) -def test_outgoing_trace_headers_append_to_baggage_span_streaming_sync( +def test_outgoing_trace_headers_append_to_baggage_sync( sentry_init, capture_items, httpx_mock, @@ -1511,7 +540,6 @@ def test_outgoing_trace_headers_append_to_baggage_span_streaming_sync( traces_sample_rate=1.0, integrations=[HttpxIntegration()], release="d08ebdb9309e1b004c6f52202de58a09c2268e42", - trace_lifecycle="stream", ) url = "http://example.com/" @@ -1519,7 +547,7 @@ def test_outgoing_trace_headers_append_to_baggage_span_streaming_sync( items = capture_items("span") with mock.patch("sentry_sdk.tracing_utils.Random.randrange", return_value=500000): - with sentry_sdk.traces.start_span(name="test"): + with sentry_sdk.start_span(name="test"): response = httpx.Client().get(url, headers={"baGGage": "custom=data"}) sentry_sdk.flush() @@ -1534,7 +562,7 @@ def test_outgoing_trace_headers_append_to_baggage_span_streaming_sync( @pytest.mark.asyncio -async def test_outgoing_trace_headers_append_to_baggage_span_streaming_async( +async def test_outgoing_trace_headers_append_to_baggage_async( sentry_init, capture_items, httpx_mock, @@ -1545,7 +573,6 @@ async def test_outgoing_trace_headers_append_to_baggage_span_streaming_async( traces_sample_rate=1.0, integrations=[HttpxIntegration()], release="d08ebdb9309e1b004c6f52202de58a09c2268e42", - trace_lifecycle="stream", ) url = "http://example.com/" @@ -1553,7 +580,7 @@ async def test_outgoing_trace_headers_append_to_baggage_span_streaming_async( items = capture_items("span") with mock.patch("sentry_sdk.tracing_utils.Random.randrange", return_value=500000): - with sentry_sdk.traces.start_span(name="test"): + with sentry_sdk.start_span(name="test"): response = await httpx.AsyncClient().get( url, headers={"baGGage": "custom=data"} ) @@ -1569,7 +596,7 @@ async def test_outgoing_trace_headers_append_to_baggage_span_streaming_async( assert "sentry-sampled=true" in baggage -def test_outgoing_trace_headers_span_streaming_no_current_span(sentry_init, httpx_mock): +def test_outgoing_trace_headers_no_current_span(sentry_init, httpx_mock): """ Even when there is no active span, trace propagation headers should still be attached to outgoing requests when span streaming is enabled. @@ -1586,15 +613,13 @@ def test_outgoing_trace_headers_span_streaming_no_current_span(sentry_init, http traces_sample_rate=1.0, trace_propagation_targets=[MATCH_ALL], integrations=[HttpxIntegration()], - trace_lifecycle="stream", ) url = "http://example.com/" httpx_client = httpx.Client() - # No start_span / start_transaction -> get_current_span() is None - assert sentry_sdk.traces.get_current_span() is None + assert sentry_sdk.get_current_span() is None response = httpx_client.get(url) @@ -1612,9 +637,7 @@ def test_outgoing_trace_headers_span_streaming_no_current_span(sentry_init, http @pytest.mark.asyncio -async def test_outgoing_trace_headers_span_streaming_no_current_span_async( - sentry_init, httpx_mock -): +async def test_outgoing_trace_headers_no_current_span_async(sentry_init, httpx_mock): """ The async client must match the sync client: trace propagation headers are attached to outgoing requests even when there is no active span and span @@ -1626,15 +649,13 @@ async def test_outgoing_trace_headers_span_streaming_no_current_span_async( traces_sample_rate=1.0, trace_propagation_targets=[MATCH_ALL], integrations=[HttpxIntegration()], - trace_lifecycle="stream", ) url = "http://example.com/" httpx_client = httpx.AsyncClient() - # No start_span / start_transaction -> get_current_span() is None - assert sentry_sdk.traces.get_current_span() is None + assert sentry_sdk.get_current_span() is None response = await httpx_client.get(url) @@ -1651,9 +672,7 @@ async def test_outgoing_trace_headers_span_streaming_no_current_span_async( assert f"sentry-trace_id={trace_id}" in request_headers["baggage"] -def test_request_source_disabled_span_streaming_sync( - sentry_init, capture_items, httpx_mock -): +def test_request_source_disabled_sync(sentry_init, capture_items, httpx_mock): httpx_mock.add_response() sentry_init( @@ -1661,14 +680,13 @@ def test_request_source_disabled_span_streaming_sync( traces_sample_rate=1.0, enable_http_request_source=False, http_request_source_threshold_ms=0, - trace_lifecycle="stream", ) items = capture_items("span") url = "http://example.com/" - with sentry_sdk.traces.start_span(name="test"): + with sentry_sdk.start_span(name="test"): httpx.Client().get(url) sentry_sdk.flush() @@ -1682,9 +700,7 @@ def test_request_source_disabled_span_streaming_sync( @pytest.mark.asyncio -async def test_request_source_disabled_span_streaming_async( - sentry_init, capture_items, httpx_mock -): +async def test_request_source_disabled_async(sentry_init, capture_items, httpx_mock): httpx_mock.add_response() sentry_init( @@ -1692,14 +708,13 @@ async def test_request_source_disabled_span_streaming_async( traces_sample_rate=1.0, enable_http_request_source=False, http_request_source_threshold_ms=0, - trace_lifecycle="stream", ) items = capture_items("span") url = "http://example.com/" - with sentry_sdk.traces.start_span(name="test"): + with sentry_sdk.start_span(name="test"): await httpx.AsyncClient().get(url) sentry_sdk.flush() @@ -1713,7 +728,7 @@ async def test_request_source_disabled_span_streaming_async( @pytest.mark.parametrize("enable_http_request_source", [None, True]) -def test_request_source_enabled_span_streaming_sync( +def test_request_source_enabled_sync( sentry_init, capture_items, enable_http_request_source, @@ -1725,7 +740,6 @@ def test_request_source_enabled_span_streaming_sync( "integrations": [HttpxIntegration()], "traces_sample_rate": 1.0, "http_request_source_threshold_ms": 0, - "trace_lifecycle": "stream", } if enable_http_request_source is not None: sentry_options["enable_http_request_source"] = enable_http_request_source @@ -1736,7 +750,7 @@ def test_request_source_enabled_span_streaming_sync( url = "http://example.com/" - with sentry_sdk.traces.start_span(name="test"): + with sentry_sdk.start_span(name="test"): httpx.Client().get(url) sentry_sdk.flush() @@ -1751,7 +765,7 @@ def test_request_source_enabled_span_streaming_sync( @pytest.mark.asyncio @pytest.mark.parametrize("enable_http_request_source", [None, True]) -async def test_request_source_enabled_span_streaming_async( +async def test_request_source_enabled_async( sentry_init, capture_items, enable_http_request_source, @@ -1763,7 +777,6 @@ async def test_request_source_enabled_span_streaming_async( "integrations": [HttpxIntegration()], "traces_sample_rate": 1.0, "http_request_source_threshold_ms": 0, - "trace_lifecycle": "stream", } if enable_http_request_source is not None: sentry_options["enable_http_request_source"] = enable_http_request_source @@ -1774,7 +787,7 @@ async def test_request_source_enabled_span_streaming_async( url = "http://example.com/" - with sentry_sdk.traces.start_span(name="test"): + with sentry_sdk.start_span(name="test"): await httpx.AsyncClient().get(url) sentry_sdk.flush() @@ -1787,7 +800,7 @@ async def test_request_source_enabled_span_streaming_async( assert SPANDATA.CODE_FUNCTION in http_span["attributes"] -def test_request_source_span_streaming_sync(sentry_init, capture_items, httpx_mock): +def test_request_source_sync(sentry_init, capture_items, httpx_mock): httpx_mock.add_response() sentry_init( @@ -1795,14 +808,13 @@ def test_request_source_span_streaming_sync(sentry_init, capture_items, httpx_mo traces_sample_rate=1.0, enable_http_request_source=True, http_request_source_threshold_ms=0, - trace_lifecycle="stream", ) items = capture_items("span") url = "http://example.com/" - with sentry_sdk.traces.start_span(name="test"): + with sentry_sdk.start_span(name="test"): httpx.Client().get(url) sentry_sdk.flush() @@ -1827,16 +839,11 @@ def test_request_source_span_streaming_sync(sentry_init, capture_items, httpx_mo is_relative_path = http_span["attributes"]["code.file.path"][0] != os.sep assert is_relative_path - assert ( - http_span["attributes"][SPANDATA.CODE_FUNCTION] - == "test_request_source_span_streaming_sync" - ) + assert http_span["attributes"][SPANDATA.CODE_FUNCTION] == "test_request_source_sync" @pytest.mark.asyncio -async def test_request_source_span_streaming_async( - sentry_init, capture_items, httpx_mock -): +async def test_request_source_async(sentry_init, capture_items, httpx_mock): httpx_mock.add_response() sentry_init( @@ -1844,14 +851,13 @@ async def test_request_source_span_streaming_async( traces_sample_rate=1.0, enable_http_request_source=True, http_request_source_threshold_ms=0, - trace_lifecycle="stream", ) items = capture_items("span") url = "http://example.com/" - with sentry_sdk.traces.start_span(name="test"): + with sentry_sdk.start_span(name="test"): await httpx.AsyncClient().get(url) sentry_sdk.flush() @@ -1877,12 +883,11 @@ async def test_request_source_span_streaming_async( assert is_relative_path assert ( - http_span["attributes"][SPANDATA.CODE_FUNCTION] - == "test_request_source_span_streaming_async" + http_span["attributes"][SPANDATA.CODE_FUNCTION] == "test_request_source_async" ) -def test_request_source_with_module_in_search_path_span_streaming_sync( +def test_request_source_with_module_in_search_path_sync( sentry_init, capture_items, httpx_mock ): """ @@ -1895,14 +900,13 @@ def test_request_source_with_module_in_search_path_span_streaming_sync( traces_sample_rate=1.0, enable_http_request_source=True, http_request_source_threshold_ms=0, - trace_lifecycle="stream", ) items = capture_items("span") url = "http://example.com/" - with sentry_sdk.traces.start_span(name="test"): + with sentry_sdk.start_span(name="test"): from httpx_helpers.helpers import get_request_with_client get_request_with_client(httpx.Client(), url) @@ -1928,7 +932,7 @@ def test_request_source_with_module_in_search_path_span_streaming_sync( @pytest.mark.asyncio -async def test_request_source_with_module_in_search_path_span_streaming_async( +async def test_request_source_with_module_in_search_path_async( sentry_init, capture_items, httpx_mock ): """ @@ -1941,14 +945,13 @@ async def test_request_source_with_module_in_search_path_span_streaming_async( traces_sample_rate=1.0, enable_http_request_source=True, http_request_source_threshold_ms=0, - trace_lifecycle="stream", ) items = capture_items("span") url = "http://example.com/" - with sentry_sdk.traces.start_span(name="test"): + with sentry_sdk.start_span(name="test"): from httpx_helpers.helpers import async_get_request_with_client await async_get_request_with_client(httpx.AsyncClient(), url) @@ -1976,7 +979,7 @@ async def test_request_source_with_module_in_search_path_span_streaming_async( ) -def test_no_request_source_if_duration_too_short_span_streaming_sync( +def test_no_request_source_if_duration_too_short_sync( sentry_init, capture_items, httpx_mock ): httpx_mock.add_response() @@ -1987,14 +990,13 @@ def test_no_request_source_if_duration_too_short_span_streaming_sync( enable_http_request_source=True, # Threshold so high no real request will ever exceed it http_request_source_threshold_ms=9999999, - trace_lifecycle="stream", ) items = capture_items("span") url = "http://example.com/" - with sentry_sdk.traces.start_span(name="test"): + with sentry_sdk.start_span(name="test"): httpx.Client().get(url) sentry_sdk.flush() @@ -2008,7 +1010,7 @@ def test_no_request_source_if_duration_too_short_span_streaming_sync( @pytest.mark.asyncio -async def test_no_request_source_if_duration_too_short_span_streaming_async( +async def test_no_request_source_if_duration_too_short_async( sentry_init, capture_items, httpx_mock ): httpx_mock.add_response() @@ -2019,14 +1021,13 @@ async def test_no_request_source_if_duration_too_short_span_streaming_async( enable_http_request_source=True, # Threshold so high no real request will ever exceed it http_request_source_threshold_ms=9999999, - trace_lifecycle="stream", ) items = capture_items("span") url = "http://example.com/" - with sentry_sdk.traces.start_span(name="test"): + with sentry_sdk.start_span(name="test"): await httpx.AsyncClient().get(url) sentry_sdk.flush() @@ -2039,7 +1040,7 @@ async def test_no_request_source_if_duration_too_short_span_streaming_async( assert SPANDATA.CODE_FUNCTION not in http_span["attributes"] -def test_request_source_if_duration_over_threshold_span_streaming_sync( +def test_request_source_if_duration_over_threshold_sync( sentry_init, capture_items, httpx_mock ): httpx_mock.add_response() @@ -2050,14 +1051,13 @@ def test_request_source_if_duration_over_threshold_span_streaming_sync( enable_http_request_source=True, # Threshold of 0 means any non-zero duration qualifies http_request_source_threshold_ms=0, - trace_lifecycle="stream", ) items = capture_items("span") url = "http://example.com/" - with sentry_sdk.traces.start_span(name="test"): + with sentry_sdk.start_span(name="test"): httpx.Client().get(url) sentry_sdk.flush() @@ -2084,12 +1084,12 @@ def test_request_source_if_duration_over_threshold_span_streaming_sync( assert ( http_span["attributes"][SPANDATA.CODE_FUNCTION] - == "test_request_source_if_duration_over_threshold_span_streaming_sync" + == "test_request_source_if_duration_over_threshold_sync" ) @pytest.mark.asyncio -async def test_request_source_if_duration_over_threshold_span_streaming_async( +async def test_request_source_if_duration_over_threshold_async( sentry_init, capture_items, httpx_mock ): httpx_mock.add_response() @@ -2100,14 +1100,13 @@ async def test_request_source_if_duration_over_threshold_span_streaming_async( enable_http_request_source=True, # Threshold of 0 means any non-zero duration qualifies http_request_source_threshold_ms=0, - trace_lifecycle="stream", ) items = capture_items("span") url = "http://example.com/" - with sentry_sdk.traces.start_span(name="test"): + with sentry_sdk.start_span(name="test"): await httpx.AsyncClient().get(url) sentry_sdk.flush() @@ -2134,24 +1133,23 @@ async def test_request_source_if_duration_over_threshold_span_streaming_async( assert ( http_span["attributes"][SPANDATA.CODE_FUNCTION] - == "test_request_source_if_duration_over_threshold_span_streaming_async" + == "test_request_source_if_duration_over_threshold_async" ) -def test_span_origin_span_streaming_sync(sentry_init, capture_items, httpx_mock): +def test_span_origin_sync(sentry_init, capture_items, httpx_mock): httpx_mock.add_response() sentry_init( integrations=[HttpxIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", ) items = capture_items("span") url = "http://example.com/" - with sentry_sdk.traces.start_span(name="test"): + with sentry_sdk.start_span(name="test"): httpx.Client().get(url) sentry_sdk.flush() @@ -2162,20 +1160,19 @@ def test_span_origin_span_streaming_sync(sentry_init, capture_items, httpx_mock) @pytest.mark.asyncio -async def test_span_origin_span_streaming_async(sentry_init, capture_items, httpx_mock): +async def test_span_origin_async(sentry_init, capture_items, httpx_mock): httpx_mock.add_response() sentry_init( integrations=[HttpxIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", ) items = capture_items("span") url = "http://example.com/" - with sentry_sdk.traces.start_span(name="test"): + with sentry_sdk.start_span(name="test"): await httpx.AsyncClient().get(url) sentry_sdk.flush() @@ -2186,7 +1183,7 @@ async def test_span_origin_span_streaming_async(sentry_init, capture_items, http @pytest.mark.parametrize("send_default_pii", [True, False]) -def test_http_url_attributes_span_streaming_sync( +def test_http_url_attributes_sync( sentry_init, capture_items, httpx_mock, send_default_pii ): httpx_mock.add_response() @@ -2195,14 +1192,13 @@ def test_http_url_attributes_span_streaming_sync( integrations=[HttpxIntegration()], traces_sample_rate=1.0, send_default_pii=send_default_pii, - trace_lifecycle="stream", ) items = capture_items("span") url = "http://example.com/?foo=bar#frag" - with sentry_sdk.traces.start_span(name="test"): + with sentry_sdk.start_span(name="test"): httpx.Client().get(url) sentry_sdk.flush() @@ -2224,7 +1220,7 @@ def test_http_url_attributes_span_streaming_sync( @pytest.mark.asyncio @pytest.mark.parametrize("send_default_pii", [True, False]) -async def test_http_url_attributes_span_streaming_async( +async def test_http_url_attributes_async( sentry_init, capture_items, httpx_mock, send_default_pii ): httpx_mock.add_response() @@ -2233,14 +1229,13 @@ async def test_http_url_attributes_span_streaming_async( integrations=[HttpxIntegration()], traces_sample_rate=1.0, send_default_pii=send_default_pii, - trace_lifecycle="stream", ) items = capture_items("span") url = "http://example.com/?foo=bar#frag" - with sentry_sdk.traces.start_span(name="test"): + with sentry_sdk.start_span(name="test"): await httpx.AsyncClient().get(url) sentry_sdk.flush() @@ -2261,7 +1256,7 @@ async def test_http_url_attributes_span_streaming_async( @pytest.mark.parametrize("send_default_pii", [True, False]) -def test_http_url_attributes_no_query_or_fragment_span_streaming_sync( +def test_http_url_attributes_no_query_or_fragment_sync( sentry_init, capture_items, httpx_mock, send_default_pii ): httpx_mock.add_response() @@ -2270,14 +1265,13 @@ def test_http_url_attributes_no_query_or_fragment_span_streaming_sync( integrations=[HttpxIntegration()], traces_sample_rate=1.0, send_default_pii=send_default_pii, - trace_lifecycle="stream", ) items = capture_items("span") url = "http://example.com/" - with sentry_sdk.traces.start_span(name="test"): + with sentry_sdk.start_span(name="test"): httpx.Client().get(url) sentry_sdk.flush() @@ -2297,7 +1291,7 @@ def test_http_url_attributes_no_query_or_fragment_span_streaming_sync( @pytest.mark.asyncio @pytest.mark.parametrize("send_default_pii", [True, False]) -async def test_http_url_attributes_no_query_or_fragment_span_streaming_async( +async def test_http_url_attributes_no_query_or_fragment_async( sentry_init, capture_items, httpx_mock, send_default_pii ): httpx_mock.add_response() @@ -2306,14 +1300,13 @@ async def test_http_url_attributes_no_query_or_fragment_span_streaming_async( integrations=[HttpxIntegration()], traces_sample_rate=1.0, send_default_pii=send_default_pii, - trace_lifecycle="stream", ) items = capture_items("span") url = "http://example.com/" - with sentry_sdk.traces.start_span(name="test"): + with sentry_sdk.start_span(name="test"): await httpx.AsyncClient().get(url) sentry_sdk.flush() @@ -2396,7 +1389,7 @@ async def test_http_url_attributes_no_query_or_fragment_span_streaming_async( ), ], ) -def test_url_query_data_collection_span_streaming_sync( +def test_url_query_data_collection_sync( sentry_init, capture_items, httpx_mock, init_kwargs, expected_query ): httpx_mock.add_response() @@ -2404,7 +1397,6 @@ def test_url_query_data_collection_span_streaming_sync( sentry_init( integrations=[HttpxIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", **init_kwargs, ) @@ -2412,7 +1404,7 @@ def test_url_query_data_collection_span_streaming_sync( url = "http://example.com/?toy=tennisball&color=red&auth=secret#frag" - with sentry_sdk.traces.start_span(name="test"): + with sentry_sdk.start_span(name="test"): httpx.Client().get(url) sentry_sdk.flush() @@ -2491,7 +1483,7 @@ def test_url_query_data_collection_span_streaming_sync( ), ], ) -async def test_url_query_data_collection_span_streaming_async( +async def test_url_query_data_collection_async( sentry_init, capture_items, httpx_mock, init_kwargs, expected_query ): httpx_mock.add_response() @@ -2499,7 +1491,6 @@ async def test_url_query_data_collection_span_streaming_async( sentry_init( integrations=[HttpxIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", **init_kwargs, ) @@ -2507,7 +1498,7 @@ async def test_url_query_data_collection_span_streaming_async( url = "http://example.com/?toy=tennisball&color=red&auth=secret#frag" - with sentry_sdk.traces.start_span(name="test"): + with sentry_sdk.start_span(name="test"): await httpx.AsyncClient().get(url) sentry_sdk.flush() @@ -2539,7 +1530,7 @@ async def test_url_query_data_collection_span_streaming_async( ), ], ) -def test_url_full_reassembly_span_streaming_sync( +def test_url_full_reassembly_sync( sentry_init, capture_items, httpx_mock, init_kwargs, expected_url_full ): httpx_mock.add_response() @@ -2547,7 +1538,6 @@ def test_url_full_reassembly_span_streaming_sync( sentry_init( integrations=[HttpxIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", **init_kwargs, ) @@ -2555,7 +1545,7 @@ def test_url_full_reassembly_span_streaming_sync( url = "http://example.com/?toy=tennisball&color=red&auth=secret#frag" - with sentry_sdk.traces.start_span(name="test"): + with sentry_sdk.start_span(name="test"): httpx.Client().get(url) sentry_sdk.flush() @@ -2585,7 +1575,7 @@ def test_url_full_reassembly_span_streaming_sync( ), ], ) -async def test_url_full_reassembly_span_streaming_async( +async def test_url_full_reassembly_async( sentry_init, capture_items, httpx_mock, init_kwargs, expected_url_full ): httpx_mock.add_response() @@ -2593,7 +1583,6 @@ async def test_url_full_reassembly_span_streaming_async( sentry_init( integrations=[HttpxIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", **init_kwargs, ) @@ -2601,7 +1590,7 @@ async def test_url_full_reassembly_span_streaming_async( url = "http://example.com/?toy=tennisball&color=red&auth=secret#frag" - with sentry_sdk.traces.start_span(name="test"): + with sentry_sdk.start_span(name="test"): await httpx.AsyncClient().get(url) sentry_sdk.flush() @@ -2634,7 +1623,7 @@ async def test_url_full_reassembly_span_streaming_async( ), ], ) -def test_url_query_params_off_keeps_bare_url_span_streaming_sync( +def test_url_query_params_off_keeps_bare_url_sync( sentry_init, capture_items, httpx_mock, init_kwargs, expected_url_full ): httpx_mock.add_response() @@ -2642,7 +1631,6 @@ def test_url_query_params_off_keeps_bare_url_span_streaming_sync( sentry_init( integrations=[HttpxIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", **init_kwargs, ) @@ -2650,7 +1638,7 @@ def test_url_query_params_off_keeps_bare_url_span_streaming_sync( url = "http://example.com/?toy=tennisball&color=red&auth=secret#frag" - with sentry_sdk.traces.start_span(name="test"): + with sentry_sdk.start_span(name="test"): httpx.Client().get(url) sentry_sdk.flush() @@ -2691,7 +1679,7 @@ def test_url_query_params_off_keeps_bare_url_span_streaming_sync( ), ], ) -async def test_url_query_params_off_keeps_bare_url_span_streaming_async( +async def test_url_query_params_off_keeps_bare_url_async( sentry_init, capture_items, httpx_mock, init_kwargs, expected_url_full ): httpx_mock.add_response() @@ -2699,7 +1687,6 @@ async def test_url_query_params_off_keeps_bare_url_span_streaming_async( sentry_init( integrations=[HttpxIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", **init_kwargs, ) @@ -2707,7 +1694,7 @@ async def test_url_query_params_off_keeps_bare_url_span_streaming_async( url = "http://example.com/?toy=tennisball&color=red&auth=secret#frag" - with sentry_sdk.traces.start_span(name="test"): + with sentry_sdk.start_span(name="test"): await httpx.AsyncClient().get(url) sentry_sdk.flush() @@ -2761,7 +1748,7 @@ async def test_url_query_params_off_keeps_bare_url_span_streaming_async( ), ], ) -def test_crumb_url_query_data_collection_span_streaming_sync( +def test_crumb_url_query_data_collection_sync( sentry_init, capture_events, httpx_mock, @@ -2774,13 +1761,12 @@ def test_crumb_url_query_data_collection_span_streaming_sync( sentry_init( integrations=[HttpxIntegration()], - trace_lifecycle="stream", **init_kwargs, ) url = "http://example.com/?toy=tennisball&color=red&auth=secret#frag" - with sentry_sdk.traces.start_span(name="segment"): + with sentry_sdk.start_span(name="segment"): events = capture_events() httpx.Client().get(url) @@ -2838,7 +1824,7 @@ def test_crumb_url_query_data_collection_span_streaming_sync( ), ], ) -async def test_crumb_url_query_data_collection_span_streaming_async( +async def test_crumb_url_query_data_collection_async( sentry_init, capture_events, httpx_mock, @@ -2851,13 +1837,12 @@ async def test_crumb_url_query_data_collection_span_streaming_async( sentry_init( integrations=[HttpxIntegration()], - trace_lifecycle="stream", **init_kwargs, ) url = "http://example.com/?toy=tennisball&color=red&auth=secret#frag" - with sentry_sdk.traces.start_span(name="segment"): + with sentry_sdk.start_span(name="segment"): events = capture_events() await httpx.AsyncClient().get(url) @@ -2877,86 +1862,8 @@ async def test_crumb_url_query_data_collection_span_streaming_async( assert crumb["data"][SPANDATA.HTTP_FRAGMENT] == expected_fragment -@pytest.mark.parametrize( - "init_kwargs", - [ - pytest.param( - {"data_collection": {}}, - id="data_collection_denylist_default", - ), - pytest.param( - {"data_collection": {"url_query_params": {"mode": "off"}}}, - id="data_collection_off", - ), - ], -) -def test_crumb_url_query_unfiltered_legacy_sync( - sentry_init, capture_events, httpx_mock, init_kwargs -): - """ - Behaviour that existed prior to data collection and span streaming. - Remove when we've dropped transaction support and have fully migrated - to span streaming. - """ - httpx_mock.add_response() - - sentry_init(integrations=[HttpxIntegration()], **init_kwargs) - - url = "http://example.com/?toy=tennisball&color=red&auth=secret#frag" - - events = capture_events() - - httpx.Client().get(url) - capture_message("Testing!") - - (event,) = events - - crumb = event["breadcrumbs"]["values"][0] - - assert crumb["data"]["url"] == "http://example.com/" - assert crumb["data"][SPANDATA.HTTP_QUERY] == "toy=tennisball&color=red&auth=secret" - assert crumb["data"][SPANDATA.HTTP_FRAGMENT] == "frag" - - -@pytest.mark.asyncio -@pytest.mark.parametrize( - "init_kwargs", - [ - pytest.param( - {"data_collection": {}}, - id="data_collection_denylist_default", - ), - pytest.param( - {"data_collection": {"url_query_params": {"mode": "off"}}}, - id="data_collection_off", - ), - ], -) -async def test_crumb_url_query_unfiltered_legacy_async( - sentry_init, capture_events, httpx_mock, init_kwargs -): - httpx_mock.add_response() - - sentry_init(integrations=[HttpxIntegration()], **init_kwargs) - - url = "http://example.com/?toy=tennisball&color=red&auth=secret#frag" - - events = capture_events() - - await httpx.AsyncClient().get(url) - capture_message("Testing!") - - (event,) = events - - crumb = event["breadcrumbs"]["values"][0] - - assert crumb["data"]["url"] == "http://example.com/" - assert crumb["data"][SPANDATA.HTTP_QUERY] == "toy=tennisball&color=red&auth=secret" - assert crumb["data"][SPANDATA.HTTP_FRAGMENT] == "frag" - - @pytest.mark.tests_internal_exceptions -def test_omit_url_data_if_parsing_fails_span_streaming( +def test_omit_url_data_if_parsing_fails( sentry_init, capture_events, capture_items, httpx_mock ): httpx_mock.add_response() @@ -2964,7 +1871,6 @@ def test_omit_url_data_if_parsing_fails_span_streaming( sentry_init( integrations=[HttpxIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", data_collection={}, ) @@ -2972,7 +1878,7 @@ def test_omit_url_data_if_parsing_fails_span_streaming( url = "http://example.com/?toy=tennisball&color=red&auth=secret#frag" - with sentry_sdk.traces.start_span(name="segment"): + with sentry_sdk.start_span(name="segment"): events = capture_events() with mock.patch( diff --git a/tests/integrations/httpx2/test_httpx2.py b/tests/integrations/httpx2/test_httpx2.py index d0523bd05b..2008145bd0 100644 --- a/tests/integrations/httpx2/test_httpx2.py +++ b/tests/integrations/httpx2/test_httpx2.py @@ -5,54 +5,22 @@ import pytest import sentry_sdk -from sentry_sdk import capture_message, start_transaction +from sentry_sdk import capture_message from sentry_sdk.consts import MATCH_ALL, OP, SPANDATA from sentry_sdk.integrations.httpx2 import Httpx2Integration from tests.conftest import ApproxDict -def test_crumb_capture_and_hint_sync(sentry_init, capture_events, httpx2_mock): - httpx2_mock.add_response() - - def before_breadcrumb(crumb, hint): - crumb["data"]["extra"] = "foo" - return crumb - - sentry_init( - integrations=[Httpx2Integration()], - before_breadcrumb=before_breadcrumb, +def _get_http_client_span(items): + return next( + item.payload + for item in items + if item.payload.get("attributes", {}).get("sentry.op") == OP.HTTP_CLIENT ) - url = "http://example.com/" - - with start_transaction(): - events = capture_events() - - response = httpx2.Client().get(url) - - assert response.status_code == 200 - capture_message("Testing!") - - (event,) = events - - crumb = event["breadcrumbs"]["values"][0] - assert crumb["type"] == "http" - assert crumb["category"] == "httplib" - assert crumb["data"] == ApproxDict( - { - "url": url, - SPANDATA.HTTP_METHOD: "GET", - SPANDATA.HTTP_FRAGMENT: "", - SPANDATA.HTTP_QUERY: "", - SPANDATA.HTTP_STATUS_CODE: 200, - "reason": "OK", - "extra": "foo", - } - ) - @pytest.mark.parametrize("send_default_pii", [True, False]) -def test_crumb_capture_and_hint_sync_span_streaming( +def test_crumb_capture_and_hint_sync( sentry_init, capture_events, httpx2_mock, send_default_pii ): httpx2_mock.add_response() @@ -64,13 +32,12 @@ def before_breadcrumb(crumb, hint): sentry_init( integrations=[Httpx2Integration()], before_breadcrumb=before_breadcrumb, - trace_lifecycle="stream", send_default_pii=send_default_pii, ) url = "http://example.com/" - with sentry_sdk.traces.start_span(name="segment"): + with sentry_sdk.start_span(name="segment"): events = capture_events() response = httpx2.Client().get(url) @@ -107,47 +74,9 @@ def before_breadcrumb(crumb, hint): ) -@pytest.mark.asyncio -async def test_crumb_capture_and_hint_async(sentry_init, capture_events, httpx2_mock): - httpx2_mock.add_response() - - def before_breadcrumb(crumb, hint): - crumb["data"]["extra"] = "foo" - return crumb - - sentry_init(integrations=[Httpx2Integration()], before_breadcrumb=before_breadcrumb) - - url = "http://example.com/" - - with start_transaction(): - events = capture_events() - - response = await httpx2.AsyncClient().get(url) - - assert response.status_code == 200 - capture_message("Testing!") - - (event,) = events - - crumb = event["breadcrumbs"]["values"][0] - assert crumb["type"] == "http" - assert crumb["category"] == "httplib" - assert crumb["data"] == ApproxDict( - { - "url": url, - SPANDATA.HTTP_METHOD: "GET", - SPANDATA.HTTP_FRAGMENT: "", - SPANDATA.HTTP_QUERY: "", - SPANDATA.HTTP_STATUS_CODE: 200, - "reason": "OK", - "extra": "foo", - } - ) - - @pytest.mark.asyncio @pytest.mark.parametrize("send_default_pii", [True, False]) -async def test_crumb_capture_and_hint_async_span_streaming( +async def test_crumb_capture_and_hint_async( sentry_init, capture_events, httpx2_mock, send_default_pii ): httpx2_mock.add_response() @@ -159,13 +88,12 @@ def before_breadcrumb(crumb, hint): sentry_init( integrations=[Httpx2Integration()], before_breadcrumb=before_breadcrumb, - trace_lifecycle="stream", send_default_pii=send_default_pii, ) url = "http://example.com/" - with sentry_sdk.traces.start_span(name="segment"): + with sentry_sdk.start_span(name="segment"): events = capture_events() response = await httpx2.AsyncClient().get(url) @@ -217,42 +145,6 @@ def test_crumb_capture_without_span_sync(sentry_init, capture_events, httpx2_moc assert response.status_code == 200 capture_message("Testing!") - (event,) = events - - crumb = event["breadcrumbs"]["values"][0] - assert crumb["type"] == "http" - assert crumb["category"] == "httplib" - assert crumb["data"] == ApproxDict( - { - "url": url, - SPANDATA.HTTP_METHOD: "GET", - SPANDATA.HTTP_FRAGMENT: "", - SPANDATA.HTTP_QUERY: "", - SPANDATA.HTTP_STATUS_CODE: 200, - "reason": "OK", - } - ) - - -def test_crumb_capture_without_span_sync_span_streaming( - sentry_init, capture_events, httpx2_mock -): - httpx2_mock.add_response() - - sentry_init( - integrations=[Httpx2Integration()], - trace_lifecycle="stream", - ) - - url = "http://example.com/" - - events = capture_events() - - response = httpx2.Client().get(url) - - assert response.status_code == 200 - capture_message("Testing!") - sentry_sdk.flush() (event,) = events @@ -288,43 +180,6 @@ async def test_crumb_capture_without_span_async( assert response.status_code == 200 capture_message("Testing!") - (event,) = events - - crumb = event["breadcrumbs"]["values"][0] - assert crumb["type"] == "http" - assert crumb["category"] == "httplib" - assert crumb["data"] == ApproxDict( - { - "url": url, - SPANDATA.HTTP_METHOD: "GET", - SPANDATA.HTTP_FRAGMENT: "", - SPANDATA.HTTP_QUERY: "", - SPANDATA.HTTP_STATUS_CODE: 200, - "reason": "OK", - } - ) - - -@pytest.mark.asyncio -async def test_crumb_capture_without_span_async_span_streaming( - sentry_init, capture_events, httpx2_mock -): - httpx2_mock.add_response() - - sentry_init( - integrations=[Httpx2Integration()], - trace_lifecycle="stream", - ) - - url = "http://example.com/" - - events = capture_events() - - response = await httpx2.AsyncClient().get(url) - - assert response.status_code == 200 - capture_message("Testing!") - sentry_sdk.flush() (event,) = events @@ -341,55 +196,6 @@ async def test_crumb_capture_without_span_async_span_streaming( ) -@pytest.mark.parametrize( - "status_code,level", - [ - (200, None), - (301, None), - (403, "warning"), - (405, "warning"), - (500, "error"), - ], -) -def test_crumb_capture_client_error_sync( - sentry_init, capture_events, httpx2_mock, status_code, level -): - httpx2_mock.add_response(status_code=status_code) - - sentry_init(integrations=[Httpx2Integration()]) - - url = "http://example.com/" - - with start_transaction(): - events = capture_events() - - response = httpx2.Client().get(url) - - assert response.status_code == status_code - capture_message("Testing!") - - (event,) = events - - crumb = event["breadcrumbs"]["values"][0] - assert crumb["type"] == "http" - assert crumb["category"] == "httplib" - - if level is None: - assert "level" not in crumb - else: - assert crumb["level"] == level - - assert crumb["data"] == ApproxDict( - { - "url": url, - SPANDATA.HTTP_METHOD: "GET", - SPANDATA.HTTP_FRAGMENT: "", - SPANDATA.HTTP_QUERY: "", - SPANDATA.HTTP_STATUS_CODE: status_code, - } - ) - - @pytest.mark.parametrize( "status_code,level", [ @@ -401,20 +207,19 @@ def test_crumb_capture_client_error_sync( ], ) @pytest.mark.parametrize("send_default_pii", [True, False]) -def test_crumb_capture_client_error_sync_span_streaming( +def test_crumb_capture_client_error_sync( sentry_init, capture_events, httpx2_mock, status_code, level, send_default_pii ): httpx2_mock.add_response(status_code=status_code) sentry_init( integrations=[Httpx2Integration()], - trace_lifecycle="stream", send_default_pii=send_default_pii, ) url = "http://example.com/" - with sentry_sdk.traces.start_span(name="segment"): + with sentry_sdk.start_span(name="segment"): events = capture_events() response = httpx2.Client().get(url) @@ -452,56 +257,6 @@ def test_crumb_capture_client_error_sync_span_streaming( ) -@pytest.mark.asyncio -@pytest.mark.parametrize( - "status_code,level", - [ - (200, None), - (301, None), - (403, "warning"), - (405, "warning"), - (500, "error"), - ], -) -async def test_crumb_capture_client_error_async( - sentry_init, capture_events, httpx2_mock, status_code, level -): - httpx2_mock.add_response(status_code=status_code) - - sentry_init(integrations=[Httpx2Integration()]) - - url = "http://example.com/" - - with start_transaction(): - events = capture_events() - - response = await httpx2.AsyncClient().get(url) - - assert response.status_code == status_code - capture_message("Testing!") - - (event,) = events - - crumb = event["breadcrumbs"]["values"][0] - assert crumb["type"] == "http" - assert crumb["category"] == "httplib" - - if level is None: - assert "level" not in crumb - else: - assert crumb["level"] == level - - assert crumb["data"] == ApproxDict( - { - "url": url, - SPANDATA.HTTP_METHOD: "GET", - SPANDATA.HTTP_FRAGMENT: "", - SPANDATA.HTTP_QUERY: "", - SPANDATA.HTTP_STATUS_CODE: status_code, - } - ) - - @pytest.mark.asyncio @pytest.mark.parametrize( "status_code,level", @@ -514,20 +269,19 @@ async def test_crumb_capture_client_error_async( ], ) @pytest.mark.parametrize("send_default_pii", [True, False]) -async def test_crumb_capture_client_error_async_span_streaming( +async def test_crumb_capture_client_error_async( sentry_init, capture_events, httpx2_mock, status_code, level, send_default_pii ): httpx2_mock.add_response(status_code=status_code) sentry_init( integrations=[Httpx2Integration()], - trace_lifecycle="stream", send_default_pii=send_default_pii, ) url = "http://example.com/" - with sentry_sdk.traces.start_span(name="segment"): + with sentry_sdk.start_span(name="segment"): events = capture_events() response = await httpx2.AsyncClient().get(url) @@ -565,216 +319,6 @@ async def test_crumb_capture_client_error_async_span_streaming( ) -def test_outgoing_trace_headers_legacy_sync(sentry_init, httpx2_mock): - httpx2_mock.add_response() - - sentry_init( - traces_sample_rate=1.0, - integrations=[Httpx2Integration()], - ) - - url = "http://example.com/" - - with start_transaction( - name="/interactions/other-dogs/new-dog", - op="greeting.sniff", - trace_id="01234567890123456789012345678901", - ) as transaction: - response = httpx2.Client().get(url) - - request_span = transaction._span_recorder.spans[-1] - assert response.request.headers[ - "sentry-trace" - ] == "{trace_id}-{parent_span_id}-{sampled}".format( - trace_id=transaction.trace_id, - parent_span_id=request_span.span_id, - sampled=1, - ) - - -@pytest.mark.asyncio -async def test_outgoing_trace_headers_legacy_async(sentry_init, httpx2_mock): - httpx2_mock.add_response() - - sentry_init( - traces_sample_rate=1.0, - integrations=[Httpx2Integration()], - ) - - url = "http://example.com/" - - with start_transaction( - name="/interactions/other-dogs/new-dog", - op="greeting.sniff", - trace_id="01234567890123456789012345678901", - ) as transaction: - response = await httpx2.AsyncClient().get(url) - - request_span = transaction._span_recorder.spans[-1] - assert response.request.headers[ - "sentry-trace" - ] == "{trace_id}-{parent_span_id}-{sampled}".format( - trace_id=transaction.trace_id, - parent_span_id=request_span.span_id, - sampled=1, - ) - - -def test_outgoing_trace_headers_append_to_baggage_legacy_sync( - sentry_init, - httpx2_mock, -): - httpx2_mock.add_response() - - sentry_init( - traces_sample_rate=1.0, - integrations=[Httpx2Integration()], - release="d08ebdb9309e1b004c6f52202de58a09c2268e42", - ) - - url = "http://example.com/" - - # patch random.randrange to return a predictable sample_rand value - with mock.patch("sentry_sdk.tracing_utils.Random.randrange", return_value=500000): - with start_transaction( - name="/interactions/other-dogs/new-dog", - op="greeting.sniff", - trace_id="01234567890123456789012345678901", - ) as transaction: - response = httpx2.Client().get(url, headers={"baGGage": "custom=data"}) - - request_span = transaction._span_recorder.spans[-1] - assert response.request.headers[ - "sentry-trace" - ] == "{trace_id}-{parent_span_id}-{sampled}".format( - trace_id=transaction.trace_id, - parent_span_id=request_span.span_id, - sampled=1, - ) - assert ( - response.request.headers["baggage"] - == "custom=data,sentry-trace_id=01234567890123456789012345678901,sentry-sample_rand=0.500000,sentry-environment=production,sentry-release=d08ebdb9309e1b004c6f52202de58a09c2268e42,sentry-transaction=/interactions/other-dogs/new-dog,sentry-sample_rate=1.0,sentry-sampled=true" - ) - - -@pytest.mark.asyncio -async def test_outgoing_trace_headers_append_to_baggage_legacy_async( - sentry_init, - httpx2_mock, -): - httpx2_mock.add_response() - - sentry_init( - traces_sample_rate=1.0, - integrations=[Httpx2Integration()], - release="d08ebdb9309e1b004c6f52202de58a09c2268e42", - ) - - url = "http://example.com/" - - # patch random.randrange to return a predictable sample_rand value - with mock.patch("sentry_sdk.tracing_utils.Random.randrange", return_value=500000): - with start_transaction( - name="/interactions/other-dogs/new-dog", - op="greeting.sniff", - trace_id="01234567890123456789012345678901", - ) as transaction: - response = await httpx2.AsyncClient().get( - url, headers={"baGGage": "custom=data"} - ) - - request_span = transaction._span_recorder.spans[-1] - assert response.request.headers[ - "sentry-trace" - ] == "{trace_id}-{parent_span_id}-{sampled}".format( - trace_id=transaction.trace_id, - parent_span_id=request_span.span_id, - sampled=1, - ) - assert ( - response.request.headers["baggage"] - == "custom=data,sentry-trace_id=01234567890123456789012345678901,sentry-sample_rand=0.500000,sentry-environment=production,sentry-release=d08ebdb9309e1b004c6f52202de58a09c2268e42,sentry-transaction=/interactions/other-dogs/new-dog,sentry-sample_rate=1.0,sentry-sampled=true" - ) - - -@pytest.mark.parametrize( - "trace_propagation_targets,url,trace_propagated", - [ - [ - None, - "https://example.com/", - False, - ], - [ - [], - "https://example.com/", - False, - ], - [ - [MATCH_ALL], - "https://example.com/", - True, - ], - [ - ["https://example.com/"], - "https://example.com/", - True, - ], - [ - ["https://example.com/"], - "https://example.com", - False, - ], - [ - ["https://example.com"], - "https://example.com", - True, - ], - [ - ["https://example.com", r"https?:\/\/[\w\-]+(\.[\w\-]+)+\.net"], - "https://example.net", - False, - ], - [ - ["https://example.com", r"https?:\/\/[\w\-]+(\.[\w\-]+)+\.net"], - "https://good.example.net", - True, - ], - [ - ["https://example.com", r"https?:\/\/[\w\-]+(\.[\w\-]+)+\.net"], - "https://good.example.net/some/thing", - True, - ], - ], -) -def test_option_trace_propagation_targets_sync( - sentry_init, - httpx2_mock, - trace_propagation_targets, - url, - trace_propagated, -): - httpx2_mock.add_response() - - sentry_init( - release="test", - trace_propagation_targets=trace_propagation_targets, - traces_sample_rate=1.0, - integrations=[Httpx2Integration()], - ) - - with sentry_sdk.start_transaction(): - httpx2.Client().get(url) - - request_headers = httpx2_mock.get_request().headers - - if trace_propagated: - assert "sentry-trace" in request_headers - else: - assert "sentry-trace" not in request_headers - - -@pytest.mark.asyncio @pytest.mark.parametrize( "trace_propagation_targets,url,trace_propagated", [ @@ -814,645 +358,133 @@ def test_option_trace_propagation_targets_sync( False, ], [ - ["https://example.com", r"https?:\/\/[\w\-]+(\.[\w\-]+)+\.net"], - "https://good.example.net", - True, - ], - [ - ["https://example.com", r"https?:\/\/[\w\-]+(\.[\w\-]+)+\.net"], - "https://good.example.net/some/thing", - True, - ], - ], -) -async def test_option_trace_propagation_targets_async( - sentry_init, - httpx2_mock, - trace_propagation_targets, - url, - trace_propagated, -): - httpx2_mock.add_response() - - sentry_init( - release="test", - trace_propagation_targets=trace_propagation_targets, - traces_sample_rate=1.0, - integrations=[Httpx2Integration()], - ) - - with sentry_sdk.start_transaction(): - await httpx2.AsyncClient().get(url) - - request_headers = httpx2_mock.get_request().headers - - if trace_propagated: - assert "sentry-trace" in request_headers - else: - assert "sentry-trace" not in request_headers - - -def test_do_not_propagate_outside_transaction(sentry_init, httpx2_mock): - httpx2_mock.add_response() - - sentry_init( - traces_sample_rate=1.0, - trace_propagation_targets=[MATCH_ALL], - integrations=[Httpx2Integration()], - ) - - httpx2_client = httpx2.Client() - httpx2_client.get("http://example.com/") - - request_headers = httpx2_mock.get_request().headers - assert "sentry-trace" not in request_headers - - -@pytest.mark.tests_internal_exceptions -def test_omit_url_data_if_parsing_fails(sentry_init, capture_events, httpx2_mock): - httpx2_mock.add_response() - - sentry_init(integrations=[Httpx2Integration()]) - - httpx2_client = httpx2.Client() - url = "http://example.com" - - events = capture_events() - with mock.patch( - "sentry_sdk.integrations.httpx2.parse_url", - side_effect=ValueError, - ): - response = httpx2_client.get(url) - - assert response.status_code == 200 - capture_message("Testing!") - - (event,) = events - assert event["breadcrumbs"]["values"][0]["data"] == ApproxDict( - { - SPANDATA.HTTP_METHOD: "GET", - SPANDATA.HTTP_STATUS_CODE: 200, - "reason": "OK", - # no url related data - } - ) - - assert "url" not in event["breadcrumbs"]["values"][0]["data"] - assert SPANDATA.HTTP_FRAGMENT not in event["breadcrumbs"]["values"][0]["data"] - assert SPANDATA.HTTP_QUERY not in event["breadcrumbs"]["values"][0]["data"] - - -def test_request_source_disabled_legacy_sync(sentry_init, capture_events, httpx2_mock): - httpx2_mock.add_response() - sentry_options = { - "integrations": [Httpx2Integration()], - "traces_sample_rate": 1.0, - "enable_http_request_source": False, - "http_request_source_threshold_ms": 0, - } - - sentry_init(**sentry_options) - - events = capture_events() - - url = "http://example.com/" - - with start_transaction(name="test_transaction"): - httpx2.Client().get(url) - - (event,) = events - - span = event["spans"][-1] - assert span["description"].startswith("GET") - - data = span.get("data", {}) - - assert SPANDATA.CODE_LINENO not in data - assert SPANDATA.CODE_NAMESPACE not in data - assert SPANDATA.CODE_FILEPATH not in data - assert SPANDATA.CODE_FUNCTION not in data - - -@pytest.mark.asyncio -async def test_request_source_disabled_legacy_async( - sentry_init, capture_events, httpx2_mock -): - httpx2_mock.add_response() - sentry_options = { - "integrations": [Httpx2Integration()], - "traces_sample_rate": 1.0, - "enable_http_request_source": False, - "http_request_source_threshold_ms": 0, - } - - sentry_init(**sentry_options) - - events = capture_events() - - url = "http://example.com/" - - with start_transaction(name="test_transaction"): - await httpx2.AsyncClient().get(url) - - (event,) = events - - span = event["spans"][-1] - assert span["description"].startswith("GET") - - data = span.get("data", {}) - - assert SPANDATA.CODE_LINENO not in data - assert SPANDATA.CODE_NAMESPACE not in data - assert SPANDATA.CODE_FILEPATH not in data - assert SPANDATA.CODE_FUNCTION not in data - - -@pytest.mark.parametrize("enable_http_request_source", [None, True]) -def test_request_source_enabled_legacy_sync( - sentry_init, - capture_events, - enable_http_request_source, - httpx2_mock, -): - httpx2_mock.add_response() - sentry_options = { - "integrations": [Httpx2Integration()], - "traces_sample_rate": 1.0, - "http_request_source_threshold_ms": 0, - } - if enable_http_request_source is not None: - sentry_options["enable_http_request_source"] = enable_http_request_source - - sentry_init(**sentry_options) - - events = capture_events() - - url = "http://example.com/" - - with start_transaction(name="test_transaction"): - httpx2.Client().get(url) - - (event,) = events - - span = event["spans"][-1] - assert span["description"].startswith("GET") - - data = span.get("data", {}) - - assert SPANDATA.CODE_LINENO in data - assert SPANDATA.CODE_NAMESPACE in data - assert SPANDATA.CODE_FILEPATH in data - assert SPANDATA.CODE_FUNCTION in data - - -@pytest.mark.asyncio -@pytest.mark.parametrize("enable_http_request_source", [None, True]) -async def test_request_source_enabled_legacy_async( - sentry_init, - capture_events, - enable_http_request_source, - httpx2_mock, -): - httpx2_mock.add_response() - sentry_options = { - "integrations": [Httpx2Integration()], - "traces_sample_rate": 1.0, - "http_request_source_threshold_ms": 0, - } - if enable_http_request_source is not None: - sentry_options["enable_http_request_source"] = enable_http_request_source - - sentry_init(**sentry_options) - - events = capture_events() - - url = "http://example.com/" - - with start_transaction(name="test_transaction"): - await httpx2.AsyncClient().get(url) - - (event,) = events - - span = event["spans"][-1] - assert span["description"].startswith("GET") - - data = span.get("data", {}) - - assert SPANDATA.CODE_LINENO in data - assert SPANDATA.CODE_NAMESPACE in data - assert SPANDATA.CODE_FILEPATH in data - assert SPANDATA.CODE_FUNCTION in data - - -def test_request_source_legacy_sync(sentry_init, capture_events, httpx2_mock): - httpx2_mock.add_response() - - sentry_init( - integrations=[Httpx2Integration()], - traces_sample_rate=1.0, - enable_http_request_source=True, - http_request_source_threshold_ms=0, - ) - - events = capture_events() - - url = "http://example.com/" - - with start_transaction(name="test_transaction"): - httpx2.Client().get(url) - - (event,) = events - - span = event["spans"][-1] - assert span["description"].startswith("GET") - - data = span.get("data", {}) - - assert SPANDATA.CODE_LINENO in data - assert SPANDATA.CODE_NAMESPACE in data - assert SPANDATA.CODE_FILEPATH in data - assert SPANDATA.CODE_FUNCTION in data - - assert type(data.get(SPANDATA.CODE_LINENO)) == int - assert data.get(SPANDATA.CODE_LINENO) > 0 - assert data.get(SPANDATA.CODE_NAMESPACE) == "tests.integrations.httpx2.test_httpx2" - assert data.get(SPANDATA.CODE_FILEPATH).endswith( - "tests/integrations/httpx2/test_httpx2.py" - ) - - is_relative_path = data.get(SPANDATA.CODE_FILEPATH)[0] != os.sep - assert is_relative_path - - assert data.get(SPANDATA.CODE_FUNCTION) == "test_request_source_legacy_sync" - - -@pytest.mark.asyncio -async def test_request_source_legacy_async(sentry_init, capture_events, httpx2_mock): - httpx2_mock.add_response() - - sentry_init( - integrations=[Httpx2Integration()], - traces_sample_rate=1.0, - enable_http_request_source=True, - http_request_source_threshold_ms=0, - ) - - events = capture_events() - - url = "http://example.com/" - - with start_transaction(name="test_transaction"): - await httpx2.AsyncClient().get(url) - - (event,) = events - - span = event["spans"][-1] - assert span["description"].startswith("GET") - - data = span.get("data", {}) - - assert SPANDATA.CODE_LINENO in data - assert SPANDATA.CODE_NAMESPACE in data - assert SPANDATA.CODE_FILEPATH in data - assert SPANDATA.CODE_FUNCTION in data - - assert type(data.get(SPANDATA.CODE_LINENO)) == int - assert data.get(SPANDATA.CODE_LINENO) > 0 - assert data.get(SPANDATA.CODE_NAMESPACE) == "tests.integrations.httpx2.test_httpx2" - assert data.get(SPANDATA.CODE_FILEPATH).endswith( - "tests/integrations/httpx2/test_httpx2.py" - ) - - is_relative_path = data.get(SPANDATA.CODE_FILEPATH)[0] != os.sep - assert is_relative_path - - assert data.get(SPANDATA.CODE_FUNCTION) == "test_request_source_legacy_async" - - -def test_request_source_with_module_in_search_path_legacy_sync( - sentry_init, capture_events, httpx2_mock -): - """ - Test that request source is relative to the path of the module it ran in - """ - httpx2_mock.add_response() - sentry_init( - integrations=[Httpx2Integration()], - traces_sample_rate=1.0, - enable_http_request_source=True, - http_request_source_threshold_ms=0, - ) - - events = capture_events() - - url = "http://example.com/" - - with start_transaction(name="test_transaction"): - from httpx2_helpers.helpers import get_request_with_client - - get_request_with_client(httpx2.Client(), url) - - (event,) = events - - span = event["spans"][-1] - assert span["description"].startswith("GET") - - data = span.get("data", {}) - - assert SPANDATA.CODE_LINENO in data - assert SPANDATA.CODE_NAMESPACE in data - assert SPANDATA.CODE_FILEPATH in data - assert SPANDATA.CODE_FUNCTION in data - - assert type(data.get(SPANDATA.CODE_LINENO)) == int - assert data.get(SPANDATA.CODE_LINENO) > 0 - assert data.get(SPANDATA.CODE_NAMESPACE) == "httpx2_helpers.helpers" - assert data.get(SPANDATA.CODE_FILEPATH) == "httpx2_helpers/helpers.py" - - is_relative_path = data.get(SPANDATA.CODE_FILEPATH)[0] != os.sep - assert is_relative_path - - assert data.get(SPANDATA.CODE_FUNCTION) == "get_request_with_client" - - -@pytest.mark.asyncio -async def test_request_source_with_module_in_search_path_legacy_async( - sentry_init, capture_events, httpx2_mock -): - """ - Test that request source is relative to the path of the module it ran in - """ - httpx2_mock.add_response() - sentry_init( - integrations=[Httpx2Integration()], - traces_sample_rate=1.0, - enable_http_request_source=True, - http_request_source_threshold_ms=0, - ) - - events = capture_events() - - url = "http://example.com/" - - with start_transaction(name="test_transaction"): - from httpx2_helpers.helpers import async_get_request_with_client - - await async_get_request_with_client(httpx2.AsyncClient(), url) - - (event,) = events - - span = event["spans"][-1] - assert span["description"].startswith("GET") - - data = span.get("data", {}) - - assert SPANDATA.CODE_LINENO in data - assert SPANDATA.CODE_NAMESPACE in data - assert SPANDATA.CODE_FILEPATH in data - assert SPANDATA.CODE_FUNCTION in data - - assert type(data.get(SPANDATA.CODE_LINENO)) == int - assert data.get(SPANDATA.CODE_LINENO) > 0 - assert data.get(SPANDATA.CODE_NAMESPACE) == "httpx2_helpers.helpers" - assert data.get(SPANDATA.CODE_FILEPATH) == "httpx2_helpers/helpers.py" - - is_relative_path = data.get(SPANDATA.CODE_FILEPATH)[0] != os.sep - assert is_relative_path - - assert data.get(SPANDATA.CODE_FUNCTION) == "async_get_request_with_client" - - -def test_no_request_source_if_duration_too_short_legacy_sync( - sentry_init, capture_events, httpx2_mock -): - httpx2_mock.add_response() - - sentry_init( - integrations=[Httpx2Integration()], - traces_sample_rate=1.0, - enable_http_request_source=True, - # Threshold so high no real request will ever exceed it - http_request_source_threshold_ms=9999999, - ) - - events = capture_events() - - url = "http://example.com/" - - with start_transaction(name="test_transaction"): - httpx2.Client().get(url) - - (event,) = events - - span = event["spans"][-1] - assert span["description"].startswith("GET") - - data = span.get("data", {}) - - assert SPANDATA.CODE_LINENO not in data - assert SPANDATA.CODE_NAMESPACE not in data - assert SPANDATA.CODE_FILEPATH not in data - assert SPANDATA.CODE_FUNCTION not in data - - -@pytest.mark.asyncio -async def test_no_request_source_if_duration_too_short_legacy_async( - sentry_init, capture_events, httpx2_mock -): - httpx2_mock.add_response() - - sentry_init( - integrations=[Httpx2Integration()], - traces_sample_rate=1.0, - enable_http_request_source=True, - # Threshold so high no real request will ever exceed it - http_request_source_threshold_ms=9999999, - ) - - events = capture_events() - - url = "http://example.com/" - - with start_transaction(name="test_transaction"): - await httpx2.AsyncClient().get(url) - - (event,) = events - - span = event["spans"][-1] - assert span["description"].startswith("GET") - - data = span.get("data", {}) - - assert SPANDATA.CODE_LINENO not in data - assert SPANDATA.CODE_NAMESPACE not in data - assert SPANDATA.CODE_FILEPATH not in data - assert SPANDATA.CODE_FUNCTION not in data - - -def test_request_source_if_duration_over_threshold_legacy_sync( - sentry_init, capture_events, httpx2_mock + ["https://example.com", r"https?:\/\/[\w\-]+(\.[\w\-]+)+\.net"], + "https://good.example.net", + True, + ], + [ + ["https://example.com", r"https?:\/\/[\w\-]+(\.[\w\-]+)+\.net"], + "https://good.example.net/some/thing", + True, + ], + ], +) +def test_option_trace_propagation_targets_sync( + sentry_init, + httpx2_mock, + trace_propagation_targets, + url, + trace_propagated, ): httpx2_mock.add_response() sentry_init( - integrations=[Httpx2Integration()], + release="test", + trace_propagation_targets=trace_propagation_targets, traces_sample_rate=1.0, - enable_http_request_source=True, - # Threshold is low so any request will exceed it - http_request_source_threshold_ms=0, + integrations=[Httpx2Integration()], ) - events = capture_events() - - url = "http://example.com/" - - with start_transaction(name="test_transaction"): - httpx2.Client().get(url) - - (event,) = events - - span = event["spans"][-1] - assert span["description"].startswith("GET") - - data = span.get("data", {}) - - assert SPANDATA.CODE_LINENO in data - assert SPANDATA.CODE_NAMESPACE in data - assert SPANDATA.CODE_FILEPATH in data - assert SPANDATA.CODE_FUNCTION in data - - assert type(data.get(SPANDATA.CODE_LINENO)) == int - assert data.get(SPANDATA.CODE_LINENO) > 0 - assert data.get(SPANDATA.CODE_NAMESPACE) == "tests.integrations.httpx2.test_httpx2" - assert data.get(SPANDATA.CODE_FILEPATH).endswith( - "tests/integrations/httpx2/test_httpx2.py" - ) + httpx2.Client().get(url) - is_relative_path = data.get(SPANDATA.CODE_FILEPATH)[0] != os.sep - assert is_relative_path + request_headers = httpx2_mock.get_request().headers - assert ( - data.get(SPANDATA.CODE_FUNCTION) - == "test_request_source_if_duration_over_threshold_legacy_sync" - ) + if trace_propagated: + assert "sentry-trace" in request_headers + else: + assert "sentry-trace" not in request_headers @pytest.mark.asyncio -async def test_request_source_if_duration_over_threshold_legacy_async( - sentry_init, capture_events, httpx2_mock +@pytest.mark.parametrize( + "trace_propagation_targets,url,trace_propagated", + [ + [ + None, + "https://example.com/", + False, + ], + [ + [], + "https://example.com/", + False, + ], + [ + [MATCH_ALL], + "https://example.com/", + True, + ], + [ + ["https://example.com/"], + "https://example.com/", + True, + ], + [ + ["https://example.com/"], + "https://example.com", + False, + ], + [ + ["https://example.com"], + "https://example.com", + True, + ], + [ + ["https://example.com", r"https?:\/\/[\w\-]+(\.[\w\-]+)+\.net"], + "https://example.net", + False, + ], + [ + ["https://example.com", r"https?:\/\/[\w\-]+(\.[\w\-]+)+\.net"], + "https://good.example.net", + True, + ], + [ + ["https://example.com", r"https?:\/\/[\w\-]+(\.[\w\-]+)+\.net"], + "https://good.example.net/some/thing", + True, + ], + ], +) +async def test_option_trace_propagation_targets_async( + sentry_init, + httpx2_mock, + trace_propagation_targets, + url, + trace_propagated, ): httpx2_mock.add_response() sentry_init( - integrations=[Httpx2Integration()], - traces_sample_rate=1.0, - enable_http_request_source=True, - # Threshold is low so any request will exceed it - http_request_source_threshold_ms=0, - ) - - events = capture_events() - - url = "http://example.com/" - - with start_transaction(name="test_transaction"): - await httpx2.AsyncClient().get(url) - - (event,) = events - - span = event["spans"][-1] - assert span["description"].startswith("GET") - - data = span.get("data", {}) - - assert SPANDATA.CODE_LINENO in data - assert SPANDATA.CODE_NAMESPACE in data - assert SPANDATA.CODE_FILEPATH in data - assert SPANDATA.CODE_FUNCTION in data - - assert type(data.get(SPANDATA.CODE_LINENO)) == int - assert data.get(SPANDATA.CODE_LINENO) > 0 - assert data.get(SPANDATA.CODE_NAMESPACE) == "tests.integrations.httpx2.test_httpx2" - assert data.get(SPANDATA.CODE_FILEPATH).endswith( - "tests/integrations/httpx2/test_httpx2.py" - ) - - is_relative_path = data.get(SPANDATA.CODE_FILEPATH)[0] != os.sep - assert is_relative_path - - assert ( - data.get(SPANDATA.CODE_FUNCTION) - == "test_request_source_if_duration_over_threshold_legacy_async" - ) - - -def test_span_origin_legacy_sync(sentry_init, capture_events, httpx2_mock): - httpx2_mock.add_response() - - sentry_init( - integrations=[Httpx2Integration()], + release="test", + trace_propagation_targets=trace_propagation_targets, traces_sample_rate=1.0, - ) - - events = capture_events() - - url = "http://example.com/" - - with start_transaction(name="test_transaction"): - httpx2.Client().get(url) - - (event,) = events - - assert event["contexts"]["trace"]["origin"] == "manual" - assert event["spans"][0]["origin"] == "auto.http.httpx2" - - -@pytest.mark.asyncio -async def test_span_origin_legacy_async(sentry_init, capture_events, httpx2_mock): - httpx2_mock.add_response() - - sentry_init( integrations=[Httpx2Integration()], - traces_sample_rate=1.0, ) - events = capture_events() - - url = "http://example.com/" - - with start_transaction(name="test_transaction"): - await httpx2.AsyncClient().get(url) - - (event,) = events - - assert event["contexts"]["trace"]["origin"] == "manual" - assert event["spans"][0]["origin"] == "auto.http.httpx2" + await httpx2.AsyncClient().get(url) + request_headers = httpx2_mock.get_request().headers -def _get_http_client_span(items): - return next( - item.payload - for item in items - if item.payload.get("attributes", {}).get("sentry.op") == OP.HTTP_CLIENT - ) + if trace_propagated: + assert "sentry-trace" in request_headers + else: + assert "sentry-trace" not in request_headers -def test_outgoing_trace_headers_span_streaming_sync( - sentry_init, capture_items, httpx2_mock -): +def test_outgoing_trace_headers_sync(sentry_init, capture_items, httpx2_mock): httpx2_mock.add_response() sentry_init( traces_sample_rate=1.0, integrations=[Httpx2Integration()], - trace_lifecycle="stream", ) url = "http://example.com/" items = capture_items("span") - with sentry_sdk.traces.start_span(name="test"): + with sentry_sdk.start_span(name="test"): response = httpx2.Client().get(url) sentry_sdk.flush() @@ -1469,22 +501,19 @@ def test_outgoing_trace_headers_span_streaming_sync( @pytest.mark.asyncio -async def test_outgoing_trace_headers_span_streaming_async( - sentry_init, capture_items, httpx2_mock -): +async def test_outgoing_trace_headers_async(sentry_init, capture_items, httpx2_mock): httpx2_mock.add_response() sentry_init( traces_sample_rate=1.0, integrations=[Httpx2Integration()], - trace_lifecycle="stream", ) url = "http://example.com/" items = capture_items("span") - with sentry_sdk.traces.start_span(name="test"): + with sentry_sdk.start_span(name="test"): response = await httpx2.AsyncClient().get(url) sentry_sdk.flush() @@ -1500,7 +529,7 @@ async def test_outgoing_trace_headers_span_streaming_async( ) -def test_outgoing_trace_headers_append_to_baggage_span_streaming_sync( +def test_outgoing_trace_headers_append_to_baggage_sync( sentry_init, capture_items, httpx2_mock, @@ -1511,7 +540,6 @@ def test_outgoing_trace_headers_append_to_baggage_span_streaming_sync( traces_sample_rate=1.0, integrations=[Httpx2Integration()], release="d08ebdb9309e1b004c6f52202de58a09c2268e42", - trace_lifecycle="stream", ) url = "http://example.com/" @@ -1519,7 +547,7 @@ def test_outgoing_trace_headers_append_to_baggage_span_streaming_sync( items = capture_items("span") with mock.patch("sentry_sdk.tracing_utils.Random.randrange", return_value=500000): - with sentry_sdk.traces.start_span(name="test"): + with sentry_sdk.start_span(name="test"): response = httpx2.Client().get(url, headers={"baGGage": "custom=data"}) sentry_sdk.flush() @@ -1534,7 +562,7 @@ def test_outgoing_trace_headers_append_to_baggage_span_streaming_sync( @pytest.mark.asyncio -async def test_outgoing_trace_headers_append_to_baggage_span_streaming_async( +async def test_outgoing_trace_headers_append_to_baggage_async( sentry_init, capture_items, httpx2_mock, @@ -1545,7 +573,6 @@ async def test_outgoing_trace_headers_append_to_baggage_span_streaming_async( traces_sample_rate=1.0, integrations=[Httpx2Integration()], release="d08ebdb9309e1b004c6f52202de58a09c2268e42", - trace_lifecycle="stream", ) url = "http://example.com/" @@ -1553,7 +580,7 @@ async def test_outgoing_trace_headers_append_to_baggage_span_streaming_async( items = capture_items("span") with mock.patch("sentry_sdk.tracing_utils.Random.randrange", return_value=500000): - with sentry_sdk.traces.start_span(name="test"): + with sentry_sdk.start_span(name="test"): response = await httpx2.AsyncClient().get( url, headers={"baGGage": "custom=data"} ) @@ -1569,9 +596,7 @@ async def test_outgoing_trace_headers_append_to_baggage_span_streaming_async( assert "sentry-sampled=true" in baggage -def test_outgoing_trace_headers_span_streaming_no_current_span( - sentry_init, httpx2_mock -): +def test_outgoing_trace_headers_no_current_span(sentry_init, httpx2_mock): """ Even when there is no active span, trace propagation headers should still be attached to outgoing requests when span streaming is enabled. @@ -1588,15 +613,13 @@ def test_outgoing_trace_headers_span_streaming_no_current_span( traces_sample_rate=1.0, trace_propagation_targets=[MATCH_ALL], integrations=[Httpx2Integration()], - trace_lifecycle="stream", ) url = "http://example.com/" httpx2_client = httpx2.Client() - # No start_span / start_transaction -> get_current_span() is None - assert sentry_sdk.traces.get_current_span() is None + assert sentry_sdk.get_current_span() is None response = httpx2_client.get(url) @@ -1614,9 +637,7 @@ def test_outgoing_trace_headers_span_streaming_no_current_span( @pytest.mark.asyncio -async def test_outgoing_trace_headers_span_streaming_no_current_span_async( - sentry_init, httpx2_mock -): +async def test_outgoing_trace_headers_no_current_span_async(sentry_init, httpx2_mock): """ The async client must match the sync client: trace propagation headers are attached to outgoing requests even when there is no active span and span @@ -1628,15 +649,13 @@ async def test_outgoing_trace_headers_span_streaming_no_current_span_async( traces_sample_rate=1.0, trace_propagation_targets=[MATCH_ALL], integrations=[Httpx2Integration()], - trace_lifecycle="stream", ) url = "http://example.com/" httpx2_client = httpx2.AsyncClient() - # No start_span / start_transaction -> get_current_span() is None - assert sentry_sdk.traces.get_current_span() is None + assert sentry_sdk.get_current_span() is None response = await httpx2_client.get(url) @@ -1653,9 +672,7 @@ async def test_outgoing_trace_headers_span_streaming_no_current_span_async( assert f"sentry-trace_id={trace_id}" in request_headers["baggage"] -def test_request_source_disabled_span_streaming_sync( - sentry_init, capture_items, httpx2_mock -): +def test_request_source_disabled_sync(sentry_init, capture_items, httpx2_mock): httpx2_mock.add_response() sentry_init( @@ -1663,14 +680,13 @@ def test_request_source_disabled_span_streaming_sync( traces_sample_rate=1.0, enable_http_request_source=False, http_request_source_threshold_ms=0, - trace_lifecycle="stream", ) items = capture_items("span") url = "http://example.com/" - with sentry_sdk.traces.start_span(name="test"): + with sentry_sdk.start_span(name="test"): httpx2.Client().get(url) sentry_sdk.flush() @@ -1684,9 +700,7 @@ def test_request_source_disabled_span_streaming_sync( @pytest.mark.asyncio -async def test_request_source_disabled_span_streaming_async( - sentry_init, capture_items, httpx2_mock -): +async def test_request_source_disabled_async(sentry_init, capture_items, httpx2_mock): httpx2_mock.add_response() sentry_init( @@ -1694,14 +708,13 @@ async def test_request_source_disabled_span_streaming_async( traces_sample_rate=1.0, enable_http_request_source=False, http_request_source_threshold_ms=0, - trace_lifecycle="stream", ) items = capture_items("span") url = "http://example.com/" - with sentry_sdk.traces.start_span(name="test"): + with sentry_sdk.start_span(name="test"): await httpx2.AsyncClient().get(url) sentry_sdk.flush() @@ -1715,7 +728,7 @@ async def test_request_source_disabled_span_streaming_async( @pytest.mark.parametrize("enable_http_request_source", [None, True]) -def test_request_source_enabled_span_streaming_sync( +def test_request_source_enabled_sync( sentry_init, capture_items, enable_http_request_source, @@ -1727,7 +740,6 @@ def test_request_source_enabled_span_streaming_sync( "integrations": [Httpx2Integration()], "traces_sample_rate": 1.0, "http_request_source_threshold_ms": 0, - "trace_lifecycle": "stream", } if enable_http_request_source is not None: sentry_options["enable_http_request_source"] = enable_http_request_source @@ -1738,7 +750,7 @@ def test_request_source_enabled_span_streaming_sync( url = "http://example.com/" - with sentry_sdk.traces.start_span(name="test"): + with sentry_sdk.start_span(name="test"): httpx2.Client().get(url) sentry_sdk.flush() @@ -1753,7 +765,7 @@ def test_request_source_enabled_span_streaming_sync( @pytest.mark.asyncio @pytest.mark.parametrize("enable_http_request_source", [None, True]) -async def test_request_source_enabled_span_streaming_async( +async def test_request_source_enabled_async( sentry_init, capture_items, enable_http_request_source, @@ -1765,7 +777,6 @@ async def test_request_source_enabled_span_streaming_async( "integrations": [Httpx2Integration()], "traces_sample_rate": 1.0, "http_request_source_threshold_ms": 0, - "trace_lifecycle": "stream", } if enable_http_request_source is not None: sentry_options["enable_http_request_source"] = enable_http_request_source @@ -1776,7 +787,7 @@ async def test_request_source_enabled_span_streaming_async( url = "http://example.com/" - with sentry_sdk.traces.start_span(name="test"): + with sentry_sdk.start_span(name="test"): await httpx2.AsyncClient().get(url) sentry_sdk.flush() @@ -1789,7 +800,7 @@ async def test_request_source_enabled_span_streaming_async( assert SPANDATA.CODE_FUNCTION in http_span["attributes"] -def test_request_source_span_streaming_sync(sentry_init, capture_items, httpx2_mock): +def test_request_source_sync(sentry_init, capture_items, httpx2_mock): httpx2_mock.add_response() sentry_init( @@ -1797,14 +808,13 @@ def test_request_source_span_streaming_sync(sentry_init, capture_items, httpx2_m traces_sample_rate=1.0, enable_http_request_source=True, http_request_source_threshold_ms=0, - trace_lifecycle="stream", ) items = capture_items("span") url = "http://example.com/" - with sentry_sdk.traces.start_span(name="test"): + with sentry_sdk.start_span(name="test"): httpx2.Client().get(url) sentry_sdk.flush() @@ -1829,16 +839,11 @@ def test_request_source_span_streaming_sync(sentry_init, capture_items, httpx2_m is_relative_path = http_span["attributes"]["code.file.path"][0] != os.sep assert is_relative_path - assert ( - http_span["attributes"][SPANDATA.CODE_FUNCTION] - == "test_request_source_span_streaming_sync" - ) + assert http_span["attributes"][SPANDATA.CODE_FUNCTION] == "test_request_source_sync" @pytest.mark.asyncio -async def test_request_source_span_streaming_async( - sentry_init, capture_items, httpx2_mock -): +async def test_request_source_async(sentry_init, capture_items, httpx2_mock): httpx2_mock.add_response() sentry_init( @@ -1846,14 +851,13 @@ async def test_request_source_span_streaming_async( traces_sample_rate=1.0, enable_http_request_source=True, http_request_source_threshold_ms=0, - trace_lifecycle="stream", ) items = capture_items("span") url = "http://example.com/" - with sentry_sdk.traces.start_span(name="test"): + with sentry_sdk.start_span(name="test"): await httpx2.AsyncClient().get(url) sentry_sdk.flush() @@ -1879,12 +883,11 @@ async def test_request_source_span_streaming_async( assert is_relative_path assert ( - http_span["attributes"][SPANDATA.CODE_FUNCTION] - == "test_request_source_span_streaming_async" + http_span["attributes"][SPANDATA.CODE_FUNCTION] == "test_request_source_async" ) -def test_request_source_with_module_in_search_path_span_streaming_sync( +def test_request_source_with_module_in_search_path_sync( sentry_init, capture_items, httpx2_mock ): """ @@ -1897,14 +900,13 @@ def test_request_source_with_module_in_search_path_span_streaming_sync( traces_sample_rate=1.0, enable_http_request_source=True, http_request_source_threshold_ms=0, - trace_lifecycle="stream", ) items = capture_items("span") url = "http://example.com/" - with sentry_sdk.traces.start_span(name="test"): + with sentry_sdk.start_span(name="test"): from httpx2_helpers.helpers import get_request_with_client get_request_with_client(httpx2.Client(), url) @@ -1930,7 +932,7 @@ def test_request_source_with_module_in_search_path_span_streaming_sync( @pytest.mark.asyncio -async def test_request_source_with_module_in_search_path_span_streaming_async( +async def test_request_source_with_module_in_search_path_async( sentry_init, capture_items, httpx2_mock ): """ @@ -1943,14 +945,13 @@ async def test_request_source_with_module_in_search_path_span_streaming_async( traces_sample_rate=1.0, enable_http_request_source=True, http_request_source_threshold_ms=0, - trace_lifecycle="stream", ) items = capture_items("span") url = "http://example.com/" - with sentry_sdk.traces.start_span(name="test"): + with sentry_sdk.start_span(name="test"): from httpx2_helpers.helpers import async_get_request_with_client await async_get_request_with_client(httpx2.AsyncClient(), url) @@ -1978,7 +979,7 @@ async def test_request_source_with_module_in_search_path_span_streaming_async( ) -def test_no_request_source_if_duration_too_short_span_streaming_sync( +def test_no_request_source_if_duration_too_short_sync( sentry_init, capture_items, httpx2_mock ): httpx2_mock.add_response() @@ -1989,14 +990,13 @@ def test_no_request_source_if_duration_too_short_span_streaming_sync( enable_http_request_source=True, # Threshold so high no real request will ever exceed it http_request_source_threshold_ms=9999999, - trace_lifecycle="stream", ) items = capture_items("span") url = "http://example.com/" - with sentry_sdk.traces.start_span(name="test"): + with sentry_sdk.start_span(name="test"): httpx2.Client().get(url) sentry_sdk.flush() @@ -2010,7 +1010,7 @@ def test_no_request_source_if_duration_too_short_span_streaming_sync( @pytest.mark.asyncio -async def test_no_request_source_if_duration_too_short_span_streaming_async( +async def test_no_request_source_if_duration_too_short_async( sentry_init, capture_items, httpx2_mock ): httpx2_mock.add_response() @@ -2021,14 +1021,13 @@ async def test_no_request_source_if_duration_too_short_span_streaming_async( enable_http_request_source=True, # Threshold so high no real request will ever exceed it http_request_source_threshold_ms=9999999, - trace_lifecycle="stream", ) items = capture_items("span") url = "http://example.com/" - with sentry_sdk.traces.start_span(name="test"): + with sentry_sdk.start_span(name="test"): await httpx2.AsyncClient().get(url) sentry_sdk.flush() @@ -2041,7 +1040,7 @@ async def test_no_request_source_if_duration_too_short_span_streaming_async( assert SPANDATA.CODE_FUNCTION not in http_span["attributes"] -def test_request_source_if_duration_over_threshold_span_streaming_sync( +def test_request_source_if_duration_over_threshold_sync( sentry_init, capture_items, httpx2_mock ): httpx2_mock.add_response() @@ -2052,14 +1051,13 @@ def test_request_source_if_duration_over_threshold_span_streaming_sync( enable_http_request_source=True, # Threshold of 0 means any non-zero duration qualifies http_request_source_threshold_ms=0, - trace_lifecycle="stream", ) items = capture_items("span") url = "http://example.com/" - with sentry_sdk.traces.start_span(name="test"): + with sentry_sdk.start_span(name="test"): httpx2.Client().get(url) sentry_sdk.flush() @@ -2086,12 +1084,12 @@ def test_request_source_if_duration_over_threshold_span_streaming_sync( assert ( http_span["attributes"][SPANDATA.CODE_FUNCTION] - == "test_request_source_if_duration_over_threshold_span_streaming_sync" + == "test_request_source_if_duration_over_threshold_sync" ) @pytest.mark.asyncio -async def test_request_source_if_duration_over_threshold_span_streaming_async( +async def test_request_source_if_duration_over_threshold_async( sentry_init, capture_items, httpx2_mock ): httpx2_mock.add_response() @@ -2102,14 +1100,13 @@ async def test_request_source_if_duration_over_threshold_span_streaming_async( enable_http_request_source=True, # Threshold of 0 means any non-zero duration qualifies http_request_source_threshold_ms=0, - trace_lifecycle="stream", ) items = capture_items("span") url = "http://example.com/" - with sentry_sdk.traces.start_span(name="test"): + with sentry_sdk.start_span(name="test"): await httpx2.AsyncClient().get(url) sentry_sdk.flush() @@ -2136,24 +1133,23 @@ async def test_request_source_if_duration_over_threshold_span_streaming_async( assert ( http_span["attributes"][SPANDATA.CODE_FUNCTION] - == "test_request_source_if_duration_over_threshold_span_streaming_async" + == "test_request_source_if_duration_over_threshold_async" ) -def test_span_origin_span_streaming_sync(sentry_init, capture_items, httpx2_mock): +def test_span_origin_sync(sentry_init, capture_items, httpx2_mock): httpx2_mock.add_response() sentry_init( integrations=[Httpx2Integration()], traces_sample_rate=1.0, - trace_lifecycle="stream", ) items = capture_items("span") url = "http://example.com/" - with sentry_sdk.traces.start_span(name="test"): + with sentry_sdk.start_span(name="test"): httpx2.Client().get(url) sentry_sdk.flush() @@ -2164,22 +1160,19 @@ def test_span_origin_span_streaming_sync(sentry_init, capture_items, httpx2_mock @pytest.mark.asyncio -async def test_span_origin_span_streaming_async( - sentry_init, capture_items, httpx2_mock -): +async def test_span_origin_async(sentry_init, capture_items, httpx2_mock): httpx2_mock.add_response() sentry_init( integrations=[Httpx2Integration()], traces_sample_rate=1.0, - trace_lifecycle="stream", ) items = capture_items("span") url = "http://example.com/" - with sentry_sdk.traces.start_span(name="test"): + with sentry_sdk.start_span(name="test"): await httpx2.AsyncClient().get(url) sentry_sdk.flush() @@ -2189,23 +1182,20 @@ async def test_span_origin_span_streaming_async( assert http_span["attributes"]["sentry.origin"] == "auto.http.httpx2" -def test_http_url_attributes_span_streaming_sync( - sentry_init, capture_items, httpx2_mock -): +def test_http_url_attributes_sync(sentry_init, capture_items, httpx2_mock): httpx2_mock.add_response() sentry_init( integrations=[Httpx2Integration()], traces_sample_rate=1.0, send_default_pii=True, - trace_lifecycle="stream", ) items = capture_items("span") url = "http://example.com/?foo=bar#frag" - with sentry_sdk.traces.start_span(name="test"): + with sentry_sdk.start_span(name="test"): httpx2.Client().get(url) sentry_sdk.flush() @@ -2220,23 +1210,20 @@ def test_http_url_attributes_span_streaming_sync( @pytest.mark.asyncio -async def test_http_url_attributes_span_streaming_async( - sentry_init, capture_items, httpx2_mock -): +async def test_http_url_attributes_async(sentry_init, capture_items, httpx2_mock): httpx2_mock.add_response() sentry_init( integrations=[Httpx2Integration()], traces_sample_rate=1.0, send_default_pii=True, - trace_lifecycle="stream", ) items = capture_items("span") url = "http://example.com/?foo=bar#frag" - with sentry_sdk.traces.start_span(name="test"): + with sentry_sdk.start_span(name="test"): await httpx2.AsyncClient().get(url) sentry_sdk.flush() @@ -2250,7 +1237,7 @@ async def test_http_url_attributes_span_streaming_async( assert http_span["attributes"]["http.response.status_code"] == 200 -def test_http_url_attributes_no_query_or_fragment_span_streaming_sync( +def test_http_url_attributes_no_query_or_fragment_sync( sentry_init, capture_items, httpx2_mock ): httpx2_mock.add_response() @@ -2259,14 +1246,13 @@ def test_http_url_attributes_no_query_or_fragment_span_streaming_sync( integrations=[Httpx2Integration()], traces_sample_rate=1.0, send_default_pii=True, - trace_lifecycle="stream", ) items = capture_items("span") url = "http://example.com/" - with sentry_sdk.traces.start_span(name="test"): + with sentry_sdk.start_span(name="test"): httpx2.Client().get(url) sentry_sdk.flush() @@ -2281,7 +1267,7 @@ def test_http_url_attributes_no_query_or_fragment_span_streaming_sync( @pytest.mark.asyncio -async def test_http_url_attributes_no_query_or_fragment_span_streaming_async( +async def test_http_url_attributes_no_query_or_fragment_async( sentry_init, capture_items, httpx2_mock ): httpx2_mock.add_response() @@ -2290,14 +1276,13 @@ async def test_http_url_attributes_no_query_or_fragment_span_streaming_async( integrations=[Httpx2Integration()], traces_sample_rate=1.0, send_default_pii=True, - trace_lifecycle="stream", ) items = capture_items("span") url = "http://example.com/" - with sentry_sdk.traces.start_span(name="test"): + with sentry_sdk.start_span(name="test"): await httpx2.AsyncClient().get(url) sentry_sdk.flush() @@ -2311,22 +1296,19 @@ async def test_http_url_attributes_no_query_or_fragment_span_streaming_async( assert http_span["attributes"]["http.response.status_code"] == 200 -def test_http_url_attributes_pii_disabled_span_streaming_sync( - sentry_init, capture_items, httpx2_mock -): +def test_http_url_attributes_pii_disabled_sync(sentry_init, capture_items, httpx2_mock): httpx2_mock.add_response() sentry_init( integrations=[Httpx2Integration()], traces_sample_rate=1.0, - trace_lifecycle="stream", ) items = capture_items("span") url = "http://example.com/?foo=bar#frag" - with sentry_sdk.traces.start_span(name="test"): + with sentry_sdk.start_span(name="test"): httpx2.Client().get(url) sentry_sdk.flush() @@ -2341,7 +1323,7 @@ def test_http_url_attributes_pii_disabled_span_streaming_sync( @pytest.mark.asyncio -async def test_http_url_attributes_pii_disabled_span_streaming_async( +async def test_http_url_attributes_pii_disabled_async( sentry_init, capture_items, httpx2_mock ): httpx2_mock.add_response() @@ -2349,14 +1331,13 @@ async def test_http_url_attributes_pii_disabled_span_streaming_async( sentry_init( integrations=[Httpx2Integration()], traces_sample_rate=1.0, - trace_lifecycle="stream", ) items = capture_items("span") url = "http://example.com/?foo=bar#frag" - with sentry_sdk.traces.start_span(name="test"): + with sentry_sdk.start_span(name="test"): await httpx2.AsyncClient().get(url) sentry_sdk.flush() @@ -2435,7 +1416,7 @@ async def test_http_url_attributes_pii_disabled_span_streaming_async( ), ], ) -def test_url_query_data_collection_span_streaming_sync( +def test_url_query_data_collection_sync( sentry_init, capture_items, httpx2_mock, init_kwargs, expected_query ): httpx2_mock.add_response() @@ -2443,7 +1424,6 @@ def test_url_query_data_collection_span_streaming_sync( sentry_init( integrations=[Httpx2Integration()], traces_sample_rate=1.0, - trace_lifecycle="stream", **init_kwargs, ) @@ -2451,7 +1431,7 @@ def test_url_query_data_collection_span_streaming_sync( url = "http://example.com/?toy=tennisball&color=red&auth=secret#frag" - with sentry_sdk.traces.start_span(name="test"): + with sentry_sdk.start_span(name="test"): httpx2.Client().get(url) sentry_sdk.flush() @@ -2530,7 +1510,7 @@ def test_url_query_data_collection_span_streaming_sync( ), ], ) -async def test_url_query_data_collection_span_streaming_async( +async def test_url_query_data_collection_async( sentry_init, capture_items, httpx2_mock, init_kwargs, expected_query ): httpx2_mock.add_response() @@ -2538,7 +1518,6 @@ async def test_url_query_data_collection_span_streaming_async( sentry_init( integrations=[Httpx2Integration()], traces_sample_rate=1.0, - trace_lifecycle="stream", **init_kwargs, ) @@ -2546,7 +1525,7 @@ async def test_url_query_data_collection_span_streaming_async( url = "http://example.com/?toy=tennisball&color=red&auth=secret#frag" - with sentry_sdk.traces.start_span(name="test"): + with sentry_sdk.start_span(name="test"): await httpx2.AsyncClient().get(url) sentry_sdk.flush() @@ -2578,7 +1557,7 @@ async def test_url_query_data_collection_span_streaming_async( ), ], ) -def test_url_full_reassembly_span_streaming_sync( +def test_url_full_reassembly_sync( sentry_init, capture_items, httpx2_mock, init_kwargs, expected_url_full ): httpx2_mock.add_response() @@ -2586,7 +1565,6 @@ def test_url_full_reassembly_span_streaming_sync( sentry_init( integrations=[Httpx2Integration()], traces_sample_rate=1.0, - trace_lifecycle="stream", **init_kwargs, ) @@ -2594,7 +1572,7 @@ def test_url_full_reassembly_span_streaming_sync( url = "http://example.com/?toy=tennisball&color=red&auth=secret#frag" - with sentry_sdk.traces.start_span(name="test"): + with sentry_sdk.start_span(name="test"): httpx2.Client().get(url) sentry_sdk.flush() @@ -2624,7 +1602,7 @@ def test_url_full_reassembly_span_streaming_sync( ), ], ) -async def test_url_full_reassembly_span_streaming_async( +async def test_url_full_reassembly_async( sentry_init, capture_items, httpx2_mock, init_kwargs, expected_url_full ): httpx2_mock.add_response() @@ -2632,7 +1610,6 @@ async def test_url_full_reassembly_span_streaming_async( sentry_init( integrations=[Httpx2Integration()], traces_sample_rate=1.0, - trace_lifecycle="stream", **init_kwargs, ) @@ -2640,7 +1617,7 @@ async def test_url_full_reassembly_span_streaming_async( url = "http://example.com/?toy=tennisball&color=red&auth=secret#frag" - with sentry_sdk.traces.start_span(name="test"): + with sentry_sdk.start_span(name="test"): await httpx2.AsyncClient().get(url) sentry_sdk.flush() @@ -2673,7 +1650,7 @@ async def test_url_full_reassembly_span_streaming_async( ), ], ) -def test_url_query_params_off_keeps_bare_url_span_streaming_sync( +def test_url_query_params_off_keeps_bare_url_sync( sentry_init, capture_items, httpx2_mock, init_kwargs, expected_url_full ): httpx2_mock.add_response() @@ -2681,7 +1658,6 @@ def test_url_query_params_off_keeps_bare_url_span_streaming_sync( sentry_init( integrations=[Httpx2Integration()], traces_sample_rate=1.0, - trace_lifecycle="stream", **init_kwargs, ) @@ -2689,7 +1665,7 @@ def test_url_query_params_off_keeps_bare_url_span_streaming_sync( url = "http://example.com/?toy=tennisball&color=red&auth=secret#frag" - with sentry_sdk.traces.start_span(name="test"): + with sentry_sdk.start_span(name="test"): httpx2.Client().get(url) sentry_sdk.flush() @@ -2730,7 +1706,7 @@ def test_url_query_params_off_keeps_bare_url_span_streaming_sync( ), ], ) -async def test_url_query_params_off_keeps_bare_url_span_streaming_async( +async def test_url_query_params_off_keeps_bare_url_async( sentry_init, capture_items, httpx2_mock, init_kwargs, expected_url_full ): httpx2_mock.add_response() @@ -2738,7 +1714,6 @@ async def test_url_query_params_off_keeps_bare_url_span_streaming_async( sentry_init( integrations=[Httpx2Integration()], traces_sample_rate=1.0, - trace_lifecycle="stream", **init_kwargs, ) @@ -2746,7 +1721,7 @@ async def test_url_query_params_off_keeps_bare_url_span_streaming_async( url = "http://example.com/?toy=tennisball&color=red&auth=secret#frag" - with sentry_sdk.traces.start_span(name="test"): + with sentry_sdk.start_span(name="test"): await httpx2.AsyncClient().get(url) sentry_sdk.flush() @@ -2800,7 +1775,7 @@ async def test_url_query_params_off_keeps_bare_url_span_streaming_async( ), ], ) -def test_crumb_url_query_data_collection_span_streaming_sync( +def test_crumb_url_query_data_collection_sync( sentry_init, capture_events, httpx2_mock, @@ -2813,13 +1788,12 @@ def test_crumb_url_query_data_collection_span_streaming_sync( sentry_init( integrations=[Httpx2Integration()], - trace_lifecycle="stream", **init_kwargs, ) url = "http://example.com/?toy=tennisball&color=red&auth=secret#frag" - with sentry_sdk.traces.start_span(name="segment"): + with sentry_sdk.start_span(name="segment"): events = capture_events() httpx2.Client().get(url) @@ -2877,7 +1851,7 @@ def test_crumb_url_query_data_collection_span_streaming_sync( ), ], ) -async def test_crumb_url_query_data_collection_span_streaming_async( +async def test_crumb_url_query_data_collection_async( sentry_init, capture_events, httpx2_mock, @@ -2890,13 +1864,12 @@ async def test_crumb_url_query_data_collection_span_streaming_async( sentry_init( integrations=[Httpx2Integration()], - trace_lifecycle="stream", **init_kwargs, ) url = "http://example.com/?toy=tennisball&color=red&auth=secret#frag" - with sentry_sdk.traces.start_span(name="segment"): + with sentry_sdk.start_span(name="segment"): events = capture_events() await httpx2.AsyncClient().get(url) @@ -2916,86 +1889,8 @@ async def test_crumb_url_query_data_collection_span_streaming_async( assert crumb["data"][SPANDATA.HTTP_FRAGMENT] == expected_fragment -@pytest.mark.parametrize( - "init_kwargs", - [ - pytest.param( - {"data_collection": {}}, - id="data_collection_denylist_default", - ), - pytest.param( - {"data_collection": {"url_query_params": {"mode": "off"}}}, - id="data_collection_off", - ), - ], -) -def test_crumb_url_query_unfiltered_legacy_sync( - sentry_init, capture_events, httpx2_mock, init_kwargs -): - """ - Behaviour that existed prior to data collection and span streaming. - Remove when we've dropped transaction support and have fully migrated - to span streaming. - """ - httpx2_mock.add_response() - - sentry_init(integrations=[Httpx2Integration()], **init_kwargs) - - url = "http://example.com/?toy=tennisball&color=red&auth=secret#frag" - - events = capture_events() - - httpx2.Client().get(url) - capture_message("Testing!") - - (event,) = events - - crumb = event["breadcrumbs"]["values"][0] - - assert crumb["data"]["url"] == "http://example.com/" - assert crumb["data"][SPANDATA.HTTP_QUERY] == "toy=tennisball&color=red&auth=secret" - assert crumb["data"][SPANDATA.HTTP_FRAGMENT] == "frag" - - -@pytest.mark.asyncio -@pytest.mark.parametrize( - "init_kwargs", - [ - pytest.param( - {"data_collection": {}}, - id="data_collection_denylist_default", - ), - pytest.param( - {"data_collection": {"url_query_params": {"mode": "off"}}}, - id="data_collection_off", - ), - ], -) -async def test_crumb_url_query_unfiltered_legacy_async( - sentry_init, capture_events, httpx2_mock, init_kwargs -): - httpx2_mock.add_response() - - sentry_init(integrations=[Httpx2Integration()], **init_kwargs) - - url = "http://example.com/?toy=tennisball&color=red&auth=secret#frag" - - events = capture_events() - - await httpx2.AsyncClient().get(url) - capture_message("Testing!") - - (event,) = events - - crumb = event["breadcrumbs"]["values"][0] - - assert crumb["data"]["url"] == "http://example.com/" - assert crumb["data"][SPANDATA.HTTP_QUERY] == "toy=tennisball&color=red&auth=secret" - assert crumb["data"][SPANDATA.HTTP_FRAGMENT] == "frag" - - @pytest.mark.tests_internal_exceptions -def test_omit_url_data_if_parsing_fails_span_streaming( +def test_omit_url_data_if_parsing_fails( sentry_init, capture_events, capture_items, httpx2_mock ): httpx2_mock.add_response() @@ -3003,7 +1898,6 @@ def test_omit_url_data_if_parsing_fails_span_streaming( sentry_init( integrations=[Httpx2Integration()], traces_sample_rate=1.0, - trace_lifecycle="stream", data_collection={}, ) @@ -3011,7 +1905,7 @@ def test_omit_url_data_if_parsing_fails_span_streaming( url = "http://example.com/?toy=tennisball&color=red&auth=secret#frag" - with sentry_sdk.traces.start_span(name="segment"): + with sentry_sdk.start_span(name="segment"): events = capture_events() with mock.patch( diff --git a/tests/integrations/huey/test_huey.py b/tests/integrations/huey/test_huey.py index a81a348d87..d528307033 100644 --- a/tests/integrations/huey/test_huey.py +++ b/tests/integrations/huey/test_huey.py @@ -6,7 +6,6 @@ from huey.exceptions import CancelExecution, RetryTask import sentry_sdk -from sentry_sdk import start_transaction from sentry_sdk.consts import OP, SPANDATA from sentry_sdk.integrations.huey import HueyIntegration from sentry_sdk.traces import SegmentNameSource, SpanStatus @@ -24,12 +23,11 @@ @pytest.fixture def init_huey(sentry_init): - def inner(has_span_streaming=None, init_kwargs=None): + def inner(init_kwargs=None): sentry_init_kwargs = { "integrations": [HueyIntegration()], "traces_sample_rate": 1.0, "send_default_pii": True, - "trace_lifecycle": "stream" if has_span_streaming else "static", } sentry_init_kwargs.update(init_kwargs or {}) sentry_init(**sentry_init_kwargs) @@ -76,75 +74,35 @@ def increase(num): @pytest.mark.parametrize("task_fails", [True, False], ids=["error", "success"]) -@pytest.mark.parametrize( - "has_span_streaming", [True, False], ids=["streaming", "no_streaming"] -) -def test_task_transaction_or_segment( - capture_events, capture_items, init_huey, task_fails, has_span_streaming -): - huey = init_huey(has_span_streaming=has_span_streaming) +def test_task_segment(capture_items, init_huey, task_fails): + huey = init_huey() @huey.task() def division(a, b): return a / b - if has_span_streaming: - items = capture_items("span") - execute_huey_task( - huey, division, 1, int(not task_fails), exceptions=(DivisionByZero,) - ) - sentry_sdk.get_client().flush() - - payloads = [i.payload for i in items] - # The task is enqueued without a wrapping span, so in streaming mode no - # producer (queue.submit.huey) span is created (see the early return in - # patch_enqueue). Only the consumer segment is emitted. - assert len(payloads) == 1 - (execute_span,) = payloads - - assert execute_span["is_segment"] - assert execute_span["attributes"]["sentry.op"] == OP.QUEUE_TASK_HUEY - assert ( - execute_span["attributes"][SPANDATA.MESSAGING_DESTINATION_NAME] == huey.name - ) - assert execute_span["name"] == "division" - assert execute_span["status"] == ( - SpanStatus.ERROR if task_fails else SpanStatus.OK - ) - else: - events = capture_events() - execute_huey_task( - huey, division, 1, int(not task_fails), exceptions=(DivisionByZero,) - ) - - if task_fails: - error_event = events.pop(0) - assert error_event["exception"]["values"][0]["type"] == "ZeroDivisionError" - assert error_event["exception"]["values"][0]["mechanism"]["type"] == "huey" - - (event,) = events - assert event["type"] == "transaction" - assert event["transaction"] == "division" - assert event["transaction_info"] == {"source": "task"} - assert ( - event["contexts"]["trace"]["data"][SPANDATA.MESSAGING_DESTINATION_NAME] - == huey.name - ) - - if task_fails: - assert event["contexts"]["trace"]["status"] == "internal_error" - else: - assert event["contexts"]["trace"]["status"] == "ok" - - assert "huey_task_id" in event["tags"] - assert "huey_task_retry" in event["tags"] + items = capture_items("span") + execute_huey_task( + huey, division, 1, int(not task_fails), exceptions=(DivisionByZero,) + ) + sentry_sdk.get_client().flush() + payloads = [i.payload for i in items] + # The task is enqueued without a wrapping span, so in streaming mode no + # producer (queue.submit.huey) span is created (see the early return in + # patch_enqueue). Only the consumer segment is emitted. + assert len(payloads) == 1 + (execute_span,) = payloads -@pytest.mark.parametrize( - "has_span_streaming", [True, False], ids=["streaming", "no_streaming"] -) -def test_task_retry(capture_events, capture_items, init_huey, has_span_streaming): - huey = init_huey(has_span_streaming=has_span_streaming) + assert execute_span["is_segment"] + assert execute_span["attributes"]["sentry.op"] == OP.QUEUE_TASK_HUEY + assert execute_span["attributes"][SPANDATA.MESSAGING_DESTINATION_NAME] == huey.name + assert execute_span["name"] == "division" + assert execute_span["status"] == (SpanStatus.ERROR if task_fails else SpanStatus.OK) + + +def test_task_retry(capture_items, init_huey): + huey = init_huey() context = {"retry": True} @huey.task() @@ -153,108 +111,70 @@ def retry_task(context): context["retry"] = False raise RetryTask() - if has_span_streaming: - items = capture_items("span") - execute_huey_task(huey, retry_task, context) - sentry_sdk.get_client().flush() - - payloads = [i.payload for i in items] - # The initial enqueue happens without a wrapping span, so no producer - # span is created for it. The re-enqueue triggered by RetryTask happens - # inside the running consumer segment, so it does get a child span. - assert len(payloads) == 2 - - re_enqueue_span, execute_span = payloads + items = capture_items("span") + execute_huey_task(huey, retry_task, context) + sentry_sdk.get_client().flush() - assert re_enqueue_span["attributes"]["sentry.op"] == OP.QUEUE_SUBMIT_HUEY - assert not re_enqueue_span["is_segment"] + payloads = [i.payload for i in items] + # The initial enqueue happens without a wrapping span, so no producer + # span is created for it. The re-enqueue triggered by RetryTask happens + # inside the running consumer segment, so it does get a child span. + assert len(payloads) == 2 - assert execute_span["attributes"]["sentry.op"] == OP.QUEUE_TASK_HUEY - assert execute_span["is_segment"] - assert execute_span["name"] == "retry_task" - assert execute_span["status"] == SpanStatus.OK + re_enqueue_span, execute_span = payloads - assert len(huey) == 1 + assert re_enqueue_span["attributes"]["sentry.op"] == OP.QUEUE_SUBMIT_HUEY + assert not re_enqueue_span["is_segment"] - task = huey.dequeue() - huey.execute(task) + assert execute_span["attributes"]["sentry.op"] == OP.QUEUE_TASK_HUEY + assert execute_span["is_segment"] + assert execute_span["name"] == "retry_task" + assert execute_span["status"] == SpanStatus.OK - sentry_sdk.get_client().flush() + assert len(huey) == 1 - all_payloads = [i.payload for i in items] + task = huey.dequeue() + huey.execute(task) - assert len(all_payloads) == 3 - retry_span = all_payloads[2] + sentry_sdk.get_client().flush() - assert retry_span["is_segment"] - assert retry_span["name"] == "retry_task" - assert retry_span["status"] == SpanStatus.OK - assert len(huey) == 0 - else: - events = capture_events() - result = execute_huey_task(huey, retry_task, context) - (event,) = events + all_payloads = [i.payload for i in items] - assert event["transaction"] == "retry_task" - assert event["tags"]["huey_task_id"] == result.task.id - assert len(huey) == 1 + assert len(all_payloads) == 3 + retry_span = all_payloads[2] - task = huey.dequeue() - huey.execute(task) - (event, _) = events - - assert event["transaction"] == "retry_task" - assert event["tags"]["huey_task_id"] == result.task.id - assert len(huey) == 0 + assert retry_span["is_segment"] + assert retry_span["name"] == "retry_task" + assert retry_span["status"] == SpanStatus.OK + assert len(huey) == 0 -@pytest.mark.parametrize( - "has_span_streaming", [True, False], ids=["streaming", "no_streaming"] -) -def test_task_cancel_does_not_override_status( - capture_events, capture_items, init_huey, has_span_streaming -): - huey = init_huey(has_span_streaming=has_span_streaming) +def test_task_cancel_does_not_override_status(capture_items, init_huey): + huey = init_huey() @huey.task() def cancel_task(): raise CancelExecution() - if has_span_streaming: - items = capture_items("span") - execute_huey_task(huey, cancel_task) - sentry_sdk.get_client().flush() + items = capture_items("span") + execute_huey_task(huey, cancel_task) + sentry_sdk.get_client().flush() - payloads = [i.payload for i in items] - # Enqueued without a wrapping span -> no producer span in streaming mode. - assert len(payloads) == 1 - (execute_span,) = payloads - - assert execute_span["attributes"]["sentry.op"] == OP.QUEUE_TASK_HUEY - assert execute_span["is_segment"] - assert execute_span["name"] == "cancel_task" - assert execute_span["status"] == SpanStatus.OK - else: - events = capture_events() - execute_huey_task(huey, cancel_task) + payloads = [i.payload for i in items] + # Enqueued without a wrapping span -> no producer span in streaming mode. + assert len(payloads) == 1 + (execute_span,) = payloads - if HUEY_VERSION < (3, 0, 1): - (event, _) = events - else: - (event,) = events - assert event["transaction"] == "cancel_task" - assert event["contexts"]["trace"]["status"] == "aborted" + assert execute_span["attributes"]["sentry.op"] == OP.QUEUE_TASK_HUEY + assert execute_span["is_segment"] + assert execute_span["name"] == "cancel_task" + assert execute_span["status"] == SpanStatus.OK @pytest.mark.parametrize("lock_name", ["lock.a", "lock.b"], ids=["locked", "unlocked"]) -@pytest.mark.parametrize( - "has_span_streaming", [True, False], ids=["streaming", "no_streaming"] -) @pytest.mark.skipif(HUEY_VERSION < (2, 5), reason="is_locked was added in 2.5") -def test_task_lock( - capture_events, capture_items, init_huey, lock_name, has_span_streaming -): - huey = init_huey(has_span_streaming=has_span_streaming) +def test_task_lock(capture_items, init_huey, lock_name): + huey = init_huey() task_lock_name = "lock.a" should_be_locked = task_lock_name == lock_name @@ -264,39 +184,22 @@ def test_task_lock( def maybe_locked_task(): pass - if has_span_streaming: - items = capture_items("span") - with huey.lock_task(lock_name): - assert huey.is_locked(task_lock_name) == should_be_locked - execute_huey_task(huey, maybe_locked_task) - sentry_sdk.get_client().flush() - - payloads = [i.payload for i in items] - # Enqueued without a wrapping span -> no producer span in streaming mode. - assert len(payloads) == 1 - (execute_span,) = payloads - - assert execute_span["attributes"]["sentry.op"] == OP.QUEUE_TASK_HUEY - - assert execute_span["is_segment"] - assert execute_span["name"] == "maybe_locked_task" - assert execute_span["status"] == SpanStatus.OK - else: - events = capture_events() + items = capture_items("span") + with huey.lock_task(lock_name): + assert huey.is_locked(task_lock_name) == should_be_locked + execute_huey_task(huey, maybe_locked_task) + sentry_sdk.get_client().flush() - with huey.lock_task(lock_name): - assert huey.is_locked(task_lock_name) == should_be_locked - result = execute_huey_task(huey, maybe_locked_task) + payloads = [i.payload for i in items] + # Enqueued without a wrapping span -> no producer span in streaming mode. + assert len(payloads) == 1 + (execute_span,) = payloads - (event,) = events + assert execute_span["attributes"]["sentry.op"] == OP.QUEUE_TASK_HUEY - assert event["transaction"] == "maybe_locked_task" - assert event["tags"]["huey_task_id"] == result.task.id - assert ( - event["contexts"]["trace"]["status"] == "aborted" - if should_be_locked - else event["contexts"]["trace"]["status"] == "ok" - ) + assert execute_span["is_segment"] + assert execute_span["name"] == "maybe_locked_task" + assert execute_span["status"] == SpanStatus.OK assert len(huey) == 0 @@ -304,33 +207,23 @@ def maybe_locked_task(): "init_kwargs,expected_args,expected_kwargs", DATA_COLLECTION_QUEUES_CASES, ) -@pytest.mark.parametrize( - "has_span_streaming", [True, False], ids=["streaming", "no_streaming"] -) def test_task_args_kwargs_data_collection( - capture_events, capture_items, init_huey, - has_span_streaming, init_kwargs, expected_args, expected_kwargs, ): - huey = init_huey(has_span_streaming=has_span_streaming, init_kwargs=init_kwargs) + huey = init_huey(init_kwargs=init_kwargs) @huey.task() def division(a, b): return a / b - if has_span_streaming: - items = capture_items("event") - execute_huey_task(huey, division, 1, b=0, exceptions=(DivisionByZero,)) - sentry_sdk.get_client().flush() - events = [item.payload for item in items] - else: - events = capture_events() - execute_huey_task(huey, division, 1, b=0, exceptions=(DivisionByZero,)) - + items = capture_items("event") + execute_huey_task(huey, division, 1, b=0, exceptions=(DivisionByZero,)) + sentry_sdk.get_client().flush() + events = [item.payload for item in items] (event,) = [event for event in events if "exception" in event] huey_job = event["extra"]["huey-job"] @@ -343,69 +236,92 @@ def division(a, b): assert huey_job["kwargs"] == expected_kwargs -def test_huey_enqueue(init_huey, capture_events): +def test_huey_enqueue(init_huey, capture_items): huey = init_huey() @huey.task(name="different_task_name") def dummy_task(): pass - events = capture_events() + items = capture_items("span") - with start_transaction() as transaction: + with sentry_sdk.start_span(name="test"): dummy_task() - (event,) = events + sentry_sdk.get_client().flush() + + payloads = [i.payload for i in items] - assert event["contexts"]["trace"]["trace_id"] == transaction.trace_id - assert event["contexts"]["trace"]["span_id"] == transaction.span_id + enqueue_span = next( + p + for p in payloads + if p.get("attributes", {}).get("sentry.op") == OP.QUEUE_SUBMIT_HUEY + ) + segment_span = next(p for p in payloads if p.get("is_segment")) - assert len(event["spans"]) - assert event["spans"][0]["op"] == "queue.submit.huey" - assert event["spans"][0]["description"] == "different_task_name" - assert event["spans"][0]["data"][SPANDATA.MESSAGING_DESTINATION_NAME] == huey.name + assert enqueue_span["trace_id"] == segment_span["trace_id"] + assert enqueue_span["parent_span_id"] == segment_span["span_id"] + assert enqueue_span["name"] == "different_task_name" + assert enqueue_span["attributes"]["sentry.op"] == OP.QUEUE_SUBMIT_HUEY + assert enqueue_span["attributes"][SPANDATA.MESSAGING_DESTINATION_NAME] == huey.name -def test_huey_propagate_trace(init_huey, capture_events): +def test_huey_propagate_trace(init_huey, capture_items): huey = init_huey() - events = capture_events() + items = capture_items("span") @huey.task() def propagated_trace_task(): pass - with start_transaction() as outer_transaction: + with sentry_sdk.start_span(name="producer"): execute_huey_task(huey, propagated_trace_task) - assert ( - events[0]["transaction"] == "propagated_trace_task" - ) # the "inner" transaction - assert events[0]["contexts"]["trace"]["trace_id"] == outer_transaction.trace_id + sentry_sdk.get_client().flush() + + payloads = [i.payload for i in items] + + producer_span = next(p for p in payloads if p.get("name") == "producer") + execute_span = next( + p + for p in payloads + if p.get("attributes", {}).get("sentry.op") == OP.QUEUE_TASK_HUEY + ) + + assert execute_span["name"] == "propagated_trace_task" + assert execute_span["trace_id"] == producer_span["trace_id"] -def test_span_origin_producer(init_huey, capture_events): +def test_span_origin_producer(init_huey, capture_items): huey = init_huey() @huey.task(name="different_task_name") def dummy_task(): pass - events = capture_events() + items = capture_items("span") - with start_transaction(): + with sentry_sdk.start_span(name="test"): dummy_task() - (event,) = events + sentry_sdk.get_client().flush() - assert event["contexts"]["trace"]["origin"] == "manual" - assert event["spans"][0]["origin"] == "auto.queue.huey" + payloads = [i.payload for i in items] + enqueue_span = next( + p + for p in payloads + if p.get("attributes", {}).get("sentry.op") == OP.QUEUE_SUBMIT_HUEY + ) -def test_span_origin_consumer(init_huey, capture_events): + assert enqueue_span["attributes"]["sentry.origin"] == "auto.queue.huey" + + +def test_span_origin_consumer(init_huey, capture_items): huey = init_huey() - events = capture_events() + items = capture_items("span") @huey.task() def propagated_trace_task(): @@ -413,17 +329,22 @@ def propagated_trace_task(): execute_huey_task(huey, propagated_trace_task) - (event,) = events + sentry_sdk.get_client().flush() + + payloads = [i.payload for i in items] + + execute_span = next( + p + for p in payloads + if p.get("attributes", {}).get("sentry.op") == OP.QUEUE_TASK_HUEY + ) - assert event["contexts"]["trace"]["origin"] == "auto.queue.huey" + assert execute_span["attributes"]["sentry.origin"] == "auto.queue.huey" -@pytest.mark.parametrize("has_span_streaming", [True, False]) @pytest.mark.skipif(HUEY_VERSION < (3, 0), reason="group was added in 3.0") -def test_huey_enqueue_group( - init_huey, capture_events, capture_items, has_span_streaming -): - huey = init_huey(has_span_streaming=has_span_streaming) +def test_huey_enqueue_group(init_huey, capture_items): + huey = init_huey() @huey.task() def task1(): @@ -433,130 +354,85 @@ def task1(): def task2(): pass - if has_span_streaming: - items = capture_items("span") + items = capture_items("span") - with sentry_sdk.traces.start_span(name="submission"): - huey.enqueue(group([task1.s(), task2.s()])) - - for _ in range(2): - task = huey.dequeue() - huey.execute(task) + with sentry_sdk.start_span(name="submission"): + huey.enqueue(group([task1.s(), task2.s()])) - sentry_sdk.get_client().flush() - assert len(items) == 6 - - ( - task1_enqueue_span, - task2_enqueue_span, - group_span, - submission_span, - task1_execute_span, - task2_execute_span, - ) = [i.payload for i in items] - - # The enqueue happens inside a wrapping span, so the group producer - # tree is created and parented under that segment. - assert submission_span["is_segment"] - assert submission_span["name"] == "submission" - assert not group_span["is_segment"] - assert not task1_enqueue_span["is_segment"] - assert not task2_enqueue_span["is_segment"] - assert task1_execute_span["is_segment"] - assert task2_execute_span["is_segment"] - - assert group_span["parent_span_id"] == submission_span["span_id"] - assert group_span["name"] == "Huey Task Group" - assert group_span["status"] == "ok" - assert group_span["attributes"]["sentry.op"] == "queue.submit.huey" - assert group_span["attributes"]["sentry.origin"] == "auto.queue.huey" - - assert task1_enqueue_span["name"] == "task1" - assert task1_enqueue_span["status"] == "ok" - assert task1_enqueue_span["parent_span_id"] == group_span["span_id"] - assert task1_enqueue_span["attributes"]["sentry.segment.name"] == "submission" - assert task1_enqueue_span["attributes"]["sentry.op"] == "queue.submit.huey" - assert task1_enqueue_span["attributes"]["sentry.origin"] == "auto.queue.huey" - - assert task2_enqueue_span["name"] == "task2" - assert task2_enqueue_span["status"] == "ok" - assert task2_enqueue_span["parent_span_id"] == group_span["span_id"] - assert task2_enqueue_span["attributes"]["sentry.segment.name"] == "submission" - assert task2_enqueue_span["attributes"]["sentry.op"] == "queue.submit.huey" - assert task2_enqueue_span["attributes"]["sentry.origin"] == "auto.queue.huey" - - assert task1_execute_span["name"] == "task1" - assert task1_execute_span["status"] == "ok" - assert task1_execute_span["attributes"]["messaging.message.system"] == "huey" - assert task1_execute_span["parent_span_id"] == task1_enqueue_span["span_id"] - assert task1_execute_span["attributes"]["sentry.op"] == "queue.task.huey" - assert task1_execute_span["attributes"]["sentry.origin"] == "auto.queue.huey" - assert ( - task1_execute_span["attributes"]["sentry.segment.name.source"] - == SegmentNameSource.TASK - ) - assert task1_execute_span["attributes"]["messaging.message.id"] is not None - assert task1_execute_span["attributes"]["messaging.message.retry.count"] == 0 - - assert task2_execute_span["name"] == "task2" - assert task2_execute_span["status"] == "ok" - assert task2_execute_span["parent_span_id"] == task2_enqueue_span["span_id"] - assert task2_execute_span["attributes"]["messaging.message.system"] == "huey" - assert task2_execute_span["attributes"]["sentry.op"] == "queue.task.huey" - assert task2_execute_span["attributes"]["sentry.origin"] == "auto.queue.huey" - assert ( - task2_execute_span["attributes"]["sentry.segment.name.source"] - == SegmentNameSource.TASK - ) + for _ in range(2): + task = huey.dequeue() + huey.execute(task) - else: - events = capture_events() - with start_transaction() as transaction: - huey.enqueue(group([task1.s(), task2.s()])) + sentry_sdk.get_client().flush() + assert len(items) == 6 + + ( + task1_enqueue_span, + task2_enqueue_span, + group_span, + submission_span, + task1_execute_span, + task2_execute_span, + ) = [i.payload for i in items] + + # The enqueue happens inside a wrapping span, so the group producer + # tree is created and parented under that segment. + assert submission_span["is_segment"] + assert submission_span["name"] == "submission" + assert not group_span["is_segment"] + assert not task1_enqueue_span["is_segment"] + assert not task2_enqueue_span["is_segment"] + assert task1_execute_span["is_segment"] + assert task2_execute_span["is_segment"] + + assert group_span["parent_span_id"] == submission_span["span_id"] + assert group_span["name"] == "Huey Task Group" + assert group_span["status"] == "ok" + assert group_span["attributes"]["sentry.op"] == "queue.submit.huey" + assert group_span["attributes"]["sentry.origin"] == "auto.queue.huey" + + assert task1_enqueue_span["name"] == "task1" + assert task1_enqueue_span["status"] == "ok" + assert task1_enqueue_span["parent_span_id"] == group_span["span_id"] + assert task1_enqueue_span["attributes"]["sentry.segment.name"] == "submission" + assert task1_enqueue_span["attributes"]["sentry.op"] == "queue.submit.huey" + assert task1_enqueue_span["attributes"]["sentry.origin"] == "auto.queue.huey" + + assert task2_enqueue_span["name"] == "task2" + assert task2_enqueue_span["status"] == "ok" + assert task2_enqueue_span["parent_span_id"] == group_span["span_id"] + assert task2_enqueue_span["attributes"]["sentry.segment.name"] == "submission" + assert task2_enqueue_span["attributes"]["sentry.op"] == "queue.submit.huey" + assert task2_enqueue_span["attributes"]["sentry.origin"] == "auto.queue.huey" + + assert task1_execute_span["name"] == "task1" + assert task1_execute_span["status"] == "ok" + assert task1_execute_span["attributes"]["messaging.message.system"] == "huey" + assert task1_execute_span["parent_span_id"] == task1_enqueue_span["span_id"] + assert task1_execute_span["attributes"]["sentry.op"] == "queue.task.huey" + assert task1_execute_span["attributes"]["sentry.origin"] == "auto.queue.huey" + assert ( + task1_execute_span["attributes"]["sentry.segment.name.source"] + == SegmentNameSource.TASK + ) + assert task1_execute_span["attributes"]["messaging.message.id"] is not None + assert task1_execute_span["attributes"]["messaging.message.retry.count"] == 0 + + assert task2_execute_span["name"] == "task2" + assert task2_execute_span["status"] == "ok" + assert task2_execute_span["parent_span_id"] == task2_enqueue_span["span_id"] + assert task2_execute_span["attributes"]["messaging.message.system"] == "huey" + assert task2_execute_span["attributes"]["sentry.op"] == "queue.task.huey" + assert task2_execute_span["attributes"]["sentry.origin"] == "auto.queue.huey" + assert ( + task2_execute_span["attributes"]["sentry.segment.name.source"] + == SegmentNameSource.TASK + ) - for _ in range(2): - task = huey.dequeue() - huey.execute(task) - assert len(events) == 3 - - # Assert enqueue spans were successfully recorded - producer_event = events[0] - assert producer_event["type"] == "transaction" - assert producer_event["contexts"]["trace"]["trace_id"] == transaction.trace_id - assert producer_event["contexts"]["trace"]["origin"] == "manual" - - spans = producer_event["spans"] - assert len(spans) == 3 - assert spans[0]["op"] == "queue.submit.huey" - assert spans[0]["description"] == "Huey Task Group" - assert spans[1]["op"] == "queue.submit.huey" - assert spans[1]["description"] == "task1" - assert spans[2]["op"] == "queue.submit.huey" - assert spans[2]["description"] == "task2" - - # Consumer transaction assertions (one per task) - consumer_events = events[1:] - for consumer_event, expected_name in zip(consumer_events, ["task1", "task2"]): - assert consumer_event["type"] == "transaction" - assert consumer_event["transaction"] == expected_name - assert consumer_event["transaction_info"] == {"source": "task"} - assert consumer_event["contexts"]["trace"]["op"] == "queue.task.huey" - assert consumer_event["contexts"]["trace"]["origin"] == "auto.queue.huey" - assert consumer_event["contexts"]["trace"]["status"] == "ok" - assert ( - consumer_event["contexts"]["trace"]["trace_id"] == transaction.trace_id - ) - assert "huey_task_id" in consumer_event["tags"] - assert consumer_event["tags"]["huey_task_retry"] is False - - -@pytest.mark.parametrize("has_span_streaming", [True, False]) @pytest.mark.skipif(HUEY_VERSION < (3, 0), reason="chord was added in 3.0") -def test_huey_enqueue_chord( - init_huey, capture_events, capture_items, has_span_streaming -): - huey = init_huey(has_span_streaming=has_span_streaming) +def test_huey_enqueue_chord(init_huey, capture_items): + huey = init_huey() @huey.task() def task1(): @@ -566,123 +442,74 @@ def task1(): def task2(results): pass - if has_span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="submission"): - huey.enqueue(chord([task1.s()], task2.s())) + items = capture_items("span") + with sentry_sdk.start_span(name="submission"): + huey.enqueue(chord([task1.s()], task2.s())) - for _ in range(2): - task = huey.dequeue() - huey.execute(task) - - sentry_sdk.get_client().flush() - assert len(items) == 6 - - ( - task1_enqueue_span, - chord_span, - submission_span, - task2_enqueue_span, - task1_execute_span, - task2_execute_span, - ) = [i.payload for i in items] - - # The enqueue happens inside a wrapping span, so the chord producer - # tree is created and parented under that segment. - assert submission_span["is_segment"] - assert submission_span["name"] == "submission" - assert not chord_span["is_segment"] - assert not task1_enqueue_span["is_segment"] - assert not task2_enqueue_span["is_segment"] - assert task1_execute_span["is_segment"] - assert task2_execute_span["is_segment"] - - assert chord_span["parent_span_id"] == submission_span["span_id"] - assert chord_span["name"] == "Huey Chord" - assert chord_span["status"] == "ok" - assert chord_span["attributes"]["sentry.op"] == "queue.submit.huey" - assert chord_span["attributes"]["sentry.origin"] == "auto.queue.huey" - - assert task1_enqueue_span["name"] == "task1" - assert task1_enqueue_span["status"] == "ok" - assert task1_enqueue_span["parent_span_id"] == chord_span["span_id"] - assert task1_enqueue_span["attributes"]["sentry.segment.name"] == "submission" - assert task1_enqueue_span["attributes"]["sentry.op"] == "queue.submit.huey" - assert task1_enqueue_span["attributes"]["sentry.origin"] == "auto.queue.huey" - - assert task1_execute_span["name"] == "task1" - assert task1_execute_span["status"] == "ok" - assert task1_execute_span["attributes"]["messaging.message.system"] == "huey" - assert task1_execute_span["parent_span_id"] == task1_enqueue_span["span_id"] - assert task1_execute_span["attributes"]["sentry.op"] == "queue.task.huey" - assert task1_execute_span["attributes"]["sentry.origin"] == "auto.queue.huey" - assert ( - task1_execute_span["attributes"]["sentry.segment.name.source"] - == SegmentNameSource.TASK - ) - # chord callback (task2) is enqueued during task1's execution - assert task2_enqueue_span["name"] == "task2" - assert task2_enqueue_span["status"] == "ok" - assert task2_enqueue_span["parent_span_id"] == task1_execute_span["span_id"] - assert task2_enqueue_span["attributes"]["sentry.segment.name"] == "task1" - assert task2_enqueue_span["attributes"]["sentry.op"] == "queue.submit.huey" - assert task2_enqueue_span["attributes"]["sentry.origin"] == "auto.queue.huey" - - assert task2_execute_span["name"] == "task2" - assert task2_execute_span["status"] == "ok" - assert task2_execute_span["parent_span_id"] == task2_enqueue_span["span_id"] - assert task2_execute_span["attributes"]["messaging.message.system"] == "huey" - assert task2_execute_span["attributes"]["sentry.op"] == "queue.task.huey" - assert task2_execute_span["attributes"]["sentry.origin"] == "auto.queue.huey" - assert ( - task2_execute_span["attributes"]["sentry.segment.name.source"] - == SegmentNameSource.TASK - ) - else: - events = capture_events() - with start_transaction() as transaction: - huey.enqueue(chord([task1.s()], task2.s())) - - for _ in range(2): - task = huey.dequeue() - huey.execute(task) + for _ in range(2): + task = huey.dequeue() + huey.execute(task) - assert len(events) == 3 - - # Enqueue spans - producer_event = events[0] - assert producer_event["contexts"]["trace"]["trace_id"] == transaction.trace_id - assert producer_event["contexts"]["trace"]["origin"] == "manual" - - spans = producer_event["spans"] - assert len(spans) == 2 - assert spans[0]["op"] == "queue.submit.huey" - assert spans[0]["description"] == "Huey Chord" - assert spans[1]["op"] == "queue.submit.huey" - assert spans[1]["description"] == "task1" - - task1_event = events[1] - # Confirm the first task enqueued the chord callback - assert len(task1_event["spans"]) == 1 - assert task1_event["spans"][0]["op"] == "queue.submit.huey" - assert task1_event["spans"][0]["description"] == "task2" - assert task1_event["type"] == "transaction" - assert task1_event["transaction"] == "task1" - assert task1_event["transaction_info"] == {"source": "task"} - assert task1_event["contexts"]["trace"]["op"] == "queue.task.huey" - assert task1_event["contexts"]["trace"]["origin"] == "auto.queue.huey" - assert task1_event["contexts"]["trace"]["status"] == "ok" - assert task1_event["contexts"]["trace"]["trace_id"] == transaction.trace_id - assert "huey_task_id" in task1_event["tags"] - assert task1_event["tags"]["huey_task_retry"] is False - - task2_event = events[2] - assert task2_event["type"] == "transaction" - assert task2_event["transaction"] == "task2" - assert task2_event["transaction_info"] == {"source": "task"} - assert task2_event["contexts"]["trace"]["op"] == "queue.task.huey" - assert task2_event["contexts"]["trace"]["origin"] == "auto.queue.huey" - assert task2_event["contexts"]["trace"]["status"] == "ok" - assert task2_event["contexts"]["trace"]["trace_id"] == transaction.trace_id - assert "huey_task_id" in task2_event["tags"] - assert task2_event["tags"]["huey_task_retry"] is False + sentry_sdk.get_client().flush() + assert len(items) == 6 + + ( + task1_enqueue_span, + chord_span, + submission_span, + task2_enqueue_span, + task1_execute_span, + task2_execute_span, + ) = [i.payload for i in items] + + # The enqueue happens inside a wrapping span, so the chord producer + # tree is created and parented under that segment. + assert submission_span["is_segment"] + assert submission_span["name"] == "submission" + assert not chord_span["is_segment"] + assert not task1_enqueue_span["is_segment"] + assert not task2_enqueue_span["is_segment"] + assert task1_execute_span["is_segment"] + assert task2_execute_span["is_segment"] + + assert chord_span["parent_span_id"] == submission_span["span_id"] + assert chord_span["name"] == "Huey Chord" + assert chord_span["status"] == "ok" + assert chord_span["attributes"]["sentry.op"] == "queue.submit.huey" + assert chord_span["attributes"]["sentry.origin"] == "auto.queue.huey" + + assert task1_enqueue_span["name"] == "task1" + assert task1_enqueue_span["status"] == "ok" + assert task1_enqueue_span["parent_span_id"] == chord_span["span_id"] + assert task1_enqueue_span["attributes"]["sentry.segment.name"] == "submission" + assert task1_enqueue_span["attributes"]["sentry.op"] == "queue.submit.huey" + assert task1_enqueue_span["attributes"]["sentry.origin"] == "auto.queue.huey" + + assert task1_execute_span["name"] == "task1" + assert task1_execute_span["status"] == "ok" + assert task1_execute_span["attributes"]["messaging.message.system"] == "huey" + assert task1_execute_span["parent_span_id"] == task1_enqueue_span["span_id"] + assert task1_execute_span["attributes"]["sentry.op"] == "queue.task.huey" + assert task1_execute_span["attributes"]["sentry.origin"] == "auto.queue.huey" + assert ( + task1_execute_span["attributes"]["sentry.segment.name.source"] + == SegmentNameSource.TASK + ) + # chord callback (task2) is enqueued during task1's execution + assert task2_enqueue_span["name"] == "task2" + assert task2_enqueue_span["status"] == "ok" + assert task2_enqueue_span["parent_span_id"] == task1_execute_span["span_id"] + assert task2_enqueue_span["attributes"]["sentry.segment.name"] == "task1" + assert task2_enqueue_span["attributes"]["sentry.op"] == "queue.submit.huey" + assert task2_enqueue_span["attributes"]["sentry.origin"] == "auto.queue.huey" + + assert task2_execute_span["name"] == "task2" + assert task2_execute_span["status"] == "ok" + assert task2_execute_span["parent_span_id"] == task2_enqueue_span["span_id"] + assert task2_execute_span["attributes"]["messaging.message.system"] == "huey" + assert task2_execute_span["attributes"]["sentry.op"] == "queue.task.huey" + assert task2_execute_span["attributes"]["sentry.origin"] == "auto.queue.huey" + assert ( + task2_execute_span["attributes"]["sentry.segment.name.source"] + == SegmentNameSource.TASK + ) diff --git a/tests/integrations/huggingface_hub/test_huggingface_hub.py b/tests/integrations/huggingface_hub/test_huggingface_hub.py index 3a04a51d52..de72a586ff 100644 --- a/tests/integrations/huggingface_hub/test_huggingface_hub.py +++ b/tests/integrations/huggingface_hub/test_huggingface_hub.py @@ -467,1067 +467,416 @@ def mock_hf_chat_completion_api_streaming_tools(httpx_mock): yield rsps -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.httpx_mock(assert_all_requests_were_expected=False) @pytest.mark.parametrize("send_default_pii", [True, False]) -@pytest.mark.parametrize("include_prompts", [True, False]) def test_text_generation( sentry_init: "Any", - capture_events: "Any", capture_items: "Any", send_default_pii: "Any", - include_prompts: "Any", mock_hf_text_generation_api: "Any", - stream_gen_ai_spans: "Any", - span_streaming: "Any", ) -> None: sentry_init( traces_sample_rate=1.0, send_default_pii=send_default_pii, - integrations=[HuggingfaceHubIntegration(include_prompts=include_prompts)], - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", + integrations=[HuggingfaceHubIntegration()], ) client = InferenceClient(model="test-model") + items = capture_items("span") - if span_streaming: - items = capture_items("transaction", "span") - - with sentry_sdk.traces.start_span(name="test"): - client.text_generation( - "Hello", - stream=False, - details=True, - ) - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - span = None - for sp in spans: - if "sentry.op" in sp["attributes"] and sp["attributes"][ - "sentry.op" - ].startswith("gen_ai"): - assert span is None, "there is exactly one gen_ai span" - span = sp - elif "sentry.op" in sp["attributes"]: - # there should be no other spans, just the gen_ai span - # and optionally some http.client spans from talking to the hf api - assert sp["attributes"]["sentry.op"] == "http.client" - - assert span is not None - - assert span["attributes"]["sentry.op"] == "gen_ai.text_completion" - assert span["name"] == "text_completion test-model" - assert span["attributes"]["sentry.origin"] == "auto.ai.huggingface_hub" - - expected_data = { - "gen_ai.operation.name": "text_completion", - "gen_ai.request.model": "test-model", - "gen_ai.response.finish_reasons": "length", - "gen_ai.response.streaming": False, - "gen_ai.usage.total_tokens": 10, - "sentry.op": "gen_ai.text_completion", - "sentry.origin": "auto.ai.huggingface_hub", - } - - if send_default_pii and include_prompts: - expected_data["gen_ai.request.messages"] = "Hello" - expected_data["gen_ai.response.text"] = ( - "[mocked] Hello! How can i help you?" - ) - - if not send_default_pii or not include_prompts: - assert "gen_ai.request.messages" not in expected_data - assert "gen_ai.response.text" not in expected_data - - assert span["attributes"] == ApproxDict(expected_data) - - # text generation does not set the response model - assert "gen_ai.response.model" not in span["attributes"] - elif stream_gen_ai_spans: - items = capture_items("transaction", "span") - - with sentry_sdk.start_transaction(name="test"): - client.text_generation( - "Hello", - stream=False, - details=True, - ) - - spans = [item.payload for item in items if item.type == "span"] - span = None - for sp in spans: - if sp["attributes"]["sentry.op"].startswith("gen_ai"): - assert span is None, "there is exactly one gen_ai span" - span = sp - else: - # there should be no other spans, just the gen_ai span - # and optionally some http.client spans from talking to the hf api - assert sp["attributes"]["sentry.op"] == "http.client" - - assert span is not None - - assert span["attributes"]["sentry.op"] == "gen_ai.text_completion" - assert span["name"] == "text_completion test-model" - assert span["attributes"]["sentry.origin"] == "auto.ai.huggingface_hub" - - expected_data = { - "gen_ai.operation.name": "text_completion", - "gen_ai.request.model": "test-model", - "gen_ai.response.finish_reasons": "length", - "gen_ai.response.streaming": False, - "gen_ai.usage.total_tokens": 10, - "sentry.op": "gen_ai.text_completion", - "sentry.origin": "auto.ai.huggingface_hub", - } - - if send_default_pii and include_prompts: - expected_data["gen_ai.request.messages"] = "Hello" - expected_data["gen_ai.response.text"] = ( - "[mocked] Hello! How can i help you?" - ) - - if not send_default_pii or not include_prompts: - assert "gen_ai.request.messages" not in expected_data - assert "gen_ai.response.text" not in expected_data - - assert span["attributes"] == ApproxDict(expected_data) + client.text_generation( + "Hello", + stream=False, + details=True, + ) - # text generation does not set the response model - assert "gen_ai.response.model" not in span["attributes"] - else: - events = capture_events() - - with sentry_sdk.start_transaction(name="test"): - client.text_generation( - "Hello", - stream=False, - details=True, - ) - - (transaction,) = events - - span = None - for sp in transaction["spans"]: - if sp["op"].startswith("gen_ai"): - assert span is None, "there is exactly one gen_ai span" - span = sp - else: - # there should be no other spans, just the gen_ai span - # and optionally some http.client spans from talking to the hf api - assert sp["op"] == "http.client" - - assert span is not None - - assert span["op"] == "gen_ai.text_completion" - assert span["description"] == "text_completion test-model" - assert span["origin"] == "auto.ai.huggingface_hub" - - expected_data = { - "gen_ai.operation.name": "text_completion", - "gen_ai.request.model": "test-model", - "gen_ai.response.finish_reasons": "length", - "gen_ai.response.streaming": False, - "gen_ai.usage.total_tokens": 10, - } + sentry_sdk.flush() + spans = [item.payload for item in items] + span = None + for sp in spans: + if "sentry.op" in sp["attributes"] and sp["attributes"]["sentry.op"].startswith( + "gen_ai" + ): + assert span is None, "there is exactly one gen_ai span" + span = sp + elif "sentry.op" in sp["attributes"]: + # there should be no other spans, just the gen_ai span + # and optionally some http.client spans from talking to the hf api + assert sp["attributes"]["sentry.op"] == "http.client" + + assert span is not None + + assert span["attributes"]["sentry.op"] == "gen_ai.text_completion" + assert span["name"] == "text_completion test-model" + assert span["attributes"]["sentry.origin"] == "auto.ai.huggingface_hub" + + expected_data = { + "gen_ai.operation.name": "text_completion", + "gen_ai.request.model": "test-model", + "gen_ai.response.finish_reasons": "length", + "gen_ai.response.streaming": False, + "gen_ai.usage.total_tokens": 10, + "sentry.op": "gen_ai.text_completion", + "sentry.origin": "auto.ai.huggingface_hub", + } - if send_default_pii and include_prompts: - expected_data["gen_ai.request.messages"] = "Hello" - expected_data["gen_ai.response.text"] = ( - "[mocked] Hello! How can i help you?" - ) + if send_default_pii: + expected_data["gen_ai.request.messages"] = "Hello" + expected_data["gen_ai.response.text"] = "[mocked] Hello! How can i help you?" - if not send_default_pii or not include_prompts: - assert "gen_ai.request.messages" not in expected_data - assert "gen_ai.response.text" not in expected_data + if not send_default_pii: + assert "gen_ai.request.messages" not in expected_data + assert "gen_ai.response.text" not in expected_data - assert span["data"] == ApproxDict(expected_data) + assert span["attributes"] == ApproxDict(expected_data) - # text generation does not set the response model - assert "gen_ai.response.model" not in span["data"] + # text generation does not set the response model + assert "gen_ai.response.model" not in span["attributes"] -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.httpx_mock(assert_all_requests_were_expected=False) @pytest.mark.parametrize("send_default_pii", [True, False]) -@pytest.mark.parametrize("include_prompts", [True, False]) def test_text_generation_streaming( sentry_init: "Any", - capture_events: "Any", capture_items: "Any", send_default_pii: "Any", - include_prompts: "Any", mock_hf_text_generation_api_streaming: "Any", - stream_gen_ai_spans: "Any", - span_streaming: "Any", ) -> None: sentry_init( traces_sample_rate=1.0, send_default_pii=send_default_pii, - integrations=[HuggingfaceHubIntegration(include_prompts=include_prompts)], - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", + integrations=[HuggingfaceHubIntegration()], ) client = InferenceClient(model="test-model") + items = capture_items("span") + + for _ in client.text_generation( + prompt="Hello", + stream=True, + details=True, + ): + pass + + sentry_sdk.flush() + spans = [item.payload for item in items] + span = None + for sp in spans: + if "sentry.op" in sp["attributes"] and sp["attributes"]["sentry.op"].startswith( + "gen_ai" + ): + assert span is None, "there is exactly one gen_ai span" + span = sp + elif "sentry.op" in sp["attributes"]: + # there should be no other spans, just the gen_ai span + # and optionally some http.client spans from talking to the hf api + assert sp["attributes"]["sentry.op"] == "http.client" + + assert span is not None + + assert span["attributes"]["sentry.op"] == "gen_ai.text_completion" + assert span["name"] == "text_completion test-model" + assert span["attributes"]["sentry.origin"] == "auto.ai.huggingface_hub" + + expected_data = { + "gen_ai.operation.name": "text_completion", + "gen_ai.request.model": "test-model", + "gen_ai.response.finish_reasons": "length", + "gen_ai.response.streaming": True, + "gen_ai.usage.total_tokens": 10, + "sentry.environment": "production", + "sentry.op": "gen_ai.text_completion", + "sentry.origin": "auto.ai.huggingface_hub", + } - if span_streaming: - items = capture_items("span") - - with sentry_sdk.traces.start_span(name="test"): - for _ in client.text_generation( - prompt="Hello", - stream=True, - details=True, - ): - pass - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - span = None - for sp in spans: - if "sentry.op" in sp["attributes"] and sp["attributes"][ - "sentry.op" - ].startswith("gen_ai"): - assert span is None, "there is exactly one gen_ai span" - span = sp - elif "sentry.op" in sp["attributes"]: - # there should be no other spans, just the gen_ai span - # and optionally some http.client spans from talking to the hf api - assert sp["attributes"]["sentry.op"] == "http.client" - - assert span is not None - - assert span["attributes"]["sentry.op"] == "gen_ai.text_completion" - assert span["name"] == "text_completion test-model" - assert span["attributes"]["sentry.origin"] == "auto.ai.huggingface_hub" - - expected_data = { - "gen_ai.operation.name": "text_completion", - "gen_ai.request.model": "test-model", - "gen_ai.response.finish_reasons": "length", - "gen_ai.response.streaming": True, - "gen_ai.usage.total_tokens": 10, - "sentry.environment": "production", - "sentry.op": "gen_ai.text_completion", - "sentry.origin": "auto.ai.huggingface_hub", - } - - if send_default_pii and include_prompts: - expected_data["gen_ai.request.messages"] = "Hello" - expected_data["gen_ai.response.text"] = "the mocked model response" - - if not send_default_pii or not include_prompts: - assert "gen_ai.request.messages" not in expected_data - assert "gen_ai.response.text" not in expected_data - - assert span["attributes"] == ApproxDict(expected_data) - - # text generation does not set the response model - assert "gen_ai.response.model" not in span["attributes"] - elif stream_gen_ai_spans: - items = capture_items("transaction", "span") - - with sentry_sdk.start_transaction(name="test"): - for _ in client.text_generation( - prompt="Hello", - stream=True, - details=True, - ): - pass - - spans = [item.payload for item in items if item.type == "span"] - span = None - for sp in spans: - if sp["attributes"]["sentry.op"].startswith("gen_ai"): - assert span is None, "there is exactly one gen_ai span" - span = sp - else: - # there should be no other spans, just the gen_ai span - # and optionally some http.client spans from talking to the hf api - assert sp["attributes"]["sentry.op"] == "http.client" - - assert span is not None - - assert span["attributes"]["sentry.op"] == "gen_ai.text_completion" - assert span["name"] == "text_completion test-model" - assert span["attributes"]["sentry.origin"] == "auto.ai.huggingface_hub" - - expected_data = { - "gen_ai.operation.name": "text_completion", - "gen_ai.request.model": "test-model", - "gen_ai.response.finish_reasons": "length", - "gen_ai.response.streaming": True, - "gen_ai.usage.total_tokens": 10, - "sentry.environment": "production", - "sentry.op": "gen_ai.text_completion", - "sentry.origin": "auto.ai.huggingface_hub", - } - - if send_default_pii and include_prompts: - expected_data["gen_ai.request.messages"] = "Hello" - expected_data["gen_ai.response.text"] = "the mocked model response" - - if not send_default_pii or not include_prompts: - assert "gen_ai.request.messages" not in expected_data - assert "gen_ai.response.text" not in expected_data - - assert span["attributes"] == ApproxDict(expected_data) - - # text generation does not set the response model - assert "gen_ai.response.model" not in span["attributes"] - else: - events = capture_events() - - with sentry_sdk.start_transaction(name="test"): - for _ in client.text_generation( - prompt="Hello", - stream=True, - details=True, - ): - pass - - (transaction,) = events - - span = None - for sp in transaction["spans"]: - if sp["op"].startswith("gen_ai"): - assert span is None, "there is exactly one gen_ai span" - span = sp - else: - # there should be no other spans, just the gen_ai span - # and optionally some http.client spans from talking to the hf api - assert sp["op"] == "http.client" - - assert span is not None - - assert span["op"] == "gen_ai.text_completion" - assert span["description"] == "text_completion test-model" - assert span["origin"] == "auto.ai.huggingface_hub" - - expected_data = { - "gen_ai.operation.name": "text_completion", - "gen_ai.request.model": "test-model", - "gen_ai.response.finish_reasons": "length", - "gen_ai.response.streaming": True, - "gen_ai.usage.total_tokens": 10, - } - - if send_default_pii and include_prompts: - expected_data["gen_ai.request.messages"] = "Hello" - expected_data["gen_ai.response.text"] = "the mocked model response" + if send_default_pii: + expected_data["gen_ai.request.messages"] = "Hello" + expected_data["gen_ai.response.text"] = "the mocked model response" - if not send_default_pii or not include_prompts: - assert "gen_ai.request.messages" not in expected_data - assert "gen_ai.response.text" not in expected_data + if not send_default_pii: + assert "gen_ai.request.messages" not in expected_data + assert "gen_ai.response.text" not in expected_data - assert span["data"] == ApproxDict(expected_data) + assert span["attributes"] == ApproxDict(expected_data) - # text generation does not set the response model - assert "gen_ai.response.model" not in span["data"] + # text generation does not set the response model + assert "gen_ai.response.model" not in span["attributes"] -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.httpx_mock(assert_all_requests_were_expected=False) @pytest.mark.parametrize("send_default_pii", [True, False]) -@pytest.mark.parametrize("include_prompts", [True, False]) def test_chat_completion( sentry_init: "Any", - capture_events: "Any", capture_items: "Any", send_default_pii: "Any", - include_prompts: "Any", mock_hf_chat_completion_api: "Any", - stream_gen_ai_spans: "Any", - span_streaming: "Any", ) -> None: sentry_init( traces_sample_rate=1.0, send_default_pii=send_default_pii, - integrations=[HuggingfaceHubIntegration(include_prompts=include_prompts)], - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", + integrations=[HuggingfaceHubIntegration()], ) client = get_hf_provider_inference_client() + items = capture_items("span") - if span_streaming: - items = capture_items("span") - - with sentry_sdk.traces.start_span(name="test"): - client.chat_completion( - messages=[ - { - "role": "user", - "content": "Message demonstrating the absence of truncation.", - }, - {"role": "user", "content": "Hello!"}, - ], - stream=False, - ) - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - span = None - for sp in spans: - if "sentry.op" in sp["attributes"] and sp["attributes"][ - "sentry.op" - ].startswith("gen_ai"): - assert span is None, "there is exactly one gen_ai span" - span = sp - elif "sentry.op" in sp["attributes"]: - # there should be no other spans, just the gen_ai span - # and optionally some http.client spans from talking to the hf api - assert sp["attributes"]["sentry.op"] == "http.client" - - assert span is not None - - assert span["attributes"]["sentry.op"] == "gen_ai.chat" - assert span["name"] == "chat test-model" - assert span["attributes"]["sentry.origin"] == "auto.ai.huggingface_hub" - - expected_data = { - "gen_ai.operation.name": "chat", - "gen_ai.request.model": "test-model", - "gen_ai.response.finish_reasons": "stop", - "gen_ai.response.model": "test-model-123", - "gen_ai.response.streaming": False, - "gen_ai.usage.input_tokens": 10, - "gen_ai.usage.output_tokens": 8, - "gen_ai.usage.total_tokens": 18, - "sentry.environment": "production", - "sentry.op": "gen_ai.chat", - "sentry.origin": "auto.ai.huggingface_hub", - } - - if send_default_pii and include_prompts: - expected_data["gen_ai.request.messages"] = safe_serialize( - [ - { - "role": "user", - "content": "Message demonstrating the absence of truncation.", - }, - {"role": "user", "content": "Hello!"}, - ] - ) - expected_data["gen_ai.response.text"] = ( - "[mocked] Hello! How can I help you today?" - ) - - if not send_default_pii or not include_prompts: - assert "gen_ai.request.messages" not in expected_data - assert "gen_ai.response.text" not in expected_data - - assert span["attributes"] == ApproxDict(expected_data) - elif stream_gen_ai_spans: - items = capture_items("transaction", "span") - - with sentry_sdk.start_transaction(name="test"): - client.chat_completion( - messages=[ - { - "role": "user", - "content": "Message demonstrating the absence of truncation.", - }, - {"role": "user", "content": "Hello!"}, - ], - stream=False, - ) - - spans = [item.payload for item in items if item.type == "span"] - span = None - for sp in spans: - if sp["attributes"]["sentry.op"].startswith("gen_ai"): - assert span is None, "there is exactly one gen_ai span" - span = sp - else: - # there should be no other spans, just the gen_ai span - # and optionally some http.client spans from talking to the hf api - assert sp["attributes"]["sentry.op"] == "http.client" - - assert span is not None - - assert span["attributes"]["sentry.op"] == "gen_ai.chat" - assert span["name"] == "chat test-model" - assert span["attributes"]["sentry.origin"] == "auto.ai.huggingface_hub" - - expected_data = { - "gen_ai.operation.name": "chat", - "gen_ai.request.model": "test-model", - "gen_ai.response.finish_reasons": "stop", - "gen_ai.response.model": "test-model-123", - "gen_ai.response.streaming": False, - "gen_ai.usage.input_tokens": 10, - "gen_ai.usage.output_tokens": 8, - "gen_ai.usage.total_tokens": 18, - "sentry.environment": "production", - "sentry.op": "gen_ai.chat", - "sentry.origin": "auto.ai.huggingface_hub", - } + client.chat_completion( + messages=[ + { + "role": "user", + "content": "Message demonstrating the absence of truncation.", + }, + {"role": "user", "content": "Hello!"}, + ], + stream=False, + ) - if send_default_pii and include_prompts: - expected_data["gen_ai.request.messages"] = safe_serialize( - [ - { - "role": "user", - "content": "Message demonstrating the absence of truncation.", - }, - {"role": "user", "content": "Hello!"}, - ] - ) - expected_data["gen_ai.response.text"] = ( - "[mocked] Hello! How can I help you today?" - ) - - if not send_default_pii or not include_prompts: - assert "gen_ai.request.messages" not in expected_data - assert "gen_ai.response.text" not in expected_data - - assert span["attributes"] == ApproxDict(expected_data) - else: - events = capture_events() - - with sentry_sdk.start_transaction(name="test"): - client.chat_completion( - messages=[{"role": "user", "content": "Hello!"}], - stream=False, - ) - - (transaction,) = events - - span = None - for sp in transaction["spans"]: - if sp["op"].startswith("gen_ai"): - assert span is None, "there is exactly one gen_ai span" - span = sp - else: - # there should be no other spans, just the gen_ai span - # and optionally some http.client spans from talking to the hf api - assert sp["op"] == "http.client" - - assert span is not None - - assert span["op"] == "gen_ai.chat" - assert span["description"] == "chat test-model" - assert span["origin"] == "auto.ai.huggingface_hub" - - expected_data = { - "gen_ai.operation.name": "chat", - "gen_ai.request.model": "test-model", - "gen_ai.response.finish_reasons": "stop", - "gen_ai.response.model": "test-model-123", - "gen_ai.response.streaming": False, - "gen_ai.usage.input_tokens": 10, - "gen_ai.usage.output_tokens": 8, - "gen_ai.usage.total_tokens": 18, - } + sentry_sdk.flush() + spans = [item.payload for item in items] + span = None + for sp in spans: + if "sentry.op" in sp["attributes"] and sp["attributes"]["sentry.op"].startswith( + "gen_ai" + ): + assert span is None, "there is exactly one gen_ai span" + span = sp + elif "sentry.op" in sp["attributes"]: + # there should be no other spans, just the gen_ai span + # and optionally some http.client spans from talking to the hf api + assert sp["attributes"]["sentry.op"] == "http.client" + + assert span is not None + + assert span["attributes"]["sentry.op"] == "gen_ai.chat" + assert span["name"] == "chat test-model" + assert span["attributes"]["sentry.origin"] == "auto.ai.huggingface_hub" + + expected_data = { + "gen_ai.operation.name": "chat", + "gen_ai.request.model": "test-model", + "gen_ai.response.finish_reasons": "stop", + "gen_ai.response.model": "test-model-123", + "gen_ai.response.streaming": False, + "gen_ai.usage.input_tokens": 10, + "gen_ai.usage.output_tokens": 8, + "gen_ai.usage.total_tokens": 18, + "sentry.environment": "production", + "sentry.op": "gen_ai.chat", + "sentry.origin": "auto.ai.huggingface_hub", + } - if send_default_pii and include_prompts: - expected_data["gen_ai.request.messages"] = ( - '[{"role": "user", "content": "Hello!"}]' - ) - expected_data["gen_ai.response.text"] = ( - "[mocked] Hello! How can I help you today?" - ) + if send_default_pii: + expected_data["gen_ai.request.messages"] = safe_serialize( + [ + { + "role": "user", + "content": "Message demonstrating the absence of truncation.", + }, + {"role": "user", "content": "Hello!"}, + ] + ) + expected_data["gen_ai.response.text"] = ( + "[mocked] Hello! How can I help you today?" + ) - if not send_default_pii or not include_prompts: - assert "gen_ai.request.messages" not in expected_data - assert "gen_ai.response.text" not in expected_data + if not send_default_pii: + assert "gen_ai.request.messages" not in expected_data + assert "gen_ai.response.text" not in expected_data - assert span["data"] == ApproxDict(expected_data) + assert span["attributes"] == ApproxDict(expected_data) -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.httpx_mock(assert_all_requests_were_expected=False) @pytest.mark.parametrize("send_default_pii", [True, False]) -@pytest.mark.parametrize("include_prompts", [True, False]) def test_chat_completion_streaming( sentry_init: "Any", - capture_events: "Any", capture_items: "Any", send_default_pii: "Any", - include_prompts: "Any", mock_hf_chat_completion_api_streaming: "Any", - stream_gen_ai_spans: "Any", - span_streaming: "Any", ) -> None: sentry_init( traces_sample_rate=1.0, send_default_pii=send_default_pii, - integrations=[HuggingfaceHubIntegration(include_prompts=include_prompts)], - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", + integrations=[HuggingfaceHubIntegration()], ) client = get_hf_provider_inference_client() + items = capture_items("span") - if span_streaming: - items = capture_items("span") + _ = list( + client.chat_completion( + [ + { + "role": "user", + "content": "Message demonstrating the absence of truncation.", + }, + {"role": "user", "content": "Hello!"}, + ], + stream=True, + ) + ) - with sentry_sdk.traces.start_span(name="test"): - _ = list( - client.chat_completion( - [ - { - "role": "user", - "content": "Message demonstrating the absence of truncation.", - }, - {"role": "user", "content": "Hello!"}, - ], - stream=True, - ) - ) - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - span = None - for sp in spans: - if "sentry.op" in sp["attributes"] and sp["attributes"][ - "sentry.op" - ].startswith("gen_ai"): - assert span is None, "there is exactly one gen_ai span" - span = sp - elif "sentry.op" in sp["attributes"]: - # there should be no other spans, just the gen_ai span - # and optionally some http.client spans from talking to the hf api - assert sp["attributes"]["sentry.op"] == "http.client" - - assert span is not None - - assert span["attributes"]["sentry.op"] == "gen_ai.chat" - assert span["name"] == "chat test-model" - assert span["attributes"]["sentry.origin"] == "auto.ai.huggingface_hub" - - expected_data = { - "gen_ai.operation.name": "chat", - "gen_ai.request.model": "test-model", - "gen_ai.response.finish_reasons": "stop", - "gen_ai.response.model": "test-model-123", - "gen_ai.response.streaming": True, - "sentry.environment": "production", - "sentry.op": "gen_ai.chat", - "sentry.origin": "auto.ai.huggingface_hub", - } - # usage is not available in older versions of the library - if HF_VERSION and HF_VERSION >= (0, 26, 0): - expected_data["gen_ai.usage.input_tokens"] = 183 - expected_data["gen_ai.usage.output_tokens"] = 14 - expected_data["gen_ai.usage.total_tokens"] = 197 - - if send_default_pii and include_prompts: - expected_data["gen_ai.request.messages"] = safe_serialize( - [ - { - "role": "user", - "content": "Message demonstrating the absence of truncation.", - }, - {"role": "user", "content": "Hello!"}, - ] - ) - expected_data["gen_ai.response.text"] = "the mocked model response" - - if not send_default_pii or not include_prompts: - assert "gen_ai.request.messages" not in expected_data - assert "gen_ai.response.text" not in expected_data - - assert span["attributes"] == ApproxDict(expected_data) - elif stream_gen_ai_spans: - items = capture_items("transaction", "span") - - with sentry_sdk.start_transaction(name="test"): - _ = list( - client.chat_completion( - [ - { - "role": "user", - "content": "Message demonstrating the absence of truncation.", - }, - {"role": "user", "content": "Hello!"}, - ], - stream=True, - ) - ) - - spans = [item.payload for item in items if item.type == "span"] - span = None - for sp in spans: - if sp["attributes"]["sentry.op"].startswith("gen_ai"): - assert span is None, "there is exactly one gen_ai span" - span = sp - else: - # there should be no other spans, just the gen_ai span - # and optionally some http.client spans from talking to the hf api - assert sp["attributes"]["sentry.op"] == "http.client" - - assert span is not None - - assert span["attributes"]["sentry.op"] == "gen_ai.chat" - assert span["name"] == "chat test-model" - assert span["attributes"]["sentry.origin"] == "auto.ai.huggingface_hub" - - expected_data = { - "gen_ai.operation.name": "chat", - "gen_ai.request.model": "test-model", - "gen_ai.response.finish_reasons": "stop", - "gen_ai.response.model": "test-model-123", - "gen_ai.response.streaming": True, - "sentry.environment": "production", - "sentry.op": "gen_ai.chat", - "sentry.origin": "auto.ai.huggingface_hub", - } - # usage is not available in older versions of the library - if HF_VERSION and HF_VERSION >= (0, 26, 0): - expected_data["gen_ai.usage.input_tokens"] = 183 - expected_data["gen_ai.usage.output_tokens"] = 14 - expected_data["gen_ai.usage.total_tokens"] = 197 - - if send_default_pii and include_prompts: - expected_data["gen_ai.request.messages"] = safe_serialize( - [ - { - "role": "user", - "content": "Message demonstrating the absence of truncation.", - }, - {"role": "user", "content": "Hello!"}, - ] - ) - expected_data["gen_ai.response.text"] = "the mocked model response" - - if not send_default_pii or not include_prompts: - assert "gen_ai.request.messages" not in expected_data - assert "gen_ai.response.text" not in expected_data - - assert span["attributes"] == ApproxDict(expected_data) - else: - events = capture_events() - - with sentry_sdk.start_transaction(name="test"): - _ = list( - client.chat_completion( - [{"role": "user", "content": "Hello!"}], - stream=True, - ) - ) - - (transaction,) = events - - span = None - for sp in transaction["spans"]: - if sp["op"].startswith("gen_ai"): - assert span is None, "there is exactly one gen_ai span" - span = sp - else: - # there should be no other spans, just the gen_ai span - # and optionally some http.client spans from talking to the hf api - assert sp["op"] == "http.client" - - assert span is not None - - assert span["op"] == "gen_ai.chat" - assert span["description"] == "chat test-model" - assert span["origin"] == "auto.ai.huggingface_hub" - - expected_data = { - "gen_ai.operation.name": "chat", - "gen_ai.request.model": "test-model", - "gen_ai.response.finish_reasons": "stop", - "gen_ai.response.model": "test-model-123", - "gen_ai.response.streaming": True, - } - # usage is not available in older versions of the library - if HF_VERSION and HF_VERSION >= (0, 26, 0): - expected_data["gen_ai.usage.input_tokens"] = 183 - expected_data["gen_ai.usage.output_tokens"] = 14 - expected_data["gen_ai.usage.total_tokens"] = 197 + sentry_sdk.flush() + spans = [item.payload for item in items] + span = None + for sp in spans: + if "sentry.op" in sp["attributes"] and sp["attributes"]["sentry.op"].startswith( + "gen_ai" + ): + assert span is None, "there is exactly one gen_ai span" + span = sp + elif "sentry.op" in sp["attributes"]: + # there should be no other spans, just the gen_ai span + # and optionally some http.client spans from talking to the hf api + assert sp["attributes"]["sentry.op"] == "http.client" + + assert span is not None + + assert span["attributes"]["sentry.op"] == "gen_ai.chat" + assert span["name"] == "chat test-model" + assert span["attributes"]["sentry.origin"] == "auto.ai.huggingface_hub" + + expected_data = { + "gen_ai.operation.name": "chat", + "gen_ai.request.model": "test-model", + "gen_ai.response.finish_reasons": "stop", + "gen_ai.response.model": "test-model-123", + "gen_ai.response.streaming": True, + "sentry.environment": "production", + "sentry.op": "gen_ai.chat", + "sentry.origin": "auto.ai.huggingface_hub", + } + # usage is not available in older versions of the library + if HF_VERSION and HF_VERSION >= (0, 26, 0): + expected_data["gen_ai.usage.input_tokens"] = 183 + expected_data["gen_ai.usage.output_tokens"] = 14 + expected_data["gen_ai.usage.total_tokens"] = 197 - if send_default_pii and include_prompts: - expected_data["gen_ai.request.messages"] = ( - '[{"role": "user", "content": "Hello!"}]' - ) - expected_data["gen_ai.response.text"] = "the mocked model response" + if send_default_pii: + expected_data["gen_ai.request.messages"] = safe_serialize( + [ + { + "role": "user", + "content": "Message demonstrating the absence of truncation.", + }, + {"role": "user", "content": "Hello!"}, + ] + ) + expected_data["gen_ai.response.text"] = "the mocked model response" - if not send_default_pii or not include_prompts: - assert "gen_ai.request.messages" not in expected_data - assert "gen_ai.response.text" not in expected_data + if not send_default_pii: + assert "gen_ai.request.messages" not in expected_data + assert "gen_ai.response.text" not in expected_data - assert span["data"] == ApproxDict(expected_data) + assert span["attributes"] == ApproxDict(expected_data) -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.httpx_mock(assert_all_requests_were_expected=False) def test_chat_completion_api_error( sentry_init: "Any", - capture_events: "Any", capture_items: "Any", mock_hf_api_with_errors: "Any", - stream_gen_ai_spans: "Any", - span_streaming: "Any", ) -> None: sentry_init( traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = get_hf_provider_inference_client() - if span_streaming: - items = capture_items("event", "span") - - with sentry_sdk.traces.start_span(name="test"), pytest.raises(HfHubHTTPError): - client.chat_completion( - messages=[{"role": "user", "content": "Hello!"}], - ) - - (error,) = (item.payload for item in items if item.type == "event") - - assert error["exception"]["values"][0]["mechanism"]["type"] == "huggingface_hub" - assert not error["exception"]["values"][0]["mechanism"]["handled"] - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - span = None - for sp in spans: - if "sentry.op" in sp["attributes"] and sp["attributes"][ - "sentry.op" - ].startswith("gen_ai"): - assert span is None, "there is exactly one gen_ai span" - span = sp - elif "sentry.op" in sp["attributes"]: - # there should be no other spans, just the gen_ai span - # and optionally some http.client spans from talking to the hf api - assert sp["attributes"]["sentry.op"] == "http.client" - - assert span is not None - - assert span["attributes"]["sentry.op"] == "gen_ai.chat" - assert span["name"] == "chat test-model" - assert span["attributes"]["sentry.origin"] == "auto.ai.huggingface_hub" - assert span["status"] == "error" - - (manual_span,) = (span for span in spans if span["name"] == "test") - - assert error["contexts"]["trace"]["trace_id"] == manual_span["trace_id"] - expected_data = { - "gen_ai.operation.name": "chat", - "gen_ai.request.model": "test-model", - "sentry.environment": "production", - "sentry.op": "gen_ai.chat", - "sentry.origin": "auto.ai.huggingface_hub", - } - assert span["attributes"] == ApproxDict(expected_data) - elif stream_gen_ai_spans: - items = capture_items("event", "transaction", "span") - - with sentry_sdk.start_transaction(name="test"), pytest.raises(HfHubHTTPError): - client.chat_completion( - messages=[{"role": "user", "content": "Hello!"}], - ) - - (error,) = (item.payload for item in items if item.type == "event") - - assert error["exception"]["values"][0]["mechanism"]["type"] == "huggingface_hub" - assert not error["exception"]["values"][0]["mechanism"]["handled"] - - spans = [item.payload for item in items if item.type == "span"] - span = None - for sp in spans: - if sp["attributes"]["sentry.op"].startswith("gen_ai"): - assert span is None, "there is exactly one gen_ai span" - span = sp - else: - # there should be no other spans, just the gen_ai span - # and optionally some http.client spans from talking to the hf api - assert sp["attributes"]["sentry.op"] == "http.client" - - assert span is not None - - assert span["attributes"]["sentry.op"] == "gen_ai.chat" - assert span["name"] == "chat test-model" - assert span["attributes"]["sentry.origin"] == "auto.ai.huggingface_hub" - assert span["status"] == "error" - - (transaction,) = (item.payload for item in items if item.type == "transaction") - - assert ( - error["contexts"]["trace"]["trace_id"] - == transaction["contexts"]["trace"]["trace_id"] - ) - expected_data = { - "gen_ai.operation.name": "chat", - "gen_ai.request.model": "test-model", - "sentry.environment": "production", - "sentry.op": "gen_ai.chat", - "sentry.origin": "auto.ai.huggingface_hub", - } - assert span["attributes"] == ApproxDict(expected_data) - else: - events = capture_events() - - with sentry_sdk.start_transaction(name="test"), pytest.raises(HfHubHTTPError): - client.chat_completion( - messages=[{"role": "user", "content": "Hello!"}], - ) - - ( - error, - transaction, - ) = events - - assert error["exception"]["values"][0]["mechanism"]["type"] == "huggingface_hub" - assert not error["exception"]["values"][0]["mechanism"]["handled"] - - span = None - for sp in transaction["spans"]: - if sp["op"].startswith("gen_ai"): - assert span is None, "there is exactly one gen_ai span" - span = sp - else: - # there should be no other spans, just the gen_ai span - # and optionally some http.client spans from talking to the hf api - assert sp["op"] == "http.client" - - assert span is not None - - assert span["op"] == "gen_ai.chat" - assert span["description"] == "chat test-model" - assert span["origin"] == "auto.ai.huggingface_hub" - assert span["status"] == "internal_error" - assert span.get("tags", {}).get("status") == "internal_error" - - assert ( - error["contexts"]["trace"]["trace_id"] - == transaction["contexts"]["trace"]["trace_id"] + items = capture_items("event", "span") + + with pytest.raises(HfHubHTTPError): + client.chat_completion( + messages=[{"role": "user", "content": "Hello!"}], ) - expected_data = { - "gen_ai.operation.name": "chat", - "gen_ai.request.model": "test-model", - } - assert span["data"] == ApproxDict(expected_data) + + (error,) = (item.payload for item in items if item.type == "event") + + assert error["exception"]["values"][0]["mechanism"]["type"] == "huggingface_hub" + assert not error["exception"]["values"][0]["mechanism"]["handled"] + + sentry_sdk.flush() + spans = [item.payload for item in items if item.type == "span"] + span = None + for sp in spans: + if "sentry.op" in sp["attributes"] and sp["attributes"]["sentry.op"].startswith( + "gen_ai" + ): + assert span is None, "there is exactly one gen_ai span" + span = sp + elif "sentry.op" in sp["attributes"]: + # there should be no other spans, just the gen_ai span + # and optionally some http.client spans from talking to the hf api + assert sp["attributes"]["sentry.op"] == "http.client" + + assert span is not None + + assert span["attributes"]["sentry.op"] == "gen_ai.chat" + assert span["name"] == "chat test-model" + assert span["attributes"]["sentry.origin"] == "auto.ai.huggingface_hub" + assert span["status"] == "error" + + assert error["contexts"]["trace"]["trace_id"] == span["trace_id"] + expected_data = { + "gen_ai.operation.name": "chat", + "gen_ai.request.model": "test-model", + "sentry.environment": "production", + "sentry.op": "gen_ai.chat", + "sentry.origin": "auto.ai.huggingface_hub", + } + assert span["attributes"] == ApproxDict(expected_data) -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.httpx_mock(assert_all_requests_were_expected=False) def test_span_status_error( sentry_init: "Any", - capture_events: "Any", capture_items: "Any", mock_hf_api_with_errors: "Any", - stream_gen_ai_spans: "Any", - span_streaming: "Any", ) -> None: client = get_hf_provider_inference_client() sentry_init( traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) + items = capture_items("event", "span") - if span_streaming: - items = capture_items("event", "span") - - with sentry_sdk.traces.start_span(name="test"), pytest.raises(HfHubHTTPError): - client.chat_completion( - messages=[{"role": "user", "content": "Hello!"}], - ) - - (error,) = [item.payload for item in items if item.type == "event"] - assert error["level"] == "error" - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - span = None - for sp in spans: - if "sentry.op" in sp["attributes"] and sp["attributes"][ - "sentry.op" - ].startswith("gen_ai"): - assert span is None, "there is exactly one gen_ai span" - span = sp - elif "sentry.op" in sp["attributes"]: - # there should be no other spans, just the gen_ai span - # and optionally some http.client spans from talking to the hf api - assert sp["attributes"]["sentry.op"] == "http.client" - - assert span is not None - assert span["status"] == "error" - elif stream_gen_ai_spans: - items = capture_items("event", "transaction", "span") - - with sentry_sdk.start_transaction(name="test"), pytest.raises(HfHubHTTPError): - client.chat_completion( - messages=[{"role": "user", "content": "Hello!"}], - ) - - (error,) = [item.payload for item in items if item.type == "event"] - assert error["level"] == "error" - - spans = [item.payload for item in items if item.type == "span"] - span = None - for sp in spans: - if sp["attributes"]["sentry.op"].startswith("gen_ai"): - assert span is None, "there is exactly one gen_ai span" - span = sp - else: - # there should be no other spans, just the gen_ai span - # and optionally some http.client spans from talking to the hf api - assert sp["attributes"]["sentry.op"] == "http.client" - - assert span is not None - assert span["status"] == "error" - else: - events = capture_events() - - with sentry_sdk.start_transaction(name="test"), pytest.raises(HfHubHTTPError): - client.chat_completion( - messages=[{"role": "user", "content": "Hello!"}], - ) + with pytest.raises(HfHubHTTPError): + client.chat_completion( + messages=[{"role": "user", "content": "Hello!"}], + ) - (error, transaction) = events - assert error["level"] == "error" + (error,) = [item.payload for item in items if item.type == "event"] + assert error["level"] == "error" - span = None - for sp in transaction["spans"]: - if sp["op"].startswith("gen_ai"): - assert span is None, "there is exactly one gen_ai span" - span = sp - else: - # there should be no other spans, just the gen_ai span - # and optionally some http.client spans from talking to the hf api - assert sp["op"] == "http.client" + sentry_sdk.flush() + spans = [item.payload for item in items if item.type == "span"] + span = None + for sp in spans: + if "sentry.op" in sp["attributes"] and sp["attributes"]["sentry.op"].startswith( + "gen_ai" + ): + assert span is None, "there is exactly one gen_ai span" + span = sp + elif "sentry.op" in sp["attributes"]: + # there should be no other spans, just the gen_ai span + # and optionally some http.client spans from talking to the hf api + assert sp["attributes"]["sentry.op"] == "http.client" - assert span is not None - assert span["status"] == "internal_error" - assert span["tags"]["status"] == "internal_error" + assert span is not None + assert span["status"] == "error" -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.httpx_mock(assert_all_requests_were_expected=False) @pytest.mark.parametrize("send_default_pii", [True, False]) -@pytest.mark.parametrize("include_prompts", [True, False]) def test_chat_completion_with_tools( sentry_init: "Any", - capture_events: "Any", capture_items: "Any", send_default_pii: "Any", - include_prompts: "Any", mock_hf_chat_completion_api_tools: "Any", - stream_gen_ai_spans: "Any", - span_streaming: "Any", ): sentry_init( traces_sample_rate=1.0, send_default_pii=send_default_pii, - integrations=[HuggingfaceHubIntegration(include_prompts=include_prompts)], - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", + integrations=[HuggingfaceHubIntegration()], ) client = get_hf_provider_inference_client() @@ -1546,196 +895,76 @@ def test_chat_completion_with_tools( }, } ] + items = capture_items("span") - if span_streaming: - items = capture_items("span") - - with sentry_sdk.traces.start_span(name="test"): - client.chat_completion( - messages=[{"role": "user", "content": "What is the weather in Paris?"}], - tools=tools, - tool_choice="auto", - ) - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - span = None - for sp in spans: - if "sentry.op" in sp["attributes"] and sp["attributes"][ - "sentry.op" - ].startswith("gen_ai"): - assert span is None, "there is exactly one gen_ai span" - span = sp - elif "sentry.op" in sp["attributes"]: - # there should be no other spans, just the gen_ai span - # and optionally some http.client spans from talking to the hf api - assert sp["attributes"]["sentry.op"] == "http.client" - - assert span is not None - - assert span["attributes"]["sentry.op"] == "gen_ai.chat" - assert span["name"] == "chat test-model" - assert span["attributes"]["sentry.origin"] == "auto.ai.huggingface_hub" - - expected_data = { - "gen_ai.operation.name": "chat", - "gen_ai.request.available_tools": '[{"type": "function", "function": {"name": "get_weather", "description": "Get current weather", "parameters": {"type": "object", "properties": {"location": {"type": "string"}}, "required": ["location"]}}}]', - "gen_ai.request.model": "test-model", - "gen_ai.response.finish_reasons": "tool_calls", - "gen_ai.response.model": "test-model-123", - "gen_ai.usage.input_tokens": 10, - "gen_ai.usage.output_tokens": 8, - "gen_ai.usage.total_tokens": 18, - "sentry.environment": "production", - "sentry.op": "gen_ai.chat", - "sentry.origin": "auto.ai.huggingface_hub", - } - - if send_default_pii and include_prompts: - expected_data["gen_ai.request.messages"] = ( - '[{"role": "user", "content": "What is the weather in Paris?"}]' - ) - expected_data["gen_ai.response.tool_calls"] = ( - '[{"function": {"arguments": {"location": "Paris"}, "name": "get_weather", "description": "None"}, "id": "call_123", "type": "function"}]' - ) - - if not send_default_pii or not include_prompts: - assert "gen_ai.request.messages" not in expected_data - assert "gen_ai.response.text" not in expected_data - assert "gen_ai.response.tool_calls" not in expected_data - - assert span["attributes"] == ApproxDict(expected_data) - elif stream_gen_ai_spans: - items = capture_items("transaction", "span") - - with sentry_sdk.start_transaction(name="test"): - client.chat_completion( - messages=[{"role": "user", "content": "What is the weather in Paris?"}], - tools=tools, - tool_choice="auto", - ) - - spans = [item.payload for item in items if item.type == "span"] - span = None - for sp in spans: - if sp["attributes"]["sentry.op"].startswith("gen_ai"): - assert span is None, "there is exactly one gen_ai span" - span = sp - else: - # there should be no other spans, just the gen_ai span - # and optionally some http.client spans from talking to the hf api - assert sp["attributes"]["sentry.op"] == "http.client" - - assert span is not None - - assert span["attributes"]["sentry.op"] == "gen_ai.chat" - assert span["name"] == "chat test-model" - assert span["attributes"]["sentry.origin"] == "auto.ai.huggingface_hub" - - expected_data = { - "gen_ai.operation.name": "chat", - "gen_ai.request.available_tools": '[{"type": "function", "function": {"name": "get_weather", "description": "Get current weather", "parameters": {"type": "object", "properties": {"location": {"type": "string"}}, "required": ["location"]}}}]', - "gen_ai.request.model": "test-model", - "gen_ai.response.finish_reasons": "tool_calls", - "gen_ai.response.model": "test-model-123", - "gen_ai.usage.input_tokens": 10, - "gen_ai.usage.output_tokens": 8, - "gen_ai.usage.total_tokens": 18, - "sentry.environment": "production", - "sentry.op": "gen_ai.chat", - "sentry.origin": "auto.ai.huggingface_hub", - } - - if send_default_pii and include_prompts: - expected_data["gen_ai.request.messages"] = ( - '[{"role": "user", "content": "What is the weather in Paris?"}]' - ) - expected_data["gen_ai.response.tool_calls"] = ( - '[{"function": {"arguments": {"location": "Paris"}, "name": "get_weather", "description": "None"}, "id": "call_123", "type": "function"}]' - ) - - if not send_default_pii or not include_prompts: - assert "gen_ai.request.messages" not in expected_data - assert "gen_ai.response.text" not in expected_data - assert "gen_ai.response.tool_calls" not in expected_data + client.chat_completion( + messages=[{"role": "user", "content": "What is the weather in Paris?"}], + tools=tools, + tool_choice="auto", + ) - assert span["attributes"] == ApproxDict(expected_data) - else: - events = capture_events() - - with sentry_sdk.start_transaction(name="test"): - client.chat_completion( - messages=[{"role": "user", "content": "What is the weather in Paris?"}], - tools=tools, - tool_choice="auto", - ) - - (transaction,) = events - - span = None - for sp in transaction["spans"]: - if sp["op"].startswith("gen_ai"): - assert span is None, "there is exactly one gen_ai span" - span = sp - else: - # there should be no other spans, just the gen_ai span - # and optionally some http.client spans from talking to the hf api - assert sp["op"] == "http.client" - - assert span is not None - - assert span["op"] == "gen_ai.chat" - assert span["description"] == "chat test-model" - assert span["origin"] == "auto.ai.huggingface_hub" - - expected_data = { - "gen_ai.operation.name": "chat", - "gen_ai.request.available_tools": '[{"type": "function", "function": {"name": "get_weather", "description": "Get current weather", "parameters": {"type": "object", "properties": {"location": {"type": "string"}}, "required": ["location"]}}}]', - "gen_ai.request.model": "test-model", - "gen_ai.response.finish_reasons": "tool_calls", - "gen_ai.response.model": "test-model-123", - "gen_ai.usage.input_tokens": 10, - "gen_ai.usage.output_tokens": 8, - "gen_ai.usage.total_tokens": 18, - } + sentry_sdk.flush() + spans = [item.payload for item in items] + span = None + for sp in spans: + if "sentry.op" in sp["attributes"] and sp["attributes"]["sentry.op"].startswith( + "gen_ai" + ): + assert span is None, "there is exactly one gen_ai span" + span = sp + elif "sentry.op" in sp["attributes"]: + # there should be no other spans, just the gen_ai span + # and optionally some http.client spans from talking to the hf api + assert sp["attributes"]["sentry.op"] == "http.client" + + assert span is not None + + assert span["attributes"]["sentry.op"] == "gen_ai.chat" + assert span["name"] == "chat test-model" + assert span["attributes"]["sentry.origin"] == "auto.ai.huggingface_hub" + + expected_data = { + "gen_ai.operation.name": "chat", + "gen_ai.request.available_tools": '[{"type": "function", "function": {"name": "get_weather", "description": "Get current weather", "parameters": {"type": "object", "properties": {"location": {"type": "string"}}, "required": ["location"]}}}]', + "gen_ai.request.model": "test-model", + "gen_ai.response.finish_reasons": "tool_calls", + "gen_ai.response.model": "test-model-123", + "gen_ai.usage.input_tokens": 10, + "gen_ai.usage.output_tokens": 8, + "gen_ai.usage.total_tokens": 18, + "sentry.environment": "production", + "sentry.op": "gen_ai.chat", + "sentry.origin": "auto.ai.huggingface_hub", + } - if send_default_pii and include_prompts: - expected_data["gen_ai.request.messages"] = ( - '[{"role": "user", "content": "What is the weather in Paris?"}]' - ) - expected_data["gen_ai.response.tool_calls"] = ( - '[{"function": {"arguments": {"location": "Paris"}, "name": "get_weather", "description": "None"}, "id": "call_123", "type": "function"}]' - ) + if send_default_pii: + expected_data["gen_ai.request.messages"] = ( + '[{"role": "user", "content": "What is the weather in Paris?"}]' + ) + expected_data["gen_ai.response.tool_calls"] = ( + '[{"function": {"arguments": {"location": "Paris"}, "name": "get_weather", "description": "None"}, "id": "call_123", "type": "function"}]' + ) - if not send_default_pii or not include_prompts: - assert "gen_ai.request.messages" not in expected_data - assert "gen_ai.response.text" not in expected_data - assert "gen_ai.response.tool_calls" not in expected_data + if not send_default_pii: + assert "gen_ai.request.messages" not in expected_data + assert "gen_ai.response.text" not in expected_data + assert "gen_ai.response.tool_calls" not in expected_data - assert span["data"] == ApproxDict(expected_data) + assert span["attributes"] == ApproxDict(expected_data) -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.httpx_mock(assert_all_requests_were_expected=False) @pytest.mark.parametrize("send_default_pii", [True, False]) -@pytest.mark.parametrize("include_prompts", [True, False]) def test_chat_completion_streaming_with_tools( sentry_init: "Any", - capture_events: "Any", capture_items: "Any", send_default_pii: "Any", - include_prompts: "Any", mock_hf_chat_completion_api_streaming_tools: "Any", - stream_gen_ai_spans: "Any", - span_streaming: "Any", ) -> None: sentry_init( traces_sample_rate=1.0, send_default_pii=send_default_pii, - integrations=[HuggingfaceHubIntegration(include_prompts=include_prompts)], - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", + integrations=[HuggingfaceHubIntegration()], ) client = get_hf_provider_inference_client() @@ -1754,200 +983,69 @@ def test_chat_completion_streaming_with_tools( }, } ] + items = capture_items("span") - if span_streaming: - items = capture_items("span") - - with sentry_sdk.traces.start_span(name="test"): - _ = list( - client.chat_completion( - messages=[ - {"role": "user", "content": "What is the weather in Paris?"} - ], - stream=True, - tools=tools, - tool_choice="auto", - ) - ) - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - span = None - for sp in spans: - if "sentry.op" in sp["attributes"] and sp["attributes"][ - "sentry.op" - ].startswith("gen_ai"): - assert span is None, "there is exactly one gen_ai span" - span = sp - elif "sentry.op" in sp["attributes"]: - # there should be no other spans, just the gen_ai span - # and optionally some http.client spans from talking to the hf api - assert sp["attributes"]["sentry.op"] == "http.client" - - assert span is not None - - assert span["attributes"]["sentry.op"] == "gen_ai.chat" - assert span["name"] == "chat test-model" - assert span["attributes"]["sentry.origin"] == "auto.ai.huggingface_hub" - - expected_data = { - "gen_ai.operation.name": "chat", - "gen_ai.request.available_tools": '[{"type": "function", "function": {"name": "get_weather", "description": "Get current weather", "parameters": {"type": "object", "properties": {"location": {"type": "string"}}, "required": ["location"]}}}]', - "gen_ai.request.model": "test-model", - "gen_ai.response.finish_reasons": "tool_calls", - "gen_ai.response.model": "test-model-123", - "gen_ai.response.streaming": True, - "sentry.environment": "production", - "sentry.op": "gen_ai.chat", - "sentry.origin": "auto.ai.huggingface_hub", - } - - if HF_VERSION and HF_VERSION >= (0, 26, 0): - expected_data["gen_ai.usage.input_tokens"] = 183 - expected_data["gen_ai.usage.output_tokens"] = 14 - expected_data["gen_ai.usage.total_tokens"] = 197 - - if send_default_pii and include_prompts: - expected_data["gen_ai.request.messages"] = ( - '[{"role": "user", "content": "What is the weather in Paris?"}]' - ) - expected_data["gen_ai.response.text"] = "response with tool calls follows" - expected_data["gen_ai.response.tool_calls"] = ( - '[{"function": {"arguments": {"location": "Paris"}, "name": "get_weather"}, "id": "call_123", "type": "function", "index": "None"}]' - ) - - if not send_default_pii or not include_prompts: - assert "gen_ai.request.messages" not in expected_data - assert "gen_ai.response.text" not in expected_data - assert "gen_ai.response.tool_calls" not in expected_data - - assert span["attributes"] == ApproxDict(expected_data) - elif stream_gen_ai_spans: - items = capture_items("transaction", "span") - - with sentry_sdk.start_transaction(name="test"): - _ = list( - client.chat_completion( - messages=[ - {"role": "user", "content": "What is the weather in Paris?"} - ], - stream=True, - tools=tools, - tool_choice="auto", - ) - ) - - spans = [item.payload for item in items if item.type == "span"] - span = None - for sp in spans: - if sp["attributes"]["sentry.op"].startswith("gen_ai"): - assert span is None, "there is exactly one gen_ai span" - span = sp - else: - # there should be no other spans, just the gen_ai span - # and optionally some http.client spans from talking to the hf api - assert sp["attributes"]["sentry.op"] == "http.client" - - assert span is not None - - assert span["attributes"]["sentry.op"] == "gen_ai.chat" - assert span["name"] == "chat test-model" - assert span["attributes"]["sentry.origin"] == "auto.ai.huggingface_hub" - - expected_data = { - "gen_ai.operation.name": "chat", - "gen_ai.request.available_tools": '[{"type": "function", "function": {"name": "get_weather", "description": "Get current weather", "parameters": {"type": "object", "properties": {"location": {"type": "string"}}, "required": ["location"]}}}]', - "gen_ai.request.model": "test-model", - "gen_ai.response.finish_reasons": "tool_calls", - "gen_ai.response.model": "test-model-123", - "gen_ai.response.streaming": True, - "sentry.environment": "production", - "sentry.op": "gen_ai.chat", - "sentry.origin": "auto.ai.huggingface_hub", - } + _ = list( + client.chat_completion( + messages=[{"role": "user", "content": "What is the weather in Paris?"}], + stream=True, + tools=tools, + tool_choice="auto", + ) + ) - if HF_VERSION and HF_VERSION >= (0, 26, 0): - expected_data["gen_ai.usage.input_tokens"] = 183 - expected_data["gen_ai.usage.output_tokens"] = 14 - expected_data["gen_ai.usage.total_tokens"] = 197 - - if send_default_pii and include_prompts: - expected_data["gen_ai.request.messages"] = ( - '[{"role": "user", "content": "What is the weather in Paris?"}]' - ) - expected_data["gen_ai.response.text"] = "response with tool calls follows" - expected_data["gen_ai.response.tool_calls"] = ( - '[{"function": {"arguments": {"location": "Paris"}, "name": "get_weather"}, "id": "call_123", "type": "function", "index": "None"}]' - ) - - if not send_default_pii or not include_prompts: - assert "gen_ai.request.messages" not in expected_data - assert "gen_ai.response.text" not in expected_data - assert "gen_ai.response.tool_calls" not in expected_data - - assert span["attributes"] == ApproxDict(expected_data) - else: - events = capture_events() - - with sentry_sdk.start_transaction(name="test"): - _ = list( - client.chat_completion( - messages=[ - {"role": "user", "content": "What is the weather in Paris?"} - ], - stream=True, - tools=tools, - tool_choice="auto", - ) - ) - - (transaction,) = events - - span = None - for sp in transaction["spans"]: - if sp["op"].startswith("gen_ai"): - assert span is None, "there is exactly one gen_ai span" - span = sp - else: - # there should be no other spans, just the gen_ai span - # and optionally some http.client spans from talking to the hf api - assert sp["op"] == "http.client" - - assert span is not None - - assert span["op"] == "gen_ai.chat" - assert span["description"] == "chat test-model" - assert span["origin"] == "auto.ai.huggingface_hub" - - expected_data = { - "gen_ai.operation.name": "chat", - "gen_ai.request.available_tools": '[{"type": "function", "function": {"name": "get_weather", "description": "Get current weather", "parameters": {"type": "object", "properties": {"location": {"type": "string"}}, "required": ["location"]}}}]', - "gen_ai.request.model": "test-model", - "gen_ai.response.finish_reasons": "tool_calls", - "gen_ai.response.model": "test-model-123", - "gen_ai.response.streaming": True, - } + sentry_sdk.flush() + spans = [item.payload for item in items] + span = None + for sp in spans: + if "sentry.op" in sp["attributes"] and sp["attributes"]["sentry.op"].startswith( + "gen_ai" + ): + assert span is None, "there is exactly one gen_ai span" + span = sp + elif "sentry.op" in sp["attributes"]: + # there should be no other spans, just the gen_ai span + # and optionally some http.client spans from talking to the hf api + assert sp["attributes"]["sentry.op"] == "http.client" + + assert span is not None + + assert span["attributes"]["sentry.op"] == "gen_ai.chat" + assert span["name"] == "chat test-model" + assert span["attributes"]["sentry.origin"] == "auto.ai.huggingface_hub" + + expected_data = { + "gen_ai.operation.name": "chat", + "gen_ai.request.available_tools": '[{"type": "function", "function": {"name": "get_weather", "description": "Get current weather", "parameters": {"type": "object", "properties": {"location": {"type": "string"}}, "required": ["location"]}}}]', + "gen_ai.request.model": "test-model", + "gen_ai.response.finish_reasons": "tool_calls", + "gen_ai.response.model": "test-model-123", + "gen_ai.response.streaming": True, + "sentry.environment": "production", + "sentry.op": "gen_ai.chat", + "sentry.origin": "auto.ai.huggingface_hub", + } - if HF_VERSION and HF_VERSION >= (0, 26, 0): - expected_data["gen_ai.usage.input_tokens"] = 183 - expected_data["gen_ai.usage.output_tokens"] = 14 - expected_data["gen_ai.usage.total_tokens"] = 197 + if HF_VERSION and HF_VERSION >= (0, 26, 0): + expected_data["gen_ai.usage.input_tokens"] = 183 + expected_data["gen_ai.usage.output_tokens"] = 14 + expected_data["gen_ai.usage.total_tokens"] = 197 - if send_default_pii and include_prompts: - expected_data["gen_ai.request.messages"] = ( - '[{"role": "user", "content": "What is the weather in Paris?"}]' - ) - expected_data["gen_ai.response.text"] = "response with tool calls follows" - expected_data["gen_ai.response.tool_calls"] = ( - '[{"function": {"arguments": {"location": "Paris"}, "name": "get_weather"}, "id": "call_123", "type": "function", "index": "None"}]' - ) + if send_default_pii: + expected_data["gen_ai.request.messages"] = ( + '[{"role": "user", "content": "What is the weather in Paris?"}]' + ) + expected_data["gen_ai.response.text"] = "response with tool calls follows" + expected_data["gen_ai.response.tool_calls"] = ( + '[{"function": {"arguments": {"location": "Paris"}, "name": "get_weather"}, "id": "call_123", "type": "function", "index": "None"}]' + ) - if not send_default_pii or not include_prompts: - assert "gen_ai.request.messages" not in expected_data - assert "gen_ai.response.text" not in expected_data - assert "gen_ai.response.tool_calls" not in expected_data + if not send_default_pii: + assert "gen_ai.request.messages" not in expected_data + assert "gen_ai.response.text" not in expected_data + assert "gen_ai.response.tool_calls" not in expected_data - assert span["data"] == ApproxDict(expected_data) + assert span["attributes"] == ApproxDict(expected_data) DATA_COLLECTION_TOOLS = [ @@ -1966,15 +1064,13 @@ def test_chat_completion_streaming_with_tools( ] -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.httpx_mock(assert_all_requests_were_expected=False) @pytest.mark.parametrize( - "data_collection,send_default_pii,include_prompts,expected_present,expected_absent", + "data_collection,send_default_pii,expected_present,expected_absent", [ pytest.param( {"gen_ai": {"inputs": True, "outputs": True}}, False, - False, [ SPANDATA.GEN_AI_REQUEST_MESSAGES, SPANDATA.GEN_AI_RESPONSE_TEXT, @@ -1985,7 +1081,6 @@ def test_chat_completion_streaming_with_tools( pytest.param( {"gen_ai": {"inputs": False, "outputs": False}}, True, - True, [], [ SPANDATA.GEN_AI_REQUEST_MESSAGES, @@ -1996,7 +1091,6 @@ def test_chat_completion_streaming_with_tools( pytest.param( {"gen_ai": {"inputs": True, "outputs": False}}, False, - False, [ SPANDATA.GEN_AI_REQUEST_MESSAGES, ], @@ -2008,7 +1102,6 @@ def test_chat_completion_streaming_with_tools( pytest.param( {"gen_ai": {"inputs": False, "outputs": True}}, False, - False, [ SPANDATA.GEN_AI_RESPONSE_TEXT, ], @@ -2020,7 +1113,6 @@ def test_chat_completion_streaming_with_tools( pytest.param( {"gen_ai": {}}, False, - False, [ SPANDATA.GEN_AI_REQUEST_MESSAGES, SPANDATA.GEN_AI_RESPONSE_TEXT, @@ -2031,18 +1123,16 @@ def test_chat_completion_streaming_with_tools( pytest.param( None, True, - True, [ SPANDATA.GEN_AI_REQUEST_MESSAGES, SPANDATA.GEN_AI_RESPONSE_TEXT, ], [], - id="no-gen-ai-config-legacy-pii-and-include-prompts-enabled", + id="no-gen-ai-config-legacy-pii", ), pytest.param( None, False, - True, [], [ SPANDATA.GEN_AI_REQUEST_MESSAGES, @@ -2052,26 +1142,19 @@ def test_chat_completion_streaming_with_tools( ), ], ) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_text_generation_data_collection( sentry_init: "Any", - capture_events: "Any", capture_items: "Any", mock_hf_text_generation_api: "Any", data_collection: "Any", send_default_pii: "Any", - include_prompts: "Any", expected_present: "Any", expected_absent: "Any", - stream_gen_ai_spans: "Any", - span_streaming: "Any", ) -> None: sentry_init_kwargs = dict( traces_sample_rate=1.0, send_default_pii=send_default_pii, - integrations=[HuggingfaceHubIntegration(include_prompts=include_prompts)], - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", + integrations=[HuggingfaceHubIntegration()], ) if data_collection is not None: sentry_init_kwargs["data_collection"] = data_collection @@ -2080,26 +1163,13 @@ def test_text_generation_data_collection( client = InferenceClient(model="test-model") - captured = ( - capture_items("transaction", "span") - if span_streaming or stream_gen_ai_spans - else capture_events() - ) - - with sentry_sdk.start_transaction(name="test"): - client.text_generation("Hello", stream=False, details=True) + captured = capture_items("span") - if span_streaming or stream_gen_ai_spans: - sentry_sdk.flush() - spans = [item.payload for item in captured if item.type == "span"] - (span,) = [ - sp for sp in spans if sp["attributes"]["sentry.op"].startswith("gen_ai") - ] - span_data = span["attributes"] - else: - (transaction,) = captured - (span,) = [sp for sp in transaction["spans"] if sp["op"].startswith("gen_ai")] - span_data = span["data"] + client.text_generation("Hello", stream=False, details=True) + sentry_sdk.flush() + spans = [item.payload for item in captured] + (span,) = [sp for sp in spans if sp["attributes"]["sentry.op"].startswith("gen_ai")] + span_data = span["attributes"] expected_values = { SPANDATA.GEN_AI_REQUEST_MESSAGES: "Hello", @@ -2120,15 +1190,13 @@ def test_text_generation_data_collection( assert span_data[SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 10 -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.httpx_mock(assert_all_requests_were_expected=False) @pytest.mark.parametrize( - "data_collection,send_default_pii,include_prompts,expected_present,expected_absent", + "data_collection,send_default_pii,expected_present,expected_absent", [ pytest.param( {"gen_ai": {"inputs": True, "outputs": True}}, False, - False, [ SPANDATA.GEN_AI_REQUEST_MESSAGES, SPANDATA.GEN_AI_RESPONSE_TEXT, @@ -2139,7 +1207,6 @@ def test_text_generation_data_collection( pytest.param( {"gen_ai": {"inputs": False, "outputs": False}}, True, - True, [], [ SPANDATA.GEN_AI_REQUEST_MESSAGES, @@ -2150,7 +1217,6 @@ def test_text_generation_data_collection( pytest.param( {"gen_ai": {"inputs": True, "outputs": False}}, False, - False, [ SPANDATA.GEN_AI_REQUEST_MESSAGES, ], @@ -2162,7 +1228,6 @@ def test_text_generation_data_collection( pytest.param( {"gen_ai": {"inputs": False, "outputs": True}}, False, - False, [ SPANDATA.GEN_AI_RESPONSE_TEXT, ], @@ -2174,7 +1239,6 @@ def test_text_generation_data_collection( pytest.param( {"gen_ai": {}}, False, - False, [ SPANDATA.GEN_AI_REQUEST_MESSAGES, SPANDATA.GEN_AI_RESPONSE_TEXT, @@ -2185,18 +1249,16 @@ def test_text_generation_data_collection( pytest.param( None, True, - True, [ SPANDATA.GEN_AI_REQUEST_MESSAGES, SPANDATA.GEN_AI_RESPONSE_TEXT, ], [], - id="no-gen-ai-config-legacy-pii-and-include-prompts-enabled", + id="no-gen-ai-config-legacy-pii", ), pytest.param( None, False, - True, [], [ SPANDATA.GEN_AI_REQUEST_MESSAGES, @@ -2206,26 +1268,19 @@ def test_text_generation_data_collection( ), ], ) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_text_generation_streaming_data_collection( sentry_init: "Any", - capture_events: "Any", capture_items: "Any", mock_hf_text_generation_api_streaming: "Any", data_collection: "Any", send_default_pii: "Any", - include_prompts: "Any", expected_present: "Any", expected_absent: "Any", - stream_gen_ai_spans: "Any", - span_streaming: "Any", ) -> None: sentry_init_kwargs = dict( traces_sample_rate=1.0, send_default_pii=send_default_pii, - integrations=[HuggingfaceHubIntegration(include_prompts=include_prompts)], - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", + integrations=[HuggingfaceHubIntegration()], ) if data_collection is not None: sentry_init_kwargs["data_collection"] = data_collection @@ -2234,27 +1289,14 @@ def test_text_generation_streaming_data_collection( client = InferenceClient(model="test-model") - captured = ( - capture_items("transaction", "span") - if span_streaming or stream_gen_ai_spans - else capture_events() - ) + captured = capture_items("span") - with sentry_sdk.start_transaction(name="test"): - for _ in client.text_generation(prompt="Hello", stream=True, details=True): - pass - - if span_streaming or stream_gen_ai_spans: - sentry_sdk.flush() - spans = [item.payload for item in captured if item.type == "span"] - (span,) = [ - sp for sp in spans if sp["attributes"]["sentry.op"].startswith("gen_ai") - ] - span_data = span["attributes"] - else: - (transaction,) = captured - (span,) = [sp for sp in transaction["spans"] if sp["op"].startswith("gen_ai")] - span_data = span["data"] + for _ in client.text_generation(prompt="Hello", stream=True, details=True): + pass + sentry_sdk.flush() + spans = [item.payload for item in captured] + (span,) = [sp for sp in spans if sp["attributes"]["sentry.op"].startswith("gen_ai")] + span_data = span["attributes"] expected_values = { SPANDATA.GEN_AI_REQUEST_MESSAGES: "Hello", @@ -2276,15 +1318,13 @@ def test_text_generation_streaming_data_collection( assert span_data[SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 10 -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.httpx_mock(assert_all_requests_were_expected=False) @pytest.mark.parametrize( - "data_collection,send_default_pii,include_prompts,expected_present,expected_absent", + "data_collection,send_default_pii,expected_present,expected_absent", [ pytest.param( {"gen_ai": {"inputs": True, "outputs": True}}, False, - False, [ SPANDATA.GEN_AI_REQUEST_MESSAGES, SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS, @@ -2296,7 +1336,6 @@ def test_text_generation_streaming_data_collection( pytest.param( {"gen_ai": {"inputs": False, "outputs": False}}, True, - True, [], [ SPANDATA.GEN_AI_REQUEST_MESSAGES, @@ -2308,7 +1347,6 @@ def test_text_generation_streaming_data_collection( pytest.param( {"gen_ai": {"inputs": True, "outputs": False}}, False, - False, [ SPANDATA.GEN_AI_REQUEST_MESSAGES, SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS, @@ -2321,7 +1359,6 @@ def test_text_generation_streaming_data_collection( pytest.param( {"gen_ai": {"inputs": False, "outputs": True}}, False, - False, [ SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS, ], @@ -2334,7 +1371,6 @@ def test_text_generation_streaming_data_collection( pytest.param( {"gen_ai": {}}, False, - False, [ SPANDATA.GEN_AI_REQUEST_MESSAGES, SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS, @@ -2346,19 +1382,17 @@ def test_text_generation_streaming_data_collection( pytest.param( None, True, - True, [ SPANDATA.GEN_AI_REQUEST_MESSAGES, SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS, SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS, ], [], - id="no-gen-ai-config-legacy-pii-and-include-prompts-enabled", + id="no-gen-ai-config-legacy-pii", ), pytest.param( None, False, - True, [ SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS, ], @@ -2370,26 +1404,19 @@ def test_text_generation_streaming_data_collection( ), ], ) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_chat_completion_data_collection_tools( sentry_init: "Any", - capture_events: "Any", capture_items: "Any", mock_hf_chat_completion_api_tools: "Any", data_collection: "Any", send_default_pii: "Any", - include_prompts: "Any", expected_present: "Any", expected_absent: "Any", - stream_gen_ai_spans: "Any", - span_streaming: "Any", ) -> None: sentry_init_kwargs = dict( traces_sample_rate=1.0, send_default_pii=send_default_pii, - integrations=[HuggingfaceHubIntegration(include_prompts=include_prompts)], - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", + integrations=[HuggingfaceHubIntegration()], ) if data_collection is not None: sentry_init_kwargs["data_collection"] = data_collection @@ -2398,30 +1425,17 @@ def test_chat_completion_data_collection_tools( client = get_hf_provider_inference_client() - captured = ( - capture_items("transaction", "span") - if span_streaming or stream_gen_ai_spans - else capture_events() - ) + captured = capture_items("span") - with sentry_sdk.start_transaction(name="test"): - client.chat_completion( - messages=[{"role": "user", "content": "What is the weather in Paris?"}], - tools=DATA_COLLECTION_TOOLS, - tool_choice="auto", - ) - - if span_streaming or stream_gen_ai_spans: - sentry_sdk.flush() - spans = [item.payload for item in captured if item.type == "span"] - (span,) = [ - sp for sp in spans if sp["attributes"]["sentry.op"].startswith("gen_ai") - ] - span_data = span["attributes"] - else: - (transaction,) = captured - (span,) = [sp for sp in transaction["spans"] if sp["op"].startswith("gen_ai")] - span_data = span["data"] + client.chat_completion( + messages=[{"role": "user", "content": "What is the weather in Paris?"}], + tools=DATA_COLLECTION_TOOLS, + tool_choice="auto", + ) + sentry_sdk.flush() + spans = [item.payload for item in captured] + (span,) = [sp for sp in spans if sp["attributes"]["sentry.op"].startswith("gen_ai")] + span_data = span["attributes"] expected_values = { SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS: '[{"type": "function", "function": {"name": "get_weather", "description": "Get current weather", "parameters": {"type": "object", "properties": {"location": {"type": "string"}}, "required": ["location"]}}}]', @@ -2449,15 +1463,13 @@ def test_chat_completion_data_collection_tools( assert span_data[SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 18 -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.httpx_mock(assert_all_requests_were_expected=False) @pytest.mark.parametrize( - "data_collection,send_default_pii,include_prompts,expected_present,expected_absent", + "data_collection,send_default_pii,expected_present,expected_absent", [ pytest.param( {"gen_ai": {"inputs": True, "outputs": True}}, False, - False, [ SPANDATA.GEN_AI_REQUEST_MESSAGES, SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS, @@ -2470,7 +1482,6 @@ def test_chat_completion_data_collection_tools( pytest.param( {"gen_ai": {"inputs": False, "outputs": False}}, True, - True, [], [ SPANDATA.GEN_AI_REQUEST_MESSAGES, @@ -2483,7 +1494,6 @@ def test_chat_completion_data_collection_tools( pytest.param( {"gen_ai": {"inputs": True, "outputs": False}}, False, - False, [ SPANDATA.GEN_AI_REQUEST_MESSAGES, SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS, @@ -2497,7 +1507,6 @@ def test_chat_completion_data_collection_tools( pytest.param( {"gen_ai": {"inputs": False, "outputs": True}}, False, - False, [ SPANDATA.GEN_AI_RESPONSE_TEXT, SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS, @@ -2511,7 +1520,6 @@ def test_chat_completion_data_collection_tools( pytest.param( {"gen_ai": {}}, False, - False, [ SPANDATA.GEN_AI_REQUEST_MESSAGES, SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS, @@ -2524,7 +1532,6 @@ def test_chat_completion_data_collection_tools( pytest.param( None, True, - True, [ SPANDATA.GEN_AI_REQUEST_MESSAGES, SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS, @@ -2532,12 +1539,11 @@ def test_chat_completion_data_collection_tools( SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS, ], [], - id="no-gen-ai-config-legacy-pii-and-include-prompts-enabled", + id="no-gen-ai-config-legacy-pii", ), pytest.param( None, False, - True, [ SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS, ], @@ -2550,26 +1556,19 @@ def test_chat_completion_data_collection_tools( ), ], ) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_chat_completion_streaming_data_collection_tools( sentry_init: "Any", - capture_events: "Any", capture_items: "Any", mock_hf_chat_completion_api_streaming_tools: "Any", data_collection: "Any", send_default_pii: "Any", - include_prompts: "Any", expected_present: "Any", expected_absent: "Any", - stream_gen_ai_spans: "Any", - span_streaming: "Any", ) -> None: sentry_init_kwargs = dict( traces_sample_rate=1.0, send_default_pii=send_default_pii, - integrations=[HuggingfaceHubIntegration(include_prompts=include_prompts)], - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", + integrations=[HuggingfaceHubIntegration()], ) if data_collection is not None: sentry_init_kwargs["data_collection"] = data_collection @@ -2578,32 +1577,19 @@ def test_chat_completion_streaming_data_collection_tools( client = get_hf_provider_inference_client() - captured = ( - capture_items("transaction", "span") - if span_streaming or stream_gen_ai_spans - else capture_events() - ) - - with sentry_sdk.start_transaction(name="test"): - for _ in client.chat_completion( - messages=[{"role": "user", "content": "What is the weather in Paris?"}], - tools=DATA_COLLECTION_TOOLS, - tool_choice="auto", - stream=True, - ): - pass - - if span_streaming or stream_gen_ai_spans: - sentry_sdk.flush() - spans = [item.payload for item in captured if item.type == "span"] - (span,) = [ - sp for sp in spans if sp["attributes"]["sentry.op"].startswith("gen_ai") - ] - span_data = span["attributes"] - else: - (transaction,) = captured - (span,) = [sp for sp in transaction["spans"] if sp["op"].startswith("gen_ai")] - span_data = span["data"] + captured = capture_items("span") + + for _ in client.chat_completion( + messages=[{"role": "user", "content": "What is the weather in Paris?"}], + tools=DATA_COLLECTION_TOOLS, + tool_choice="auto", + stream=True, + ): + pass + sentry_sdk.flush() + spans = [item.payload for item in captured] + (span,) = [sp for sp in spans if sp["attributes"]["sentry.op"].startswith("gen_ai")] + span_data = span["attributes"] expected_values = { SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS: '[{"type": "function", "function": {"name": "get_weather", "description": "Get current weather", "parameters": {"type": "object", "properties": {"location": {"type": "string"}}, "required": ["location"]}}}]', diff --git a/tests/integrations/langchain/test_langchain.py b/tests/integrations/langchain/test_langchain.py index a6fa363744..9cf2360fd2 100644 --- a/tests/integrations/langchain/test_langchain.py +++ b/tests/integrations/langchain/test_langchain.py @@ -29,7 +29,6 @@ google = None import sentry_sdk -from sentry_sdk import start_transaction from sentry_sdk.integrations.langchain import ( LangchainIntegration, SentryLangchainCallback, @@ -283,27 +282,16 @@ def get_word_length(word: str) -> int: return len(word) -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_langchain_text_completion( sentry_init, - capture_events, capture_items, get_model_response, - stream_gen_ai_spans, - span_streaming, ): sentry_init( - integrations=[ - LangchainIntegration( - include_prompts=True, - ) - ], + integrations=[LangchainIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) model_response = get_model_response( @@ -334,131 +322,50 @@ def test_langchain_text_completion( max_tokens=100, openai_api_key="badkey", ) + items = capture_items("span") - if span_streaming: - items = capture_items("transaction", "span") - - with patch.object( - model.client._client._client, - "send", - return_value=model_response, - ) as _, sentry_sdk.traces.start_span(name="custom parent"): - input_text = "What is the capital of France?" - model.invoke(input_text, config={"run_name": "my-snazzy-pipeline"}) - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - llm_spans = [ - span - for span in spans - if span["attributes"].get("sentry.op") == "gen_ai.text_completion" - ] - assert len(llm_spans) > 0 - - llm_span = llm_spans[0] - assert llm_span["name"] == "text_completion gpt-3.5-turbo" - assert llm_span["attributes"]["gen_ai.system"] == "openai" - assert llm_span["attributes"]["gen_ai.function_id"] == "my-snazzy-pipeline" - assert llm_span["attributes"]["gen_ai.request.model"] == "gpt-3.5-turbo" - assert ( - llm_span["attributes"]["gen_ai.response.text"] - == "The capital of France is Paris." - ) - assert llm_span["attributes"]["gen_ai.usage.total_tokens"] == 25 - assert llm_span["attributes"]["gen_ai.usage.input_tokens"] == 10 - assert llm_span["attributes"]["gen_ai.usage.output_tokens"] == 15 - elif stream_gen_ai_spans: - items = capture_items("transaction", "span") - - with patch.object( - model.client._client._client, - "send", - return_value=model_response, - ) as _, start_transaction(): - input_text = "What is the capital of France?" - model.invoke(input_text, config={"run_name": "my-snazzy-pipeline"}) - - tx = next(item.payload for item in items if item.type == "transaction") - assert tx["type"] == "transaction" - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - llm_spans = [ - span - for span in spans - if span["attributes"].get("sentry.op") == "gen_ai.text_completion" - ] - assert len(llm_spans) > 0 + with patch.object( + model.client._client._client, + "send", + return_value=model_response, + ): + input_text = "What is the capital of France?" + model.invoke(input_text, config={"run_name": "my-snazzy-pipeline"}) - llm_span = llm_spans[0] - assert llm_span["name"] == "text_completion gpt-3.5-turbo" - assert llm_span["attributes"]["gen_ai.system"] == "openai" - assert llm_span["attributes"]["gen_ai.function_id"] == "my-snazzy-pipeline" - assert llm_span["attributes"]["gen_ai.request.model"] == "gpt-3.5-turbo" - assert ( - llm_span["attributes"]["gen_ai.response.text"] - == "The capital of France is Paris." - ) - assert llm_span["attributes"]["gen_ai.usage.total_tokens"] == 25 - assert llm_span["attributes"]["gen_ai.usage.input_tokens"] == 10 - assert llm_span["attributes"]["gen_ai.usage.output_tokens"] == 15 - else: - events = capture_events() - - with patch.object( - model.client._client._client, - "send", - return_value=model_response, - ) as _, start_transaction(): - input_text = "What is the capital of France?" - model.invoke(input_text, config={"run_name": "my-snazzy-pipeline"}) - - tx = events[0] - assert tx["type"] == "transaction" - - llm_spans = [ - span - for span in tx.get("spans", []) - if span.get("op") == "gen_ai.text_completion" - ] - assert len(llm_spans) > 0 + sentry_sdk.flush() + spans = [item.payload for item in items] + llm_spans = [ + span + for span in spans + if span["attributes"].get("sentry.op") == "gen_ai.text_completion" + ] + assert len(llm_spans) > 0 - llm_span = llm_spans[0] - assert llm_span["description"] == "text_completion gpt-3.5-turbo" - assert llm_span["data"]["gen_ai.system"] == "openai" - assert llm_span["data"]["gen_ai.function_id"] == "my-snazzy-pipeline" - assert llm_span["data"]["gen_ai.request.model"] == "gpt-3.5-turbo" - assert ( - llm_span["data"]["gen_ai.response.text"] - == "The capital of France is Paris." - ) - assert llm_span["data"]["gen_ai.usage.total_tokens"] == 25 - assert llm_span["data"]["gen_ai.usage.input_tokens"] == 10 - assert llm_span["data"]["gen_ai.usage.output_tokens"] == 15 + llm_span = llm_spans[0] + assert llm_span["name"] == "text_completion gpt-3.5-turbo" + assert llm_span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "openai" + assert llm_span["attributes"]["gen_ai.function_id"] == "my-snazzy-pipeline" + assert llm_span["attributes"]["gen_ai.request.model"] == "gpt-3.5-turbo" + assert ( + llm_span["attributes"]["gen_ai.response.text"] + == "The capital of France is Paris." + ) + assert llm_span["attributes"]["gen_ai.usage.total_tokens"] == 25 + assert llm_span["attributes"]["gen_ai.usage.input_tokens"] == 10 + assert llm_span["attributes"]["gen_ai.usage.output_tokens"] == 15 -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_langchain_chat_with_run_name( sentry_init, - capture_events, capture_items, get_model_response, nonstreaming_chat_completions_model_response, - stream_gen_ai_spans, - span_streaming, ): sentry_init( - integrations=[ - LangchainIntegration( - include_prompts=True, - ) - ], + integrations=[LangchainIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) request_headers = {} @@ -487,78 +394,42 @@ def test_langchain_chat_with_run_name( temperature=0, openai_api_key="badkey", ) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with patch.object( - llm.client._client._client, - "send", - return_value=model_response, - ) as _, start_transaction(): - llm.invoke( - "How many letters in the word eudca", - config={"run_name": "my-snazzy-pipeline"}, - ) - - sentry_sdk.flush() - spans = [item.payload for item in items] - chat_spans = list( - x for x in spans if x["attributes"]["sentry.op"] == "gen_ai.chat" - ) - assert len(chat_spans) == 1 - assert ( - chat_spans[0]["attributes"][SPANDATA.GEN_AI_FUNCTION_ID] - == "my-snazzy-pipeline" + with patch.object( + llm.client._client._client, + "send", + return_value=model_response, + ): + llm.invoke( + "How many letters in the word eudca", + config={"run_name": "my-snazzy-pipeline"}, ) - else: - events = capture_events() - - with patch.object( - llm.client._client._client, - "send", - return_value=model_response, - ) as _, start_transaction(): - llm.invoke( - "How many letters in the word eudca", - config={"run_name": "my-snazzy-pipeline"}, - ) - - tx = events[0] - chat_spans = list(x for x in tx["spans"] if x["op"] == "gen_ai.chat") - assert len(chat_spans) == 1 - assert ( - chat_spans[0]["data"][SPANDATA.GEN_AI_FUNCTION_ID] == "my-snazzy-pipeline" - ) + sentry_sdk.flush() + spans = [item.payload for item in items] + chat_spans = list(x for x in spans if x["attributes"]["sentry.op"] == "gen_ai.chat") + assert len(chat_spans) == 1 + assert ( + chat_spans[0]["attributes"][SPANDATA.GEN_AI_FUNCTION_ID] == "my-snazzy-pipeline" + ) @pytest.mark.skipif( ChatGoogleGenerativeAI is None, reason="Requires langchain-google-genai.", ) -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_langchain_multi_choice_response( sentry_init, - capture_events, capture_items, get_model_response, nonstreaming_multi_candidate_google_genai_model_response, - stream_gen_ai_spans, - span_streaming, ): sentry_init( - integrations=[ - LangchainIntegration( - include_prompts=True, - ) - ], + integrations=[LangchainIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) model_response = get_model_response( @@ -571,129 +442,66 @@ def test_langchain_multi_choice_response( temperature=0, google_api_key="badkey", ) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with patch.object( - llm.client._api_client._httpx_client, - "send", - return_value=model_response, - ) as _, start_transaction(): - llm.invoke( - "How many letters in the word eudca", - ) - - sentry_sdk.flush() - spans = [item.payload for item in items] - chat_spans = list( - x for x in spans if x["attributes"]["sentry.op"] == "gen_ai.chat" - ) - assert len(chat_spans) == 1 - - assert chat_spans[0]["attributes"]["gen_ai.usage.input_tokens"] == 10 - assert chat_spans[0]["attributes"]["gen_ai.usage.output_tokens"] == 25 - assert chat_spans[0]["attributes"]["gen_ai.usage.total_tokens"] == 30 - - assert ( - chat_spans[0]["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] - == 4 + with patch.object( + llm.client._api_client._httpx_client, + "send", + return_value=model_response, + ): + llm.invoke( + "How many letters in the word eudca", ) - else: - events = capture_events() - - with patch.object( - llm.client._api_client._httpx_client, - "send", - return_value=model_response, - ) as _, start_transaction(): - llm.invoke( - "How many letters in the word eudca", - ) - - tx = events[0] - chat_spans = list(x for x in tx["spans"] if x["op"] == "gen_ai.chat") - assert len(chat_spans) == 1 + sentry_sdk.flush() + spans = [item.payload for item in items] + chat_spans = list(x for x in spans if x["attributes"]["sentry.op"] == "gen_ai.chat") + assert len(chat_spans) == 1 - assert chat_spans[0]["data"]["gen_ai.usage.input_tokens"] == 10 - assert chat_spans[0]["data"]["gen_ai.usage.output_tokens"] == 25 - assert chat_spans[0]["data"]["gen_ai.usage.total_tokens"] == 30 + assert chat_spans[0]["attributes"]["gen_ai.usage.input_tokens"] == 10 + assert chat_spans[0]["attributes"]["gen_ai.usage.output_tokens"] == 25 + assert chat_spans[0]["attributes"]["gen_ai.usage.total_tokens"] == 30 - assert chat_spans[0]["data"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] == 4 + assert ( + chat_spans[0]["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] == 4 + ) -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_langchain_tool_call_with_run_name( sentry_init, - capture_events, capture_items, - stream_gen_ai_spans, - span_streaming, ): sentry_init( - integrations=[ - LangchainIntegration( - include_prompts=True, - ) - ], + integrations=[LangchainIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with start_transaction(): - get_word_length.invoke( - {"word": "eudca"}, - config={"run_name": "my-snazzy-pipeline"}, - ) - - sentry_sdk.flush() - spans = [item.payload for item in items] - tool_spans = list( - x for x in spans if x["attributes"]["sentry.op"] == "gen_ai.execute_tool" - ) - assert len(tool_spans) == 1 - assert ( - tool_spans[0]["attributes"][SPANDATA.GEN_AI_FUNCTION_ID] - == "my-snazzy-pipeline" - ) - else: - events = capture_events() + items = capture_items("span") - with start_transaction(): - get_word_length.invoke( - {"word": "eudca"}, - config={"run_name": "my-snazzy-pipeline"}, - ) + get_word_length.invoke( + {"word": "eudca"}, + config={"run_name": "my-snazzy-pipeline"}, + ) - tx = events[0] - tool_spans = list(x for x in tx["spans"] if x["op"] == "gen_ai.execute_tool") - assert len(tool_spans) == 1 - assert ( - tool_spans[0]["data"][SPANDATA.GEN_AI_FUNCTION_ID] == "my-snazzy-pipeline" - ) + sentry_sdk.flush() + spans = [item.payload for item in items] + tool_spans = list( + x for x in spans if x["attributes"]["sentry.op"] == "gen_ai.execute_tool" + ) + assert len(tool_spans) == 1 + assert ( + tool_spans[0]["attributes"][SPANDATA.GEN_AI_FUNCTION_ID] == "my-snazzy-pipeline" + ) -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.skipif( LANGCHAIN_VERSION < (1,), reason="LangChain 1.0+ required (ONE AGENT refactor)", ) @pytest.mark.parametrize( - "send_default_pii, include_prompts", - [ - (True, True), - (True, False), - (False, True), - (False, False), - ], + "send_default_pii", + [True, False], ) @pytest.mark.parametrize( "system_instructions_content,expected_system_instructions", @@ -727,28 +535,18 @@ def test_langchain_tool_call_with_run_name( ) def test_langchain_create_agent( sentry_init, - capture_events, capture_items, send_default_pii, - include_prompts, system_instructions_content, expected_system_instructions, get_model_response, nonstreaming_responses_model_response, - stream_gen_ai_spans, - span_streaming, ): sentry_init( - integrations=[ - LangchainIntegration( - include_prompts=include_prompts, - ) - ], + integrations=[LangchainIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) model_response = get_model_response( @@ -771,284 +569,106 @@ def test_langchain_create_agent( system_prompt=SystemMessage(content=system_instructions_content), name="word_length_agent", ) + items = capture_items("span") - if span_streaming: - items = capture_items("transaction", "span") - - with patch.object( - llm.client._client._client, - "send", - return_value=model_response, - ) as _, sentry_sdk.traces.start_span(name="custom parent"): - agent.invoke( - { - "messages": [ - HumanMessage( - content="Message demonstrating the absence of truncation." - ), - HumanMessage(content="How many letters in the word eudca"), - ], - }, - ) - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert spans[2]["attributes"]["sentry.origin"] == "manual" - chat_spans = list( - x for x in spans if x["attributes"].get("sentry.op") == "gen_ai.chat" - ) - assert len(chat_spans) == 1 - assert chat_spans[0]["attributes"]["sentry.origin"] == "auto.ai.langchain" - - assert chat_spans[0]["attributes"]["gen_ai.system"] == "openai-chat" - assert chat_spans[0]["attributes"]["gen_ai.agent.name"] == "word_length_agent" - - assert chat_spans[0]["attributes"]["gen_ai.usage.input_tokens"] == 10 - assert chat_spans[0]["attributes"]["gen_ai.usage.output_tokens"] == 20 - assert chat_spans[0]["attributes"]["gen_ai.usage.total_tokens"] == 30 - - assert ( - chat_spans[0]["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] - == 4 - ) - assert ( - chat_spans[0]["attributes"][ - SPANDATA.GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS - ] - == 6 - ) - - assert ( - chat_spans[0]["attributes"][SPANDATA.GEN_AI_USAGE_REASONING_OUTPUT_TOKENS] - == 5 + with patch.object( + llm.client._client._client, + "send", + return_value=model_response, + ): + agent.invoke( + { + "messages": [ + HumanMessage( + content="Message demonstrating the absence of truncation." + ), + HumanMessage(content="How many letters in the word eudca"), + ], + }, ) - if LANGCHAIN_OPENAI_VERSION >= (0, 3, 13): - assert ( - chat_spans[0]["attributes"][SPANDATA.GEN_AI_RESPONSE_MODEL] == "gpt-4" - ) - - if send_default_pii and include_prompts: - assert ( - chat_spans[0]["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] - == "Hello, how can I help you?" - ) - - assert json.loads( - chat_spans[0]["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - ) == [ - { - "role": "user", - "content": "Message demonstrating the absence of truncation.", - }, - { - "role": "user", - "content": "How many letters in the word eudca", - }, - ] - - assert expected_system_instructions == json.loads( - chat_spans[0]["attributes"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS] - ) - else: - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in chat_spans[0].get( - "attributes", {} - ) - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in chat_spans[0].get( - "attributes", {} - ) - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in chat_spans[0].get( - "attributes", {} - ) - - elif stream_gen_ai_spans: - items = capture_items("transaction", "span") - - with patch.object( - llm.client._client._client, - "send", - return_value=model_response, - ) as _, start_transaction(): - agent.invoke( - { - "messages": [ - HumanMessage( - content="Message demonstrating the absence of truncation." - ), - HumanMessage(content="How many letters in the word eudca"), - ], - }, - ) + sentry_sdk.flush() + spans = [item.payload for item in items] + chat_spans = list( + x for x in spans if x["attributes"].get("sentry.op") == "gen_ai.chat" + ) + assert len(chat_spans) == 1 + assert chat_spans[0]["attributes"]["sentry.origin"] == "auto.ai.langchain" - tx = next(item.payload for item in items if item.type == "transaction") - assert tx["type"] == "transaction" - assert tx["contexts"]["trace"]["origin"] == "manual" + assert chat_spans[0]["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "openai-chat" + assert chat_spans[0]["attributes"]["gen_ai.agent.name"] == "word_length_agent" - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - chat_spans = list( - x for x in spans if x["attributes"]["sentry.op"] == "gen_ai.chat" - ) - assert len(chat_spans) == 1 - assert chat_spans[0]["attributes"]["sentry.origin"] == "auto.ai.langchain" + assert chat_spans[0]["attributes"]["gen_ai.usage.input_tokens"] == 10 + assert chat_spans[0]["attributes"]["gen_ai.usage.output_tokens"] == 20 + assert chat_spans[0]["attributes"]["gen_ai.usage.total_tokens"] == 30 - assert chat_spans[0]["attributes"]["gen_ai.system"] == "openai-chat" - assert chat_spans[0]["attributes"]["gen_ai.agent.name"] == "word_length_agent" + assert ( + chat_spans[0]["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] == 4 + ) + assert ( + chat_spans[0]["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS] + == 6 + ) - assert chat_spans[0]["attributes"]["gen_ai.usage.input_tokens"] == 10 - assert chat_spans[0]["attributes"]["gen_ai.usage.output_tokens"] == 20 - assert chat_spans[0]["attributes"]["gen_ai.usage.total_tokens"] == 30 + assert ( + chat_spans[0]["attributes"][SPANDATA.GEN_AI_USAGE_REASONING_OUTPUT_TOKENS] == 5 + ) - assert ( - chat_spans[0]["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] - == 4 - ) - assert ( - chat_spans[0]["attributes"][ - SPANDATA.GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS - ] - == 6 - ) + if LANGCHAIN_OPENAI_VERSION >= (0, 3, 13): + assert chat_spans[0]["attributes"][SPANDATA.GEN_AI_RESPONSE_MODEL] == "gpt-4" + if send_default_pii: assert ( - chat_spans[0]["attributes"][SPANDATA.GEN_AI_USAGE_REASONING_OUTPUT_TOKENS] - == 5 + chat_spans[0]["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] + == "Hello, how can I help you?" ) - if LANGCHAIN_OPENAI_VERSION >= (0, 3, 13): - assert ( - chat_spans[0]["attributes"][SPANDATA.GEN_AI_RESPONSE_MODEL] == "gpt-4" - ) - - if send_default_pii and include_prompts: - assert ( - chat_spans[0]["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] - == "Hello, how can I help you?" - ) - - assert json.loads( - chat_spans[0]["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - ) == [ - { - "role": "user", - "content": "Message demonstrating the absence of truncation.", - }, - { - "role": "user", - "content": "How many letters in the word eudca", - }, - ] - - assert expected_system_instructions == json.loads( - chat_spans[0]["attributes"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS] - ) - else: - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in chat_spans[0].get( - "attributes", {} - ) - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in chat_spans[0].get( - "attributes", {} - ) - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in chat_spans[0].get( - "attributes", {} - ) + assert json.loads( + chat_spans[0]["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] + ) == [ + { + "role": "user", + "content": "Message demonstrating the absence of truncation.", + }, + { + "role": "user", + "content": "How many letters in the word eudca", + }, + ] + assert expected_system_instructions == json.loads( + chat_spans[0]["attributes"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS] + ) else: - events = capture_events() - - with patch.object( - llm.client._client._client, - "send", - return_value=model_response, - ) as _, start_transaction(): - agent.invoke( - { - "messages": [ - HumanMessage(content="How many letters in the word eudca"), - ], - }, - ) - - tx = events[0] - assert tx["type"] == "transaction" - assert tx["contexts"]["trace"]["origin"] == "manual" - - chat_spans = list(x for x in tx["spans"] if x["op"] == "gen_ai.chat") - assert len(chat_spans) == 1 - assert chat_spans[0]["origin"] == "auto.ai.langchain" - - assert chat_spans[0]["data"]["gen_ai.system"] == "openai-chat" - assert chat_spans[0]["data"]["gen_ai.agent.name"] == "word_length_agent" - - assert chat_spans[0]["data"]["gen_ai.usage.input_tokens"] == 10 - assert chat_spans[0]["data"]["gen_ai.usage.output_tokens"] == 20 - assert chat_spans[0]["data"]["gen_ai.usage.total_tokens"] == 30 - - assert chat_spans[0]["data"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] == 4 - assert ( - chat_spans[0]["data"][SPANDATA.GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS] - == 6 + assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in chat_spans[0].get( + "attributes", {} ) - - assert chat_spans[0]["data"][SPANDATA.GEN_AI_USAGE_REASONING_OUTPUT_TOKENS] == 5 - - if LANGCHAIN_OPENAI_VERSION >= (0, 3, 13): - assert chat_spans[0]["data"][SPANDATA.GEN_AI_RESPONSE_MODEL] == "gpt-4" - - if send_default_pii and include_prompts: - assert ( - chat_spans[0]["data"][SPANDATA.GEN_AI_RESPONSE_TEXT] - == "Hello, how can I help you?" - ) - - assert expected_system_instructions == json.loads( - chat_spans[0]["data"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS] - ) - else: - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in chat_spans[0].get( - "data", {} - ) - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in chat_spans[0].get("data", {}) - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in chat_spans[0].get("data", {}) + assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in chat_spans[0].get( + "attributes", {} + ) + assert SPANDATA.GEN_AI_RESPONSE_TEXT not in chat_spans[0].get("attributes", {}) -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.skipif( LANGCHAIN_VERSION < (1,), reason="LangChain 1.0+ required (ONE AGENT refactor)", ) @pytest.mark.parametrize( - "send_default_pii, include_prompts", - [ - (True, True), - (True, False), - (False, True), - (False, False), - ], + "send_default_pii", + [True, False], ) def test_tool_execution_span( sentry_init, - capture_events, capture_items, send_default_pii, - include_prompts, get_model_response, nonstreaming_responses_tool_call_model_responses, - stream_gen_ai_spans, - span_streaming, ): sentry_init( - integrations=[ - LangchainIntegration( - include_prompts=include_prompts, - ) - ], + integrations=[LangchainIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) responses = nonstreaming_responses_tool_call_model_responses( @@ -1112,438 +732,132 @@ def test_tool_execution_span( tools=[get_word_length], name="word_length_agent", ) + items = capture_items("span") - if span_streaming: - items = capture_items("transaction", "span") + with patch.object( + llm.client._client._client, + "send", + side_effect=[tool_response, final_response], + ): + agent.invoke( + { + "messages": [ + HumanMessage(content="How many letters in the word eudca"), + ], + }, + ) - with patch.object( - llm.client._client._client, - "send", - side_effect=[tool_response, final_response], - ) as _, sentry_sdk.traces.start_span(name="custom parent"): - agent.invoke( - { - "messages": [ - HumanMessage(content="How many letters in the word eudca"), - ], - }, - ) + sentry_sdk.flush() + spans = [item.payload for item in items] + chat_spans = list( + x for x in spans if x["attributes"].get("sentry.op") == "gen_ai.chat" + ) + assert len(chat_spans) == 2 - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert spans[4]["attributes"]["sentry.origin"] == "manual" - chat_spans = list( - x for x in spans if x["attributes"].get("sentry.op") == "gen_ai.chat" - ) - assert len(chat_spans) == 2 + tool_exec_spans = list( + x for x in spans if x["attributes"].get("sentry.op") == "gen_ai.execute_tool" + ) + assert len(tool_exec_spans) == 1 + tool_exec_span = tool_exec_spans[0] - tool_exec_spans = list( - x - for x in spans - if x["attributes"].get("sentry.op") == "gen_ai.execute_tool" - ) - assert len(tool_exec_spans) == 1 - tool_exec_span = tool_exec_spans[0] + assert chat_spans[0]["attributes"]["sentry.origin"] == "auto.ai.langchain" + assert chat_spans[1]["attributes"]["sentry.origin"] == "auto.ai.langchain" + assert tool_exec_span["attributes"]["sentry.origin"] == "auto.ai.langchain" - assert chat_spans[0]["attributes"]["sentry.origin"] == "auto.ai.langchain" - assert chat_spans[1]["attributes"]["sentry.origin"] == "auto.ai.langchain" - assert tool_exec_span["attributes"]["sentry.origin"] == "auto.ai.langchain" + assert chat_spans[0]["attributes"]["gen_ai.agent.name"] == "word_length_agent" + assert chat_spans[1]["attributes"]["gen_ai.agent.name"] == "word_length_agent" + assert tool_exec_span["attributes"]["gen_ai.agent.name"] == "word_length_agent" - assert chat_spans[0]["attributes"]["gen_ai.agent.name"] == "word_length_agent" - assert chat_spans[1]["attributes"]["gen_ai.agent.name"] == "word_length_agent" - assert tool_exec_span["attributes"]["gen_ai.agent.name"] == "word_length_agent" + assert chat_spans[0]["attributes"]["gen_ai.usage.input_tokens"] == 142 + assert chat_spans[0]["attributes"]["gen_ai.usage.output_tokens"] == 50 + assert chat_spans[0]["attributes"]["gen_ai.usage.total_tokens"] == 192 + assert ( + chat_spans[0]["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] == 69 + ) + assert ( + chat_spans[0]["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS] + == 31 + ) + assert ( + chat_spans[0]["attributes"][SPANDATA.GEN_AI_USAGE_REASONING_OUTPUT_TOKENS] == 10 + ) + assert chat_spans[0]["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "openai-chat" - assert chat_spans[0]["attributes"]["gen_ai.usage.input_tokens"] == 142 - assert chat_spans[0]["attributes"]["gen_ai.usage.output_tokens"] == 50 - assert chat_spans[0]["attributes"]["gen_ai.usage.total_tokens"] == 192 - assert ( - chat_spans[0]["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] - == 69 - ) - assert ( - chat_spans[0]["attributes"][ - SPANDATA.GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS - ] - == 31 - ) - assert ( - chat_spans[0]["attributes"][SPANDATA.GEN_AI_USAGE_REASONING_OUTPUT_TOKENS] - == 10 - ) - assert chat_spans[0]["attributes"]["gen_ai.system"] == "openai-chat" + assert chat_spans[1]["attributes"]["gen_ai.usage.input_tokens"] == 89 + assert chat_spans[1]["attributes"]["gen_ai.usage.output_tokens"] == 28 + assert chat_spans[1]["attributes"]["gen_ai.usage.total_tokens"] == 117 + assert ( + chat_spans[1]["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] == 69 + ) + assert ( + chat_spans[1]["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS] + == 10 + ) + assert ( + chat_spans[1]["attributes"][SPANDATA.GEN_AI_USAGE_REASONING_OUTPUT_TOKENS] == 11 + ) + assert chat_spans[1]["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "openai-chat" - assert chat_spans[1]["attributes"]["gen_ai.usage.input_tokens"] == 89 - assert chat_spans[1]["attributes"]["gen_ai.usage.output_tokens"] == 28 - assert chat_spans[1]["attributes"]["gen_ai.usage.total_tokens"] == 117 - assert ( - chat_spans[1]["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] - == 69 - ) + if LANGCHAIN_OPENAI_VERSION >= (0, 3, 13): assert ( - chat_spans[1]["attributes"][ - SPANDATA.GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS - ] - == 10 + chat_spans[0]["attributes"][SPANDATA.GEN_AI_RESPONSE_MODEL] == "gpt-4-0613" ) assert ( - chat_spans[1]["attributes"][SPANDATA.GEN_AI_USAGE_REASONING_OUTPUT_TOKENS] - == 11 + chat_spans[1]["attributes"][SPANDATA.GEN_AI_RESPONSE_MODEL] == "gpt-4-0613" ) - assert chat_spans[1]["attributes"]["gen_ai.system"] == "openai-chat" - - if LANGCHAIN_OPENAI_VERSION >= (0, 3, 13): - assert ( - chat_spans[0]["attributes"][SPANDATA.GEN_AI_RESPONSE_MODEL] - == "gpt-4-0613" - ) - assert ( - chat_spans[1]["attributes"][SPANDATA.GEN_AI_RESPONSE_MODEL] - == "gpt-4-0613" - ) - if send_default_pii and include_prompts: - assert "word" in tool_exec_span["attributes"][SPANDATA.GEN_AI_TOOL_INPUT] + if send_default_pii: + assert "word" in tool_exec_span["attributes"][SPANDATA.GEN_AI_TOOL_INPUT] - assert "5" in chat_spans[1]["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] + assert "5" in chat_spans[1]["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] - # Verify tool calls are recorded when PII is enabled - assert SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS in chat_spans[0].get( - "attributes", {} - ), ( - "Tool calls should be recorded when send_default_pii=True and include_prompts=True" - ) - tool_calls_data = chat_spans[0]["attributes"][ - SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS - ] - assert isinstance(tool_calls_data, str) - assert "get_word_length" in tool_calls_data - else: - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in chat_spans[0].get( - "attributes", {} - ) - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in chat_spans[0].get( - "attributes", {} - ) - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in chat_spans[1].get( - "attributes", {} - ) - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in chat_spans[1].get( - "attributes", {} - ) - assert SPANDATA.GEN_AI_TOOL_INPUT not in tool_exec_span.get( - "attributes", {} - ) - assert SPANDATA.GEN_AI_TOOL_OUTPUT not in tool_exec_span.get( - "attributes", {} - ) - - # Verify tool calls are NOT recorded when PII is disabled - assert SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS not in chat_spans[0].get( - "attributes", {} - ), ( - f"Tool calls should NOT be recorded when send_default_pii={send_default_pii} " - f"and include_prompts={include_prompts}" - ) - assert SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS not in chat_spans[1].get( - "attributes", {} - ), ( - f"Tool calls should NOT be recorded when send_default_pii={send_default_pii} " - f"and include_prompts={include_prompts}" - ) - - # Verify that available tools are always recorded regardless of PII settings - for chat_span in chat_spans: - tools_data = chat_span["attributes"][ - SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS - ] - assert "get_word_length" in tools_data - elif stream_gen_ai_spans: - items = capture_items("transaction", "span") - - with patch.object( - llm.client._client._client, - "send", - side_effect=[tool_response, final_response], - ) as _, sentry_sdk.traces.start_span(name="custom parent"): - agent.invoke( - { - "messages": [ - HumanMessage(content="How many letters in the word eudca"), - ], - }, - ) - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - chat_spans = list( - x for x in spans if x["attributes"]["sentry.op"] == "gen_ai.chat" - ) - assert len(chat_spans) == 2 - - tool_exec_spans = list( - x for x in spans if x["attributes"]["sentry.op"] == "gen_ai.execute_tool" - ) - assert len(tool_exec_spans) == 1 - tool_exec_span = tool_exec_spans[0] - - assert chat_spans[0]["attributes"]["sentry.origin"] == "auto.ai.langchain" - assert chat_spans[1]["attributes"]["sentry.origin"] == "auto.ai.langchain" - assert tool_exec_span["attributes"]["sentry.origin"] == "auto.ai.langchain" - - assert chat_spans[0]["attributes"]["gen_ai.agent.name"] == "word_length_agent" - assert chat_spans[1]["attributes"]["gen_ai.agent.name"] == "word_length_agent" - assert tool_exec_span["attributes"]["gen_ai.agent.name"] == "word_length_agent" - - assert chat_spans[0]["attributes"]["gen_ai.usage.input_tokens"] == 142 - assert chat_spans[0]["attributes"]["gen_ai.usage.output_tokens"] == 50 - assert chat_spans[0]["attributes"]["gen_ai.usage.total_tokens"] == 192 - assert ( - chat_spans[0]["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] - == 69 - ) - assert ( - chat_spans[0]["attributes"][ - SPANDATA.GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS - ] - == 31 - ) - assert ( - chat_spans[0]["attributes"][SPANDATA.GEN_AI_USAGE_REASONING_OUTPUT_TOKENS] - == 10 - ) - assert chat_spans[0]["attributes"]["gen_ai.system"] == "openai-chat" - - assert chat_spans[1]["attributes"]["gen_ai.usage.input_tokens"] == 89 - assert chat_spans[1]["attributes"]["gen_ai.usage.output_tokens"] == 28 - assert chat_spans[1]["attributes"]["gen_ai.usage.total_tokens"] == 117 - assert ( - chat_spans[1]["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] - == 69 - ) - assert ( - chat_spans[1]["attributes"][ - SPANDATA.GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS - ] - == 10 - ) - assert ( - chat_spans[1]["attributes"][SPANDATA.GEN_AI_USAGE_REASONING_OUTPUT_TOKENS] - == 11 - ) - assert chat_spans[1]["attributes"]["gen_ai.system"] == "openai-chat" - - if LANGCHAIN_OPENAI_VERSION >= (0, 3, 13): - assert ( - chat_spans[0]["attributes"][SPANDATA.GEN_AI_RESPONSE_MODEL] - == "gpt-4-0613" - ) - assert ( - chat_spans[1]["attributes"][SPANDATA.GEN_AI_RESPONSE_MODEL] - == "gpt-4-0613" - ) - - if send_default_pii and include_prompts: - assert "word" in tool_exec_span["attributes"][SPANDATA.GEN_AI_TOOL_INPUT] - - assert "5" in chat_spans[1]["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] - - # Verify tool calls are recorded when PII is enabled - assert SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS in chat_spans[0].get( - "attributes", {} - ), ( - "Tool calls should be recorded when send_default_pii=True and include_prompts=True" - ) - tool_calls_data = chat_spans[0]["attributes"][ - SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS - ] - assert isinstance(tool_calls_data, str) - assert "get_word_length" in tool_calls_data - else: - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in chat_spans[0].get( - "attributes", {} - ) - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in chat_spans[0].get( - "attributes", {} - ) - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in chat_spans[1].get( - "attributes", {} - ) - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in chat_spans[1].get( - "attributes", {} - ) - assert SPANDATA.GEN_AI_TOOL_INPUT not in tool_exec_span.get( - "attributes", {} - ) - assert SPANDATA.GEN_AI_TOOL_OUTPUT not in tool_exec_span.get( - "attributes", {} - ) - - # Verify tool calls are NOT recorded when PII is disabled - assert SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS not in chat_spans[0].get( - "attributes", {} - ), ( - f"Tool calls should NOT be recorded when send_default_pii={send_default_pii} " - f"and include_prompts={include_prompts}" - ) - assert SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS not in chat_spans[1].get( - "attributes", {} - ), ( - f"Tool calls should NOT be recorded when send_default_pii={send_default_pii} " - f"and include_prompts={include_prompts}" - ) - - # Verify that available tools are always recorded regardless of PII settings - for chat_span in chat_spans: - tools_data = chat_span["attributes"][ - SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS - ] - assert "get_word_length" in tools_data + # Verify tool calls are recorded when PII is enabled + assert SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS in chat_spans[0].get( + "attributes", {} + ), "Tool calls should be recorded when send_default_pii=True" + tool_calls_data = chat_spans[0]["attributes"][ + SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS + ] + assert isinstance(tool_calls_data, str) + assert "get_word_length" in tool_calls_data else: - events = capture_events() - - with patch.object( - llm.client._client._client, - "send", - side_effect=[tool_response, final_response], - ) as _, start_transaction(): - agent.invoke( - { - "messages": [ - HumanMessage(content="How many letters in the word eudca"), - ], - }, - ) - - tx = events[0] - assert tx["type"] == "transaction" - assert tx["contexts"]["trace"]["origin"] == "manual" - - chat_spans = list(x for x in tx["spans"] if x["op"] == "gen_ai.chat") - assert len(chat_spans) == 2 - tool_exec_spans = list( - x for x in tx["spans"] if x["op"] == "gen_ai.execute_tool" - ) - - assert len(tool_exec_spans) == 1 - tool_exec_span = tool_exec_spans[0] - - assert chat_spans[0]["origin"] == "auto.ai.langchain" - assert chat_spans[1]["origin"] == "auto.ai.langchain" - assert tool_exec_span["origin"] == "auto.ai.langchain" - - assert chat_spans[0]["data"]["gen_ai.agent.name"] == "word_length_agent" - assert chat_spans[1]["data"]["gen_ai.agent.name"] == "word_length_agent" - assert tool_exec_span["data"]["gen_ai.agent.name"] == "word_length_agent" - - assert chat_spans[0]["data"]["gen_ai.usage.input_tokens"] == 142 - assert chat_spans[0]["data"]["gen_ai.usage.output_tokens"] == 50 - assert chat_spans[0]["data"]["gen_ai.usage.total_tokens"] == 192 - assert ( - chat_spans[0]["data"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] == 69 - ) - assert ( - chat_spans[0]["data"][SPANDATA.GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS] - == 31 - ) - assert ( - chat_spans[0]["data"][SPANDATA.GEN_AI_USAGE_REASONING_OUTPUT_TOKENS] == 10 - ) - assert chat_spans[0]["data"]["gen_ai.system"] == "openai-chat" - - assert chat_spans[1]["data"]["gen_ai.usage.input_tokens"] == 89 - assert chat_spans[1]["data"]["gen_ai.usage.output_tokens"] == 28 - assert chat_spans[1]["data"]["gen_ai.usage.total_tokens"] == 117 - assert ( - chat_spans[1]["data"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] == 69 - ) - assert ( - chat_spans[1]["data"][SPANDATA.GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS] - == 10 + assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in chat_spans[0].get( + "attributes", {} ) - assert ( - chat_spans[1]["data"][SPANDATA.GEN_AI_USAGE_REASONING_OUTPUT_TOKENS] == 11 + assert SPANDATA.GEN_AI_RESPONSE_TEXT not in chat_spans[0].get("attributes", {}) + assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in chat_spans[1].get( + "attributes", {} ) - assert chat_spans[1]["data"]["gen_ai.system"] == "openai-chat" - - if LANGCHAIN_OPENAI_VERSION >= (0, 3, 13): - assert chat_spans[0]["data"][SPANDATA.GEN_AI_RESPONSE_MODEL] == "gpt-4-0613" - assert chat_spans[1]["data"][SPANDATA.GEN_AI_RESPONSE_MODEL] == "gpt-4-0613" - - if send_default_pii and include_prompts: - assert "word" in tool_exec_span["data"][SPANDATA.GEN_AI_TOOL_INPUT] - - assert "5" in chat_spans[1]["data"][SPANDATA.GEN_AI_RESPONSE_TEXT] + assert SPANDATA.GEN_AI_RESPONSE_TEXT not in chat_spans[1].get("attributes", {}) + assert SPANDATA.GEN_AI_TOOL_INPUT not in tool_exec_span.get("attributes", {}) + assert SPANDATA.GEN_AI_TOOL_OUTPUT not in tool_exec_span.get("attributes", {}) - # Verify tool calls are recorded when PII is enabled - assert SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS in chat_spans[0].get( - "data", {} - ), ( - "Tool calls should be recorded when send_default_pii=True and include_prompts=True" - ) - tool_calls_data = chat_spans[0]["data"][SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS] - assert isinstance(tool_calls_data, str) - assert "get_word_length" in tool_calls_data - else: - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in chat_spans[0].get("data", {}) - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in chat_spans[0].get("data", {}) - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in chat_spans[1].get("data", {}) - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in chat_spans[1].get("data", {}) - assert SPANDATA.GEN_AI_TOOL_INPUT not in tool_exec_span.get("data", {}) - assert SPANDATA.GEN_AI_TOOL_OUTPUT not in tool_exec_span.get("data", {}) - - # Verify tool calls are NOT recorded when PII is disabled - assert SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS not in chat_spans[0].get( - "data", {} - ), ( - f"Tool calls should NOT be recorded when send_default_pii={send_default_pii} " - f"and include_prompts={include_prompts}" - ) - assert SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS not in chat_spans[1].get( - "data", {} - ), ( - f"Tool calls should NOT be recorded when send_default_pii={send_default_pii} " - f"and include_prompts={include_prompts}" - ) + # Verify tool calls are NOT recorded when PII is disabled + assert SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS not in chat_spans[0].get( + "attributes", {} + ), f"Tool calls should NOT be recorded when send_default_pii={send_default_pii}" + assert SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS not in chat_spans[1].get( + "attributes", {} + ), f"Tool calls should NOT be recorded when send_default_pii={send_default_pii}" - # Verify that available tools are always recorded regardless of PII settings - for chat_span in chat_spans: - tools_data = chat_span["data"][SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS] - assert "get_word_length" in tools_data + # Verify that available tools are always recorded regardless of PII settings + for chat_span in chat_spans: + tools_data = chat_span["attributes"][SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS] + assert "get_word_length" in tools_data -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) -@pytest.mark.parametrize( - "send_default_pii, include_prompts", - [ - (True, False), - (False, True), - (False, False), - ], -) -def test_langchain_openai_tools_agent_no_prompts( +def test_langchain_openai_tools_agent_no_sensitive_data( sentry_init, - capture_events, capture_items, - send_default_pii, - include_prompts, get_model_response, server_side_event_chunks, streaming_chat_completions_model_responses, - stream_gen_ai_spans, - span_streaming, ): sentry_init( - integrations=[ - LangchainIntegration( - include_prompts=include_prompts, - ) - ], + integrations=[LangchainIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, - send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", + send_default_pii=False, ) prompt = ChatPromptTemplate.from_messages( @@ -1581,353 +895,107 @@ def test_langchain_openai_tools_agent_no_prompts( agent = create_openai_tools_agent(llm, [get_word_length], prompt) agent_executor = AgentExecutor(agent=agent, tools=[get_word_length], verbose=True) + items = capture_items("span") - if span_streaming: - items = capture_items("transaction", "span") - - with patch.object( - llm.client._client._client, - "send", - side_effect=[tool_response, final_response], - ) as _, sentry_sdk.traces.start_span(name="custom parent"): - list( - agent_executor.invoke( - {"input": "How many letters in the word eudca"}, - {"run_name": "my-snazzy-pipeline"}, - ) - ) - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert spans[4]["attributes"]["sentry.origin"] == "manual" - invoke_agent_span = next( - x - for x in spans - if x["attributes"].get("sentry.op") == "gen_ai.invoke_agent" - ) - chat_spans = list( - x for x in spans if x["attributes"].get("sentry.op") == "gen_ai.chat" - ) - tool_exec_span = next( - x - for x in spans - if x["attributes"].get("sentry.op") == "gen_ai.execute_tool" - ) - - assert len(chat_spans) == 2 - - assert invoke_agent_span["attributes"]["sentry.origin"] == "auto.ai.langchain" - assert chat_spans[0]["attributes"]["sentry.origin"] == "auto.ai.langchain" - assert chat_spans[1]["attributes"]["sentry.origin"] == "auto.ai.langchain" - assert tool_exec_span["attributes"]["sentry.origin"] == "auto.ai.langchain" - - assert ( - invoke_agent_span["attributes"]["gen_ai.function_id"] - == "my-snazzy-pipeline" - ) - - # We can't guarantee anything about the "shape" of the langchain execution graph - assert ( - len( - list( - x - for x in spans - if x["attributes"].get("sentry.op") == "gen_ai.chat" - ) - ) - > 0 - ) - - # Token usage is only available in newer versions of langchain (v0.2+) - # where usage_metadata is supported on AIMessageChunk - if "gen_ai.usage.input_tokens" in chat_spans[0]["attributes"]: - assert chat_spans[0]["attributes"]["gen_ai.usage.input_tokens"] == 142 - assert chat_spans[0]["attributes"]["gen_ai.usage.output_tokens"] == 50 - assert chat_spans[0]["attributes"]["gen_ai.usage.total_tokens"] == 192 - - if "gen_ai.usage.input_tokens" in chat_spans[1]["attributes"]: - assert chat_spans[1]["attributes"]["gen_ai.usage.input_tokens"] == 89 - assert chat_spans[1]["attributes"]["gen_ai.usage.output_tokens"] == 28 - assert chat_spans[1]["attributes"]["gen_ai.usage.total_tokens"] == 117 - - if LANGCHAIN_OPENAI_VERSION >= (0, 3, 13): - assert ( - chat_spans[0]["attributes"][SPANDATA.GEN_AI_RESPONSE_MODEL] - == "gpt-3.5-turbo" - ) - assert ( - chat_spans[1]["attributes"][SPANDATA.GEN_AI_RESPONSE_MODEL] - == "gpt-3.5-turbo" + with patch.object( + llm.client._client._client, + "send", + side_effect=[tool_response, final_response], + ): + list( + agent_executor.invoke( + {"input": "How many letters in the word eudca"}, + {"run_name": "my-snazzy-pipeline"}, ) - - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in chat_spans[0].get( - "attributes", {} - ) - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in chat_spans[0].get( - "attributes", {} - ) - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in chat_spans[0].get("attributes", {}) - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in chat_spans[1].get( - "attributes", {} - ) - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in chat_spans[1].get( - "attributes", {} ) - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in chat_spans[1].get("attributes", {}) - assert SPANDATA.GEN_AI_TOOL_INPUT not in tool_exec_span.get("attributes", {}) - assert SPANDATA.GEN_AI_TOOL_OUTPUT not in tool_exec_span.get("attributes", {}) - # Verify tool calls are NOT recorded when PII is disabled - assert SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS not in chat_spans[0].get( - "attributes", {} - ), ( - f"Tool calls should NOT be recorded when send_default_pii={send_default_pii} " - f"and include_prompts={include_prompts}" - ) - assert SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS not in chat_spans[1].get( - "attributes", {} - ), ( - f"Tool calls should NOT be recorded when send_default_pii={send_default_pii} " - f"and include_prompts={include_prompts}" - ) + sentry_sdk.flush() + spans = [item.payload for item in items] + invoke_agent_span = next( + x for x in spans if x["attributes"].get("sentry.op") == "gen_ai.invoke_agent" + ) + chat_spans = list( + x for x in spans if x["attributes"].get("sentry.op") == "gen_ai.chat" + ) + tool_exec_span = next( + x for x in spans if x["attributes"].get("sentry.op") == "gen_ai.execute_tool" + ) - # Verify finish_reasons is always an array of strings - assert chat_spans[0]["attributes"][SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS] == [ - "function_call" - ] - assert chat_spans[1]["attributes"][SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS] == [ - "stop" - ] + assert len(chat_spans) == 2 - # Verify that available tools are always recorded regardless of PII settings - for chat_span in chat_spans: - tools_data = chat_span["attributes"][ - SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS - ] - assert tools_data is not None, ( - "Available tools should always be recorded regardless of PII settings" - ) - assert "get_word_length" in tools_data - elif stream_gen_ai_spans: - items = capture_items("transaction", "span") - - with patch.object( - llm.client._client._client, - "send", - side_effect=[tool_response, final_response], - ) as _, start_transaction(): - list( - agent_executor.invoke( - {"input": "How many letters in the word eudca"}, - {"run_name": "my-snazzy-pipeline"}, - ) - ) + assert invoke_agent_span["attributes"]["sentry.origin"] == "auto.ai.langchain" + assert chat_spans[0]["attributes"]["sentry.origin"] == "auto.ai.langchain" + assert chat_spans[1]["attributes"]["sentry.origin"] == "auto.ai.langchain" + assert tool_exec_span["attributes"]["sentry.origin"] == "auto.ai.langchain" - tx = next(item.payload for item in items if item.type == "transaction") - assert tx["type"] == "transaction" - assert tx["contexts"]["trace"]["origin"] == "manual" + assert invoke_agent_span["attributes"]["gen_ai.function_id"] == "my-snazzy-pipeline" - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - invoke_agent_span = next( - x for x in spans if x["attributes"]["sentry.op"] == "gen_ai.invoke_agent" - ) - chat_spans = list( - x for x in spans if x["attributes"]["sentry.op"] == "gen_ai.chat" - ) - tool_exec_span = next( - x for x in spans if x["attributes"]["sentry.op"] == "gen_ai.execute_tool" - ) + # We can't guarantee anything about the "shape" of the langchain execution graph + assert ( + len(list(x for x in spans if x["attributes"].get("sentry.op") == "gen_ai.chat")) + > 0 + ) - assert len(chat_spans) == 2 + # Token usage is only available in newer versions of langchain (v0.2+) + # where usage_metadata is supported on AIMessageChunk + if "gen_ai.usage.input_tokens" in chat_spans[0]["attributes"]: + assert chat_spans[0]["attributes"]["gen_ai.usage.input_tokens"] == 142 + assert chat_spans[0]["attributes"]["gen_ai.usage.output_tokens"] == 50 + assert chat_spans[0]["attributes"]["gen_ai.usage.total_tokens"] == 192 - assert invoke_agent_span["attributes"]["sentry.origin"] == "auto.ai.langchain" - assert chat_spans[0]["attributes"]["sentry.origin"] == "auto.ai.langchain" - assert chat_spans[1]["attributes"]["sentry.origin"] == "auto.ai.langchain" - assert tool_exec_span["attributes"]["sentry.origin"] == "auto.ai.langchain" + if "gen_ai.usage.input_tokens" in chat_spans[1]["attributes"]: + assert chat_spans[1]["attributes"]["gen_ai.usage.input_tokens"] == 89 + assert chat_spans[1]["attributes"]["gen_ai.usage.output_tokens"] == 28 + assert chat_spans[1]["attributes"]["gen_ai.usage.total_tokens"] == 117 + if LANGCHAIN_OPENAI_VERSION >= (0, 3, 13): assert ( - invoke_agent_span["attributes"]["gen_ai.function_id"] - == "my-snazzy-pipeline" + chat_spans[0]["attributes"][SPANDATA.GEN_AI_RESPONSE_MODEL] + == "gpt-3.5-turbo" ) - - # We can't guarantee anything about the "shape" of the langchain execution graph assert ( - len(list(x for x in spans if x["attributes"]["sentry.op"] == "gen_ai.chat")) - > 0 - ) - - # Token usage is only available in newer versions of langchain (v0.2+) - # where usage_metadata is supported on AIMessageChunk - if "gen_ai.usage.input_tokens" in chat_spans[0]["attributes"]: - assert chat_spans[0]["attributes"]["gen_ai.usage.input_tokens"] == 142 - assert chat_spans[0]["attributes"]["gen_ai.usage.output_tokens"] == 50 - assert chat_spans[0]["attributes"]["gen_ai.usage.total_tokens"] == 192 - - if "gen_ai.usage.input_tokens" in chat_spans[1]["attributes"]: - assert chat_spans[1]["attributes"]["gen_ai.usage.input_tokens"] == 89 - assert chat_spans[1]["attributes"]["gen_ai.usage.output_tokens"] == 28 - assert chat_spans[1]["attributes"]["gen_ai.usage.total_tokens"] == 117 - - if LANGCHAIN_OPENAI_VERSION >= (0, 3, 13): - assert ( - chat_spans[0]["attributes"][SPANDATA.GEN_AI_RESPONSE_MODEL] - == "gpt-3.5-turbo" - ) - assert ( - chat_spans[1]["attributes"][SPANDATA.GEN_AI_RESPONSE_MODEL] - == "gpt-3.5-turbo" - ) - - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in chat_spans[0].get( - "attributes", {} - ) - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in chat_spans[0].get( - "attributes", {} - ) - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in chat_spans[0].get("attributes", {}) - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in chat_spans[1].get( - "attributes", {} - ) - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in chat_spans[1].get( - "attributes", {} - ) - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in chat_spans[1].get("attributes", {}) - assert SPANDATA.GEN_AI_TOOL_INPUT not in tool_exec_span.get("attributes", {}) - assert SPANDATA.GEN_AI_TOOL_OUTPUT not in tool_exec_span.get("attributes", {}) - - # Verify tool calls are NOT recorded when PII is disabled - assert SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS not in chat_spans[0].get( - "attributes", {} - ), ( - f"Tool calls should NOT be recorded when send_default_pii={send_default_pii} " - f"and include_prompts={include_prompts}" - ) - assert SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS not in chat_spans[1].get( - "attributes", {} - ), ( - f"Tool calls should NOT be recorded when send_default_pii={send_default_pii} " - f"and include_prompts={include_prompts}" - ) - - # Verify finish_reasons is always an array of strings - assert chat_spans[0]["attributes"][SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS] == [ - "function_call" - ] - assert chat_spans[1]["attributes"][SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS] == [ - "stop" - ] - - # Verify that available tools are always recorded regardless of PII settings - for chat_span in chat_spans: - tools_data = chat_span["attributes"][ - SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS - ] - assert tools_data is not None, ( - "Available tools should always be recorded regardless of PII settings" - ) - assert "get_word_length" in tools_data - else: - events = capture_events() - - with patch.object( - llm.client._client._client, - "send", - side_effect=[tool_response, final_response], - ) as _, start_transaction(): - list( - agent_executor.invoke( - {"input": "How many letters in the word eudca"}, - {"run_name": "my-snazzy-pipeline"}, - ) - ) - - tx = events[0] - assert tx["type"] == "transaction" - assert tx["contexts"]["trace"]["origin"] == "manual" - - invoke_agent_span = next( - x for x in tx["spans"] if x["op"] == "gen_ai.invoke_agent" - ) - chat_spans = list(x for x in tx["spans"] if x["op"] == "gen_ai.chat") - tool_exec_span = next( - x for x in tx["spans"] if x["op"] == "gen_ai.execute_tool" - ) - - assert len(chat_spans) == 2 - - assert invoke_agent_span["origin"] == "auto.ai.langchain" - assert chat_spans[0]["origin"] == "auto.ai.langchain" - assert chat_spans[1]["origin"] == "auto.ai.langchain" - assert tool_exec_span["origin"] == "auto.ai.langchain" - - assert invoke_agent_span["data"]["gen_ai.function_id"] == "my-snazzy-pipeline" - - # We can't guarantee anything about the "shape" of the langchain execution graph - assert len(list(x for x in tx["spans"] if x["op"] == "gen_ai.chat")) > 0 - - # Token usage is only available in newer versions of langchain (v0.2+) - # where usage_metadata is supported on AIMessageChunk - if "gen_ai.usage.input_tokens" in chat_spans[0]["data"]: - assert chat_spans[0]["data"]["gen_ai.usage.input_tokens"] == 142 - assert chat_spans[0]["data"]["gen_ai.usage.output_tokens"] == 50 - assert chat_spans[0]["data"]["gen_ai.usage.total_tokens"] == 192 - - if "gen_ai.usage.input_tokens" in chat_spans[1]["data"]: - assert chat_spans[1]["data"]["gen_ai.usage.input_tokens"] == 89 - assert chat_spans[1]["data"]["gen_ai.usage.output_tokens"] == 28 - assert chat_spans[1]["data"]["gen_ai.usage.total_tokens"] == 117 - - if LANGCHAIN_OPENAI_VERSION >= (0, 3, 13): - assert ( - chat_spans[0]["data"][SPANDATA.GEN_AI_RESPONSE_MODEL] == "gpt-3.5-turbo" - ) - assert ( - chat_spans[1]["data"][SPANDATA.GEN_AI_RESPONSE_MODEL] == "gpt-3.5-turbo" - ) - - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in chat_spans[0].get("data", {}) - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in chat_spans[0].get("data", {}) - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in chat_spans[0].get("data", {}) - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in chat_spans[1].get("data", {}) - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in chat_spans[1].get("data", {}) - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in chat_spans[1].get("data", {}) - assert SPANDATA.GEN_AI_TOOL_INPUT not in tool_exec_span.get("data", {}) - assert SPANDATA.GEN_AI_TOOL_OUTPUT not in tool_exec_span.get("data", {}) + chat_spans[1]["attributes"][SPANDATA.GEN_AI_RESPONSE_MODEL] + == "gpt-3.5-turbo" + ) + + assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in chat_spans[0].get( + "attributes", {} + ) + assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in chat_spans[0].get("attributes", {}) + assert SPANDATA.GEN_AI_RESPONSE_TEXT not in chat_spans[0].get("attributes", {}) + assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in chat_spans[1].get( + "attributes", {} + ) + assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in chat_spans[1].get("attributes", {}) + assert SPANDATA.GEN_AI_RESPONSE_TEXT not in chat_spans[1].get("attributes", {}) + assert SPANDATA.GEN_AI_TOOL_INPUT not in tool_exec_span.get("attributes", {}) + assert SPANDATA.GEN_AI_TOOL_OUTPUT not in tool_exec_span.get("attributes", {}) + + # Verify tool calls are NOT recorded when PII is disabled + assert SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS not in chat_spans[0].get( + "attributes", {} + ), "Tool calls should NOT be recorded when send_default_pii=False" + assert SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS not in chat_spans[1].get( + "attributes", {} + ), "Tool calls should NOT be recorded when send_default_pii=False" + + # Verify finish_reasons is always an array of strings + assert chat_spans[0]["attributes"][SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS] == [ + "function_call" + ] + assert chat_spans[1]["attributes"][SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS] == [ + "stop" + ] - # Verify tool calls are NOT recorded when PII is disabled - assert SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS not in chat_spans[0].get( - "data", {} - ), ( - f"Tool calls should NOT be recorded when send_default_pii={send_default_pii} " - f"and include_prompts={include_prompts}" - ) - assert SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS not in chat_spans[1].get( - "data", {} - ), ( - f"Tool calls should NOT be recorded when send_default_pii={send_default_pii} " - f"and include_prompts={include_prompts}" + # Verify that available tools are always recorded regardless of PII settings + for chat_span in chat_spans: + tools_data = chat_span["attributes"][SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS] + assert tools_data is not None, ( + "Available tools should always be recorded regardless of PII settings" ) - - # Verify finish_reasons is always an array of strings - assert chat_spans[0]["data"][SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS] == [ - "function_call" - ] - assert chat_spans[1]["data"][SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS] == [ - "stop" - ] - - # Verify that available tools are always recorded regardless of PII settings - for chat_span in chat_spans: - tools_data = chat_span["data"][SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS] - assert tools_data is not None, ( - "Available tools should always be recorded regardless of PII settings" - ) - assert "get_word_length" in tools_data + assert "get_word_length" in tools_data -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize( "system_instructions_content,expected_system_instructions", [ @@ -1973,27 +1041,18 @@ def test_langchain_openai_tools_agent_no_prompts( ) def test_langchain_openai_tools_agent( sentry_init, - capture_events, capture_items, system_instructions_content, expected_system_instructions, get_model_response, server_side_event_chunks, streaming_chat_completions_model_responses, - stream_gen_ai_spans, - span_streaming, ): sentry_init( - integrations=[ - LangchainIntegration( - include_prompts=True, - ) - ], + integrations=[LangchainIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) prompt = ChatPromptTemplate.from_messages( @@ -2031,378 +1090,133 @@ def test_langchain_openai_tools_agent( agent = create_openai_tools_agent(llm, [get_word_length], prompt) agent_executor = AgentExecutor(agent=agent, tools=[get_word_length], verbose=True) + items = capture_items("span") - if span_streaming: - items = capture_items("transaction", "span") - - with patch.object( - llm.client._client._client, - "send", - side_effect=[tool_response, final_response], - ) as _, sentry_sdk.traces.start_span(name="custom parent"): - list( - agent_executor.stream( - { - "input": [ - "Message demonstrating the absence of truncation.", - "How many letters in the word eudca", - ] - } - ) - ) - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert spans[4]["attributes"]["sentry.origin"] == "manual" - invoke_agent_span = next( - x - for x in spans - if x["attributes"].get("sentry.op") == "gen_ai.invoke_agent" - ) - chat_spans = list( - x for x in spans if x["attributes"].get("sentry.op") == "gen_ai.chat" - ) - tool_exec_span = next( - x - for x in spans - if x["attributes"].get("sentry.op") == "gen_ai.execute_tool" - ) - - assert len(chat_spans) == 2 - - assert invoke_agent_span["attributes"]["sentry.origin"] == "auto.ai.langchain" - assert chat_spans[0]["attributes"]["sentry.origin"] == "auto.ai.langchain" - assert chat_spans[1]["attributes"]["sentry.origin"] == "auto.ai.langchain" - assert tool_exec_span["attributes"]["sentry.origin"] == "auto.ai.langchain" - - # We can't guarantee anything about the "shape" of the langchain execution graph - assert ( - len( - list( - x - for x in spans - if x["attributes"].get("sentry.op") == "gen_ai.chat" - ) - ) - > 0 - ) - - # Token usage is only available in newer versions of langchain (v0.2+) - # where usage_metadata is supported on AIMessageChunk - if "gen_ai.usage.input_tokens" in chat_spans[0]["attributes"]: - assert chat_spans[0]["attributes"]["gen_ai.usage.input_tokens"] == 142 - assert chat_spans[0]["attributes"]["gen_ai.usage.output_tokens"] == 50 - assert chat_spans[0]["attributes"]["gen_ai.usage.total_tokens"] == 192 - - if "gen_ai.usage.input_tokens" in chat_spans[1]["attributes"]: - assert chat_spans[1]["attributes"]["gen_ai.usage.input_tokens"] == 89 - assert chat_spans[1]["attributes"]["gen_ai.usage.output_tokens"] == 28 - assert chat_spans[1]["attributes"]["gen_ai.usage.total_tokens"] == 117 - - if LANGCHAIN_OPENAI_VERSION >= (0, 3, 13): - assert ( - chat_spans[0]["attributes"][SPANDATA.GEN_AI_RESPONSE_MODEL] - == "gpt-3.5-turbo" - ) - assert ( - chat_spans[1]["attributes"][SPANDATA.GEN_AI_RESPONSE_MODEL] - == "gpt-3.5-turbo" + with patch.object( + llm.client._client._client, + "send", + side_effect=[tool_response, final_response], + ): + list( + agent_executor.stream( + { + "input": [ + "Message demonstrating the absence of truncation.", + "How many letters in the word eudca", + ] + } ) - - assert "5" in chat_spans[0]["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] - assert "word" in tool_exec_span["attributes"][SPANDATA.GEN_AI_TOOL_INPUT] - assert 5 == int(tool_exec_span["attributes"][SPANDATA.GEN_AI_TOOL_OUTPUT]) - - assert json.loads( - chat_spans[0]["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - ) == [ - { - "role": "user", - "content": "['Message demonstrating the absence of truncation.', 'How many letters in the word eudca']", - } - ] - - assert expected_system_instructions == json.loads( - chat_spans[0]["attributes"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS] - ) - - assert "5" in chat_spans[1]["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] - - # Verify tool calls are recorded when PII is enabled - assert SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS in chat_spans[0].get( - "attributes", {} - ), ( - "Tool calls should be recorded when send_default_pii=True and include_prompts=True" ) - tool_calls_data = chat_spans[0]["attributes"][ - SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS - ] - assert isinstance(tool_calls_data, (list, str)) # Could be serialized - if isinstance(tool_calls_data, str): - assert "get_word_length" in tool_calls_data - elif isinstance(tool_calls_data, list) and len(tool_calls_data) > 0: - # Check if tool calls contain expected function name - tool_call_str = str(tool_calls_data) - assert "get_word_length" in tool_call_str - - # Verify finish_reasons is always an array of strings - assert chat_spans[0]["attributes"][SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS] == [ - "function_call" - ] - assert chat_spans[1]["attributes"][SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS] == [ - "stop" - ] + sentry_sdk.flush() + spans = [item.payload for item in items] + invoke_agent_span = next( + x for x in spans if x["attributes"].get("sentry.op") == "gen_ai.invoke_agent" + ) + chat_spans = list( + x for x in spans if x["attributes"].get("sentry.op") == "gen_ai.chat" + ) + tool_exec_span = next( + x for x in spans if x["attributes"].get("sentry.op") == "gen_ai.execute_tool" + ) - # Verify that available tools are always recorded regardless of PII settings - for chat_span in chat_spans: - tools_data = chat_span["attributes"][ - SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS - ] - assert tools_data is not None, ( - "Available tools should always be recorded regardless of PII settings" - ) - assert "get_word_length" in tools_data - elif stream_gen_ai_spans: - items = capture_items("transaction", "span") - - with patch.object( - llm.client._client._client, - "send", - side_effect=[tool_response, final_response], - ) as _, start_transaction(): - list( - agent_executor.stream( - { - "input": [ - "Message demonstrating the absence of truncation.", - "How many letters in the word eudca", - ] - } - ) - ) + assert len(chat_spans) == 2 - tx = next(item.payload for item in items if item.type == "transaction") - assert tx["type"] == "transaction" - assert tx["contexts"]["trace"]["origin"] == "manual" + assert invoke_agent_span["attributes"]["sentry.origin"] == "auto.ai.langchain" + assert chat_spans[0]["attributes"]["sentry.origin"] == "auto.ai.langchain" + assert chat_spans[1]["attributes"]["sentry.origin"] == "auto.ai.langchain" + assert tool_exec_span["attributes"]["sentry.origin"] == "auto.ai.langchain" - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - invoke_agent_span = next( - x for x in spans if x["attributes"]["sentry.op"] == "gen_ai.invoke_agent" - ) - chat_spans = list( - x for x in spans if x["attributes"]["sentry.op"] == "gen_ai.chat" - ) - tool_exec_span = next( - x for x in spans if x["attributes"]["sentry.op"] == "gen_ai.execute_tool" - ) + # We can't guarantee anything about the "shape" of the langchain execution graph + assert ( + len(list(x for x in spans if x["attributes"].get("sentry.op") == "gen_ai.chat")) + > 0 + ) - assert len(chat_spans) == 2 + # Token usage is only available in newer versions of langchain (v0.2+) + # where usage_metadata is supported on AIMessageChunk + if "gen_ai.usage.input_tokens" in chat_spans[0]["attributes"]: + assert chat_spans[0]["attributes"]["gen_ai.usage.input_tokens"] == 142 + assert chat_spans[0]["attributes"]["gen_ai.usage.output_tokens"] == 50 + assert chat_spans[0]["attributes"]["gen_ai.usage.total_tokens"] == 192 - assert invoke_agent_span["attributes"]["sentry.origin"] == "auto.ai.langchain" - assert chat_spans[0]["attributes"]["sentry.origin"] == "auto.ai.langchain" - assert chat_spans[1]["attributes"]["sentry.origin"] == "auto.ai.langchain" - assert tool_exec_span["attributes"]["sentry.origin"] == "auto.ai.langchain" + if "gen_ai.usage.input_tokens" in chat_spans[1]["attributes"]: + assert chat_spans[1]["attributes"]["gen_ai.usage.input_tokens"] == 89 + assert chat_spans[1]["attributes"]["gen_ai.usage.output_tokens"] == 28 + assert chat_spans[1]["attributes"]["gen_ai.usage.total_tokens"] == 117 - # We can't guarantee anything about the "shape" of the langchain execution graph + if LANGCHAIN_OPENAI_VERSION >= (0, 3, 13): assert ( - len(list(x for x in spans if x["attributes"]["sentry.op"] == "gen_ai.chat")) - > 0 - ) - - # Token usage is only available in newer versions of langchain (v0.2+) - # where usage_metadata is supported on AIMessageChunk - if "gen_ai.usage.input_tokens" in chat_spans[0]["attributes"]: - assert chat_spans[0]["attributes"]["gen_ai.usage.input_tokens"] == 142 - assert chat_spans[0]["attributes"]["gen_ai.usage.output_tokens"] == 50 - assert chat_spans[0]["attributes"]["gen_ai.usage.total_tokens"] == 192 - - if "gen_ai.usage.input_tokens" in chat_spans[1]["attributes"]: - assert chat_spans[1]["attributes"]["gen_ai.usage.input_tokens"] == 89 - assert chat_spans[1]["attributes"]["gen_ai.usage.output_tokens"] == 28 - assert chat_spans[1]["attributes"]["gen_ai.usage.total_tokens"] == 117 - - if LANGCHAIN_OPENAI_VERSION >= (0, 3, 13): - assert ( - chat_spans[0]["attributes"][SPANDATA.GEN_AI_RESPONSE_MODEL] - == "gpt-3.5-turbo" - ) - assert ( - chat_spans[1]["attributes"][SPANDATA.GEN_AI_RESPONSE_MODEL] - == "gpt-3.5-turbo" - ) - - assert "5" in chat_spans[0]["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] - assert "word" in tool_exec_span["attributes"][SPANDATA.GEN_AI_TOOL_INPUT] - assert 5 == int(tool_exec_span["attributes"][SPANDATA.GEN_AI_TOOL_OUTPUT]) - - assert json.loads( - chat_spans[0]["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - ) == [ - { - "role": "user", - "content": "['Message demonstrating the absence of truncation.', 'How many letters in the word eudca']", - } - ] - - assert expected_system_instructions == json.loads( - chat_spans[0]["attributes"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS] - ) - - assert "5" in chat_spans[1]["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] - - # Verify tool calls are recorded when PII is enabled - assert SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS in chat_spans[0].get( - "attributes", {} - ), ( - "Tool calls should be recorded when send_default_pii=True and include_prompts=True" - ) - tool_calls_data = chat_spans[0]["attributes"][ - SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS - ] - - assert isinstance(tool_calls_data, (list, str)) # Could be serialized - if isinstance(tool_calls_data, str): - assert "get_word_length" in tool_calls_data - elif isinstance(tool_calls_data, list) and len(tool_calls_data) > 0: - # Check if tool calls contain expected function name - tool_call_str = str(tool_calls_data) - assert "get_word_length" in tool_call_str - - # Verify finish_reasons is always an array of strings - assert chat_spans[0]["attributes"][SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS] == [ - "function_call" - ] - assert chat_spans[1]["attributes"][SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS] == [ - "stop" - ] - - # Verify that available tools are always recorded regardless of PII settings - for chat_span in chat_spans: - tools_data = chat_span["attributes"][ - SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS - ] - assert tools_data is not None, ( - "Available tools should always be recorded regardless of PII settings" - ) - assert "get_word_length" in tools_data - else: - events = capture_events() - - with patch.object( - llm.client._client._client, - "send", - side_effect=[tool_response, final_response], - ) as _, start_transaction(): - list(agent_executor.stream({"input": "How many letters in the word eudca"})) - - tx = events[0] - assert tx["type"] == "transaction" - assert tx["contexts"]["trace"]["origin"] == "manual" - - invoke_agent_span = next( - x for x in tx["spans"] if x["op"] == "gen_ai.invoke_agent" + chat_spans[0]["attributes"][SPANDATA.GEN_AI_RESPONSE_MODEL] + == "gpt-3.5-turbo" ) - chat_spans = list(x for x in tx["spans"] if x["op"] == "gen_ai.chat") - tool_exec_span = next( - x for x in tx["spans"] if x["op"] == "gen_ai.execute_tool" + assert ( + chat_spans[1]["attributes"][SPANDATA.GEN_AI_RESPONSE_MODEL] + == "gpt-3.5-turbo" ) - assert len(chat_spans) == 2 - - assert invoke_agent_span["origin"] == "auto.ai.langchain" - assert chat_spans[0]["origin"] == "auto.ai.langchain" - assert chat_spans[1]["origin"] == "auto.ai.langchain" - assert tool_exec_span["origin"] == "auto.ai.langchain" + assert "5" in chat_spans[0]["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] + assert "word" in tool_exec_span["attributes"][SPANDATA.GEN_AI_TOOL_INPUT] + assert 5 == int(tool_exec_span["attributes"][SPANDATA.GEN_AI_TOOL_OUTPUT]) - # We can't guarantee anything about the "shape" of the langchain execution graph - assert len(list(x for x in tx["spans"] if x["op"] == "gen_ai.chat")) > 0 - - # Token usage is only available in newer versions of langchain (v0.2+) - # where usage_metadata is supported on AIMessageChunk - if "gen_ai.usage.input_tokens" in chat_spans[0]["data"]: - assert chat_spans[0]["data"]["gen_ai.usage.input_tokens"] == 142 - assert chat_spans[0]["data"]["gen_ai.usage.output_tokens"] == 50 - assert chat_spans[0]["data"]["gen_ai.usage.total_tokens"] == 192 + assert json.loads( + chat_spans[0]["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] + ) == [ + { + "role": "user", + "content": "['Message demonstrating the absence of truncation.', 'How many letters in the word eudca']", + } + ] - if "gen_ai.usage.input_tokens" in chat_spans[1]["data"]: - assert chat_spans[1]["data"]["gen_ai.usage.input_tokens"] == 89 - assert chat_spans[1]["data"]["gen_ai.usage.output_tokens"] == 28 - assert chat_spans[1]["data"]["gen_ai.usage.total_tokens"] == 117 + assert expected_system_instructions == json.loads( + chat_spans[0]["attributes"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS] + ) - if LANGCHAIN_OPENAI_VERSION >= (0, 3, 13): - assert ( - chat_spans[0]["data"][SPANDATA.GEN_AI_RESPONSE_MODEL] == "gpt-3.5-turbo" - ) - assert ( - chat_spans[1]["data"][SPANDATA.GEN_AI_RESPONSE_MODEL] == "gpt-3.5-turbo" - ) + assert "5" in chat_spans[1]["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] - assert "5" in chat_spans[0]["data"][SPANDATA.GEN_AI_RESPONSE_TEXT] - assert "word" in tool_exec_span["data"][SPANDATA.GEN_AI_TOOL_INPUT] - assert 5 == int(tool_exec_span["data"][SPANDATA.GEN_AI_TOOL_OUTPUT]) + # Verify tool calls are recorded when PII is enabled + assert SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS in chat_spans[0].get("attributes", {}), ( + "Tool calls should be recorded when send_default_pii=True" + ) + tool_calls_data = chat_spans[0]["attributes"][SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS] - assert expected_system_instructions == json.loads( - chat_spans[0]["data"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS] - ) + assert isinstance(tool_calls_data, (list, str)) # Could be serialized + if isinstance(tool_calls_data, str): + assert "get_word_length" in tool_calls_data + elif isinstance(tool_calls_data, list) and len(tool_calls_data) > 0: + # Check if tool calls contain expected function name + tool_call_str = str(tool_calls_data) + assert "get_word_length" in tool_call_str - assert "5" in chat_spans[1]["data"][SPANDATA.GEN_AI_RESPONSE_TEXT] + # Verify finish_reasons is always an array of strings + assert chat_spans[0]["attributes"][SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS] == [ + "function_call" + ] + assert chat_spans[1]["attributes"][SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS] == [ + "stop" + ] - # Verify tool calls are recorded when PII is enabled - assert SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS in chat_spans[0].get("data", {}), ( - "Tool calls should be recorded when send_default_pii=True and include_prompts=True" + # Verify that available tools are always recorded regardless of PII settings + for chat_span in chat_spans: + tools_data = chat_span["attributes"][SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS] + assert tools_data is not None, ( + "Available tools should always be recorded regardless of PII settings" ) - tool_calls_data = chat_spans[0]["data"][SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS] - - assert isinstance(tool_calls_data, (list, str)) # Could be serialized - if isinstance(tool_calls_data, str): - assert "get_word_length" in tool_calls_data - elif isinstance(tool_calls_data, list) and len(tool_calls_data) > 0: - # Check if tool calls contain expected function name - tool_call_str = str(tool_calls_data) - assert "get_word_length" in tool_call_str - - # Verify finish_reasons is always an array of strings - assert chat_spans[0]["data"][SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS] == [ - "function_call" - ] - assert chat_spans[1]["data"][SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS] == [ - "stop" - ] - - # Verify that available tools are always recorded regardless of PII settings - for chat_span in chat_spans: - tools_data = chat_span["data"][SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS] - assert tools_data is not None, ( - "Available tools should always be recorded regardless of PII settings" - ) - assert "get_word_length" in tools_data + assert "get_word_length" in tools_data -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_langchain_openai_tools_agent_with_config( sentry_init, - capture_events, capture_items, get_model_response, server_side_event_chunks, streaming_chat_completions_model_responses, - stream_gen_ai_spans, - span_streaming, ): sentry_init( - integrations=[ - LangchainIntegration( - include_prompts=True, - ) - ], + integrations=[LangchainIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) prompt = ChatPromptTemplate.from_messages( @@ -2442,117 +1256,39 @@ def test_langchain_openai_tools_agent_with_config( ) agent_executor = AgentExecutor(agent=agent, tools=[get_word_length], verbose=True) + items = capture_items("span") - if span_streaming: - items = capture_items("transaction", "span") - - with patch.object( - llm.client._client._client, - "send", - side_effect=[tool_response, final_response], - ) as _, sentry_sdk.traces.start_span(name="custom parent"): - list( - agent_executor.invoke( - {"input": "How many letters in the word eudca"}, - ) - ) - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert spans[4]["attributes"]["sentry.origin"] == "manual" - invoke_agent_span = next( - x - for x in spans - if x["attributes"].get("sentry.op") == "gen_ai.invoke_agent" - ) - assert ( - invoke_agent_span["attributes"]["gen_ai.function_id"] - == "my-snazzy-pipeline" - ) - elif stream_gen_ai_spans: - items = capture_items("transaction", "span") - - with patch.object( - llm.client._client._client, - "send", - side_effect=[tool_response, final_response], - ) as _, start_transaction(): - list( - agent_executor.invoke( - {"input": "How many letters in the word eudca"}, - ) + with patch.object( + llm.client._client._client, + "send", + side_effect=[tool_response, final_response], + ): + list( + agent_executor.invoke( + {"input": "How many letters in the word eudca"}, ) - - tx = next(item.payload for item in items if item.type == "transaction") - assert tx["type"] == "transaction" - assert tx["contexts"]["trace"]["origin"] == "manual" - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - invoke_agent_span = next( - x for x in spans if x["attributes"]["sentry.op"] == "gen_ai.invoke_agent" ) - assert ( - invoke_agent_span["attributes"]["gen_ai.function_id"] - == "my-snazzy-pipeline" - ) - else: - events = capture_events() - - with patch.object( - llm.client._client._client, - "send", - side_effect=[tool_response, final_response], - ) as _, start_transaction(): - list( - agent_executor.invoke( - {"input": "How many letters in the word eudca"}, - ) - ) - - tx = events[0] - assert tx["type"] == "transaction" - assert tx["contexts"]["trace"]["origin"] == "manual" - invoke_agent_span = next( - x for x in tx["spans"] if x["op"] == "gen_ai.invoke_agent" - ) - assert invoke_agent_span["data"]["gen_ai.function_id"] == "my-snazzy-pipeline" + sentry_sdk.flush() + spans = [item.payload for item in items] + invoke_agent_span = next( + x for x in spans if x["attributes"].get("sentry.op") == "gen_ai.invoke_agent" + ) + assert invoke_agent_span["attributes"]["gen_ai.function_id"] == "my-snazzy-pipeline" -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) -@pytest.mark.parametrize( - "send_default_pii, include_prompts", - [ - (True, False), - (False, True), - (False, False), - ], -) -def test_langchain_openai_tools_agent_stream_no_prompts( +def test_langchain_openai_tools_agent_stream_no_sensitive_data( sentry_init, - capture_events, capture_items, - send_default_pii, - include_prompts, get_model_response, server_side_event_chunks, streaming_chat_completions_model_responses, - stream_gen_ai_spans, - span_streaming, ): sentry_init( - integrations=[ - LangchainIntegration( - include_prompts=include_prompts, - ) - ], + integrations=[LangchainIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, - send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", + send_default_pii=False, ) prompt = ChatPromptTemplate.from_messages( @@ -2590,359 +1326,110 @@ def test_langchain_openai_tools_agent_stream_no_prompts( agent = create_openai_tools_agent(llm, [get_word_length], prompt) agent_executor = AgentExecutor(agent=agent, tools=[get_word_length], verbose=True) + items = capture_items("span") - if span_streaming: - items = capture_items("transaction", "span") - - with patch.object( - llm.client._client._client, - "send", - side_effect=[tool_response, final_response], - ) as _, sentry_sdk.traces.start_span(name="custom parent"): - list( - agent_executor.stream( - {"input": "How many letters in the word eudca"}, - {"run_name": "my-snazzy-pipeline"}, - ) - ) - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert spans[4]["attributes"]["sentry.origin"] == "manual" - invoke_agent_span = next( - x - for x in spans - if x["attributes"].get("sentry.op") == "gen_ai.invoke_agent" - ) - chat_spans = list( - x for x in spans if x["attributes"].get("sentry.op") == "gen_ai.chat" - ) - tool_exec_span = next( - x - for x in spans - if x["attributes"].get("sentry.op") == "gen_ai.execute_tool" - ) - - assert len(chat_spans) == 2 - - assert invoke_agent_span["attributes"]["sentry.origin"] == "auto.ai.langchain" - assert chat_spans[0]["attributes"]["sentry.origin"] == "auto.ai.langchain" - assert chat_spans[1]["attributes"]["sentry.origin"] == "auto.ai.langchain" - assert tool_exec_span["attributes"]["sentry.origin"] == "auto.ai.langchain" - - assert ( - invoke_agent_span["attributes"]["gen_ai.function_id"] - == "my-snazzy-pipeline" - ) - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - # We can't guarantee anything about the "shape" of the langchain execution graph - assert ( - len( - list( - x - for x in spans - if x["attributes"].get("sentry.op") == "gen_ai.chat" - ) - ) - > 0 - ) - - # Token usage is only available in newer versions of langchain (v0.2+) - # where usage_metadata is supported on AIMessageChunk - if "gen_ai.usage.input_tokens" in chat_spans[0]["attributes"]: - assert chat_spans[0]["attributes"]["gen_ai.usage.input_tokens"] == 142 - assert chat_spans[0]["attributes"]["gen_ai.usage.output_tokens"] == 50 - assert chat_spans[0]["attributes"]["gen_ai.usage.total_tokens"] == 192 - - if "gen_ai.usage.input_tokens" in chat_spans[1]["attributes"]: - assert chat_spans[1]["attributes"]["gen_ai.usage.input_tokens"] == 89 - assert chat_spans[1]["attributes"]["gen_ai.usage.output_tokens"] == 28 - assert chat_spans[1]["attributes"]["gen_ai.usage.total_tokens"] == 117 - - if LANGCHAIN_OPENAI_VERSION >= (0, 3, 13): - assert ( - chat_spans[0]["attributes"][SPANDATA.GEN_AI_RESPONSE_MODEL] - == "gpt-3.5-turbo" - ) - assert ( - chat_spans[1]["attributes"][SPANDATA.GEN_AI_RESPONSE_MODEL] - == "gpt-3.5-turbo" + with patch.object( + llm.client._client._client, + "send", + side_effect=[tool_response, final_response], + ): + list( + agent_executor.stream( + {"input": "How many letters in the word eudca"}, + {"run_name": "my-snazzy-pipeline"}, ) - - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in chat_spans[0].get( - "attributes", {} - ) - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in chat_spans[0].get( - "attributes", {} - ) - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in chat_spans[0].get("attributes", {}) - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in chat_spans[1].get( - "attributes", {} - ) - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in chat_spans[1].get( - "attributes", {} - ) - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in chat_spans[1].get("attributes", {}) - assert SPANDATA.GEN_AI_TOOL_INPUT not in tool_exec_span.get("attributes", {}) - assert SPANDATA.GEN_AI_TOOL_OUTPUT not in tool_exec_span.get("attributes", {}) - - # Verify tool calls are NOT recorded when PII is disabled - assert SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS not in chat_spans[0].get( - "attributes", {} - ), ( - f"Tool calls should NOT be recorded when send_default_pii={send_default_pii} " - f"and include_prompts={include_prompts}" - ) - assert SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS not in chat_spans[1].get( - "attributes", {} - ), ( - f"Tool calls should NOT be recorded when send_default_pii={send_default_pii} " - f"and include_prompts={include_prompts}" ) - # Verify finish_reasons is always an array of strings - assert chat_spans[0]["attributes"][SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS] == [ - "function_call" - ] - assert chat_spans[1]["attributes"][SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS] == [ - "stop" - ] + sentry_sdk.flush() + spans = [item.payload for item in items] + invoke_agent_span = next( + x for x in spans if x["attributes"].get("sentry.op") == "gen_ai.invoke_agent" + ) + chat_spans = list( + x for x in spans if x["attributes"].get("sentry.op") == "gen_ai.chat" + ) + tool_exec_span = next( + x for x in spans if x["attributes"].get("sentry.op") == "gen_ai.execute_tool" + ) - # Verify that available tools are always recorded regardless of PII settings - for chat_span in chat_spans: - tools_data = chat_span["attributes"][ - SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS - ] + assert len(chat_spans) == 2 - assert tools_data is not None, ( - "Available tools should always be recorded regardless of PII settings" - ) - assert "get_word_length" in tools_data - elif stream_gen_ai_spans: - items = capture_items("transaction", "span") - - with patch.object( - llm.client._client._client, - "send", - side_effect=[tool_response, final_response], - ) as _, start_transaction(): - list( - agent_executor.stream( - {"input": "How many letters in the word eudca"}, - {"run_name": "my-snazzy-pipeline"}, - ) - ) + assert invoke_agent_span["attributes"]["sentry.origin"] == "auto.ai.langchain" + assert chat_spans[0]["attributes"]["sentry.origin"] == "auto.ai.langchain" + assert chat_spans[1]["attributes"]["sentry.origin"] == "auto.ai.langchain" + assert tool_exec_span["attributes"]["sentry.origin"] == "auto.ai.langchain" - tx = next(item.payload for item in items if item.type == "transaction") - assert tx["type"] == "transaction" - assert tx["contexts"]["trace"]["origin"] == "manual" + assert invoke_agent_span["attributes"]["gen_ai.function_id"] == "my-snazzy-pipeline" - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - invoke_agent_span = next( - x for x in spans if x["attributes"]["sentry.op"] == "gen_ai.invoke_agent" - ) - chat_spans = list( - x for x in spans if x["attributes"]["sentry.op"] == "gen_ai.chat" - ) - tool_exec_span = next( - x for x in spans if x["attributes"]["sentry.op"] == "gen_ai.execute_tool" - ) + sentry_sdk.flush() + spans = [item.payload for item in items] + # We can't guarantee anything about the "shape" of the langchain execution graph + assert ( + len(list(x for x in spans if x["attributes"].get("sentry.op") == "gen_ai.chat")) + > 0 + ) - assert len(chat_spans) == 2 + # Token usage is only available in newer versions of langchain (v0.2+) + # where usage_metadata is supported on AIMessageChunk + if "gen_ai.usage.input_tokens" in chat_spans[0]["attributes"]: + assert chat_spans[0]["attributes"]["gen_ai.usage.input_tokens"] == 142 + assert chat_spans[0]["attributes"]["gen_ai.usage.output_tokens"] == 50 + assert chat_spans[0]["attributes"]["gen_ai.usage.total_tokens"] == 192 - assert invoke_agent_span["attributes"]["sentry.origin"] == "auto.ai.langchain" - assert chat_spans[0]["attributes"]["sentry.origin"] == "auto.ai.langchain" - assert chat_spans[1]["attributes"]["sentry.origin"] == "auto.ai.langchain" - assert tool_exec_span["attributes"]["sentry.origin"] == "auto.ai.langchain" + if "gen_ai.usage.input_tokens" in chat_spans[1]["attributes"]: + assert chat_spans[1]["attributes"]["gen_ai.usage.input_tokens"] == 89 + assert chat_spans[1]["attributes"]["gen_ai.usage.output_tokens"] == 28 + assert chat_spans[1]["attributes"]["gen_ai.usage.total_tokens"] == 117 + if LANGCHAIN_OPENAI_VERSION >= (0, 3, 13): assert ( - invoke_agent_span["attributes"]["gen_ai.function_id"] - == "my-snazzy-pipeline" + chat_spans[0]["attributes"][SPANDATA.GEN_AI_RESPONSE_MODEL] + == "gpt-3.5-turbo" ) - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - # We can't guarantee anything about the "shape" of the langchain execution graph assert ( - len(list(x for x in spans if x["attributes"]["sentry.op"] == "gen_ai.chat")) - > 0 - ) + chat_spans[1]["attributes"][SPANDATA.GEN_AI_RESPONSE_MODEL] + == "gpt-3.5-turbo" + ) + + assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in chat_spans[0].get( + "attributes", {} + ) + assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in chat_spans[0].get("attributes", {}) + assert SPANDATA.GEN_AI_RESPONSE_TEXT not in chat_spans[0].get("attributes", {}) + assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in chat_spans[1].get( + "attributes", {} + ) + assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in chat_spans[1].get("attributes", {}) + assert SPANDATA.GEN_AI_RESPONSE_TEXT not in chat_spans[1].get("attributes", {}) + assert SPANDATA.GEN_AI_TOOL_INPUT not in tool_exec_span.get("attributes", {}) + assert SPANDATA.GEN_AI_TOOL_OUTPUT not in tool_exec_span.get("attributes", {}) + + # Verify tool calls are NOT recorded when PII is disabled + assert SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS not in chat_spans[0].get( + "attributes", {} + ), "Tool calls should NOT be recorded when send_default_pii=False" + assert SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS not in chat_spans[1].get( + "attributes", {} + ), "Tool calls should NOT be recorded when send_default_pii=False" + + # Verify finish_reasons is always an array of strings + assert chat_spans[0]["attributes"][SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS] == [ + "function_call" + ] + assert chat_spans[1]["attributes"][SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS] == [ + "stop" + ] - # Token usage is only available in newer versions of langchain (v0.2+) - # where usage_metadata is supported on AIMessageChunk - if "gen_ai.usage.input_tokens" in chat_spans[0]["attributes"]: - assert chat_spans[0]["attributes"]["gen_ai.usage.input_tokens"] == 142 - assert chat_spans[0]["attributes"]["gen_ai.usage.output_tokens"] == 50 - assert chat_spans[0]["attributes"]["gen_ai.usage.total_tokens"] == 192 - - if "gen_ai.usage.input_tokens" in chat_spans[1]["attributes"]: - assert chat_spans[1]["attributes"]["gen_ai.usage.input_tokens"] == 89 - assert chat_spans[1]["attributes"]["gen_ai.usage.output_tokens"] == 28 - assert chat_spans[1]["attributes"]["gen_ai.usage.total_tokens"] == 117 - - if LANGCHAIN_OPENAI_VERSION >= (0, 3, 13): - assert ( - chat_spans[0]["attributes"][SPANDATA.GEN_AI_RESPONSE_MODEL] - == "gpt-3.5-turbo" - ) - assert ( - chat_spans[1]["attributes"][SPANDATA.GEN_AI_RESPONSE_MODEL] - == "gpt-3.5-turbo" - ) + # Verify that available tools are always recorded regardless of PII settings + for chat_span in chat_spans: + tools_data = chat_span["attributes"][SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS] - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in chat_spans[0].get( - "attributes", {} - ) - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in chat_spans[0].get( - "attributes", {} - ) - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in chat_spans[0].get("attributes", {}) - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in chat_spans[1].get( - "attributes", {} - ) - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in chat_spans[1].get( - "attributes", {} + assert tools_data is not None, ( + "Available tools should always be recorded regardless of PII settings" ) - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in chat_spans[1].get("attributes", {}) - assert SPANDATA.GEN_AI_TOOL_INPUT not in tool_exec_span.get("attributes", {}) - assert SPANDATA.GEN_AI_TOOL_OUTPUT not in tool_exec_span.get("attributes", {}) + assert "get_word_length" in tools_data - # Verify tool calls are NOT recorded when PII is disabled - assert SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS not in chat_spans[0].get( - "attributes", {} - ), ( - f"Tool calls should NOT be recorded when send_default_pii={send_default_pii} " - f"and include_prompts={include_prompts}" - ) - assert SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS not in chat_spans[1].get( - "attributes", {} - ), ( - f"Tool calls should NOT be recorded when send_default_pii={send_default_pii} " - f"and include_prompts={include_prompts}" - ) - # Verify finish_reasons is always an array of strings - assert chat_spans[0]["attributes"][SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS] == [ - "function_call" - ] - assert chat_spans[1]["attributes"][SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS] == [ - "stop" - ] - - # Verify that available tools are always recorded regardless of PII settings - for chat_span in chat_spans: - tools_data = chat_span["attributes"][ - SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS - ] - - assert tools_data is not None, ( - "Available tools should always be recorded regardless of PII settings" - ) - assert "get_word_length" in tools_data - else: - events = capture_events() - - with patch.object( - llm.client._client._client, - "send", - side_effect=[tool_response, final_response], - ) as _, start_transaction(): - list( - agent_executor.stream( - {"input": "How many letters in the word eudca"}, - {"run_name": "my-snazzy-pipeline"}, - ) - ) - - tx = events[0] - assert tx["type"] == "transaction" - assert tx["contexts"]["trace"]["origin"] == "manual" - - invoke_agent_span = next( - x for x in tx["spans"] if x["op"] == "gen_ai.invoke_agent" - ) - chat_spans = list(x for x in tx["spans"] if x["op"] == "gen_ai.chat") - tool_exec_span = next( - x for x in tx["spans"] if x["op"] == "gen_ai.execute_tool" - ) - - assert len(chat_spans) == 2 - - assert invoke_agent_span["origin"] == "auto.ai.langchain" - assert chat_spans[0]["origin"] == "auto.ai.langchain" - assert chat_spans[1]["origin"] == "auto.ai.langchain" - assert tool_exec_span["origin"] == "auto.ai.langchain" - - assert invoke_agent_span["data"]["gen_ai.function_id"] == "my-snazzy-pipeline" - - # We can't guarantee anything about the "shape" of the langchain execution graph - assert len(list(x for x in tx["spans"] if x["op"] == "gen_ai.chat")) > 0 - - # Token usage is only available in newer versions of langchain (v0.2+) - # where usage_metadata is supported on AIMessageChunk - if "gen_ai.usage.input_tokens" in chat_spans[0]["data"]: - assert chat_spans[0]["data"]["gen_ai.usage.input_tokens"] == 142 - assert chat_spans[0]["data"]["gen_ai.usage.output_tokens"] == 50 - assert chat_spans[0]["data"]["gen_ai.usage.total_tokens"] == 192 - - if "gen_ai.usage.input_tokens" in chat_spans[1]["data"]: - assert chat_spans[1]["data"]["gen_ai.usage.input_tokens"] == 89 - assert chat_spans[1]["data"]["gen_ai.usage.output_tokens"] == 28 - assert chat_spans[1]["data"]["gen_ai.usage.total_tokens"] == 117 - - if LANGCHAIN_OPENAI_VERSION >= (0, 3, 13): - assert ( - chat_spans[0]["data"][SPANDATA.GEN_AI_RESPONSE_MODEL] == "gpt-3.5-turbo" - ) - assert ( - chat_spans[1]["data"][SPANDATA.GEN_AI_RESPONSE_MODEL] == "gpt-3.5-turbo" - ) - - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in chat_spans[0].get("data", {}) - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in chat_spans[0].get("data", {}) - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in chat_spans[0].get("data", {}) - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in chat_spans[1].get("data", {}) - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in chat_spans[1].get("data", {}) - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in chat_spans[1].get("data", {}) - assert SPANDATA.GEN_AI_TOOL_INPUT not in tool_exec_span.get("data", {}) - assert SPANDATA.GEN_AI_TOOL_OUTPUT not in tool_exec_span.get("data", {}) - - # Verify tool calls are NOT recorded when PII is disabled - assert SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS not in chat_spans[0].get( - "data", {} - ), ( - f"Tool calls should NOT be recorded when send_default_pii={send_default_pii} " - f"and include_prompts={include_prompts}" - ) - assert SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS not in chat_spans[1].get( - "data", {} - ), ( - f"Tool calls should NOT be recorded when send_default_pii={send_default_pii} " - f"and include_prompts={include_prompts}" - ) - - # Verify finish_reasons is always an array of strings - assert chat_spans[0]["data"][SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS] == [ - "function_call" - ] - assert chat_spans[1]["data"][SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS] == [ - "stop" - ] - - # Verify that available tools are always recorded regardless of PII settings - for chat_span in chat_spans: - tools_data = chat_span["data"][SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS] - assert tools_data is not None, ( - "Available tools should always be recorded regardless of PII settings" - ) - assert "get_word_length" in tools_data - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize( "system_instructions_content,expected_system_instructions", [ @@ -2989,27 +1476,18 @@ def test_langchain_openai_tools_agent_stream_no_prompts( ) def test_langchain_openai_tools_agent_stream( sentry_init, - capture_events, capture_items, system_instructions_content, expected_system_instructions, get_model_response, server_side_event_chunks, streaming_chat_completions_model_responses, - stream_gen_ai_spans, - span_streaming, ): sentry_init( - integrations=[ - LangchainIntegration( - include_prompts=True, - ) - ], + integrations=[LangchainIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) prompt = ChatPromptTemplate.from_messages( @@ -3047,396 +1525,136 @@ def test_langchain_openai_tools_agent_stream( agent = create_openai_tools_agent(llm, [get_word_length], prompt) agent_executor = AgentExecutor(agent=agent, tools=[get_word_length], verbose=True) + items = capture_items("span") - if span_streaming: - items = capture_items("transaction", "span") - - with patch.object( - llm.client._client._client, - "send", - side_effect=[tool_response, final_response], - ) as _, sentry_sdk.traces.start_span(name="custom parent"): - list( - agent_executor.stream( - { - "input": [ - "Message demonstrating the absence of truncation.", - "How many letters in the word eudca", - ] - }, - {"run_name": "my-snazzy-pipeline"}, - ) - ) - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert spans[4]["attributes"]["sentry.origin"] == "manual" - invoke_agent_span = next( - x - for x in spans - if x["attributes"].get("sentry.op") == "gen_ai.invoke_agent" - ) - chat_spans = list( - x for x in spans if x["attributes"].get("sentry.op") == "gen_ai.chat" - ) - tool_exec_span = next( - x - for x in spans - if x["attributes"].get("sentry.op") == "gen_ai.execute_tool" - ) - - assert len(chat_spans) == 2 - - assert invoke_agent_span["attributes"]["sentry.origin"] == "auto.ai.langchain" - assert chat_spans[0]["attributes"]["sentry.origin"] == "auto.ai.langchain" - assert chat_spans[1]["attributes"]["sentry.origin"] == "auto.ai.langchain" - assert tool_exec_span["attributes"]["sentry.origin"] == "auto.ai.langchain" - - assert ( - invoke_agent_span["attributes"]["gen_ai.function_id"] - == "my-snazzy-pipeline" - ) - - # We can't guarantee anything about the "shape" of the langchain execution graph - assert ( - len( - list( - x - for x in spans - if x["attributes"].get("sentry.op") == "gen_ai.chat" - ) - ) - > 0 - ) - - # Token usage is only available in newer versions of langchain (v0.2+) - # where usage_metadata is supported on AIMessageChunk - if "gen_ai.usage.input_tokens" in chat_spans[0]["attributes"]: - assert chat_spans[0]["attributes"]["gen_ai.usage.input_tokens"] == 142 - assert chat_spans[0]["attributes"]["gen_ai.usage.output_tokens"] == 50 - assert chat_spans[0]["attributes"]["gen_ai.usage.total_tokens"] == 192 - - if "gen_ai.usage.input_tokens" in chat_spans[1]["attributes"]: - assert chat_spans[1]["attributes"]["gen_ai.usage.input_tokens"] == 89 - assert chat_spans[1]["attributes"]["gen_ai.usage.output_tokens"] == 28 - assert chat_spans[1]["attributes"]["gen_ai.usage.total_tokens"] == 117 - - if LANGCHAIN_OPENAI_VERSION >= (0, 3, 13): - assert ( - chat_spans[0]["attributes"][SPANDATA.GEN_AI_RESPONSE_MODEL] - == "gpt-3.5-turbo" - ) - assert ( - chat_spans[1]["attributes"][SPANDATA.GEN_AI_RESPONSE_MODEL] - == "gpt-3.5-turbo" + with patch.object( + llm.client._client._client, + "send", + side_effect=[tool_response, final_response], + ): + list( + agent_executor.stream( + { + "input": [ + "Message demonstrating the absence of truncation.", + "How many letters in the word eudca", + ] + }, + {"run_name": "my-snazzy-pipeline"}, ) - - assert "5" in chat_spans[0]["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] - assert "word" in tool_exec_span["attributes"][SPANDATA.GEN_AI_TOOL_INPUT] - assert 5 == int(tool_exec_span["attributes"][SPANDATA.GEN_AI_TOOL_OUTPUT]) - - assert json.loads( - chat_spans[0]["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - ) == [ - { - "role": "user", - "content": "['Message demonstrating the absence of truncation.', 'How many letters in the word eudca']", - } - ] - - assert expected_system_instructions == json.loads( - chat_spans[0]["attributes"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS] ) - assert "5" in chat_spans[1]["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] - - # Verify tool calls are recorded when PII is enabled - assert SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS in chat_spans[0].get( - "attributes", {} - ), ( - "Tool calls should be recorded when send_default_pii=True and include_prompts=True" - ) - tool_calls_data = chat_spans[0]["attributes"][ - SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS - ] + sentry_sdk.flush() + spans = [item.payload for item in items] + invoke_agent_span = next( + x for x in spans if x["attributes"].get("sentry.op") == "gen_ai.invoke_agent" + ) + chat_spans = list( + x for x in spans if x["attributes"].get("sentry.op") == "gen_ai.chat" + ) + tool_exec_span = next( + x for x in spans if x["attributes"].get("sentry.op") == "gen_ai.execute_tool" + ) - assert isinstance(tool_calls_data, (list, str)) # Could be serialized - if isinstance(tool_calls_data, str): - assert "get_word_length" in tool_calls_data - elif isinstance(tool_calls_data, list) and len(tool_calls_data) > 0: - # Check if tool calls contain expected function name - tool_call_str = str(tool_calls_data) - assert "get_word_length" in tool_call_str - - # Verify finish_reasons is always an array of strings - assert chat_spans[0]["attributes"][SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS] == [ - "function_call" - ] - assert chat_spans[1]["attributes"][SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS] == [ - "stop" - ] + assert len(chat_spans) == 2 - # Verify that available tools are always recorded regardless of PII settings - for chat_span in chat_spans: - tools_data = chat_span["attributes"][ - SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS - ] - assert tools_data is not None, ( - "Available tools should always be recorded regardless of PII settings" - ) - assert "get_word_length" in tools_data - elif stream_gen_ai_spans: - items = capture_items("transaction", "span") - - with patch.object( - llm.client._client._client, - "send", - side_effect=[tool_response, final_response], - ) as _, start_transaction(): - list( - agent_executor.stream( - { - "input": [ - "Message demonstrating the absence of truncation.", - "How many letters in the word eudca", - ] - }, - {"run_name": "my-snazzy-pipeline"}, - ) - ) + assert invoke_agent_span["attributes"]["sentry.origin"] == "auto.ai.langchain" + assert chat_spans[0]["attributes"]["sentry.origin"] == "auto.ai.langchain" + assert chat_spans[1]["attributes"]["sentry.origin"] == "auto.ai.langchain" + assert tool_exec_span["attributes"]["sentry.origin"] == "auto.ai.langchain" - tx = next(item.payload for item in items if item.type == "transaction") - assert tx["type"] == "transaction" - assert tx["contexts"]["trace"]["origin"] == "manual" + assert invoke_agent_span["attributes"]["gen_ai.function_id"] == "my-snazzy-pipeline" - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - invoke_agent_span = next( - x for x in spans if x["attributes"]["sentry.op"] == "gen_ai.invoke_agent" - ) - chat_spans = list( - x for x in spans if x["attributes"]["sentry.op"] == "gen_ai.chat" - ) - tool_exec_span = next( - x for x in spans if x["attributes"]["sentry.op"] == "gen_ai.execute_tool" - ) + # We can't guarantee anything about the "shape" of the langchain execution graph + assert ( + len(list(x for x in spans if x["attributes"].get("sentry.op") == "gen_ai.chat")) + > 0 + ) - assert len(chat_spans) == 2 + # Token usage is only available in newer versions of langchain (v0.2+) + # where usage_metadata is supported on AIMessageChunk + if "gen_ai.usage.input_tokens" in chat_spans[0]["attributes"]: + assert chat_spans[0]["attributes"]["gen_ai.usage.input_tokens"] == 142 + assert chat_spans[0]["attributes"]["gen_ai.usage.output_tokens"] == 50 + assert chat_spans[0]["attributes"]["gen_ai.usage.total_tokens"] == 192 - assert invoke_agent_span["attributes"]["sentry.origin"] == "auto.ai.langchain" - assert chat_spans[0]["attributes"]["sentry.origin"] == "auto.ai.langchain" - assert chat_spans[1]["attributes"]["sentry.origin"] == "auto.ai.langchain" - assert tool_exec_span["attributes"]["sentry.origin"] == "auto.ai.langchain" + if "gen_ai.usage.input_tokens" in chat_spans[1]["attributes"]: + assert chat_spans[1]["attributes"]["gen_ai.usage.input_tokens"] == 89 + assert chat_spans[1]["attributes"]["gen_ai.usage.output_tokens"] == 28 + assert chat_spans[1]["attributes"]["gen_ai.usage.total_tokens"] == 117 + if LANGCHAIN_OPENAI_VERSION >= (0, 3, 13): assert ( - invoke_agent_span["attributes"]["gen_ai.function_id"] - == "my-snazzy-pipeline" + chat_spans[0]["attributes"][SPANDATA.GEN_AI_RESPONSE_MODEL] + == "gpt-3.5-turbo" ) - - # We can't guarantee anything about the "shape" of the langchain execution graph assert ( - len(list(x for x in spans if x["attributes"]["sentry.op"] == "gen_ai.chat")) - > 0 - ) - - # Token usage is only available in newer versions of langchain (v0.2+) - # where usage_metadata is supported on AIMessageChunk - if "gen_ai.usage.input_tokens" in chat_spans[0]["attributes"]: - assert chat_spans[0]["attributes"]["gen_ai.usage.input_tokens"] == 142 - assert chat_spans[0]["attributes"]["gen_ai.usage.output_tokens"] == 50 - assert chat_spans[0]["attributes"]["gen_ai.usage.total_tokens"] == 192 - - if "gen_ai.usage.input_tokens" in chat_spans[1]["attributes"]: - assert chat_spans[1]["attributes"]["gen_ai.usage.input_tokens"] == 89 - assert chat_spans[1]["attributes"]["gen_ai.usage.output_tokens"] == 28 - assert chat_spans[1]["attributes"]["gen_ai.usage.total_tokens"] == 117 - - if LANGCHAIN_OPENAI_VERSION >= (0, 3, 13): - assert ( - chat_spans[0]["attributes"][SPANDATA.GEN_AI_RESPONSE_MODEL] - == "gpt-3.5-turbo" - ) - assert ( - chat_spans[1]["attributes"][SPANDATA.GEN_AI_RESPONSE_MODEL] - == "gpt-3.5-turbo" - ) - - assert "5" in chat_spans[0]["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] - assert "word" in tool_exec_span["attributes"][SPANDATA.GEN_AI_TOOL_INPUT] - assert 5 == int(tool_exec_span["attributes"][SPANDATA.GEN_AI_TOOL_OUTPUT]) - - assert json.loads( - chat_spans[0]["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - ) == [ - { - "role": "user", - "content": "['Message demonstrating the absence of truncation.', 'How many letters in the word eudca']", - } - ] - - assert expected_system_instructions == json.loads( - chat_spans[0]["attributes"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS] + chat_spans[1]["attributes"][SPANDATA.GEN_AI_RESPONSE_MODEL] + == "gpt-3.5-turbo" ) - assert "5" in chat_spans[1]["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] - - # Verify tool calls are recorded when PII is enabled - assert SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS in chat_spans[0].get( - "attributes", {} - ), ( - "Tool calls should be recorded when send_default_pii=True and include_prompts=True" - ) - tool_calls_data = chat_spans[0]["attributes"][ - SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS - ] - - assert isinstance(tool_calls_data, (list, str)) # Could be serialized - if isinstance(tool_calls_data, str): - assert "get_word_length" in tool_calls_data - elif isinstance(tool_calls_data, list) and len(tool_calls_data) > 0: - # Check if tool calls contain expected function name - tool_call_str = str(tool_calls_data) - assert "get_word_length" in tool_call_str - - # Verify finish_reasons is always an array of strings - assert chat_spans[0]["attributes"][SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS] == [ - "function_call" - ] - assert chat_spans[1]["attributes"][SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS] == [ - "stop" - ] - - # Verify that available tools are always recorded regardless of PII settings - for chat_span in chat_spans: - tools_data = chat_span["attributes"][ - SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS - ] - assert tools_data is not None, ( - "Available tools should always be recorded regardless of PII settings" - ) - assert "get_word_length" in tools_data - else: - events = capture_events() - - with patch.object( - llm.client._client._client, - "send", - side_effect=[tool_response, final_response], - ) as _, start_transaction(): - list( - agent_executor.stream( - {"input": "How many letters in the word eudca"}, - {"run_name": "my-snazzy-pipeline"}, - ) - ) - - tx = events[0] - assert tx["type"] == "transaction" - assert tx["contexts"]["trace"]["origin"] == "manual" - - invoke_agent_span = next( - x for x in tx["spans"] if x["op"] == "gen_ai.invoke_agent" - ) - chat_spans = list(x for x in tx["spans"] if x["op"] == "gen_ai.chat") - tool_exec_span = next( - x for x in tx["spans"] if x["op"] == "gen_ai.execute_tool" - ) - - assert len(chat_spans) == 2 - - assert invoke_agent_span["origin"] == "auto.ai.langchain" - assert chat_spans[0]["origin"] == "auto.ai.langchain" - assert chat_spans[1]["origin"] == "auto.ai.langchain" - assert tool_exec_span["origin"] == "auto.ai.langchain" + assert "5" in chat_spans[0]["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] + assert "word" in tool_exec_span["attributes"][SPANDATA.GEN_AI_TOOL_INPUT] + assert 5 == int(tool_exec_span["attributes"][SPANDATA.GEN_AI_TOOL_OUTPUT]) - assert invoke_agent_span["data"]["gen_ai.function_id"] == "my-snazzy-pipeline" - - # We can't guarantee anything about the "shape" of the langchain execution graph - assert len(list(x for x in tx["spans"] if x["op"] == "gen_ai.chat")) > 0 - - # Token usage is only available in newer versions of langchain (v0.2+) - # where usage_metadata is supported on AIMessageChunk - if "gen_ai.usage.input_tokens" in chat_spans[0]["data"]: - assert chat_spans[0]["data"]["gen_ai.usage.input_tokens"] == 142 - assert chat_spans[0]["data"]["gen_ai.usage.output_tokens"] == 50 - assert chat_spans[0]["data"]["gen_ai.usage.total_tokens"] == 192 + assert json.loads( + chat_spans[0]["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] + ) == [ + { + "role": "user", + "content": "['Message demonstrating the absence of truncation.', 'How many letters in the word eudca']", + } + ] - if "gen_ai.usage.input_tokens" in chat_spans[1]["data"]: - assert chat_spans[1]["data"]["gen_ai.usage.input_tokens"] == 89 - assert chat_spans[1]["data"]["gen_ai.usage.output_tokens"] == 28 - assert chat_spans[1]["data"]["gen_ai.usage.total_tokens"] == 117 + assert expected_system_instructions == json.loads( + chat_spans[0]["attributes"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS] + ) - if LANGCHAIN_OPENAI_VERSION >= (0, 3, 13): - assert ( - chat_spans[0]["data"][SPANDATA.GEN_AI_RESPONSE_MODEL] == "gpt-3.5-turbo" - ) - assert ( - chat_spans[1]["data"][SPANDATA.GEN_AI_RESPONSE_MODEL] == "gpt-3.5-turbo" - ) + assert "5" in chat_spans[1]["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] - assert "5" in chat_spans[0]["data"][SPANDATA.GEN_AI_RESPONSE_TEXT] - assert "word" in tool_exec_span["data"][SPANDATA.GEN_AI_TOOL_INPUT] - assert 5 == int(tool_exec_span["data"][SPANDATA.GEN_AI_TOOL_OUTPUT]) + # Verify tool calls are recorded when PII is enabled + assert SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS in chat_spans[0].get("attributes", {}), ( + "Tool calls should be recorded when send_default_pii=True" + ) + tool_calls_data = chat_spans[0]["attributes"][SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS] - assert expected_system_instructions == json.loads( - chat_spans[0]["data"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS] - ) + assert isinstance(tool_calls_data, (list, str)) # Could be serialized + if isinstance(tool_calls_data, str): + assert "get_word_length" in tool_calls_data + elif isinstance(tool_calls_data, list) and len(tool_calls_data) > 0: + # Check if tool calls contain expected function name + tool_call_str = str(tool_calls_data) + assert "get_word_length" in tool_call_str - assert "5" in chat_spans[1]["data"][SPANDATA.GEN_AI_RESPONSE_TEXT] + # Verify finish_reasons is always an array of strings + assert chat_spans[0]["attributes"][SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS] == [ + "function_call" + ] + assert chat_spans[1]["attributes"][SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS] == [ + "stop" + ] - # Verify tool calls are recorded when PII is enabled - assert SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS in chat_spans[0].get("data", {}), ( - "Tool calls should be recorded when send_default_pii=True and include_prompts=True" + # Verify that available tools are always recorded regardless of PII settings + for chat_span in chat_spans: + tools_data = chat_span["attributes"][SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS] + assert tools_data is not None, ( + "Available tools should always be recorded regardless of PII settings" ) - tool_calls_data = chat_spans[0]["data"][SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS] - assert isinstance(tool_calls_data, (list, str)) # Could be serialized - if isinstance(tool_calls_data, str): - assert "get_word_length" in tool_calls_data - elif isinstance(tool_calls_data, list) and len(tool_calls_data) > 0: - # Check if tool calls contain expected function name - tool_call_str = str(tool_calls_data) - assert "get_word_length" in tool_call_str - - # Verify finish_reasons is always an array of strings - assert chat_spans[0]["data"][SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS] == [ - "function_call" - ] - assert chat_spans[1]["data"][SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS] == [ - "stop" - ] - - # Verify that available tools are always recorded regardless of PII settings - for chat_span in chat_spans: - tools_data = chat_span["data"][SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS] - assert tools_data is not None, ( - "Available tools should always be recorded regardless of PII settings" - ) - assert "get_word_length" in tools_data + assert "get_word_length" in tools_data -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_langchain_openai_tools_agent_stream_with_config( sentry_init, - capture_events, capture_items, get_model_response, server_side_event_chunks, streaming_chat_completions_model_responses, - stream_gen_ai_spans, - span_streaming, ): sentry_init( - integrations=[ - LangchainIntegration( - include_prompts=True, - ) - ], + integrations=[LangchainIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) prompt = ChatPromptTemplate.from_messages( @@ -3476,90 +1694,30 @@ def test_langchain_openai_tools_agent_stream_with_config( ) agent_executor = AgentExecutor(agent=agent, tools=[get_word_length], verbose=True) + items = capture_items("span") - if span_streaming: - items = capture_items("transaction", "span") - - with patch.object( - llm.client._client._client, - "send", - side_effect=[tool_response, final_response], - ) as _, sentry_sdk.traces.start_span(name="custom parent"): - list( - agent_executor.stream( - {"input": "How many letters in the word eudca"}, - ) - ) - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert spans[4]["attributes"]["sentry.origin"] == "manual" - invoke_agent_span = next( - x for x in spans if x["attributes"]["sentry.op"] == "gen_ai.invoke_agent" - ) - assert ( - invoke_agent_span["attributes"]["gen_ai.function_id"] - == "my-snazzy-pipeline" - ) - elif stream_gen_ai_spans: - items = capture_items("transaction", "span") - - with patch.object( - llm.client._client._client, - "send", - side_effect=[tool_response, final_response], - ) as _, start_transaction(): - list( - agent_executor.stream( - {"input": "How many letters in the word eudca"}, - ) + with patch.object( + llm.client._client._client, + "send", + side_effect=[tool_response, final_response], + ): + list( + agent_executor.stream( + {"input": "How many letters in the word eudca"}, ) - - tx = next(item.payload for item in items if item.type == "transaction") - assert tx["type"] == "transaction" - assert tx["contexts"]["trace"]["origin"] == "manual" - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - invoke_agent_span = next( - x for x in spans if x["attributes"]["sentry.op"] == "gen_ai.invoke_agent" - ) - assert ( - invoke_agent_span["attributes"]["gen_ai.function_id"] - == "my-snazzy-pipeline" ) - else: - events = capture_events() - - with patch.object( - llm.client._client._client, - "send", - side_effect=[tool_response, final_response], - ) as _, start_transaction(): - list( - agent_executor.stream( - {"input": "How many letters in the word eudca"}, - ) - ) - tx = events[0] - assert tx["type"] == "transaction" - assert tx["contexts"]["trace"]["origin"] == "manual" - - invoke_agent_span = next( - x for x in tx["spans"] if x["op"] == "gen_ai.invoke_agent" - ) - assert invoke_agent_span["data"]["gen_ai.function_id"] == "my-snazzy-pipeline" + sentry_sdk.flush() + spans = [item.payload for item in items] + invoke_agent_span = next( + x for x in spans if x["attributes"]["sentry.op"] == "gen_ai.invoke_agent" + ) + assert invoke_agent_span["attributes"]["gen_ai.function_id"] == "my-snazzy-pipeline" -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_langchain_error( sentry_init, - capture_events, capture_items, - stream_gen_ai_spans, - span_streaming, ): class MockOpenAI(ChatOpenAI): def _stream( @@ -3579,12 +1737,10 @@ def _llm_type(self) -> str: return "acme-llm" sentry_init( - integrations=[LangchainIntegration(include_prompts=True)], + integrations=[LangchainIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) prompt = ChatPromptTemplate.from_messages( @@ -3605,34 +1761,20 @@ def _llm_type(self) -> str: agent = create_openai_tools_agent(llm, [get_word_length], prompt) agent_executor = AgentExecutor(agent=agent, tools=[get_word_length], verbose=True) + items = capture_items("event") - if span_streaming or stream_gen_ai_spans: - items = capture_items("event") - - with start_transaction(), pytest.raises(ValueError): - list(agent_executor.stream({"input": "How many letters in the word eudca"})) - - (error,) = (item.payload for item in items) - else: - events = capture_events() - - with start_transaction(), pytest.raises(ValueError): - list(agent_executor.stream({"input": "How many letters in the word eudca"})) + with pytest.raises(ValueError): + list(agent_executor.stream({"input": "How many letters in the word eudca"})) - error = events[0] + (error,) = (item.payload for item in items) assert error["level"] == "error" assert error["exception"]["values"][0]["mechanism"]["type"] == "langchain" assert not error["exception"]["values"][0]["mechanism"]["handled"] -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_span_status_error( sentry_init, - capture_events, capture_items, - stream_gen_ai_spans, - span_streaming, ): class MockOpenAI(ChatOpenAI): def _stream( @@ -3652,130 +1794,41 @@ def _llm_type(self) -> str: return "acme-llm" sentry_init( - integrations=[LangchainIntegration(include_prompts=True)], + integrations=[LangchainIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) + items = capture_items("event", "span") - if span_streaming: - items = capture_items("event", "transaction", "span") - - with start_transaction(name="test"): - prompt = ChatPromptTemplate.from_messages( - [ - ( - "system", - "You are very powerful assistant, but don't know current events", - ), - ("user", "{input}"), - MessagesPlaceholder(variable_name="agent_scratchpad"), - ] - ) - llm = MockOpenAI( - model_name="gpt-3.5-turbo", - temperature=0, - openai_api_key="badkey", - ) - agent = create_openai_tools_agent(llm, [get_word_length], prompt) - - agent_executor = AgentExecutor( - agent=agent, tools=[get_word_length], verbose=True - ) - - with pytest.raises(ValueError): - list( - agent_executor.stream( - {"input": "How many letters in the word eudca"} - ) - ) - - (error,) = (item.payload for item in items if item.type == "event") - assert error["level"] == "error" - assert error["exception"]["values"][0]["mechanism"]["type"] == "langchain" - assert not error["exception"]["values"][0]["mechanism"]["handled"] - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert spans[0]["status"] == "error" - elif stream_gen_ai_spans: - items = capture_items("event", "transaction", "span") - - with start_transaction(name="test"): - prompt = ChatPromptTemplate.from_messages( - [ - ( - "system", - "You are very powerful assistant, but don't know current events", - ), - ("user", "{input}"), - MessagesPlaceholder(variable_name="agent_scratchpad"), - ] - ) - llm = MockOpenAI( - model_name="gpt-3.5-turbo", - temperature=0, - openai_api_key="badkey", - ) - agent = create_openai_tools_agent(llm, [get_word_length], prompt) - - agent_executor = AgentExecutor( - agent=agent, tools=[get_word_length], verbose=True - ) - - with pytest.raises(ValueError): - list( - agent_executor.stream( - {"input": "How many letters in the word eudca"} - ) - ) - - (error,) = (item.payload for item in items if item.type == "event") - assert error["level"] == "error" - assert error["exception"]["values"][0]["mechanism"]["type"] == "langchain" - assert not error["exception"]["values"][0]["mechanism"]["handled"] - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert spans[0]["status"] == "error" - (transaction,) = (item.payload for item in items if item.type == "transaction") - else: - events = capture_events() - - with start_transaction(name="test"): - prompt = ChatPromptTemplate.from_messages( - [ - ( - "system", - "You are very powerful assistant, but don't know current events", - ), - ("user", "{input}"), - MessagesPlaceholder(variable_name="agent_scratchpad"), - ] - ) - llm = MockOpenAI( - model_name="gpt-3.5-turbo", - temperature=0, - openai_api_key="badkey", - ) - agent = create_openai_tools_agent(llm, [get_word_length], prompt) + prompt = ChatPromptTemplate.from_messages( + [ + ( + "system", + "You are very powerful assistant, but don't know current events", + ), + ("user", "{input}"), + MessagesPlaceholder(variable_name="agent_scratchpad"), + ] + ) + llm = MockOpenAI( + model_name="gpt-3.5-turbo", + temperature=0, + openai_api_key="badkey", + ) + agent = create_openai_tools_agent(llm, [get_word_length], prompt) - agent_executor = AgentExecutor( - agent=agent, tools=[get_word_length], verbose=True - ) + agent_executor = AgentExecutor(agent=agent, tools=[get_word_length], verbose=True) - with pytest.raises(ValueError): - list( - agent_executor.stream( - {"input": "How many letters in the word eudca"} - ) - ) + with pytest.raises(ValueError): + list(agent_executor.stream({"input": "How many letters in the word eudca"})) - (error, transaction) = events - assert error["level"] == "error" - assert error["exception"]["values"][0]["mechanism"]["type"] == "langchain" - assert not error["exception"]["values"][0]["mechanism"]["handled"] - assert transaction["spans"][0]["status"] == "internal_error" - assert transaction["spans"][0]["tags"]["status"] == "internal_error" + (error,) = (item.payload for item in items if item.type == "event") + assert error["level"] == "error" + assert error["exception"]["values"][0]["mechanism"]["type"] == "langchain" + assert not error["exception"]["values"][0]["mechanism"]["handled"] + sentry_sdk.flush() + spans = [item.payload for item in items if item.type == "span"] + assert spans[0]["status"] == "error" @tool @@ -3795,7 +1848,7 @@ def test_langchain_tool_error( nonstreaming_responses_tool_call_model_responses, ): sentry_init( - integrations=[LangchainIntegration(include_prompts=True)], + integrations=[LangchainIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, ) @@ -3843,7 +1896,7 @@ def test_langchain_tool_error( with patch.object( llm.client._client._client, "send", side_effect=[tool_response] - ), start_transaction(name="tx"), pytest.raises(ValueError): + ), pytest.raises(ValueError): agent.invoke({"messages": [HumanMessage(content="hi")]}) error_events = [event for event in events if event.get("level") == "error"] @@ -3904,9 +1957,7 @@ def _identifying_params(self): ) # Create a manual SentryLangchainCallback - manual_callback = SentryLangchainCallback( - max_span_map_size=100, include_prompts=False - ) + manual_callback = SentryLangchainCallback() # Create RunnableConfig with the manual callback config = RunnableConfig(callbacks=[manual_callback]) @@ -3929,8 +1980,8 @@ def _identifying_params(self): def test_span_map_is_instance_variable(): """Test that each SentryLangchainCallback instance has its own span_map.""" # Create two separate callback instances - callback1 = SentryLangchainCallback(max_span_map_size=100, include_prompts=True) - callback2 = SentryLangchainCallback(max_span_map_size=100, include_prompts=True) + callback1 = SentryLangchainCallback() + callback2 = SentryLangchainCallback() # Verify they have different span_map instances assert callback1.span_map is not callback2.span_map, ( @@ -3977,7 +2028,7 @@ def test_langchain_callback_manager_with_sentry_callback(sentry_init): disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, ) - sentry_callback = SentryLangchainCallback(0, False) + sentry_callback = SentryLangchainCallback() local_manager = BaseCallbackManager(handlers=[sentry_callback]) with mock.patch("sentry_sdk.integrations.langchain.manager") as mock_manager_module: @@ -4043,7 +2094,7 @@ def test_langchain_callback_list_existing_callback(sentry_init): disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, ) - sentry_callback = SentryLangchainCallback(0, False) + sentry_callback = SentryLangchainCallback() local_callbacks = [sentry_callback] with mock.patch("sentry_sdk.integrations.langchain.manager") as mock_manager_module: @@ -4070,14 +2121,9 @@ def test_langchain_callback_list_existing_callback(sentry_init): assert handler is sentry_callback -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_langchain_message_role_mapping( sentry_init, - capture_events, capture_items, - stream_gen_ai_spans, - span_streaming, ): """Test that message roles are properly normalized in langchain integration.""" @@ -4108,12 +2154,10 @@ def _llm_type(self) -> str: return "openai-chat" sentry_init( - integrations=[LangchainIntegration(include_prompts=True)], + integrations=[LangchainIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) prompt = ChatPromptTemplate.from_messages( @@ -4126,1539 +2170,110 @@ def _llm_type(self) -> str: llm = MockOpenAI( model_name="gpt-3.5-turbo", - temperature=0, - openai_api_key="badkey", - ) - agent = create_openai_tools_agent(llm, [get_word_length], prompt) - agent_executor = AgentExecutor(agent=agent, tools=[get_word_length], verbose=True) - - # Test input that should trigger message role normalization - test_input = "Hello, how are you?" - - message_data_found = False - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with start_transaction(): - list(agent_executor.stream({"input": test_input})) - - sentry_sdk.flush() - spans = [item.payload for item in items] - # Find spans with gen_ai operation that should have message data - gen_ai_spans = [ - span - for span in spans - if span["attributes"].get("sentry.op", "").startswith("gen_ai") - ] - - # Check if any span has message data with normalized roles - for span in gen_ai_spans: - span_data = span.get("attributes", {}) - if SPANDATA.GEN_AI_REQUEST_MESSAGES in span_data: - message_data_found = True - messages_data = span_data[SPANDATA.GEN_AI_REQUEST_MESSAGES] - - # Parse the message data (might be JSON string) - if isinstance(messages_data, str): - try: - messages = json.loads(messages_data) - except json.JSONDecodeError: - # If not valid JSON, skip this assertion - continue - else: - messages = messages_data - - # Verify that the input message is present and contains the test input - assert isinstance(messages, list) - assert len(messages) > 0 - - # The test input should be in one of the messages - input_found = False - for msg in messages: - if isinstance(msg, dict) and test_input in str( - msg.get("content", "") - ): - input_found = True - break - elif isinstance(msg, str) and test_input in msg: - input_found = True - break - - assert input_found, ( - f"Test input '{test_input}' not found in messages: {messages}" - ) - break - else: - events = capture_events() - - with start_transaction(): - list(agent_executor.stream({"input": test_input})) - - assert len(events) > 0 - tx = events[0] - assert tx["type"] == "transaction" - - # Find spans with gen_ai operation that should have message data - gen_ai_spans = [ - span - for span in tx.get("spans", []) - if span.get("op", "").startswith("gen_ai") - ] - - # Check if any span has message data with normalized roles - for span in gen_ai_spans: - span_data = span.get("data", {}) - if SPANDATA.GEN_AI_REQUEST_MESSAGES in span_data: - message_data_found = True - messages_data = span_data[SPANDATA.GEN_AI_REQUEST_MESSAGES] - - # Parse the message data (might be JSON string) - if isinstance(messages_data, str): - try: - messages = json.loads(messages_data) - except json.JSONDecodeError: - # If not valid JSON, skip this assertion - continue - else: - messages = messages_data - - # Verify that the input message is present and contains the test input - assert isinstance(messages, list) - assert len(messages) > 0 - - # The test input should be in one of the messages - input_found = False - for msg in messages: - if isinstance(msg, dict) and test_input in str( - msg.get("content", "") - ): - input_found = True - break - elif isinstance(msg, str) and test_input in msg: - input_found = True - break - - assert input_found, ( - f"Test input '{test_input}' not found in messages: {messages}" - ) - break - - # The message role mapping functionality is primarily tested through the normalization - # that happens in the integration code. The fact that we can capture and process - # the messages without errors indicates the role mapping is working correctly. - assert message_data_found, "No span found with gen_ai request messages data" - - -def test_langchain_message_role_normalization_units(): - """Test the message role normalization functions directly.""" - from sentry_sdk.ai.utils import normalize_message_role, normalize_message_roles - - # Test individual role normalization - assert normalize_message_role("ai") == "assistant" - assert normalize_message_role("human") == "user" - assert normalize_message_role("tool_call") == "tool" - assert normalize_message_role("system") == "system" - assert normalize_message_role("user") == "user" - assert normalize_message_role("assistant") == "assistant" - assert normalize_message_role("tool") == "tool" - - # Test unknown role (should remain unchanged) - assert normalize_message_role("unknown_role") == "unknown_role" - - # Test message list normalization - test_messages = [ - {"role": "human", "content": "Hello"}, - {"role": "ai", "content": "Hi there!"}, - {"role": "tool_call", "content": "function_call"}, - {"role": "system", "content": "You are helpful"}, - {"content": "Message without role"}, - "string message", - ] - - normalized = normalize_message_roles(test_messages) - - # Verify the original messages are not modified - assert test_messages[0]["role"] == "human" # Original unchanged - assert test_messages[1]["role"] == "ai" # Original unchanged - - # Verify the normalized messages have correct roles - assert normalized[0]["role"] == "user" # human -> user - assert normalized[1]["role"] == "assistant" # ai -> assistant - assert normalized[2]["role"] == "tool" # tool_call -> tool - assert normalized[3]["role"] == "system" # system unchanged - assert "role" not in normalized[4] # Message without role unchanged - assert normalized[5] == "string message" # String message unchanged - - -def test_langchain_message_truncation(sentry_init, capture_events): - """Test that large messages are truncated properly in Langchain integration.""" - from langchain_core.outputs import Generation, LLMResult - - sentry_init( - integrations=[LangchainIntegration(include_prompts=True)], - disabled_integrations=[StdlibIntegration], - traces_sample_rate=1.0, - send_default_pii=True, - stream_gen_ai_spans=False, - ) - events = capture_events() - - callback = SentryLangchainCallback(max_span_map_size=100, include_prompts=True) - - run_id = "12345678-1234-1234-1234-123456789012" - serialized = {"_type": "openai-chat", "model_name": "gpt-3.5-turbo"} - - large_content = ( - "This is a very long message that will exceed our size limits. " * 1000 - ) - prompts = [ - "small message 1", - large_content, - large_content, - "small message 4", - "small message 5", - ] - - with start_transaction(): - callback.on_llm_start( - serialized=serialized, - prompts=prompts, - run_id=run_id, - name="my_pipeline", - invocation_params={ - "temperature": 0.7, - "max_tokens": 100, - "model": "gpt-3.5-turbo", - }, - ) - - response = LLMResult( - generations=[[Generation(text="The response")]], - llm_output={ - "token_usage": { - "total_tokens": 25, - "prompt_tokens": 10, - "completion_tokens": 15, - } - }, - ) - callback.on_llm_end(response=response, run_id=run_id) - - assert len(events) > 0 - tx = events[0] - assert tx["type"] == "transaction" - - llm_spans = [ - span - for span in tx.get("spans", []) - if span.get("op") == "gen_ai.text_completion" - ] - assert len(llm_spans) > 0 - - llm_span = llm_spans[0] - assert llm_span["data"]["gen_ai.operation.name"] == "text_completion" - assert llm_span["data"][SPANDATA.GEN_AI_FUNCTION_ID] == "my_pipeline" - - assert SPANDATA.GEN_AI_REQUEST_MESSAGES in llm_span["data"] - messages_data = llm_span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - assert isinstance(messages_data, str) - - parsed_messages = json.loads(messages_data) - assert isinstance(parsed_messages, list) - assert len(parsed_messages) == 1 - assert "small message 5" in str(parsed_messages[0]) - assert tx["_meta"]["spans"]["0"]["data"]["gen_ai.request.messages"][""]["len"] == 5 - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) -@pytest.mark.parametrize( - "send_default_pii, include_prompts", - [ - (True, True), - (True, False), - (False, True), - (False, False), - ], -) -def test_langchain_embeddings_sync( - sentry_init, - capture_events, - capture_items, - send_default_pii, - include_prompts, - stream_gen_ai_spans, - span_streaming, -): - """Test that sync embedding methods (embed_documents, embed_query) are properly traced.""" - try: - from langchain_openai import OpenAIEmbeddings - except ImportError: - pytest.skip("langchain_openai not installed") - - sentry_init( - integrations=[LangchainIntegration(include_prompts=include_prompts)], - disabled_integrations=[StdlibIntegration], - traces_sample_rate=1.0, - send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", - ) - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - # Mock the actual API call - with mock.patch.object( - OpenAIEmbeddings, - "embed_documents", - wraps=lambda self, texts: [[0.1, 0.2, 0.3] for _ in texts], - ) as mock_embed_documents: - embeddings = OpenAIEmbeddings( - model="text-embedding-ada-002", openai_api_key="test-key" - ) - - # Force setup to re-run to ensure our mock is wrapped - LangchainIntegration.setup_once() - - with start_transaction(name="test_embeddings"): - # Test embed_documents - result = embeddings.embed_documents(["Hello world", "Test document"]) - - assert len(result) == 2 - mock_embed_documents.assert_called_once() - - sentry_sdk.flush() - spans = [item.payload for item in items] - # Find embeddings span - embeddings_spans = [ - span - for span in spans - if span["attributes"].get("sentry.op") == "gen_ai.embeddings" - ] - assert len(embeddings_spans) == 1 - - embeddings_span = embeddings_spans[0] - assert embeddings_span["name"] == "embeddings text-embedding-ada-002" - assert embeddings_span["attributes"]["sentry.origin"] == "auto.ai.langchain" - assert embeddings_span["attributes"]["gen_ai.operation.name"] == "embeddings" - assert ( - embeddings_span["attributes"]["gen_ai.request.model"] - == "text-embedding-ada-002" - ) - - # Check if input is captured based on PII settings - if send_default_pii and include_prompts: - assert SPANDATA.GEN_AI_EMBEDDINGS_INPUT in embeddings_span["attributes"] - input_data = embeddings_span["attributes"][SPANDATA.GEN_AI_EMBEDDINGS_INPUT] - - # Could be serialized as string - if isinstance(input_data, str): - assert "Hello world" in input_data - assert "Test document" in input_data - else: - assert "Hello world" in input_data - assert "Test document" in input_data - else: - assert SPANDATA.GEN_AI_EMBEDDINGS_INPUT not in embeddings_span.get( - "attributes", {} - ) - else: - events = capture_events() - - # Mock the actual API call - with mock.patch.object( - OpenAIEmbeddings, - "embed_documents", - wraps=lambda self, texts: [[0.1, 0.2, 0.3] for _ in texts], - ) as mock_embed_documents: - embeddings = OpenAIEmbeddings( - model="text-embedding-ada-002", openai_api_key="test-key" - ) - - # Force setup to re-run to ensure our mock is wrapped - LangchainIntegration.setup_once() - - with start_transaction(name="test_embeddings"): - # Test embed_documents - result = embeddings.embed_documents(["Hello world", "Test document"]) - - assert len(result) == 2 - mock_embed_documents.assert_called_once() - - # Check captured events - assert len(events) >= 1 - tx = events[0] - assert tx["type"] == "transaction" - - # Find embeddings span - embeddings_spans = [ - span - for span in tx.get("spans", []) - if span.get("op") == "gen_ai.embeddings" - ] - assert len(embeddings_spans) == 1 - - embeddings_span = embeddings_spans[0] - assert embeddings_span["description"] == "embeddings text-embedding-ada-002" - assert embeddings_span["origin"] == "auto.ai.langchain" - assert embeddings_span["data"]["gen_ai.operation.name"] == "embeddings" - assert ( - embeddings_span["data"]["gen_ai.request.model"] == "text-embedding-ada-002" - ) - - # Check if input is captured based on PII settings - if send_default_pii and include_prompts: - assert SPANDATA.GEN_AI_EMBEDDINGS_INPUT in embeddings_span["data"] - input_data = embeddings_span["data"][SPANDATA.GEN_AI_EMBEDDINGS_INPUT] - # Could be serialized as string - if isinstance(input_data, str): - assert "Hello world" in input_data - assert "Test document" in input_data - else: - assert "Hello world" in input_data - assert "Test document" in input_data - else: - assert SPANDATA.GEN_AI_EMBEDDINGS_INPUT not in embeddings_span.get( - "data", {} - ) - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) -@pytest.mark.parametrize( - "send_default_pii, include_prompts", - [ - (True, True), - (False, False), - ], -) -def test_langchain_embeddings_embed_query( - sentry_init, - capture_events, - capture_items, - send_default_pii, - include_prompts, - stream_gen_ai_spans, - span_streaming, -): - """Test that embed_query method is properly traced.""" - try: - from langchain_openai import OpenAIEmbeddings - except ImportError: - pytest.skip("langchain_openai not installed") - - sentry_init( - integrations=[LangchainIntegration(include_prompts=include_prompts)], - disabled_integrations=[StdlibIntegration], - traces_sample_rate=1.0, - send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", - ) - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - # Mock the actual API call - with mock.patch.object( - OpenAIEmbeddings, - "embed_query", - wraps=lambda self, text: [0.1, 0.2, 0.3], - ) as mock_embed_query: - embeddings = OpenAIEmbeddings( - model="text-embedding-ada-002", openai_api_key="test-key" - ) - - # Force setup to re-run to ensure our mock is wrapped - LangchainIntegration.setup_once() - - with start_transaction(name="test_embeddings_query"): - result = embeddings.embed_query("What is the capital of France?") - - assert len(result) == 3 - mock_embed_query.assert_called_once() - - sentry_sdk.flush() - spans = [item.payload for item in items] - # Find embeddings span - embeddings_spans = [ - span - for span in spans - if span["attributes"].get("sentry.op") == "gen_ai.embeddings" - ] - assert len(embeddings_spans) == 1 - - embeddings_span = embeddings_spans[0] - assert embeddings_span["attributes"]["gen_ai.operation.name"] == "embeddings" - assert ( - embeddings_span["attributes"]["gen_ai.request.model"] - == "text-embedding-ada-002" - ) - - # Check if input is captured based on PII settings - if send_default_pii and include_prompts: - assert SPANDATA.GEN_AI_EMBEDDINGS_INPUT in embeddings_span["attributes"] - input_data = embeddings_span["attributes"][SPANDATA.GEN_AI_EMBEDDINGS_INPUT] - - # Could be serialized as string - if isinstance(input_data, str): - assert "What is the capital of France?" in input_data - else: - assert "What is the capital of France?" in input_data - else: - assert SPANDATA.GEN_AI_EMBEDDINGS_INPUT not in embeddings_span.get( - "attributes", {} - ) - else: - events = capture_events() - - # Mock the actual API call - with mock.patch.object( - OpenAIEmbeddings, - "embed_query", - wraps=lambda self, text: [0.1, 0.2, 0.3], - ) as mock_embed_query: - embeddings = OpenAIEmbeddings( - model="text-embedding-ada-002", openai_api_key="test-key" - ) - - # Force setup to re-run to ensure our mock is wrapped - LangchainIntegration.setup_once() - - with start_transaction(name="test_embeddings_query"): - result = embeddings.embed_query("What is the capital of France?") - - assert len(result) == 3 - mock_embed_query.assert_called_once() - - # Check captured events - assert len(events) >= 1 - tx = events[0] - assert tx["type"] == "transaction" - - # Find embeddings span - embeddings_spans = [ - span - for span in tx.get("spans", []) - if span.get("op") == "gen_ai.embeddings" - ] - assert len(embeddings_spans) == 1 - - embeddings_span = embeddings_spans[0] - assert embeddings_span["data"]["gen_ai.operation.name"] == "embeddings" - assert ( - embeddings_span["data"]["gen_ai.request.model"] == "text-embedding-ada-002" - ) - - # Check if input is captured based on PII settings - if send_default_pii and include_prompts: - assert SPANDATA.GEN_AI_EMBEDDINGS_INPUT in embeddings_span["data"] - input_data = embeddings_span["data"][SPANDATA.GEN_AI_EMBEDDINGS_INPUT] - # Could be serialized as string - if isinstance(input_data, str): - assert "What is the capital of France?" in input_data - else: - assert "What is the capital of France?" in input_data - else: - assert SPANDATA.GEN_AI_EMBEDDINGS_INPUT not in embeddings_span.get( - "data", {} - ) - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) -@pytest.mark.parametrize( - "send_default_pii, include_prompts", - [ - (True, True), - (False, False), - ], -) -@pytest.mark.asyncio -async def test_langchain_embeddings_async( - sentry_init, - capture_events, - capture_items, - send_default_pii, - include_prompts, - stream_gen_ai_spans, - span_streaming, -): - """Test that async embedding methods (aembed_documents, aembed_query) are properly traced.""" - try: - from langchain_openai import OpenAIEmbeddings - except ImportError: - pytest.skip("langchain_openai not installed") - - sentry_init( - integrations=[LangchainIntegration(include_prompts=include_prompts)], - disabled_integrations=[StdlibIntegration], - traces_sample_rate=1.0, - send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", - ) - - async def mock_aembed_documents(self, texts): - return [[0.1, 0.2, 0.3] for _ in texts] - - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - # Mock the actual API call - with mock.patch.object( - OpenAIEmbeddings, - "aembed_documents", - wraps=mock_aembed_documents, - ) as mock_aembed: - embeddings = OpenAIEmbeddings( - model="text-embedding-ada-002", openai_api_key="test-key" - ) - - # Force setup to re-run to ensure our mock is wrapped - LangchainIntegration.setup_once() - - with start_transaction(name="test_async_embeddings"): - result = await embeddings.aembed_documents( - ["Async hello", "Async test document"] - ) - - assert len(result) == 2 - mock_aembed.assert_called_once() - - sentry_sdk.flush() - spans = [item.payload for item in items] - # Find embeddings span - embeddings_spans = [ - span - for span in spans - if span["attributes"].get("sentry.op") == "gen_ai.embeddings" - ] - assert len(embeddings_spans) == 1 - - embeddings_span = embeddings_spans[0] - assert embeddings_span["name"] == "embeddings text-embedding-ada-002" - assert embeddings_span["attributes"]["sentry.origin"] == "auto.ai.langchain" - assert embeddings_span["attributes"]["gen_ai.operation.name"] == "embeddings" - assert ( - embeddings_span["attributes"]["gen_ai.request.model"] - == "text-embedding-ada-002" - ) - - # Check if input is captured based on PII settings - if send_default_pii and include_prompts: - assert SPANDATA.GEN_AI_EMBEDDINGS_INPUT in embeddings_span["attributes"] - input_data = embeddings_span["attributes"][SPANDATA.GEN_AI_EMBEDDINGS_INPUT] - - # Could be serialized as string - if isinstance(input_data, str): - assert ( - "Async hello" in input_data or "Async test document" in input_data - ) - else: - assert ( - "Async hello" in input_data or "Async test document" in input_data - ) - else: - assert SPANDATA.GEN_AI_EMBEDDINGS_INPUT not in embeddings_span.get( - "attributes", {} - ) - - else: - events = capture_events() - - # Mock the actual API call - with mock.patch.object( - OpenAIEmbeddings, - "aembed_documents", - wraps=mock_aembed_documents, - ) as mock_aembed: - embeddings = OpenAIEmbeddings( - model="text-embedding-ada-002", openai_api_key="test-key" - ) - - # Force setup to re-run to ensure our mock is wrapped - LangchainIntegration.setup_once() - - with start_transaction(name="test_async_embeddings"): - result = await embeddings.aembed_documents( - ["Async hello", "Async test document"] - ) - - assert len(result) == 2 - mock_aembed.assert_called_once() - - # Check captured events - assert len(events) >= 1 - tx = events[0] - assert tx["type"] == "transaction" - - # Find embeddings span - embeddings_spans = [ - span - for span in tx.get("spans", []) - if span.get("op") == "gen_ai.embeddings" - ] - assert len(embeddings_spans) == 1 - - embeddings_span = embeddings_spans[0] - assert embeddings_span["description"] == "embeddings text-embedding-ada-002" - assert embeddings_span["origin"] == "auto.ai.langchain" - assert embeddings_span["data"]["gen_ai.operation.name"] == "embeddings" - assert ( - embeddings_span["data"]["gen_ai.request.model"] == "text-embedding-ada-002" - ) - - # Check if input is captured based on PII settings - if send_default_pii and include_prompts: - assert SPANDATA.GEN_AI_EMBEDDINGS_INPUT in embeddings_span["data"] - input_data = embeddings_span["data"][SPANDATA.GEN_AI_EMBEDDINGS_INPUT] - # Could be serialized as string - if isinstance(input_data, str): - assert ( - "Async hello" in input_data or "Async test document" in input_data - ) - else: - assert ( - "Async hello" in input_data or "Async test document" in input_data - ) - else: - assert SPANDATA.GEN_AI_EMBEDDINGS_INPUT not in embeddings_span.get( - "data", {} - ) - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) -@pytest.mark.asyncio -async def test_langchain_embeddings_aembed_query( - sentry_init, - capture_events, - capture_items, - stream_gen_ai_spans, - span_streaming, -): - """Test that aembed_query method is properly traced.""" - try: - from langchain_openai import OpenAIEmbeddings - except ImportError: - pytest.skip("langchain_openai not installed") - - sentry_init( - integrations=[LangchainIntegration(include_prompts=True)], - disabled_integrations=[StdlibIntegration], - traces_sample_rate=1.0, - send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", - ) - - async def mock_aembed_query(self, text): - return [0.1, 0.2, 0.3] - - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - # Mock the actual API call - with mock.patch.object( - OpenAIEmbeddings, - "aembed_query", - wraps=mock_aembed_query, - ) as mock_aembed: - embeddings = OpenAIEmbeddings( - model="text-embedding-ada-002", openai_api_key="test-key" - ) - - # Force setup to re-run to ensure our mock is wrapped - LangchainIntegration.setup_once() - - with start_transaction(name="test_async_embeddings_query"): - result = await embeddings.aembed_query("Async query test") - - assert len(result) == 3 - mock_aembed.assert_called_once() - - sentry_sdk.flush() - spans = [item.payload for item in items] - # Find embeddings span - embeddings_spans = [ - span - for span in spans - if span["attributes"].get("sentry.op") == "gen_ai.embeddings" - ] - assert len(embeddings_spans) == 1 - - embeddings_span = embeddings_spans[0] - assert embeddings_span["attributes"]["gen_ai.operation.name"] == "embeddings" - assert ( - embeddings_span["attributes"]["gen_ai.request.model"] - == "text-embedding-ada-002" - ) - - # Check if input is captured - assert SPANDATA.GEN_AI_EMBEDDINGS_INPUT in embeddings_span["attributes"] - input_data = embeddings_span["attributes"][SPANDATA.GEN_AI_EMBEDDINGS_INPUT] - else: - events = capture_events() - - # Mock the actual API call - with mock.patch.object( - OpenAIEmbeddings, - "aembed_query", - wraps=mock_aembed_query, - ) as mock_aembed: - embeddings = OpenAIEmbeddings( - model="text-embedding-ada-002", openai_api_key="test-key" - ) - - # Force setup to re-run to ensure our mock is wrapped - LangchainIntegration.setup_once() - - with start_transaction(name="test_async_embeddings_query"): - result = await embeddings.aembed_query("Async query test") - - assert len(result) == 3 - mock_aembed.assert_called_once() - - # Check captured events - assert len(events) >= 1 - tx = events[0] - assert tx["type"] == "transaction" - - # Find embeddings span - embeddings_spans = [ - span - for span in tx.get("spans", []) - if span.get("op") == "gen_ai.embeddings" - ] - assert len(embeddings_spans) == 1 - - embeddings_span = embeddings_spans[0] - assert embeddings_span["data"]["gen_ai.operation.name"] == "embeddings" - assert ( - embeddings_span["data"]["gen_ai.request.model"] == "text-embedding-ada-002" - ) - - # Check if input is captured - assert SPANDATA.GEN_AI_EMBEDDINGS_INPUT in embeddings_span["data"] - input_data = embeddings_span["data"][SPANDATA.GEN_AI_EMBEDDINGS_INPUT] - - # Could be serialized as string - if isinstance(input_data, str): - assert "Async query test" in input_data - else: - assert "Async query test" in input_data - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) -def test_langchain_embeddings_no_model_name( - sentry_init, - capture_events, - capture_items, - stream_gen_ai_spans, - span_streaming, -): - """Test embeddings when model name is not available.""" - try: - from langchain_openai import OpenAIEmbeddings - except ImportError: - pytest.skip("langchain_openai not installed") - - sentry_init( - integrations=[LangchainIntegration(include_prompts=False)], - disabled_integrations=[StdlibIntegration], - traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", - ) - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - # Mock the actual API call and remove model attribute - with mock.patch.object( - OpenAIEmbeddings, - "embed_documents", - wraps=lambda self, texts: [[0.1, 0.2, 0.3] for _ in texts], - ): - embeddings = OpenAIEmbeddings(openai_api_key="test-key") - # Remove model attribute to test fallback - delattr(embeddings, "model") - if hasattr(embeddings, "model_name"): - delattr(embeddings, "model_name") - - # Force setup to re-run to ensure our mock is wrapped - LangchainIntegration.setup_once() - - with start_transaction(name="test_embeddings_no_model"): - embeddings.embed_documents(["Test"]) - - sentry_sdk.flush() - spans = [item.payload for item in items] - # Find embeddings span - embeddings_spans = [ - span - for span in spans - if span["attributes"].get("sentry.op") == "gen_ai.embeddings" - ] - assert len(embeddings_spans) == 1 - - embeddings_span = embeddings_spans[0] - assert embeddings_span["name"] == "embeddings" - assert embeddings_span["attributes"]["gen_ai.operation.name"] == "embeddings" - # Model name should not be set if not available - assert ( - "gen_ai.request.model" not in embeddings_span["attributes"] - or embeddings_span["attributes"]["gen_ai.request.model"] is None - ) - else: - events = capture_events() - - # Mock the actual API call and remove model attribute - with mock.patch.object( - OpenAIEmbeddings, - "embed_documents", - wraps=lambda self, texts: [[0.1, 0.2, 0.3] for _ in texts], - ): - embeddings = OpenAIEmbeddings(openai_api_key="test-key") - # Remove model attribute to test fallback - delattr(embeddings, "model") - if hasattr(embeddings, "model_name"): - delattr(embeddings, "model_name") - - # Force setup to re-run to ensure our mock is wrapped - LangchainIntegration.setup_once() - - with start_transaction(name="test_embeddings_no_model"): - embeddings.embed_documents(["Test"]) - - # Check captured events - assert len(events) >= 1 - tx = events[0] - assert tx["type"] == "transaction" - - # Find embeddings span - embeddings_spans = [ - span - for span in tx.get("spans", []) - if span.get("op") == "gen_ai.embeddings" - ] - assert len(embeddings_spans) == 1 - - embeddings_span = embeddings_spans[0] - assert embeddings_span["description"] == "embeddings" - assert embeddings_span["data"]["gen_ai.operation.name"] == "embeddings" - # Model name should not be set if not available - assert ( - "gen_ai.request.model" not in embeddings_span["data"] - or embeddings_span["data"]["gen_ai.request.model"] is None - ) - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) -def test_langchain_embeddings_integration_disabled( - sentry_init, - capture_events, - capture_items, - stream_gen_ai_spans, - span_streaming, -): - """Test that embeddings are not traced when integration is disabled.""" - try: - from langchain_openai import OpenAIEmbeddings - except ImportError: - pytest.skip("langchain_openai not installed") - - sentry_init( - disabled_integrations=[StdlibIntegration], - traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", - ) - - # Initialize without LangchainIntegration - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with mock.patch.object( - OpenAIEmbeddings, - "embed_documents", - return_value=[[0.1, 0.2, 0.3]], - ): - embeddings = OpenAIEmbeddings( - model="text-embedding-ada-002", openai_api_key="test-key" - ) - - with start_transaction(name="test_embeddings_disabled"): - embeddings.embed_documents(["Test"]) - - # Check that no embeddings spans were created - sentry_sdk.flush() - spans = [item.payload for item in items] - embeddings_spans = [ - span - for span in spans - if span["attributes"].get("sentry.op") == "gen_ai.embeddings" - ] - # Should be empty since integration is disabled - assert len(embeddings_spans) == 0 - else: - events = capture_events() - - with mock.patch.object( - OpenAIEmbeddings, - "embed_documents", - return_value=[[0.1, 0.2, 0.3]], - ): - embeddings = OpenAIEmbeddings( - model="text-embedding-ada-002", openai_api_key="test-key" - ) - - with start_transaction(name="test_embeddings_disabled"): - embeddings.embed_documents(["Test"]) - - # Check that no embeddings spans were created - if events: - tx = events[0] - embeddings_spans = [ - span - for span in tx.get("spans", []) - if span.get("op") == "gen_ai.embeddings" - ] - # Should be empty since integration is disabled - assert len(embeddings_spans) == 0 - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) -def test_langchain_embeddings_multiple_providers( - sentry_init, - capture_events, - capture_items, - stream_gen_ai_spans, - span_streaming, -): - """Test that embeddings work with different providers.""" - try: - from langchain_openai import AzureOpenAIEmbeddings, OpenAIEmbeddings - except ImportError: - pytest.skip("langchain_openai not installed") - - sentry_init( - integrations=[LangchainIntegration(include_prompts=True)], - disabled_integrations=[StdlibIntegration], - traces_sample_rate=1.0, - send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", - ) - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - # Mock both providers - with mock.patch.object( - OpenAIEmbeddings, - "embed_documents", - wraps=lambda self, texts: [[0.1, 0.2, 0.3] for _ in texts], - ), mock.patch.object( - AzureOpenAIEmbeddings, - "embed_documents", - wraps=lambda self, texts: [[0.4, 0.5, 0.6] for _ in texts], - ): - openai_embeddings = OpenAIEmbeddings( - model="text-embedding-ada-002", openai_api_key="test-key" - ) - azure_embeddings = AzureOpenAIEmbeddings( - model="text-embedding-ada-002", - azure_endpoint="https://test.openai.azure.com/", - openai_api_key="test-key", - ) - - # Force setup to re-run - LangchainIntegration.setup_once() - - with start_transaction(name="test_multiple_providers"): - openai_embeddings.embed_documents(["OpenAI test"]) - azure_embeddings.embed_documents(["Azure test"]) - - sentry_sdk.flush() - spans = [item.payload for item in items] - # Find embeddings spans - embeddings_spans = [ - span - for span in spans - if span["attributes"].get("sentry.op") == "gen_ai.embeddings" - ] - # Should have 2 spans, one for each provider - assert len(embeddings_spans) == 2 - - # Verify both spans have proper data - for span in embeddings_spans: - assert span["attributes"]["gen_ai.operation.name"] == "embeddings" - assert ( - span["attributes"]["gen_ai.request.model"] == "text-embedding-ada-002" - ) - assert SPANDATA.GEN_AI_EMBEDDINGS_INPUT in span["attributes"] - else: - events = capture_events() - - # Mock both providers - with mock.patch.object( - OpenAIEmbeddings, - "embed_documents", - wraps=lambda self, texts: [[0.1, 0.2, 0.3] for _ in texts], - ), mock.patch.object( - AzureOpenAIEmbeddings, - "embed_documents", - wraps=lambda self, texts: [[0.4, 0.5, 0.6] for _ in texts], - ): - openai_embeddings = OpenAIEmbeddings( - model="text-embedding-ada-002", openai_api_key="test-key" - ) - azure_embeddings = AzureOpenAIEmbeddings( - model="text-embedding-ada-002", - azure_endpoint="https://test.openai.azure.com/", - openai_api_key="test-key", - ) - - # Force setup to re-run - LangchainIntegration.setup_once() - - with start_transaction(name="test_multiple_providers"): - openai_embeddings.embed_documents(["OpenAI test"]) - azure_embeddings.embed_documents(["Azure test"]) - - # Check captured events - assert len(events) >= 1 - tx = events[0] - assert tx["type"] == "transaction" - - # Find embeddings spans - embeddings_spans = [ - span - for span in tx.get("spans", []) - if span.get("op") == "gen_ai.embeddings" - ] - # Should have 2 spans, one for each provider - assert len(embeddings_spans) == 2 - - # Verify both spans have proper data - for span in embeddings_spans: - assert span["data"]["gen_ai.operation.name"] == "embeddings" - assert span["data"]["gen_ai.request.model"] == "text-embedding-ada-002" - assert SPANDATA.GEN_AI_EMBEDDINGS_INPUT in span["data"] - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) -def test_langchain_embeddings_multiple_calls( - sentry_init, - capture_events, - capture_items, - stream_gen_ai_spans, - span_streaming, -): - """Test that multiple embeddings calls within a transaction are all traced.""" - try: - from langchain_openai import OpenAIEmbeddings - except ImportError: - pytest.skip("langchain_openai not installed") - - sentry_init( - integrations=[LangchainIntegration(include_prompts=True)], - disabled_integrations=[StdlibIntegration], - traces_sample_rate=1.0, - send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", - ) - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - # Mock the actual API calls - with mock.patch.object( - OpenAIEmbeddings, - "embed_documents", - wraps=lambda self, texts: [[0.1, 0.2, 0.3] for _ in texts], - ), mock.patch.object( - OpenAIEmbeddings, - "embed_query", - wraps=lambda self, text: [0.4, 0.5, 0.6], - ): - embeddings = OpenAIEmbeddings( - model="text-embedding-ada-002", openai_api_key="test-key" - ) - - # Force setup to re-run - LangchainIntegration.setup_once() - - with start_transaction(name="test_multiple_embeddings"): - # Call embed_documents - embeddings.embed_documents(["First batch", "Second batch"]) - # Call embed_query - embeddings.embed_query("Single query") - # Call embed_documents again - embeddings.embed_documents(["Third batch"]) - - sentry_sdk.flush() - spans = [item.payload for item in items] - # Find embeddings spans - should have 3 (2 embed_documents + 1 embed_query) - embeddings_spans = [ - span - for span in spans - if span["attributes"].get("sentry.op") == "gen_ai.embeddings" - ] - assert len(embeddings_spans) == 3 - - # Verify all spans have proper data - for span in embeddings_spans: - assert span["attributes"]["gen_ai.operation.name"] == "embeddings" - assert ( - span["attributes"]["gen_ai.request.model"] == "text-embedding-ada-002" - ) - assert SPANDATA.GEN_AI_EMBEDDINGS_INPUT in span["attributes"] - - # Verify the input data is different for each span - input_data_list = [ - span["attributes"][SPANDATA.GEN_AI_EMBEDDINGS_INPUT] - for span in embeddings_spans - ] - else: - events = capture_events() - - # Mock the actual API calls - with mock.patch.object( - OpenAIEmbeddings, - "embed_documents", - wraps=lambda self, texts: [[0.1, 0.2, 0.3] for _ in texts], - ), mock.patch.object( - OpenAIEmbeddings, - "embed_query", - wraps=lambda self, text: [0.4, 0.5, 0.6], - ): - embeddings = OpenAIEmbeddings( - model="text-embedding-ada-002", openai_api_key="test-key" - ) - - # Force setup to re-run - LangchainIntegration.setup_once() - - with start_transaction(name="test_multiple_embeddings"): - # Call embed_documents - embeddings.embed_documents(["First batch", "Second batch"]) - # Call embed_query - embeddings.embed_query("Single query") - # Call embed_documents again - embeddings.embed_documents(["Third batch"]) - - # Check captured events - assert len(events) >= 1 - tx = events[0] - assert tx["type"] == "transaction" - - # Find embeddings spans - should have 3 (2 embed_documents + 1 embed_query) - embeddings_spans = [ - span - for span in tx.get("spans", []) - if span.get("op") == "gen_ai.embeddings" - ] - assert len(embeddings_spans) == 3 - - # Verify all spans have proper data - for span in embeddings_spans: - assert span["data"]["gen_ai.operation.name"] == "embeddings" - assert span["data"]["gen_ai.request.model"] == "text-embedding-ada-002" - assert SPANDATA.GEN_AI_EMBEDDINGS_INPUT in span["data"] - - # Verify the input data is different for each span - input_data_list = [ - span["data"][SPANDATA.GEN_AI_EMBEDDINGS_INPUT] for span in embeddings_spans - ] - # They should all be different (different inputs) - assert len(set(str(data) for data in input_data_list)) == 3 - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) -def test_langchain_embeddings_span_hierarchy( - sentry_init, - capture_events, - capture_items, - stream_gen_ai_spans, - span_streaming, -): - """Test that embeddings spans are properly nested within parent spans.""" - try: - from langchain_openai import OpenAIEmbeddings - except ImportError: - pytest.skip("langchain_openai not installed") - - sentry_init( - integrations=[LangchainIntegration(include_prompts=True)], - disabled_integrations=[StdlibIntegration], - traces_sample_rate=1.0, - send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", - ) - if span_streaming: - items = capture_items("span") - - # Mock the actual API call - with mock.patch.object( - OpenAIEmbeddings, - "embed_documents", - wraps=lambda self, texts: [[0.1, 0.2, 0.3] for _ in texts], - ): - embeddings = OpenAIEmbeddings( - model="text-embedding-ada-002", openai_api_key="test-key" - ) - - # Force setup to re-run - LangchainIntegration.setup_once() - - with sentry_sdk.traces.start_span( - name="test_span_hierarchy" - ), sentry_sdk.traces.start_span( - name="custom operation", - attributes={ - "sentry.op": "custom", - }, - ): - embeddings.embed_documents(["Test within custom span"]) - - sentry_sdk.flush() - spans = [item.payload for item in items] - # Find all spans - embeddings_spans = [ - span - for span in spans - if span["attributes"].get("sentry.op") == "gen_ai.embeddings" - ] - custom_spans = [ - span for span in spans if span["attributes"].get("sentry.op") == "custom" - ] - - assert len(embeddings_spans) == 1 - assert len(custom_spans) == 1 - - # Both spans should exist - embeddings_span = embeddings_spans[0] - custom_span = custom_spans[0] - - assert embeddings_span["attributes"]["gen_ai.operation.name"] == "embeddings" - assert custom_span["name"] == "custom operation" - elif stream_gen_ai_spans: - items = capture_items("transaction", "span") - - # Mock the actual API call - with mock.patch.object( - OpenAIEmbeddings, - "embed_documents", - wraps=lambda self, texts: [[0.1, 0.2, 0.3] for _ in texts], - ): - embeddings = OpenAIEmbeddings( - model="text-embedding-ada-002", openai_api_key="test-key" - ) - - # Force setup to re-run - LangchainIntegration.setup_once() - - with start_transaction(name="test_span_hierarchy"), sentry_sdk.start_span( - op="custom", name="custom operation" - ): - embeddings.embed_documents(["Test within custom span"]) - - spans = [item.payload for item in items if item.type == "span"] - # Find all spans - embeddings_spans = [ - span - for span in spans - if span["attributes"].get("sentry.op") == "gen_ai.embeddings" - ] - tx = next(item.payload for item in items if item.type == "transaction") - custom_spans = [ - span for span in tx.get("spans", []) if span.get("op") == "custom" - ] - - assert len(embeddings_spans) == 1 - assert len(custom_spans) == 1 - - # Both spans should exist - embeddings_span = embeddings_spans[0] - custom_span = custom_spans[0] + temperature=0, + openai_api_key="badkey", + ) + agent = create_openai_tools_agent(llm, [get_word_length], prompt) + agent_executor = AgentExecutor(agent=agent, tools=[get_word_length], verbose=True) - assert embeddings_span["attributes"]["gen_ai.operation.name"] == "embeddings" - assert custom_span["description"] == "custom operation" - else: - events = capture_events() + # Test input that should trigger message role normalization + test_input = "Hello, how are you?" - # Mock the actual API call - with mock.patch.object( - OpenAIEmbeddings, - "embed_documents", - wraps=lambda self, texts: [[0.1, 0.2, 0.3] for _ in texts], - ): - embeddings = OpenAIEmbeddings( - model="text-embedding-ada-002", openai_api_key="test-key" - ) + message_data_found = False + items = capture_items("span") - # Force setup to re-run - LangchainIntegration.setup_once() + list(agent_executor.stream({"input": test_input})) - with start_transaction(name="test_span_hierarchy"), sentry_sdk.start_span( - op="custom", name="custom operation" - ): - embeddings.embed_documents(["Test within custom span"]) + sentry_sdk.flush() + spans = [item.payload for item in items] + # Find spans with gen_ai operation that should have message data + gen_ai_spans = [ + span + for span in spans + if span["attributes"].get("sentry.op", "").startswith("gen_ai") + ] - # Check captured events - assert len(events) >= 1 - tx = events[0] - assert tx["type"] == "transaction" + # Check if any span has message data with normalized roles + for span in gen_ai_spans: + span_data = span.get("attributes", {}) + if SPANDATA.GEN_AI_REQUEST_MESSAGES in span_data: + message_data_found = True + messages_data = span_data[SPANDATA.GEN_AI_REQUEST_MESSAGES] + + # Parse the message data (might be JSON string) + if isinstance(messages_data, str): + try: + messages = json.loads(messages_data) + except json.JSONDecodeError: + # If not valid JSON, skip this assertion + continue + else: + messages = messages_data - # Find all spans - embeddings_spans = [ - span - for span in tx.get("spans", []) - if span.get("op") == "gen_ai.embeddings" - ] - custom_spans = [ - span for span in tx.get("spans", []) if span.get("op") == "custom" - ] + # Verify that the input message is present and contains the test input + assert isinstance(messages, list) + assert len(messages) > 0 - assert len(embeddings_spans) == 1 - assert len(custom_spans) == 1 + # The test input should be in one of the messages + input_found = False + for msg in messages: + if isinstance(msg, dict) and test_input in str(msg.get("content", "")): + input_found = True + break + elif isinstance(msg, str) and test_input in msg: + input_found = True + break - # Both spans should exist - embeddings_span = embeddings_spans[0] - custom_span = custom_spans[0] + assert input_found, ( + f"Test input '{test_input}' not found in messages: {messages}" + ) + break - assert embeddings_span["data"]["gen_ai.operation.name"] == "embeddings" - assert custom_span["description"] == "custom operation" + # The message role mapping functionality is primarily tested through the normalization + # that happens in the integration code. The fact that we can capture and process + # the messages without errors indicates the role mapping is working correctly. + assert message_data_found, "No span found with gen_ai request messages data" -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) -def test_langchain_embeddings_with_list_and_string_inputs( - sentry_init, - capture_events, - capture_items, - stream_gen_ai_spans, - span_streaming, -): - """Test that embeddings correctly handle both list and string inputs.""" - try: - from langchain_openai import OpenAIEmbeddings - except ImportError: - pytest.skip("langchain_openai not installed") +def test_langchain_message_role_normalization_units(): + """Test the message role normalization functions directly.""" + from sentry_sdk.ai.utils import normalize_message_role, normalize_message_roles - sentry_init( - integrations=[LangchainIntegration(include_prompts=True)], - disabled_integrations=[StdlibIntegration], - traces_sample_rate=1.0, - send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", - ) - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - # Mock the actual API calls - with mock.patch.object( - OpenAIEmbeddings, - "embed_documents", - wraps=lambda self, texts: [[0.1, 0.2, 0.3] for _ in texts], - ), mock.patch.object( - OpenAIEmbeddings, - "embed_query", - wraps=lambda self, text: [0.4, 0.5, 0.6], - ): - embeddings = OpenAIEmbeddings( - model="text-embedding-ada-002", openai_api_key="test-key" - ) + # Test individual role normalization + assert normalize_message_role("ai") == "assistant" + assert normalize_message_role("human") == "user" + assert normalize_message_role("tool_call") == "tool" + assert normalize_message_role("system") == "system" + assert normalize_message_role("user") == "user" + assert normalize_message_role("assistant") == "assistant" + assert normalize_message_role("tool") == "tool" - # Force setup to re-run - LangchainIntegration.setup_once() + # Test unknown role (should remain unchanged) + assert normalize_message_role("unknown_role") == "unknown_role" - with start_transaction(name="test_input_types"): - # embed_documents takes a list - embeddings.embed_documents( - ["List item 1", "List item 2", "List item 3"] - ) - # embed_query takes a string - embeddings.embed_query("Single string query") - - sentry_sdk.flush() - spans = [item.payload for item in items] - # Find embeddings spans - embeddings_spans = [ - span - for span in spans - if span["attributes"].get("sentry.op") == "gen_ai.embeddings" - ] - assert len(embeddings_spans) == 2 - - # Both should have input data captured as lists - for span in embeddings_spans: - assert SPANDATA.GEN_AI_EMBEDDINGS_INPUT in span["attributes"] - input_data = span["attributes"][SPANDATA.GEN_AI_EMBEDDINGS_INPUT] - # Input should be normalized to list format - if isinstance(input_data, str): - # If serialized, should contain the input text - assert ( - "List item" in input_data or "Single string query" in input_data - ), f"Expected input text in serialized data: {input_data}" - else: - events = capture_events() - - # Mock the actual API calls - with mock.patch.object( - OpenAIEmbeddings, - "embed_documents", - wraps=lambda self, texts: [[0.1, 0.2, 0.3] for _ in texts], - ), mock.patch.object( - OpenAIEmbeddings, - "embed_query", - wraps=lambda self, text: [0.4, 0.5, 0.6], - ): - embeddings = OpenAIEmbeddings( - model="text-embedding-ada-002", openai_api_key="test-key" - ) + # Test message list normalization + test_messages = [ + {"role": "human", "content": "Hello"}, + {"role": "ai", "content": "Hi there!"}, + {"role": "tool_call", "content": "function_call"}, + {"role": "system", "content": "You are helpful"}, + {"content": "Message without role"}, + "string message", + ] - # Force setup to re-run - LangchainIntegration.setup_once() + normalized = normalize_message_roles(test_messages) - with start_transaction(name="test_input_types"): - # embed_documents takes a list - embeddings.embed_documents( - ["List item 1", "List item 2", "List item 3"] - ) - # embed_query takes a string - embeddings.embed_query("Single string query") - - # Check captured events - assert len(events) >= 1 - tx = events[0] - assert tx["type"] == "transaction" - - # Find embeddings spans - embeddings_spans = [ - span - for span in tx.get("spans", []) - if span.get("op") == "gen_ai.embeddings" - ] - assert len(embeddings_spans) == 2 + # Verify the original messages are not modified + assert test_messages[0]["role"] == "human" # Original unchanged + assert test_messages[1]["role"] == "ai" # Original unchanged - # Both should have input data captured as lists - for span in embeddings_spans: - assert SPANDATA.GEN_AI_EMBEDDINGS_INPUT in span["data"] - input_data = span["data"][SPANDATA.GEN_AI_EMBEDDINGS_INPUT] - # Input should be normalized to list format - if isinstance(input_data, str): - # If serialized, should contain the input text - assert ( - "List item" in input_data or "Single string query" in input_data - ), f"Expected input text in serialized data: {input_data}" + # Verify the normalized messages have correct roles + assert normalized[0]["role"] == "user" # human -> user + assert normalized[1]["role"] == "assistant" # ai -> assistant + assert normalized[2]["role"] == "tool" # tool_call -> tool + assert normalized[3]["role"] == "system" # system unchanged + assert "role" not in normalized[4] # Message without role unchanged + assert normalized[5] == "string message" # String message unchanged # Tests for multimodal content transformation functions @@ -5872,8 +2487,6 @@ def test_transform_google_file_data(self): } -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize( "ai_type,expected_system", [ @@ -5920,89 +2533,49 @@ def test_transform_google_file_data(self): ) def test_langchain_ai_system_detection( sentry_init, - capture_events, capture_items, ai_type, expected_system, - stream_gen_ai_spans, - span_streaming, ): sentry_init( integrations=[LangchainIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) - callback = SentryLangchainCallback(max_span_map_size=100, include_prompts=True) + callback = SentryLangchainCallback() run_id = "test-ai-system-uuid" serialized = {"_type": ai_type} if ai_type is not None else {} prompts = ["Test prompt"] + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with start_transaction(): - callback.on_llm_start( - serialized=serialized, - prompts=prompts, - run_id=run_id, - invocation_params={"_type": ai_type, "model": "test-model"}, - ) + callback.on_llm_start( + serialized=serialized, + prompts=prompts, + run_id=run_id, + invocation_params={"_type": ai_type, "model": "test-model"}, + ) - generation = Mock(text="Test response", message=None) - response = Mock(generations=[[generation]]) - callback.on_llm_end(response=response, run_id=run_id) + generation = Mock(text="Test response", message=None) + response = Mock(generations=[[generation]]) + callback.on_llm_end(response=response, run_id=run_id) - sentry_sdk.flush() - spans = [item.payload for item in items] - llm_spans = [ - span - for span in spans - if span["attributes"].get("sentry.op") == "gen_ai.text_completion" - ] + sentry_sdk.flush() + spans = [item.payload for item in items] + llm_spans = [ + span + for span in spans + if span["attributes"].get("sentry.op") == "gen_ai.text_completion" + ] - assert len(llm_spans) > 0 - llm_span = llm_spans[0] + assert len(llm_spans) > 0 + llm_span = llm_spans[0] - if expected_system is not None: - assert llm_span["attributes"][SPANDATA.GEN_AI_SYSTEM] == expected_system - else: - assert SPANDATA.GEN_AI_SYSTEM not in llm_span.get("attributes", {}) + if expected_system is not None: + assert llm_span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == expected_system else: - events = capture_events() - - with start_transaction(): - callback.on_llm_start( - serialized=serialized, - prompts=prompts, - run_id=run_id, - invocation_params={"_type": ai_type, "model": "test-model"}, - ) - - generation = Mock(text="Test response", message=None) - response = Mock(generations=[[generation]]) - callback.on_llm_end(response=response, run_id=run_id) - - assert len(events) > 0 - tx = events[0] - assert tx["type"] == "transaction" - - llm_spans = [ - span - for span in tx.get("spans", []) - if span.get("op") == "gen_ai.text_completion" - ] - - assert len(llm_spans) > 0 - llm_span = llm_spans[0] - - if expected_system is not None: - assert llm_span["data"][SPANDATA.GEN_AI_SYSTEM] == expected_system - else: - assert SPANDATA.GEN_AI_SYSTEM not in llm_span.get("data", {}) + assert SPANDATA.GEN_AI_PROVIDER_NAME not in llm_span.get("attributes", {}) class TestTransformLangchainMessageContent: @@ -6121,15 +2694,12 @@ def test_transform_list_with_legacy_image_url(self): } -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize( - "data_collection,send_default_pii,include_prompts,expected_present,expected_absent", + "data_collection,send_default_pii,expected_present,expected_absent", [ pytest.param( {"gen_ai": {"inputs": True, "outputs": True}}, False, - False, { SPANDATA.GEN_AI_REQUEST_MESSAGES: [ {"role": "user", "content": "How many letters in the word eudca"} @@ -6145,7 +2715,6 @@ def test_transform_list_with_legacy_image_url(self): pytest.param( {"gen_ai": {"inputs": False, "outputs": False}}, True, - True, {}, [ SPANDATA.GEN_AI_REQUEST_MESSAGES, @@ -6157,7 +2726,6 @@ def test_transform_list_with_legacy_image_url(self): pytest.param( {"gen_ai": {"inputs": True, "outputs": False}}, False, - False, { SPANDATA.GEN_AI_REQUEST_MESSAGES: [ {"role": "user", "content": "How many letters in the word eudca"} @@ -6172,7 +2740,6 @@ def test_transform_list_with_legacy_image_url(self): pytest.param( {"gen_ai": {"inputs": False, "outputs": True}}, False, - False, {SPANDATA.GEN_AI_RESPONSE_TEXT: "the model response"}, [ SPANDATA.GEN_AI_REQUEST_MESSAGES, @@ -6183,7 +2750,6 @@ def test_transform_list_with_legacy_image_url(self): pytest.param( {"gen_ai": {}}, False, - False, { SPANDATA.GEN_AI_REQUEST_MESSAGES: [ {"role": "user", "content": "How many letters in the word eudca"} @@ -6199,7 +2765,6 @@ def test_transform_list_with_legacy_image_url(self): pytest.param( None, True, - True, { SPANDATA.GEN_AI_REQUEST_MESSAGES: [ {"role": "user", "content": "How many letters in the word eudca"} @@ -6215,7 +2780,6 @@ def test_transform_list_with_legacy_image_url(self): pytest.param( None, False, - True, {}, [ SPANDATA.GEN_AI_REQUEST_MESSAGES, @@ -6234,19 +2798,14 @@ def test_langchain_chat_data_collection( nonstreaming_chat_completions_model_response, data_collection, send_default_pii, - include_prompts, expected_present, expected_absent, - stream_gen_ai_spans, - span_streaming, ): sentry_init_kwargs = dict( - integrations=[LangchainIntegration(include_prompts=include_prompts)], + integrations=[LangchainIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) if data_collection is not None: sentry_init_kwargs["data_collection"] = data_collection @@ -6280,14 +2839,13 @@ def test_langchain_chat_data_collection( openai_api_key="badkey", ) - streamed = span_streaming or stream_gen_ai_spans - captured = capture_items("span") if streamed else capture_events() + captured = capture_items("span") with patch.object( llm.client._client._client, "send", return_value=model_response, - ) as _, start_transaction(): + ): llm.invoke( [ SystemMessage(content="You are a helpful assistant."), @@ -6295,17 +2853,10 @@ def test_langchain_chat_data_collection( ] ) - if streamed: - sentry_sdk.flush() - spans = [item.payload for item in captured] - (span,) = [ - s for s in spans if s["attributes"].get("sentry.op") == "gen_ai.chat" - ] - span_data = span["attributes"] - else: - (event,) = captured - (span,) = [s for s in event["spans"] if s["op"] == "gen_ai.chat"] - span_data = span["data"] + sentry_sdk.flush() + spans = [item.payload for item in captured] + (span,) = [s for s in spans if s["attributes"].get("sentry.op") == "gen_ai.chat"] + span_data = span["attributes"] for key, expected in expected_present.items(): assert key in span_data, f"{key} should have been collected" @@ -6319,19 +2870,16 @@ def test_langchain_chat_data_collection( # Data collection never gates non-PII attributes assert span_data[SPANDATA.GEN_AI_REQUEST_MODEL] == "gpt-3.5-turbo" - assert span_data[SPANDATA.GEN_AI_SYSTEM] == "openai-chat" + assert span_data[SPANDATA.GEN_AI_PROVIDER_NAME] == "openai-chat" assert span_data[SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize( - "data_collection,send_default_pii,include_prompts,expected_present,expected_absent", + "data_collection,send_default_pii,expected_present,expected_absent", [ pytest.param( {"gen_ai": {"inputs": True, "outputs": True}}, False, - False, { SPANDATA.GEN_AI_REQUEST_MESSAGES: [ { @@ -6350,7 +2898,6 @@ def test_langchain_chat_data_collection( pytest.param( {"gen_ai": {"inputs": False, "outputs": False}}, True, - True, {}, [ SPANDATA.GEN_AI_REQUEST_MESSAGES, @@ -6361,7 +2908,6 @@ def test_langchain_chat_data_collection( pytest.param( {"gen_ai": {"inputs": True, "outputs": False}}, False, - False, { SPANDATA.GEN_AI_REQUEST_MESSAGES: [ { @@ -6379,7 +2925,6 @@ def test_langchain_chat_data_collection( pytest.param( {"gen_ai": {"inputs": False, "outputs": True}}, False, - False, {SPANDATA.GEN_AI_RESPONSE_TEXT: "The capital of France is Paris."}, [SPANDATA.GEN_AI_REQUEST_MESSAGES], id="gen-ai-outputs-enabled-inputs-disabled", @@ -6387,7 +2932,6 @@ def test_langchain_chat_data_collection( pytest.param( {"gen_ai": {}}, False, - False, { SPANDATA.GEN_AI_REQUEST_MESSAGES: [ { @@ -6406,7 +2950,6 @@ def test_langchain_chat_data_collection( pytest.param( None, True, - True, { SPANDATA.GEN_AI_REQUEST_MESSAGES: [ { @@ -6425,7 +2968,6 @@ def test_langchain_chat_data_collection( pytest.param( None, False, - True, {}, [ SPANDATA.GEN_AI_REQUEST_MESSAGES, @@ -6442,19 +2984,14 @@ def test_langchain_text_completion_data_collection( get_model_response, data_collection, send_default_pii, - include_prompts, expected_present, expected_absent, - stream_gen_ai_spans, - span_streaming, ): sentry_init_kwargs = dict( - integrations=[LangchainIntegration(include_prompts=include_prompts)], + integrations=[LangchainIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) if data_collection is not None: sentry_init_kwargs["data_collection"] = data_collection @@ -6490,29 +3027,21 @@ def test_langchain_text_completion_data_collection( openai_api_key="badkey", ) - streamed = span_streaming or stream_gen_ai_spans - captured = capture_items("span") if streamed else capture_events() + captured = capture_items("span") with patch.object( model.client._client._client, "send", return_value=model_response, - ) as _, start_transaction(): + ): model.invoke("What is the capital of France?") - if streamed: - sentry_sdk.flush() - spans = [item.payload for item in captured] - (span,) = [ - s - for s in spans - if s["attributes"].get("sentry.op") == "gen_ai.text_completion" - ] - span_data = span["attributes"] - else: - (event,) = captured - (span,) = [s for s in event["spans"] if s["op"] == "gen_ai.text_completion"] - span_data = span["data"] + sentry_sdk.flush() + spans = [item.payload for item in captured] + (span,) = [ + s for s in spans if s["attributes"].get("sentry.op") == "gen_ai.text_completion" + ] + span_data = span["attributes"] for key, expected in expected_present.items(): assert key in span_data, f"{key} should have been collected" @@ -6526,20 +3055,17 @@ def test_langchain_text_completion_data_collection( # Data collection never gates non-PII attributes assert span_data[SPANDATA.GEN_AI_REQUEST_MODEL] == "gpt-3.5-turbo" - assert span_data[SPANDATA.GEN_AI_SYSTEM] == "openai" + assert span_data[SPANDATA.GEN_AI_PROVIDER_NAME] == "openai" assert span_data[SPANDATA.GEN_AI_REQUEST_TEMPERATURE] == 0.7 assert span_data[SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 25 -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize( - "data_collection,send_default_pii,include_prompts,expected_present,expected_absent", + "data_collection,send_default_pii,expected_present,expected_absent", [ pytest.param( {"gen_ai": {"inputs": True, "outputs": True}}, False, - False, [ SPANDATA.GEN_AI_TOOL_DEFINITIONS, SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS, @@ -6550,7 +3076,6 @@ def test_langchain_text_completion_data_collection( pytest.param( {"gen_ai": {"inputs": False, "outputs": False}}, True, - True, [], [ SPANDATA.GEN_AI_TOOL_DEFINITIONS, @@ -6562,7 +3087,6 @@ def test_langchain_text_completion_data_collection( pytest.param( {"gen_ai": {"inputs": True, "outputs": False}}, False, - False, [SPANDATA.GEN_AI_TOOL_DEFINITIONS], [ # REQUEST_AVAILABLE_TOOLS is the legacy value set when data collection is not enabled @@ -6574,7 +3098,6 @@ def test_langchain_text_completion_data_collection( pytest.param( {"gen_ai": {"inputs": False, "outputs": True}}, True, - True, [SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS], [ SPANDATA.GEN_AI_TOOL_DEFINITIONS, @@ -6585,7 +3108,6 @@ def test_langchain_text_completion_data_collection( pytest.param( {"gen_ai": {}}, False, - False, [ SPANDATA.GEN_AI_TOOL_DEFINITIONS, SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS, @@ -6596,7 +3118,6 @@ def test_langchain_text_completion_data_collection( pytest.param( None, True, - True, [ SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS, SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS, @@ -6607,7 +3128,6 @@ def test_langchain_text_completion_data_collection( pytest.param( None, False, - False, [SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS], [ SPANDATA.GEN_AI_TOOL_DEFINITIONS, @@ -6626,19 +3146,14 @@ def test_langchain_data_collection_tools( streaming_chat_completions_model_responses, data_collection, send_default_pii, - include_prompts, expected_present, expected_absent, - stream_gen_ai_spans, - span_streaming, ): sentry_init_kwargs = dict( - integrations=[LangchainIntegration(include_prompts=include_prompts)], + integrations=[LangchainIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) if data_collection is not None: sentry_init_kwargs["data_collection"] = data_collection @@ -6673,35 +3188,22 @@ def test_langchain_data_collection_tools( agent = create_openai_tools_agent(llm, [get_word_length], prompt) agent_executor = AgentExecutor(agent=agent, tools=[get_word_length], verbose=True) - streamed = span_streaming or stream_gen_ai_spans - captured = capture_items("span") if streamed else capture_events() + captured = capture_items("span") with patch.object( llm.client._client._client, "send", side_effect=[tool_response, final_response], - ) as _, start_transaction(): + ): agent_executor.invoke({"input": "How many letters in the word eudca"}) - if streamed: - sentry_sdk.flush() - spans = [item.payload for item in captured] - chat_spans = [ - s["attributes"] - for s in spans - if s["attributes"].get("sentry.op") == "gen_ai.chat" - ] - invoke_agent_span = next( - s["attributes"] - for s in spans - if s["attributes"].get("sentry.op") == "gen_ai.invoke_agent" - ) - else: - (event,) = captured - chat_spans = [s["data"] for s in event["spans"] if s["op"] == "gen_ai.chat"] - invoke_agent_span = next( - s["data"] for s in event["spans"] if s["op"] == "gen_ai.invoke_agent" - ) + sentry_sdk.flush() + spans = [item.payload for item in captured] + chat_spans = [ + s["attributes"] + for s in spans + if s["attributes"].get("sentry.op") == "gen_ai.chat" + ] assert len(chat_spans) == 2 @@ -6720,11 +3222,8 @@ def test_langchain_data_collection_tools( ): collected = key in expected_present assert (key in chat_spans[1]) is collected - assert (key in invoke_agent_span) is collected -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize("send_default_pii", [True, False]) @pytest.mark.parametrize( "data_collection,tool_calls_collected", @@ -6758,53 +3257,43 @@ def test_langchain_data_collection_request_tool_call_params( data_collection, send_default_pii, tool_calls_collected, - stream_gen_ai_spans, - span_streaming, ): sentry_init_kwargs = dict( - integrations=[LangchainIntegration(include_prompts=False)], + integrations=[LangchainIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) if data_collection is not None: sentry_init_kwargs["data_collection"] = data_collection sentry_init(**sentry_init_kwargs) - callback = SentryLangchainCallback(max_span_map_size=100, include_prompts=False) + callback = SentryLangchainCallback() - streamed = span_streaming or stream_gen_ai_spans - captured = capture_items("span") if streamed else capture_events() + captured = capture_items("span") - with start_transaction(): - callback.on_chat_model_start( - serialized={}, - messages=[[HumanMessage(content="How many letters in the word eudca")]], - run_id="test-request-tool-calls-uuid", - invocation_params={ - "model": "gpt-3.5-turbo", - "function_call": {"name": "get_word_length"}, - }, - ) - callback.on_llm_end( - response=LLMResult(generations=[[]]), - run_id="test-request-tool-calls-uuid", - ) + callback.on_chat_model_start( + serialized={}, + messages=[[HumanMessage(content="How many letters in the word eudca")]], + run_id="test-request-tool-calls-uuid", + invocation_params={ + "model": "gpt-3.5-turbo", + "function_call": {"name": "get_word_length"}, + }, + ) + callback.on_llm_end( + response=LLMResult(generations=[[]]), + run_id="test-request-tool-calls-uuid", + ) - if streamed: - sentry_sdk.flush() - spans = [item.payload for item in captured] - (span_data,) = [ - s["attributes"] - for s in spans - if s["attributes"].get("sentry.op") == "gen_ai.chat" - ] - else: - (event,) = captured - (span_data,) = [s["data"] for s in event["spans"] if s["op"] == "gen_ai.chat"] + sentry_sdk.flush() + spans = [item.payload for item in captured] + (span_data,) = [ + s["attributes"] + for s in spans + if s["attributes"].get("sentry.op") == "gen_ai.chat" + ] if tool_calls_collected: assert "get_word_length" in span_data[SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS] @@ -6815,15 +3304,12 @@ def test_langchain_data_collection_request_tool_call_params( assert span_data[SPANDATA.GEN_AI_REQUEST_MODEL] == "gpt-3.5-turbo" -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize( - "data_collection,send_default_pii,include_prompts,expected_present,expected_absent", + "data_collection,send_default_pii,expected_present,expected_absent", [ pytest.param( {"gen_ai": {"inputs": True, "outputs": True}}, False, - False, { SPANDATA.GEN_AI_TOOL_INPUT: {"word": "eudca"}, SPANDATA.GEN_AI_TOOL_OUTPUT: 5, @@ -6834,7 +3320,6 @@ def test_langchain_data_collection_request_tool_call_params( pytest.param( {"gen_ai": {"inputs": False, "outputs": False}}, True, - True, {}, [SPANDATA.GEN_AI_TOOL_INPUT, SPANDATA.GEN_AI_TOOL_OUTPUT], id="gen-ai-inputs-and-outputs-disabled-override-legacy-on", @@ -6842,7 +3327,6 @@ def test_langchain_data_collection_request_tool_call_params( pytest.param( {"gen_ai": {"inputs": True, "outputs": False}}, False, - False, {SPANDATA.GEN_AI_TOOL_INPUT: {"word": "eudca"}}, [SPANDATA.GEN_AI_TOOL_OUTPUT], id="gen-ai-inputs-enabled-outputs-disabled", @@ -6850,7 +3334,6 @@ def test_langchain_data_collection_request_tool_call_params( pytest.param( {"gen_ai": {"inputs": False, "outputs": True}}, False, - False, {SPANDATA.GEN_AI_TOOL_OUTPUT: 5}, [SPANDATA.GEN_AI_TOOL_INPUT], id="gen-ai-outputs-enabled-inputs-disabled", @@ -6858,7 +3341,6 @@ def test_langchain_data_collection_request_tool_call_params( pytest.param( {"gen_ai": {}}, False, - False, { SPANDATA.GEN_AI_TOOL_INPUT: {"word": "eudca"}, SPANDATA.GEN_AI_TOOL_OUTPUT: 5, @@ -6869,7 +3351,6 @@ def test_langchain_data_collection_request_tool_call_params( pytest.param( None, True, - True, { SPANDATA.GEN_AI_TOOL_INPUT: {"word": "eudca"}, SPANDATA.GEN_AI_TOOL_OUTPUT: 5, @@ -6880,7 +3361,6 @@ def test_langchain_data_collection_request_tool_call_params( pytest.param( None, False, - True, {}, [SPANDATA.GEN_AI_TOOL_INPUT, SPANDATA.GEN_AI_TOOL_OUTPUT], id="no-gen-ai-config-legacy-pii-disabled", @@ -6896,19 +3376,14 @@ def test_langchain_tool_execution_data_collection( streaming_chat_completions_model_responses, data_collection, send_default_pii, - include_prompts, expected_present, expected_absent, - stream_gen_ai_spans, - span_streaming, ): sentry_init_kwargs = dict( - integrations=[LangchainIntegration(include_prompts=include_prompts)], + integrations=[LangchainIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) if data_collection is not None: sentry_init_kwargs["data_collection"] = data_collection @@ -6943,29 +3418,22 @@ def test_langchain_tool_execution_data_collection( agent = create_openai_tools_agent(llm, [get_word_length], prompt) agent_executor = AgentExecutor(agent=agent, tools=[get_word_length], verbose=True) - streamed = span_streaming or stream_gen_ai_spans - captured = capture_items("span") if streamed else capture_events() + captured = capture_items("span") with patch.object( llm.client._client._client, "send", side_effect=[tool_response, final_response], - ) as _, start_transaction(): + ): agent_executor.invoke({"input": "How many letters in the word eudca"}) - if streamed: - sentry_sdk.flush() - spans = [item.payload for item in captured] - span_data = next( - s["attributes"] - for s in spans - if s["attributes"].get("sentry.op") == "gen_ai.execute_tool" - ) - else: - (event,) = captured - span_data = next( - s["data"] for s in event["spans"] if s["op"] == "gen_ai.execute_tool" - ) + sentry_sdk.flush() + spans = [item.payload for item in captured] + span_data = next( + s["attributes"] + for s in spans + if s["attributes"].get("sentry.op") == "gen_ai.execute_tool" + ) for key, expected in expected_present.items(): assert key in span_data, f"{key} should have been collected" @@ -6982,16 +3450,13 @@ def test_langchain_tool_execution_data_collection( assert span_data[SPANDATA.GEN_AI_OPERATION_NAME] == "execute_tool" -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize("agent_method", ["invoke", "stream"]) @pytest.mark.parametrize( - "data_collection,send_default_pii,include_prompts,expected_present,expected_absent", + "data_collection,send_default_pii,expected_present,expected_absent", [ pytest.param( {"gen_ai": {"inputs": True, "outputs": True}}, False, - False, { SPANDATA.GEN_AI_REQUEST_MESSAGES: [ "How many letters in the word eudca" @@ -7004,7 +3469,6 @@ def test_langchain_tool_execution_data_collection( pytest.param( {"gen_ai": {"inputs": False, "outputs": False}}, True, - True, {}, [SPANDATA.GEN_AI_REQUEST_MESSAGES, SPANDATA.GEN_AI_RESPONSE_TEXT], id="gen-ai-inputs-and-outputs-disabled-override-legacy-on", @@ -7012,7 +3476,6 @@ def test_langchain_tool_execution_data_collection( pytest.param( {"gen_ai": {"inputs": True, "outputs": False}}, False, - False, {SPANDATA.GEN_AI_REQUEST_MESSAGES: ["How many letters in the word eudca"]}, [SPANDATA.GEN_AI_RESPONSE_TEXT], id="gen-ai-inputs-enabled-outputs-disabled", @@ -7020,7 +3483,6 @@ def test_langchain_tool_execution_data_collection( pytest.param( {"gen_ai": {"inputs": False, "outputs": True}}, False, - False, {SPANDATA.GEN_AI_RESPONSE_TEXT: "The word eudca has 5 letters."}, [SPANDATA.GEN_AI_REQUEST_MESSAGES], id="gen-ai-outputs-enabled-inputs-disabled", @@ -7028,7 +3490,6 @@ def test_langchain_tool_execution_data_collection( pytest.param( {"gen_ai": {}}, False, - False, { SPANDATA.GEN_AI_REQUEST_MESSAGES: [ "How many letters in the word eudca" @@ -7041,7 +3502,6 @@ def test_langchain_tool_execution_data_collection( pytest.param( None, True, - True, { SPANDATA.GEN_AI_REQUEST_MESSAGES: [ "How many letters in the word eudca" @@ -7054,7 +3514,6 @@ def test_langchain_tool_execution_data_collection( pytest.param( None, False, - True, {}, [SPANDATA.GEN_AI_REQUEST_MESSAGES, SPANDATA.GEN_AI_RESPONSE_TEXT], id="no-gen-ai-config-legacy-pii-disabled", @@ -7070,20 +3529,15 @@ def test_langchain_agent_executor_data_collection( streaming_chat_completions_model_responses, data_collection, send_default_pii, - include_prompts, expected_present, expected_absent, agent_method, - stream_gen_ai_spans, - span_streaming, ): sentry_init_kwargs = dict( - integrations=[LangchainIntegration(include_prompts=include_prompts)], + integrations=[LangchainIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) if data_collection is not None: sentry_init_kwargs["data_collection"] = data_collection @@ -7118,32 +3572,25 @@ def test_langchain_agent_executor_data_collection( agent = create_openai_tools_agent(llm, [get_word_length], prompt) agent_executor = AgentExecutor(agent=agent, tools=[get_word_length], verbose=True) - streamed = span_streaming or stream_gen_ai_spans - captured = capture_items("span") if streamed else capture_events() + captured = capture_items("span") with patch.object( llm.client._client._client, "send", side_effect=[tool_response, final_response], - ) as _, start_transaction(): + ): if agent_method == "invoke": agent_executor.invoke({"input": "How many letters in the word eudca"}) else: list(agent_executor.stream({"input": "How many letters in the word eudca"})) - if streamed: - sentry_sdk.flush() - spans = [item.payload for item in captured] - span_data = next( - s["attributes"] - for s in spans - if s["attributes"].get("sentry.op") == "gen_ai.invoke_agent" - ) - else: - (event,) = captured - span_data = next( - s["data"] for s in event["spans"] if s["op"] == "gen_ai.invoke_agent" - ) + sentry_sdk.flush() + spans = [item.payload for item in captured] + span_data = next( + s["attributes"] + for s in spans + if s["attributes"].get("sentry.op") == "gen_ai.invoke_agent" + ) for key, expected in expected_present.items(): assert key in span_data, f"{key} should have been collected" @@ -7157,164 +3604,3 @@ def test_langchain_agent_executor_data_collection( # Data collection never gates non-PII attributes assert span_data[SPANDATA.GEN_AI_OPERATION_NAME] == "invoke_agent" - assert span_data[SPANDATA.GEN_AI_RESPONSE_STREAMING] is (agent_method == "stream") - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) -@pytest.mark.parametrize( - "method", - ["embed_documents", "embed_query", "aembed_documents", "aembed_query"], -) -@pytest.mark.parametrize( - "data_collection,send_default_pii,include_prompts,inputs_collected", - [ - pytest.param( - {"gen_ai": {"inputs": True, "outputs": True}}, - False, - False, - True, - id="gen-ai-inputs-enabled-override-legacy-off", - ), - pytest.param( - {"gen_ai": {"inputs": False, "outputs": False}}, - True, - True, - False, - id="gen-ai-inputs-disabled-override-legacy-on", - ), - pytest.param( - {"gen_ai": {"inputs": True, "outputs": False}}, - False, - False, - True, - id="gen-ai-inputs-enabled-outputs-disabled", - ), - pytest.param( - {"gen_ai": {"inputs": False, "outputs": True}}, - True, - True, - False, - id="gen-ai-outputs-enabled-inputs-disabled", - ), - pytest.param( - {"gen_ai": {}}, - False, - False, - True, - id="gen-ai-inputs-omitted-default-to-enabled", - ), - pytest.param( - None, - True, - True, - True, - id="no-gen-ai-config-legacy-pii-and-include-prompts-enabled", - ), - pytest.param( - None, - False, - True, - False, - id="no-gen-ai-config-legacy-pii-disabled", - ), - ], -) -@pytest.mark.asyncio -async def test_langchain_embeddings_data_collection( - sentry_init, - capture_events, - capture_items, - data_collection, - send_default_pii, - include_prompts, - inputs_collected, - method, - stream_gen_ai_spans, - span_streaming, -): - try: - from langchain_openai import OpenAIEmbeddings - except ImportError: - pytest.skip("langchain_openai not installed") - - sentry_init_kwargs = dict( - integrations=[LangchainIntegration(include_prompts=include_prompts)], - disabled_integrations=[StdlibIntegration], - traces_sample_rate=1.0, - send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", - ) - if data_collection is not None: - sentry_init_kwargs["data_collection"] = data_collection - - sentry_init(**sentry_init_kwargs) - - def mock_embed_documents(self, texts): - return [[0.1, 0.2, 0.3] for _ in texts] - - def mock_embed_query(self, text): - return [0.1, 0.2, 0.3] - - async def mock_aembed_documents(self, texts): - return [[0.1, 0.2, 0.3] for _ in texts] - - async def mock_aembed_query(self, text): - return [0.1, 0.2, 0.3] - - mocks = { - "embed_documents": mock_embed_documents, - "embed_query": mock_embed_query, - "aembed_documents": mock_aembed_documents, - "aembed_query": mock_aembed_query, - } - is_query = method.endswith("embed_query") - embeddings_input = "Hello world" if is_query else ["Hello world", "Test document"] - - streamed = span_streaming or stream_gen_ai_spans - captured = capture_items("span") if streamed else capture_events() - - with mock.patch.object(OpenAIEmbeddings, method, wraps=mocks[method]): - embeddings = OpenAIEmbeddings( - model="text-embedding-ada-002", openai_api_key="test-key" - ) - - # Force setup to re-run to ensure our mock is wrapped - LangchainIntegration.setup_once() - - with start_transaction(name="test_embeddings_data_collection"): - if method.startswith("a"): - await getattr(embeddings, method)(embeddings_input) - else: - getattr(embeddings, method)(embeddings_input) - - if streamed: - sentry_sdk.flush() - spans = [item.payload for item in captured] - span_data = next( - s["attributes"] - for s in spans - if s["attributes"].get("sentry.op") == "gen_ai.embeddings" - ) - else: - (event,) = captured - span_data = next( - s["data"] for s in event["spans"] if s["op"] == "gen_ai.embeddings" - ) - - if inputs_collected: - assert SPANDATA.GEN_AI_EMBEDDINGS_INPUT in span_data, ( - "Embeddings input should have been collected" - ) - assert json.loads(span_data[SPANDATA.GEN_AI_EMBEDDINGS_INPUT]) == ( - [embeddings_input] if is_query else embeddings_input - ) - else: - assert SPANDATA.GEN_AI_EMBEDDINGS_INPUT not in span_data, ( - "Embeddings input should not have been collected" - ) - - # Data collection never gates non-PII attributes - assert span_data[SPANDATA.GEN_AI_OPERATION_NAME] == "embeddings" - assert span_data[SPANDATA.GEN_AI_REQUEST_MODEL] == "text-embedding-ada-002" diff --git a/tests/integrations/langgraph/test_langgraph.py b/tests/integrations/langgraph/test_langgraph.py index 7b6a6cc3d9..a65b9f39aa 100644 --- a/tests/integrations/langgraph/test_langgraph.py +++ b/tests/integrations/langgraph/test_langgraph.py @@ -1,7 +1,7 @@ import asyncio import json import sys -from unittest.mock import MagicMock, patch +from unittest.mock import MagicMock import pytest from langchain_core.language_models.chat_models import BaseChatModel @@ -10,7 +10,6 @@ from langgraph.errors import GraphBubbleUp import sentry_sdk -from sentry_sdk import start_transaction from sentry_sdk.consts import OP, SPANDATA @@ -39,7 +38,6 @@ def mock_langgraph_imports(): _parse_langgraph_messages, _wrap_pregel_ainvoke, _wrap_pregel_invoke, - _wrap_state_graph_compile, ) @@ -139,148 +137,20 @@ def _generate(self, messages, stop=None, run_manager=None, **kwargs) -> ChatResu raise GraphBubbleUp("interrupt") -def test_langgraph_integration_init(): - """Test LanggraphIntegration initialization with different parameters.""" - integration = LanggraphIntegration() - assert integration.include_prompts is True - assert integration.identifier == "langgraph" - assert integration.origin == "auto.ai.langgraph" - - integration = LanggraphIntegration(include_prompts=False) - assert integration.include_prompts is False - assert integration.identifier == "langgraph" - assert integration.origin == "auto.ai.langgraph" - - -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) -@pytest.mark.parametrize( - "send_default_pii, include_prompts", - [ - (True, True), - (True, False), - (False, True), - (False, False), - ], -) -def test_state_graph_compile( - sentry_init, - capture_events, - capture_items, - send_default_pii, - include_prompts, - stream_gen_ai_spans, -): - """Test StateGraph.compile() wrapper creates proper create_agent span.""" - sentry_init( - integrations=[LanggraphIntegration(include_prompts=include_prompts)], - traces_sample_rate=1.0, - send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - ) - - graph = MockStateGraph() - - def original_compile(self, *args, **kwargs): - return MockCompiledGraph(self.name) - - if stream_gen_ai_spans: - items = capture_items("span") - - with patch("sentry_sdk.integrations.langgraph.StateGraph"), start_transaction(): - wrapped_compile = _wrap_state_graph_compile(original_compile) - compiled_graph = wrapped_compile( - graph, model="test-model", checkpointer=None - ) - - assert compiled_graph is not None - assert compiled_graph.name == "test_graph" - - spans = [item.payload for item in items] - agent_spans = [ - span - for span in spans - if span["attributes"]["sentry.op"] == OP.GEN_AI_CREATE_AGENT - ] - assert len(agent_spans) == 1 - agent_span = agent_spans[0] - - assert agent_span["name"] == "create_agent test_graph" - assert agent_span["attributes"]["sentry.origin"] == "auto.ai.langgraph" - assert ( - agent_span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "create_agent" - ) - assert agent_span["attributes"][SPANDATA.GEN_AI_AGENT_NAME] == "test_graph" - assert agent_span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "test-model" - assert SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS in agent_span["attributes"] - - tools_data = agent_span["attributes"][SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS] - assert tools_data == ["search_tool", "calculator"] - assert len(tools_data) == 2 - assert "search_tool" in tools_data - assert "calculator" in tools_data - else: - events = capture_events() - - with patch("sentry_sdk.integrations.langgraph.StateGraph"), start_transaction(): - wrapped_compile = _wrap_state_graph_compile(original_compile) - compiled_graph = wrapped_compile( - graph, model="test-model", checkpointer=None - ) - - assert compiled_graph is not None - assert compiled_graph.name == "test_graph" - - tx = events[0] - assert tx["type"] == "transaction" - - agent_spans = [ - span for span in tx["spans"] if span["op"] == OP.GEN_AI_CREATE_AGENT - ] - assert len(agent_spans) == 1 - agent_span = agent_spans[0] - - assert agent_span["description"] == "create_agent test_graph" - assert agent_span["origin"] == "auto.ai.langgraph" - assert agent_span["data"][SPANDATA.GEN_AI_OPERATION_NAME] == "create_agent" - assert agent_span["data"][SPANDATA.GEN_AI_AGENT_NAME] == "test_graph" - assert agent_span["data"][SPANDATA.GEN_AI_REQUEST_MODEL] == "test-model" - assert SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS in agent_span["data"] - - tools_data = agent_span["data"][SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS] - - assert tools_data == ["search_tool", "calculator"] - assert len(tools_data) == 2 - assert "search_tool" in tools_data - assert "calculator" in tools_data - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize( - "send_default_pii, include_prompts", - [ - (True, True), - (True, False), - (False, True), - (False, False), - ], + "send_default_pii", + [True, False], ) def test_pregel_invoke( sentry_init, - capture_events, capture_items, send_default_pii, - include_prompts, - stream_gen_ai_spans, - span_streaming, ): """Test Pregel.invoke() wrapper creates proper invoke_agent span.""" sentry_init( - integrations=[LanggraphIntegration(include_prompts=include_prompts)], + integrations=[LanggraphIntegration()], traces_sample_rate=1.0, send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) test_state = { @@ -312,153 +182,75 @@ def original_invoke(self, *args, **kwargs): ] return {"messages": new_messages} - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with start_transaction(): - wrapped_invoke = _wrap_pregel_invoke(original_invoke) - result = wrapped_invoke(pregel, test_state) + items = capture_items("span") - assert result is not None + wrapped_invoke = _wrap_pregel_invoke(original_invoke) + result = wrapped_invoke(pregel, test_state) - sentry_sdk.flush() - spans = [item.payload for item in items] - invoke_spans = [ - span - for span in spans - if span["attributes"]["sentry.op"] == OP.GEN_AI_INVOKE_AGENT - ] - assert len(invoke_spans) == 1 + assert result is not None - invoke_span = invoke_spans[0] - assert invoke_span["name"] == "invoke_agent test_graph" - assert invoke_span["attributes"]["sentry.origin"] == "auto.ai.langgraph" - assert ( - invoke_span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "invoke_agent" - ) - assert invoke_span["attributes"][SPANDATA.GEN_AI_PIPELINE_NAME] == "test_graph" - assert invoke_span["attributes"][SPANDATA.GEN_AI_AGENT_NAME] == "test_graph" + sentry_sdk.flush() + spans = [item.payload for item in items] + invoke_spans = [ + span + for span in spans + if span["attributes"]["sentry.op"] == OP.GEN_AI_INVOKE_AGENT + ] + assert len(invoke_spans) == 1 - if send_default_pii and include_prompts: - assert SPANDATA.GEN_AI_REQUEST_MESSAGES in invoke_span["attributes"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT in invoke_span["attributes"] + invoke_span = invoke_spans[0] + assert invoke_span["name"] == "invoke_agent test_graph" + assert invoke_span["attributes"]["sentry.origin"] == "auto.ai.langgraph" + assert invoke_span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "invoke_agent" + assert invoke_span["attributes"][SPANDATA.GEN_AI_PIPELINE_NAME] == "test_graph" + assert invoke_span["attributes"][SPANDATA.GEN_AI_AGENT_NAME] == "test_graph" + + if send_default_pii: + assert SPANDATA.GEN_AI_REQUEST_MESSAGES in invoke_span["attributes"] + assert SPANDATA.GEN_AI_RESPONSE_TEXT in invoke_span["attributes"] - request_messages = invoke_span["attributes"][ - SPANDATA.GEN_AI_REQUEST_MESSAGES - ] + request_messages = invoke_span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - if isinstance(request_messages, str): - request_messages = json.loads(request_messages) - assert len(request_messages) == 2 - assert request_messages[0]["content"] == "Hello, can you help me?" - assert request_messages[1]["content"] == "Of course! How can I assist you?" + if isinstance(request_messages, str): + request_messages = json.loads(request_messages) + assert len(request_messages) == 2 + assert request_messages[0]["content"] == "Hello, can you help me?" + assert request_messages[1]["content"] == "Of course! How can I assist you?" - response_text = invoke_span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] - assert response_text == expected_assistant_response + response_text = invoke_span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] + assert response_text == expected_assistant_response - assert SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS in invoke_span["attributes"] - tool_calls_data = invoke_span["attributes"][ - SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS - ] + assert SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS in invoke_span["attributes"] + tool_calls_data = invoke_span["attributes"][SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS] - if isinstance(tool_calls_data, str): - tool_calls_data = json.loads(tool_calls_data) + if isinstance(tool_calls_data, str): + tool_calls_data = json.loads(tool_calls_data) - assert len(tool_calls_data) == 1 - assert tool_calls_data[0]["id"] == "call_test_123" - assert tool_calls_data[0]["function"]["name"] == "search_tool" - else: - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in invoke_span.get( - "attributes", {} - ) - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in invoke_span.get( - "attributes", {} - ) - assert SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS not in invoke_span.get( - "attributes", {} - ) + assert len(tool_calls_data) == 1 + assert tool_calls_data[0]["id"] == "call_test_123" + assert tool_calls_data[0]["function"]["name"] == "search_tool" else: - events = capture_events() - - with start_transaction(): - wrapped_invoke = _wrap_pregel_invoke(original_invoke) - result = wrapped_invoke(pregel, test_state) - - assert result is not None - - tx = events[0] - assert tx["type"] == "transaction" - - invoke_spans = [ - span for span in tx["spans"] if span["op"] == OP.GEN_AI_INVOKE_AGENT - ] - assert len(invoke_spans) == 1 - - invoke_span = invoke_spans[0] - assert invoke_span["description"] == "invoke_agent test_graph" - assert invoke_span["origin"] == "auto.ai.langgraph" - assert invoke_span["data"][SPANDATA.GEN_AI_OPERATION_NAME] == "invoke_agent" - assert invoke_span["data"][SPANDATA.GEN_AI_PIPELINE_NAME] == "test_graph" - assert invoke_span["data"][SPANDATA.GEN_AI_AGENT_NAME] == "test_graph" - - if send_default_pii and include_prompts: - assert SPANDATA.GEN_AI_REQUEST_MESSAGES in invoke_span["data"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT in invoke_span["data"] - - request_messages = invoke_span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - - if isinstance(request_messages, str): - request_messages = json.loads(request_messages) - assert len(request_messages) == 1 - assert request_messages[0]["content"] == "Of course! How can I assist you?" - - response_text = invoke_span["data"][SPANDATA.GEN_AI_RESPONSE_TEXT] - assert response_text == expected_assistant_response - - assert SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS in invoke_span["data"] - tool_calls_data = invoke_span["data"][SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS] - - if isinstance(tool_calls_data, str): - tool_calls_data = json.loads(tool_calls_data) - - assert len(tool_calls_data) == 1 - assert tool_calls_data[0]["id"] == "call_test_123" - assert tool_calls_data[0]["function"]["name"] == "search_tool" - else: - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in invoke_span.get("data", {}) - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in invoke_span.get("data", {}) - assert SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS not in invoke_span.get( - "data", {} - ) + assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in invoke_span.get("attributes", {}) + assert SPANDATA.GEN_AI_RESPONSE_TEXT not in invoke_span.get("attributes", {}) + assert SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS not in invoke_span.get( + "attributes", {} + ) -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize( - "send_default_pii, include_prompts", - [ - (True, True), - (True, False), - (False, True), - (False, False), - ], + "send_default_pii", + [True, False], ) def test_pregel_ainvoke( sentry_init, - capture_events, capture_items, send_default_pii, - include_prompts, - stream_gen_ai_spans, - span_streaming, ): """Test Pregel.ainvoke() async wrapper creates proper invoke_agent span.""" sentry_init( - integrations=[LanggraphIntegration(include_prompts=include_prompts)], + integrations=[LanggraphIntegration()], traces_sample_rate=1.0, send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) test_state = {"messages": [MockMessage("What's the weather like?", name="user")]} @@ -485,124 +277,64 @@ async def original_ainvoke(self, *args, **kwargs): return {"messages": new_messages} async def run_test(): - with start_transaction(): - wrapped_ainvoke = _wrap_pregel_ainvoke(original_ainvoke) - result = await wrapped_ainvoke(pregel, test_state) - return result + wrapped_ainvoke = _wrap_pregel_ainvoke(original_ainvoke) + result = await wrapped_ainvoke(pregel, test_state) + return result - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") + items = capture_items("span") - result = asyncio.run(run_test()) - assert result is not None - - sentry_sdk.flush() - spans = [item.payload for item in items] - invoke_spans = [ - span - for span in spans - if span["attributes"]["sentry.op"] == OP.GEN_AI_INVOKE_AGENT - ] - assert len(invoke_spans) == 1 + result = asyncio.run(run_test()) + assert result is not None - invoke_span = invoke_spans[0] - assert invoke_span["name"] == "invoke_agent async_graph" - assert invoke_span["attributes"]["sentry.origin"] == "auto.ai.langgraph" - assert ( - invoke_span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "invoke_agent" - ) - assert invoke_span["attributes"][SPANDATA.GEN_AI_PIPELINE_NAME] == "async_graph" - assert invoke_span["attributes"][SPANDATA.GEN_AI_AGENT_NAME] == "async_graph" + sentry_sdk.flush() + spans = [item.payload for item in items] + invoke_spans = [ + span + for span in spans + if span["attributes"]["sentry.op"] == OP.GEN_AI_INVOKE_AGENT + ] + assert len(invoke_spans) == 1 - if send_default_pii and include_prompts: - assert SPANDATA.GEN_AI_REQUEST_MESSAGES in invoke_span["attributes"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT in invoke_span["attributes"] + invoke_span = invoke_spans[0] + assert invoke_span["name"] == "invoke_agent async_graph" + assert invoke_span["attributes"]["sentry.origin"] == "auto.ai.langgraph" + assert invoke_span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "invoke_agent" + assert invoke_span["attributes"][SPANDATA.GEN_AI_PIPELINE_NAME] == "async_graph" + assert invoke_span["attributes"][SPANDATA.GEN_AI_AGENT_NAME] == "async_graph" + + if send_default_pii: + assert SPANDATA.GEN_AI_REQUEST_MESSAGES in invoke_span["attributes"] + assert SPANDATA.GEN_AI_RESPONSE_TEXT in invoke_span["attributes"] - response_text = invoke_span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] - assert response_text == expected_assistant_response + response_text = invoke_span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] + assert response_text == expected_assistant_response - assert SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS in invoke_span["attributes"] - tool_calls_data = invoke_span["attributes"][ - SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS - ] + assert SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS in invoke_span["attributes"] + tool_calls_data = invoke_span["attributes"][SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS] - if isinstance(tool_calls_data, str): - tool_calls_data = json.loads(tool_calls_data) + if isinstance(tool_calls_data, str): + tool_calls_data = json.loads(tool_calls_data) - assert len(tool_calls_data) == 1 - assert tool_calls_data[0]["id"] == "call_weather_456" - assert tool_calls_data[0]["function"]["name"] == "get_weather" - else: - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in invoke_span.get( - "attributes", {} - ) - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in invoke_span.get( - "attributes", {} - ) - assert SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS not in invoke_span.get( - "attributes", {} - ) + assert len(tool_calls_data) == 1 + assert tool_calls_data[0]["id"] == "call_weather_456" + assert tool_calls_data[0]["function"]["name"] == "get_weather" else: - events = capture_events() - - result = asyncio.run(run_test()) - assert result is not None - - tx = events[0] - assert tx["type"] == "transaction" - - invoke_spans = [ - span for span in tx["spans"] if span["op"] == OP.GEN_AI_INVOKE_AGENT - ] - assert len(invoke_spans) == 1 - - invoke_span = invoke_spans[0] - assert invoke_span["description"] == "invoke_agent async_graph" - assert invoke_span["origin"] == "auto.ai.langgraph" - assert invoke_span["data"][SPANDATA.GEN_AI_OPERATION_NAME] == "invoke_agent" - assert invoke_span["data"][SPANDATA.GEN_AI_PIPELINE_NAME] == "async_graph" - assert invoke_span["data"][SPANDATA.GEN_AI_AGENT_NAME] == "async_graph" - - if send_default_pii and include_prompts: - assert SPANDATA.GEN_AI_REQUEST_MESSAGES in invoke_span["data"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT in invoke_span["data"] - - response_text = invoke_span["data"][SPANDATA.GEN_AI_RESPONSE_TEXT] - assert response_text == expected_assistant_response - - assert SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS in invoke_span["data"] - tool_calls_data = invoke_span["data"][SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS] - - if isinstance(tool_calls_data, str): - tool_calls_data = json.loads(tool_calls_data) - - assert len(tool_calls_data) == 1 - assert tool_calls_data[0]["id"] == "call_weather_456" - assert tool_calls_data[0]["function"]["name"] == "get_weather" - else: - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in invoke_span.get("data", {}) - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in invoke_span.get("data", {}) - assert SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS not in invoke_span.get( - "data", {} - ) + assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in invoke_span.get("attributes", {}) + assert SPANDATA.GEN_AI_RESPONSE_TEXT not in invoke_span.get("attributes", {}) + assert SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS not in invoke_span.get( + "attributes", {} + ) -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_pregel_invoke_error( sentry_init, - capture_events, capture_items, - stream_gen_ai_spans, - span_streaming, ): """Test error handling during graph execution.""" sentry_init( - integrations=[LanggraphIntegration(include_prompts=True)], + integrations=[LanggraphIntegration()], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) test_state = {"messages": [MockMessage("This will fail")]} @@ -611,1177 +343,109 @@ def test_pregel_invoke_error( def original_invoke(self, *args, **kwargs): raise Exception("Graph execution failed") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with start_transaction(), pytest.raises( - Exception, match="Graph execution failed" - ): - wrapped_invoke = _wrap_pregel_invoke(original_invoke) - wrapped_invoke(pregel, test_state) - - sentry_sdk.flush() - spans = [item.payload for item in items] - invoke_spans = [ - span - for span in spans - if span["attributes"]["sentry.op"] == OP.GEN_AI_INVOKE_AGENT - ] - assert len(invoke_spans) == 1 - - invoke_span = invoke_spans[0] - assert invoke_span.get("status") == "error" - else: - events = capture_events() - - with start_transaction(), pytest.raises( - Exception, match="Graph execution failed" - ): - wrapped_invoke = _wrap_pregel_invoke(original_invoke) - wrapped_invoke(pregel, test_state) - - tx = events[0] - invoke_spans = [ - span for span in tx["spans"] if span["op"] == OP.GEN_AI_INVOKE_AGENT - ] - assert len(invoke_spans) == 1 - - invoke_span = invoke_spans[0] - assert invoke_span.get("status") == "internal_error" - assert invoke_span.get("tags", {}).get("status") == "internal_error" - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) -def test_pregel_ainvoke_error( - sentry_init, - capture_events, - capture_items, - stream_gen_ai_spans, - span_streaming, -): - """Test error handling during async graph execution.""" - sentry_init( - integrations=[LanggraphIntegration(include_prompts=True)], - traces_sample_rate=1.0, - send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", - ) - - test_state = {"messages": [MockMessage("This will fail async")]} - pregel = MockPregelInstance("async_error_graph") - - async def original_ainvoke(self, *args, **kwargs): - raise Exception("Async graph execution failed") - - async def run_error_test(): - with start_transaction(), pytest.raises( - Exception, match="Async graph execution failed" - ): - wrapped_ainvoke = _wrap_pregel_ainvoke(original_ainvoke) - await wrapped_ainvoke(pregel, test_state) - - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - asyncio.run(run_error_test()) - - sentry_sdk.flush() - spans = [item.payload for item in items] - invoke_spans = [ - span - for span in spans - if span["attributes"]["sentry.op"] == OP.GEN_AI_INVOKE_AGENT - ] - assert len(invoke_spans) == 1 - - invoke_span = invoke_spans[0] - assert invoke_span.get("status") == "error" - else: - events = capture_events() - - asyncio.run(run_error_test()) - - tx = events[0] - invoke_spans = [ - span for span in tx["spans"] if span["op"] == OP.GEN_AI_INVOKE_AGENT - ] - assert len(invoke_spans) == 1 - - invoke_span = invoke_spans[0] - assert invoke_span.get("status") == "internal_error" - assert invoke_span.get("tags", {}).get("status") == "internal_error" - - -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) -def test_span_origin( - sentry_init, - capture_events, - capture_items, - stream_gen_ai_spans, -): - """Test that span origins are correctly set.""" - sentry_init( - integrations=[LanggraphIntegration()], - traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - ) - - graph = MockStateGraph() - - def original_compile(self, *args, **kwargs): - return MockCompiledGraph(self.name) - - if stream_gen_ai_spans: - items = capture_items("transaction", "span") - - with start_transaction(): - from sentry_sdk.integrations.langgraph import _wrap_state_graph_compile - - wrapped_compile = _wrap_state_graph_compile(original_compile) - wrapped_compile(graph) - - tx = next(item.payload for item in items if item.type == "transaction") - assert tx["contexts"]["trace"]["origin"] == "manual" - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - for span in spans: - assert span["attributes"]["sentry.origin"] == "auto.ai.langgraph" - else: - events = capture_events() - - with start_transaction(): - from sentry_sdk.integrations.langgraph import _wrap_state_graph_compile - - wrapped_compile = _wrap_state_graph_compile(original_compile) - wrapped_compile(graph) - - tx = events[0] - assert tx["contexts"]["trace"]["origin"] == "manual" - - for span in tx["spans"]: - assert span["origin"] == "auto.ai.langgraph" - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) -@pytest.mark.parametrize("graph_name", ["my_graph", None, ""]) -def test_pregel_invoke_with_different_graph_names( - sentry_init, - capture_events, - capture_items, - graph_name, - stream_gen_ai_spans, - span_streaming, -): - """Test Pregel.invoke() with different graph name scenarios.""" - sentry_init( - integrations=[LanggraphIntegration()], - traces_sample_rate=1.0, - send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", - ) - - pregel = MockPregelInstance(graph_name) if graph_name else MockPregelInstance() - if not graph_name: - delattr(pregel, "name") - delattr(pregel, "graph_name") - - def original_invoke(self, *args, **kwargs): - return {"result": "test"} - - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with start_transaction(): - wrapped_invoke = _wrap_pregel_invoke(original_invoke) - wrapped_invoke(pregel, {"messages": []}) - - sentry_sdk.flush() - spans = [item.payload for item in items] - invoke_spans = [ - span - for span in spans - if span["attributes"]["sentry.op"] == OP.GEN_AI_INVOKE_AGENT - ] - assert len(invoke_spans) == 1 - - invoke_span = invoke_spans[0] - - if graph_name and graph_name.strip(): - assert invoke_span["name"] == "invoke_agent my_graph" - assert ( - invoke_span["attributes"][SPANDATA.GEN_AI_PIPELINE_NAME] == graph_name - ) - assert invoke_span["attributes"][SPANDATA.GEN_AI_AGENT_NAME] == graph_name - else: - assert invoke_span["name"] == "invoke_agent" - assert SPANDATA.GEN_AI_PIPELINE_NAME not in invoke_span.get( - "attributes", {} - ) - assert SPANDATA.GEN_AI_AGENT_NAME not in invoke_span.get("attributes", {}) - else: - events = capture_events() - - with start_transaction(): - wrapped_invoke = _wrap_pregel_invoke(original_invoke) - wrapped_invoke(pregel, {"messages": []}) - - tx = events[0] - invoke_spans = [ - span for span in tx["spans"] if span["op"] == OP.GEN_AI_INVOKE_AGENT - ] - assert len(invoke_spans) == 1 - - invoke_span = invoke_spans[0] - - if graph_name and graph_name.strip(): - assert invoke_span["description"] == "invoke_agent my_graph" - assert invoke_span["data"][SPANDATA.GEN_AI_PIPELINE_NAME] == graph_name - assert invoke_span["data"][SPANDATA.GEN_AI_AGENT_NAME] == graph_name - else: - assert invoke_span["description"] == "invoke_agent" - assert SPANDATA.GEN_AI_PIPELINE_NAME not in invoke_span.get("data", {}) - assert SPANDATA.GEN_AI_AGENT_NAME not in invoke_span.get("data", {}) - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) -def test_pregel_invoke_span_includes_usage_data( - sentry_init, - capture_events, - capture_items, - stream_gen_ai_spans, - span_streaming, -): - """ - Test that invoke_agent spans include aggregated usage data from context_wrapper. - This verifies the new functionality added to track token usage in invoke_agent spans. - """ - sentry_init( - integrations=[LanggraphIntegration()], - traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", - ) - - test_state = { - "messages": [ - MockMessage("Hello, can you help me?", name="user"), - MockMessage("Of course! How can I assist you?", name="assistant"), - ] - } + items = capture_items("span") - pregel = MockPregelInstance("test_graph") + with pytest.raises(Exception, match="Graph execution failed"): + wrapped_invoke = _wrap_pregel_invoke(original_invoke) + wrapped_invoke(pregel, test_state) - expected_assistant_response = "I'll help you with that task!" - expected_tool_calls = [ - { - "id": "call_test_123", - "type": "function", - "function": {"name": "search_tool", "arguments": '{"query": "help"}'}, - } + sentry_sdk.flush() + spans = [item.payload for item in items] + invoke_spans = [ + span + for span in spans + if span["attributes"]["sentry.op"] == OP.GEN_AI_INVOKE_AGENT ] + assert len(invoke_spans) == 1 - def original_invoke(self, *args, **kwargs): - input_messages = args[0].get("messages", []) - new_messages = input_messages + [ - MockMessage( - content=expected_assistant_response, - name="assistant", - tool_calls=expected_tool_calls, - response_metadata={ - "token_usage": { - "total_tokens": 30, - "prompt_tokens": 10, - "completion_tokens": 20, - }, - "model_name": "gpt-4.1-2025-04-14", - }, - ) - ] - return {"messages": new_messages} - - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with start_transaction(): - wrapped_invoke = _wrap_pregel_invoke(original_invoke) - result = wrapped_invoke(pregel, test_state) - - assert result is not None - - sentry_sdk.flush() - spans = [item.payload for item in items] - invoke_spans = [ - span - for span in spans - if span["attributes"]["sentry.op"] == OP.GEN_AI_INVOKE_AGENT - ] - assert len(invoke_spans) == 1 - - invoke_agent_span = invoke_spans[0] + invoke_span = invoke_spans[0] + assert invoke_span.get("status") == "error" - # Verify invoke_agent span has usage data - assert invoke_agent_span["name"] == "invoke_agent test_graph" - assert "gen_ai.usage.input_tokens" in invoke_agent_span["attributes"] - assert "gen_ai.usage.output_tokens" in invoke_agent_span["attributes"] - assert "gen_ai.usage.total_tokens" in invoke_agent_span["attributes"] - # The usage should match the mock_usage values (aggregated across all calls) - assert invoke_agent_span["attributes"]["gen_ai.usage.input_tokens"] == 10 - assert invoke_agent_span["attributes"]["gen_ai.usage.output_tokens"] == 20 - assert invoke_agent_span["attributes"]["gen_ai.usage.total_tokens"] == 30 - else: - events = capture_events() - - with start_transaction(): - wrapped_invoke = _wrap_pregel_invoke(original_invoke) - result = wrapped_invoke(pregel, test_state) - - assert result is not None - - tx = events[0] - assert tx["type"] == "transaction" - - invoke_spans = [ - span for span in tx["spans"] if span["op"] == OP.GEN_AI_INVOKE_AGENT - ] - assert len(invoke_spans) == 1 - - invoke_agent_span = invoke_spans[0] - - # Verify invoke_agent span has usage data - assert invoke_agent_span["description"] == "invoke_agent test_graph" - assert "gen_ai.usage.input_tokens" in invoke_agent_span["data"] - assert "gen_ai.usage.output_tokens" in invoke_agent_span["data"] - assert "gen_ai.usage.total_tokens" in invoke_agent_span["data"] - - # The usage should match the mock_usage values (aggregated across all calls) - assert invoke_agent_span["data"]["gen_ai.usage.input_tokens"] == 10 - assert invoke_agent_span["data"]["gen_ai.usage.output_tokens"] == 20 - assert invoke_agent_span["data"]["gen_ai.usage.total_tokens"] == 30 - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) -def test_pregel_ainvoke_span_includes_usage_data( - sentry_init, - capture_events, - capture_items, - stream_gen_ai_spans, - span_streaming, -): - """ - Test that invoke_agent spans include aggregated usage data from context_wrapper. - This verifies the new functionality added to track token usage in invoke_agent spans. - """ - sentry_init( - integrations=[LanggraphIntegration()], - traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", - ) - - test_state = { - "messages": [ - MockMessage("Hello, can you help me?", name="user"), - MockMessage("Of course! How can I assist you?", name="assistant"), - ] - } - - pregel = MockPregelInstance("test_graph") - - expected_assistant_response = "I'll help you with that task!" - expected_tool_calls = [ - { - "id": "call_test_123", - "type": "function", - "function": {"name": "search_tool", "arguments": '{"query": "help"}'}, - } - ] - - async def original_ainvoke(self, *args, **kwargs): - input_messages = args[0].get("messages", []) - new_messages = input_messages + [ - MockMessage( - content=expected_assistant_response, - name="assistant", - tool_calls=expected_tool_calls, - response_metadata={ - "token_usage": { - "total_tokens": 30, - "prompt_tokens": 10, - "completion_tokens": 20, - }, - "model_name": "gpt-4.1-2025-04-14", - }, - ) - ] - return {"messages": new_messages} - - async def run_test(): - with start_transaction(): - wrapped_ainvoke = _wrap_pregel_ainvoke(original_ainvoke) - result = await wrapped_ainvoke(pregel, test_state) - return result - - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - result = asyncio.run(run_test()) - assert result is not None - - sentry_sdk.flush() - spans = [item.payload for item in items] - invoke_spans = [ - span - for span in spans - if span["attributes"]["sentry.op"] == OP.GEN_AI_INVOKE_AGENT - ] - assert len(invoke_spans) == 1 - - invoke_agent_span = invoke_spans[0] - - # Verify invoke_agent span has usage data - assert invoke_agent_span["name"] == "invoke_agent test_graph" - assert "gen_ai.usage.input_tokens" in invoke_agent_span["attributes"] - assert "gen_ai.usage.output_tokens" in invoke_agent_span["attributes"] - assert "gen_ai.usage.total_tokens" in invoke_agent_span["attributes"] - - # The usage should match the mock_usage values (aggregated across all calls) - assert invoke_agent_span["attributes"]["gen_ai.usage.input_tokens"] == 10 - assert invoke_agent_span["attributes"]["gen_ai.usage.output_tokens"] == 20 - assert invoke_agent_span["attributes"]["gen_ai.usage.total_tokens"] == 30 - else: - events = capture_events() - - result = asyncio.run(run_test()) - assert result is not None - - tx = events[0] - assert tx["type"] == "transaction" - - invoke_spans = [ - span for span in tx["spans"] if span["op"] == OP.GEN_AI_INVOKE_AGENT - ] - assert len(invoke_spans) == 1 - - invoke_agent_span = invoke_spans[0] - - # Verify invoke_agent span has usage data - assert invoke_agent_span["description"] == "invoke_agent test_graph" - assert "gen_ai.usage.input_tokens" in invoke_agent_span["data"] - assert "gen_ai.usage.output_tokens" in invoke_agent_span["data"] - assert "gen_ai.usage.total_tokens" in invoke_agent_span["data"] - - # The usage should match the mock_usage values (aggregated across all calls) - assert invoke_agent_span["data"]["gen_ai.usage.input_tokens"] == 10 - assert invoke_agent_span["data"]["gen_ai.usage.output_tokens"] == 20 - assert invoke_agent_span["data"]["gen_ai.usage.total_tokens"] == 30 - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) -def test_pregel_invoke_multiple_llm_calls_aggregate_usage( - sentry_init, - capture_events, - capture_items, - stream_gen_ai_spans, - span_streaming, -): - """ - Test that invoke_agent spans show aggregated usage across multiple LLM calls - (e.g., when tools are used and multiple API calls are made). - """ - sentry_init( - integrations=[LanggraphIntegration()], - traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", - ) - - test_state = { - "messages": [ - MockMessage("Hello, can you help me?", name="user"), - MockMessage("Of course! How can I assist you?", name="assistant"), - ] - } - - pregel = MockPregelInstance("test_graph") - - expected_assistant_response = "I'll help you with that task!" - expected_tool_calls = [ - { - "id": "call_test_123", - "type": "function", - "function": {"name": "search_tool", "arguments": '{"query": "help"}'}, - } - ] - - def original_invoke(self, *args, **kwargs): - input_messages = args[0].get("messages", []) - new_messages = input_messages + [ - MockMessage( - content=expected_assistant_response, - name="assistant", - tool_calls=expected_tool_calls, - response_metadata={ - "token_usage": { - "total_tokens": 15, - "prompt_tokens": 10, - "completion_tokens": 5, - }, - }, - ), - MockMessage( - content=expected_assistant_response, - name="assistant", - tool_calls=expected_tool_calls, - response_metadata={ - "token_usage": { - "total_tokens": 35, - "prompt_tokens": 20, - "completion_tokens": 15, - }, - }, - ), - ] - return {"messages": new_messages} - - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with start_transaction(): - wrapped_invoke = _wrap_pregel_invoke(original_invoke) - result = wrapped_invoke(pregel, test_state) - - assert result is not None - - sentry_sdk.flush() - spans = [item.payload for item in items] - invoke_spans = [ - span - for span in spans - if span["attributes"]["sentry.op"] == OP.GEN_AI_INVOKE_AGENT - ] - assert len(invoke_spans) == 1 - invoke_agent_span = invoke_spans[0] - - # Verify invoke_agent span has aggregated usage from both API calls - # Total: 10 + 20 = 30 input tokens, 5 + 15 = 20 output tokens, 15 + 35 = 50 total - assert invoke_agent_span["attributes"]["gen_ai.usage.input_tokens"] == 30 - assert invoke_agent_span["attributes"]["gen_ai.usage.output_tokens"] == 20 - assert invoke_agent_span["attributes"]["gen_ai.usage.total_tokens"] == 50 - else: - events = capture_events() - - with start_transaction(): - wrapped_invoke = _wrap_pregel_invoke(original_invoke) - result = wrapped_invoke(pregel, test_state) - - assert result is not None - - tx = events[0] - assert tx["type"] == "transaction" - - invoke_spans = [ - span for span in tx["spans"] if span["op"] == OP.GEN_AI_INVOKE_AGENT - ] - assert len(invoke_spans) == 1 - invoke_agent_span = invoke_spans[0] - - # Verify invoke_agent span has aggregated usage from both API calls - # Total: 10 + 20 = 30 input tokens, 5 + 15 = 20 output tokens, 15 + 35 = 50 total - assert invoke_agent_span["data"]["gen_ai.usage.input_tokens"] == 30 - assert invoke_agent_span["data"]["gen_ai.usage.output_tokens"] == 20 - assert invoke_agent_span["data"]["gen_ai.usage.total_tokens"] == 50 - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) -def test_pregel_ainvoke_multiple_llm_calls_aggregate_usage( - sentry_init, - capture_events, - capture_items, - stream_gen_ai_spans, - span_streaming, -): - """ - Test that invoke_agent spans show aggregated usage across multiple LLM calls - (e.g., when tools are used and multiple API calls are made). - """ - sentry_init( - integrations=[LanggraphIntegration()], - traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", - ) - - test_state = { - "messages": [ - MockMessage("Hello, can you help me?", name="user"), - MockMessage("Of course! How can I assist you?", name="assistant"), - ] - } - - pregel = MockPregelInstance("test_graph") - - expected_assistant_response = "I'll help you with that task!" - expected_tool_calls = [ - { - "id": "call_test_123", - "type": "function", - "function": {"name": "search_tool", "arguments": '{"query": "help"}'}, - } - ] - - async def original_ainvoke(self, *args, **kwargs): - input_messages = args[0].get("messages", []) - new_messages = input_messages + [ - MockMessage( - content=expected_assistant_response, - name="assistant", - tool_calls=expected_tool_calls, - response_metadata={ - "token_usage": { - "total_tokens": 15, - "prompt_tokens": 10, - "completion_tokens": 5, - }, - }, - ), - MockMessage( - content=expected_assistant_response, - name="assistant", - tool_calls=expected_tool_calls, - response_metadata={ - "token_usage": { - "total_tokens": 35, - "prompt_tokens": 20, - "completion_tokens": 15, - }, - }, - ), - ] - return {"messages": new_messages} - - async def run_test(): - with start_transaction(): - wrapped_ainvoke = _wrap_pregel_ainvoke(original_ainvoke) - result = await wrapped_ainvoke(pregel, test_state) - return result - - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - result = asyncio.run(run_test()) - assert result is not None - - sentry_sdk.flush() - spans = [item.payload for item in items] - invoke_spans = [ - span - for span in spans - if span["attributes"]["sentry.op"] == OP.GEN_AI_INVOKE_AGENT - ] - assert len(invoke_spans) == 1 - invoke_agent_span = invoke_spans[0] - - # Verify invoke_agent span has aggregated usage from both API calls - # Total: 10 + 20 = 30 input tokens, 5 + 15 = 20 output tokens, 15 + 35 = 50 total - assert invoke_agent_span["attributes"]["gen_ai.usage.input_tokens"] == 30 - assert invoke_agent_span["attributes"]["gen_ai.usage.output_tokens"] == 20 - assert invoke_agent_span["attributes"]["gen_ai.usage.total_tokens"] == 50 - else: - events = capture_events() - - result = asyncio.run(run_test()) - assert result is not None - - tx = events[0] - assert tx["type"] == "transaction" - - invoke_spans = [ - span for span in tx["spans"] if span["op"] == OP.GEN_AI_INVOKE_AGENT - ] - assert len(invoke_spans) == 1 - invoke_agent_span = invoke_spans[0] - - # Verify invoke_agent span has aggregated usage from both API calls - # Total: 10 + 20 = 30 input tokens, 5 + 15 = 20 output tokens, 15 + 35 = 50 total - assert invoke_agent_span["data"]["gen_ai.usage.input_tokens"] == 30 - assert invoke_agent_span["data"]["gen_ai.usage.output_tokens"] == 20 - assert invoke_agent_span["data"]["gen_ai.usage.total_tokens"] == 50 - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) -def test_pregel_invoke_span_includes_response_model( - sentry_init, - capture_events, - capture_items, - stream_gen_ai_spans, - span_streaming, -): - """ - Test that invoke_agent spans include the response model. - When an agent makes multiple LLM calls, it should report the last model used. - """ - sentry_init( - integrations=[LanggraphIntegration()], - traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", - ) - - test_state = { - "messages": [ - MockMessage("Hello, can you help me?", name="user"), - MockMessage("Of course! How can I assist you?", name="assistant"), - ] - } - - pregel = MockPregelInstance("test_graph") - - expected_assistant_response = "I'll help you with that task!" - expected_tool_calls = [ - { - "id": "call_test_123", - "type": "function", - "function": {"name": "search_tool", "arguments": '{"query": "help"}'}, - } - ] - - def original_invoke(self, *args, **kwargs): - input_messages = args[0].get("messages", []) - new_messages = input_messages + [ - MockMessage( - content=expected_assistant_response, - name="assistant", - tool_calls=expected_tool_calls, - response_metadata={ - "token_usage": { - "total_tokens": 30, - "prompt_tokens": 10, - "completion_tokens": 20, - }, - "model_name": "gpt-4.1-2025-04-14", - }, - ) - ] - return {"messages": new_messages} - - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with start_transaction(): - wrapped_invoke = _wrap_pregel_invoke(original_invoke) - result = wrapped_invoke(pregel, test_state) - - assert result is not None - - sentry_sdk.flush() - spans = [item.payload for item in items] - invoke_spans = [ - span - for span in spans - if span["attributes"]["sentry.op"] == OP.GEN_AI_INVOKE_AGENT - ] - assert len(invoke_spans) == 1 - - invoke_agent_span = invoke_spans[0] - - # Verify invoke_agent span has response model - assert invoke_agent_span["name"] == "invoke_agent test_graph" - assert "gen_ai.response.model" in invoke_agent_span["attributes"] - assert ( - invoke_agent_span["attributes"]["gen_ai.response.model"] - == "gpt-4.1-2025-04-14" - ) - else: - events = capture_events() - - with start_transaction(): - wrapped_invoke = _wrap_pregel_invoke(original_invoke) - result = wrapped_invoke(pregel, test_state) - - assert result is not None - - tx = events[0] - assert tx["type"] == "transaction" - - invoke_spans = [ - span for span in tx["spans"] if span["op"] == OP.GEN_AI_INVOKE_AGENT - ] - assert len(invoke_spans) == 1 - - invoke_agent_span = invoke_spans[0] - - # Verify invoke_agent span has response model - assert invoke_agent_span["description"] == "invoke_agent test_graph" - assert "gen_ai.response.model" in invoke_agent_span["data"] - assert ( - invoke_agent_span["data"]["gen_ai.response.model"] == "gpt-4.1-2025-04-14" - ) - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) -def test_pregel_ainvoke_span_includes_response_model( - sentry_init, - capture_events, - capture_items, - stream_gen_ai_spans, - span_streaming, -): - """ - Test that invoke_agent spans include the response model. - When an agent makes multiple LLM calls, it should report the last model used. - """ - sentry_init( - integrations=[LanggraphIntegration()], - traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", - ) - - test_state = { - "messages": [ - MockMessage("Hello, can you help me?", name="user"), - MockMessage("Of course! How can I assist you?", name="assistant"), - ] - } - - pregel = MockPregelInstance("test_graph") - - expected_assistant_response = "I'll help you with that task!" - expected_tool_calls = [ - { - "id": "call_test_123", - "type": "function", - "function": {"name": "search_tool", "arguments": '{"query": "help"}'}, - } - ] - - async def original_ainvoke(self, *args, **kwargs): - input_messages = args[0].get("messages", []) - new_messages = input_messages + [ - MockMessage( - content=expected_assistant_response, - name="assistant", - tool_calls=expected_tool_calls, - response_metadata={ - "token_usage": { - "total_tokens": 30, - "prompt_tokens": 10, - "completion_tokens": 20, - }, - "model_name": "gpt-4.1-2025-04-14", - }, - ) - ] - return {"messages": new_messages} - - async def run_test(): - with start_transaction(): - wrapped_ainvoke = _wrap_pregel_ainvoke(original_ainvoke) - result = await wrapped_ainvoke(pregel, test_state) - return result - - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - result = asyncio.run(run_test()) - assert result is not None - - sentry_sdk.flush() - spans = [item.payload for item in items] - invoke_spans = [ - span - for span in spans - if span["attributes"]["sentry.op"] == OP.GEN_AI_INVOKE_AGENT - ] - assert len(invoke_spans) == 1 - - invoke_agent_span = invoke_spans[0] - - # Verify invoke_agent span has response model - assert invoke_agent_span["name"] == "invoke_agent test_graph" - assert "gen_ai.response.model" in invoke_agent_span["attributes"] - assert ( - invoke_agent_span["attributes"]["gen_ai.response.model"] - == "gpt-4.1-2025-04-14" - ) - else: - events = capture_events() - - result = asyncio.run(run_test()) - assert result is not None - - tx = events[0] - assert tx["type"] == "transaction" - - invoke_spans = [ - span for span in tx["spans"] if span["op"] == OP.GEN_AI_INVOKE_AGENT - ] - assert len(invoke_spans) == 1 - - invoke_agent_span = invoke_spans[0] - - # Verify invoke_agent span has response model - assert invoke_agent_span["description"] == "invoke_agent test_graph" - assert "gen_ai.response.model" in invoke_agent_span["data"] - assert ( - invoke_agent_span["data"]["gen_ai.response.model"] == "gpt-4.1-2025-04-14" - ) - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) -def test_pregel_invoke_span_uses_last_response_model( - sentry_init, - capture_events, - capture_items, - stream_gen_ai_spans, - span_streaming, -): - """ - Test that when an agent makes multiple LLM calls (e.g., with tools), - the invoke_agent span reports the last response model used. - """ - sentry_init( - integrations=[LanggraphIntegration()], - traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", - ) - - test_state = { - "messages": [ - MockMessage("Hello, can you help me?", name="user"), - MockMessage("Of course! How can I assist you?", name="assistant"), - ] - } - - pregel = MockPregelInstance("test_graph") - - expected_assistant_response = "I'll help you with that task!" - expected_tool_calls = [ - { - "id": "call_test_123", - "type": "function", - "function": {"name": "search_tool", "arguments": '{"query": "help"}'}, - } - ] - - def original_invoke(self, *args, **kwargs): - input_messages = args[0].get("messages", []) - new_messages = input_messages + [ - MockMessage( - content=expected_assistant_response, - name="assistant", - tool_calls=expected_tool_calls, - response_metadata={ - "token_usage": { - "total_tokens": 15, - "prompt_tokens": 10, - "completion_tokens": 5, - }, - "model_name": "gpt-4-0613", - }, - ), - MockMessage( - content=expected_assistant_response, - name="assistant", - tool_calls=expected_tool_calls, - response_metadata={ - "token_usage": { - "total_tokens": 35, - "prompt_tokens": 20, - "completion_tokens": 15, - }, - "model_name": "gpt-4.1-2025-04-14", - }, - ), - ] - return {"messages": new_messages} - - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with start_transaction(): - wrapped_invoke = _wrap_pregel_invoke(original_invoke) - result = wrapped_invoke(pregel, test_state) - - assert result is not None - - sentry_sdk.flush() - spans = [item.payload for item in items] - invoke_spans = [ - span - for span in spans - if span["attributes"]["sentry.op"] == OP.GEN_AI_INVOKE_AGENT - ] - assert len(invoke_spans) == 1 - - invoke_agent_span = invoke_spans[0] - - # Verify invoke_agent span uses the LAST response model - assert "gen_ai.response.model" in invoke_agent_span["attributes"] - assert ( - invoke_agent_span["attributes"]["gen_ai.response.model"] - == "gpt-4.1-2025-04-14" - ) - else: - events = capture_events() - - with start_transaction(): - wrapped_invoke = _wrap_pregel_invoke(original_invoke) - result = wrapped_invoke(pregel, test_state) - - assert result is not None - - tx = events[0] - assert tx["type"] == "transaction" - - invoke_spans = [ - span for span in tx["spans"] if span["op"] == OP.GEN_AI_INVOKE_AGENT - ] - assert len(invoke_spans) == 1 - - invoke_agent_span = invoke_spans[0] - - # Verify invoke_agent span uses the LAST response model - assert "gen_ai.response.model" in invoke_agent_span["data"] - assert ( - invoke_agent_span["data"]["gen_ai.response.model"] == "gpt-4.1-2025-04-14" - ) - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) -def test_pregel_ainvoke_span_uses_last_response_model( - sentry_init, - capture_events, - capture_items, - stream_gen_ai_spans, - span_streaming, -): - """ - Test that when an agent makes multiple LLM calls (e.g., with tools), - the invoke_agent span reports the last response model used. - """ - sentry_init( - integrations=[LanggraphIntegration()], - traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", - ) - - test_state = { - "messages": [ - MockMessage("Hello, can you help me?", name="user"), - MockMessage("Of course! How can I assist you?", name="assistant"), - ] - } - - pregel = MockPregelInstance("test_graph") - - expected_assistant_response = "I'll help you with that task!" - expected_tool_calls = [ - { - "id": "call_test_123", - "type": "function", - "function": {"name": "search_tool", "arguments": '{"query": "help"}'}, - } - ] - - async def original_ainvoke(self, *args, **kwargs): - input_messages = args[0].get("messages", []) - new_messages = input_messages + [ - MockMessage( - content=expected_assistant_response, - name="assistant", - tool_calls=expected_tool_calls, - response_metadata={ - "token_usage": { - "total_tokens": 15, - "prompt_tokens": 10, - "completion_tokens": 5, - }, - "model_name": "gpt-4-0613", - }, - ), - MockMessage( - content=expected_assistant_response, - name="assistant", - tool_calls=expected_tool_calls, - response_metadata={ - "token_usage": { - "total_tokens": 35, - "prompt_tokens": 20, - "completion_tokens": 15, - }, - "model_name": "gpt-4.1-2025-04-14", - }, - ), - ] - return {"messages": new_messages} +def test_pregel_ainvoke_error( + sentry_init, + capture_items, +): + """Test error handling during async graph execution.""" + sentry_init( + integrations=[LanggraphIntegration()], + traces_sample_rate=1.0, + send_default_pii=True, + ) - async def run_test(): - with start_transaction(): + test_state = {"messages": [MockMessage("This will fail async")]} + pregel = MockPregelInstance("async_error_graph") + + async def original_ainvoke(self, *args, **kwargs): + raise Exception("Async graph execution failed") + + async def run_error_test(): + with pytest.raises(Exception, match="Async graph execution failed"): wrapped_ainvoke = _wrap_pregel_ainvoke(original_ainvoke) - result = await wrapped_ainvoke(pregel, test_state) - return result + await wrapped_ainvoke(pregel, test_state) - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") + items = capture_items("span") - result = asyncio.run(run_test()) - assert result is not None + asyncio.run(run_error_test()) - sentry_sdk.flush() - spans = [item.payload for item in items] - invoke_spans = [ - span - for span in spans - if span["attributes"]["sentry.op"] == OP.GEN_AI_INVOKE_AGENT - ] - assert len(invoke_spans) == 1 + sentry_sdk.flush() + spans = [item.payload for item in items] + invoke_spans = [ + span + for span in spans + if span["attributes"]["sentry.op"] == OP.GEN_AI_INVOKE_AGENT + ] + assert len(invoke_spans) == 1 + + invoke_span = invoke_spans[0] + assert invoke_span.get("status") == "error" - invoke_agent_span = invoke_spans[0] - # Verify invoke_agent span uses the LAST response model - assert "gen_ai.response.model" in invoke_agent_span["attributes"] - assert ( - invoke_agent_span["attributes"]["gen_ai.response.model"] - == "gpt-4.1-2025-04-14" - ) - else: - events = capture_events() +@pytest.mark.parametrize("graph_name", ["my_graph", None, ""]) +def test_pregel_invoke_with_different_graph_names( + sentry_init, + capture_items, + graph_name, +): + """Test Pregel.invoke() with different graph name scenarios.""" + sentry_init( + integrations=[LanggraphIntegration()], + traces_sample_rate=1.0, + send_default_pii=True, + ) - result = asyncio.run(run_test()) - assert result is not None + pregel = MockPregelInstance(graph_name) if graph_name else MockPregelInstance() + if not graph_name: + delattr(pregel, "name") + delattr(pregel, "graph_name") - tx = events[0] - assert tx["type"] == "transaction" + def original_invoke(self, *args, **kwargs): + return {"result": "test"} - invoke_spans = [ - span for span in tx["spans"] if span["op"] == OP.GEN_AI_INVOKE_AGENT - ] - assert len(invoke_spans) == 1 + items = capture_items("span") - invoke_agent_span = invoke_spans[0] + wrapped_invoke = _wrap_pregel_invoke(original_invoke) + wrapped_invoke(pregel, {"messages": []}) - # Verify invoke_agent span uses the LAST response model - assert "gen_ai.response.model" in invoke_agent_span["data"] - assert ( - invoke_agent_span["data"]["gen_ai.response.model"] == "gpt-4.1-2025-04-14" - ) + sentry_sdk.flush() + spans = [item.payload for item in items] + invoke_spans = [ + span + for span in spans + if span["attributes"]["sentry.op"] == OP.GEN_AI_INVOKE_AGENT + ] + assert len(invoke_spans) == 1 + + invoke_span = invoke_spans[0] + + if graph_name and graph_name.strip(): + assert invoke_span["name"] == "invoke_agent my_graph" + assert invoke_span["attributes"][SPANDATA.GEN_AI_PIPELINE_NAME] == graph_name + assert invoke_span["attributes"][SPANDATA.GEN_AI_AGENT_NAME] == graph_name + else: + assert invoke_span["name"] == "invoke_agent" + assert SPANDATA.GEN_AI_PIPELINE_NAME not in invoke_span.get("attributes", {}) + assert SPANDATA.GEN_AI_AGENT_NAME not in invoke_span.get("attributes", {}) def test_complex_message_parsing(): @@ -1831,22 +495,15 @@ def test_complex_message_parsing(): assert result[2]["function_call"]["name"] == "search" -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_extraction_functions_complex_scenario( sentry_init, - capture_events, capture_items, - stream_gen_ai_spans, - span_streaming, ): """Test extraction functions with complex scenarios including multiple messages and edge cases.""" sentry_init( - integrations=[LanggraphIntegration(include_prompts=True)], + integrations=[LanggraphIntegration()], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) pregel = MockPregelInstance("complex_graph") @@ -1882,55 +539,30 @@ def original_invoke(self, *args, **kwargs): ] return {"messages": new_messages} - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with start_transaction(): - wrapped_invoke = _wrap_pregel_invoke(original_invoke) - result = wrapped_invoke(pregel, test_state) - - assert result is not None - - sentry_sdk.flush() - spans = [item.payload for item in items] - invoke_spans = [ - span - for span in spans - if span["attributes"]["sentry.op"] == OP.GEN_AI_INVOKE_AGENT - ] - assert len(invoke_spans) == 1 - - invoke_span = invoke_spans[0] - assert SPANDATA.GEN_AI_RESPONSE_TEXT in invoke_span["attributes"] - response_text = invoke_span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] - assert response_text == "Final response" - - assert SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS in invoke_span["attributes"] - - tool_calls_data = invoke_span["attributes"][SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS] - else: - events = capture_events() + items = capture_items("span") - with start_transaction(): - wrapped_invoke = _wrap_pregel_invoke(original_invoke) - result = wrapped_invoke(pregel, test_state) + wrapped_invoke = _wrap_pregel_invoke(original_invoke) + result = wrapped_invoke(pregel, test_state) - assert result is not None + assert result is not None - tx = events[0] - invoke_spans = [ - span for span in tx["spans"] if span["op"] == OP.GEN_AI_INVOKE_AGENT - ] - assert len(invoke_spans) == 1 + sentry_sdk.flush() + spans = [item.payload for item in items] + invoke_spans = [ + span + for span in spans + if span["attributes"]["sentry.op"] == OP.GEN_AI_INVOKE_AGENT + ] + assert len(invoke_spans) == 1 - invoke_span = invoke_spans[0] - assert SPANDATA.GEN_AI_RESPONSE_TEXT in invoke_span["data"] - response_text = invoke_span["data"][SPANDATA.GEN_AI_RESPONSE_TEXT] - assert response_text == "Final response" + invoke_span = invoke_spans[0] + assert SPANDATA.GEN_AI_RESPONSE_TEXT in invoke_span["attributes"] + response_text = invoke_span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] + assert response_text == "Final response" - assert SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS in invoke_span["data"] + assert SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS in invoke_span["attributes"] - tool_calls_data = invoke_span["data"][SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS] + tool_calls_data = invoke_span["attributes"][SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS] if isinstance(tool_calls_data, str): tool_calls_data = json.loads(tool_calls_data) @@ -1942,22 +574,15 @@ def original_invoke(self, *args, **kwargs): assert tool_calls_data[1]["function"]["name"] == "calculate" -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_langgraph_message_role_mapping( sentry_init, - capture_events, capture_items, - stream_gen_ai_spans, - span_streaming, ): """Test that Langgraph integration properly maps message roles like 'ai' to 'assistant'""" sentry_init( - integrations=[LanggraphIntegration(include_prompts=True)], + integrations=[LanggraphIntegration()], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) # Mock a langgraph message with mixed roles @@ -1978,51 +603,25 @@ def __init__(self, content, message_type="human"): compiled_graph = MockCompiledGraph("test_graph") pregel = MockPregelInstance(compiled_graph) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with start_transaction(name="langgraph tx"): - # Use the wrapped invoke function directly - from sentry_sdk.integrations.langgraph import _wrap_pregel_invoke - - wrapped_invoke = _wrap_pregel_invoke( - lambda self, state_data: {"result": "success"} - ) - wrapped_invoke(pregel, state_data) - - sentry_sdk.flush() - span = next(item.payload for item in items) + # Use the wrapped invoke function directly + from sentry_sdk.integrations.langgraph import _wrap_pregel_invoke - # Verify that the span was created correctly - assert span["attributes"]["sentry.op"] == "gen_ai.invoke_agent" + wrapped_invoke = _wrap_pregel_invoke(lambda self, state_data: {"result": "success"}) + wrapped_invoke(pregel, state_data) - # If messages were captured, verify role mapping - if SPANDATA.GEN_AI_REQUEST_MESSAGES in span["attributes"]: - stored_messages = json.loads( - span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - ) - else: - events = capture_events() - - with start_transaction(name="langgraph tx"): - # Use the wrapped invoke function directly - from sentry_sdk.integrations.langgraph import _wrap_pregel_invoke - - wrapped_invoke = _wrap_pregel_invoke( - lambda self, state_data: {"result": "success"} - ) - wrapped_invoke(pregel, state_data) - - (event,) = events - span = event["spans"][0] + sentry_sdk.flush() + span = next(item.payload for item in items) - # Verify that the span was created correctly - assert span["op"] == "gen_ai.invoke_agent" + # Verify that the span was created correctly + assert span["attributes"]["sentry.op"] == "gen_ai.invoke_agent" - # If messages were captured, verify role mapping - if SPANDATA.GEN_AI_REQUEST_MESSAGES in span["data"]: - stored_messages = json.loads(span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) + # If messages were captured, verify role mapping + if SPANDATA.GEN_AI_REQUEST_MESSAGES in span["attributes"]: + stored_messages = json.loads( + span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] + ) # Find messages with specific content to verify role mapping ai_message = next( @@ -2046,62 +645,6 @@ def __init__(self, content, message_type="human"): assert "ai" not in roles -def test_langgraph_message_truncation(sentry_init, capture_events): - """Test that large messages are truncated properly in Langgraph integration.""" - - sentry_init( - integrations=[LanggraphIntegration(include_prompts=True)], - traces_sample_rate=1.0, - send_default_pii=True, - stream_gen_ai_spans=False, - ) - events = capture_events() - - large_content = ( - "This is a very long message that will exceed our size limits. " * 1000 - ) - test_state = { - "messages": [ - MockMessage("small message 1", name="user"), - MockMessage(large_content, name="assistant"), - MockMessage(large_content, name="user"), - MockMessage("small message 4", name="assistant"), - MockMessage("small message 5", name="user"), - ] - } - - pregel = MockPregelInstance("test_graph") - - def original_invoke(self, *args, **kwargs): - return {"messages": args[0].get("messages", [])} - - with start_transaction(): - wrapped_invoke = _wrap_pregel_invoke(original_invoke) - result = wrapped_invoke(pregel, test_state) - - assert result is not None - assert len(events) > 0 - tx = events[0] - assert tx["type"] == "transaction" - - invoke_spans = [ - span for span in tx.get("spans", []) if span.get("op") == OP.GEN_AI_INVOKE_AGENT - ] - assert len(invoke_spans) > 0 - - invoke_span = invoke_spans[0] - assert SPANDATA.GEN_AI_REQUEST_MESSAGES in invoke_span["data"] - - messages_data = invoke_span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - assert isinstance(messages_data, str) - - parsed_messages = json.loads(messages_data) - assert isinstance(parsed_messages, list) - assert len(parsed_messages) == 1 - assert "small message 5" in str(parsed_messages[0]) - assert tx["_meta"]["spans"]["0"]["data"]["gen_ai.request.messages"][""]["len"] == 5 - - def test_graph_bubble_up_ignored(sentry_init, capture_items): sentry_init( integrations=[LanggraphIntegration()], @@ -2116,27 +659,18 @@ def test_graph_bubble_up_ignored(sentry_init, capture_items): assert len(events) == 0 -def _invoke_span_data(items_or_events, span_streaming): - if span_streaming: - sentry_sdk.flush() - spans = [item.payload for item in items_or_events] - invoke_spans = [ - span - for span in spans - if span["attributes"]["sentry.op"] == OP.GEN_AI_INVOKE_AGENT - ] - assert len(invoke_spans) == 1 - return invoke_spans[0]["attributes"] - - tx = items_or_events[0] +def _invoke_span_data(items_or_events): + sentry_sdk.flush() + spans = [item.payload for item in items_or_events] invoke_spans = [ - span for span in tx["spans"] if span["op"] == OP.GEN_AI_INVOKE_AGENT + span + for span in spans + if span["attributes"]["sentry.op"] == OP.GEN_AI_INVOKE_AGENT ] assert len(invoke_spans) == 1 - return invoke_spans[0]["data"] + return invoke_spans[0]["attributes"] -@pytest.mark.parametrize("span_streaming", [True, False]) @pytest.mark.parametrize( "data_collection, send_default_pii, expect_inputs", [ @@ -2180,19 +714,15 @@ def _invoke_span_data(items_or_events, span_streaming): ) def test_pregel_invoke_gates_request_messages_on_inputs_setting( sentry_init, - capture_events, capture_items, data_collection, send_default_pii, expect_inputs, - span_streaming, ): init_kwargs = { "integrations": [LanggraphIntegration()], "traces_sample_rate": 1.0, "send_default_pii": send_default_pii, - "stream_gen_ai_spans": span_streaming, - "trace_lifecycle": "stream" if span_streaming else "static", } if data_collection is not None: init_kwargs["data_collection"] = data_collection @@ -2213,13 +743,12 @@ def original_invoke(self, *args, **kwargs): ] } - captured = capture_items("span") if span_streaming else capture_events() + captured = capture_items("span") - with start_transaction(): - wrapped_invoke = _wrap_pregel_invoke(original_invoke) - wrapped_invoke(pregel, test_state) + wrapped_invoke = _wrap_pregel_invoke(original_invoke) + wrapped_invoke(pregel, test_state) - data = _invoke_span_data(captured, span_streaming) + data = _invoke_span_data(captured) if expect_inputs: assert SPANDATA.GEN_AI_REQUEST_MESSAGES in data @@ -2227,7 +756,6 @@ def original_invoke(self, *args, **kwargs): assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in data -@pytest.mark.parametrize("span_streaming", [True, False]) @pytest.mark.parametrize( "data_collection, send_default_pii, expect_outputs", [ @@ -2271,19 +799,15 @@ def original_invoke(self, *args, **kwargs): ) def test_pregel_invoke_gates_response_text_and_tool_calls_on_outputs_setting( sentry_init, - capture_events, capture_items, data_collection, send_default_pii, expect_outputs, - span_streaming, ): init_kwargs = { "integrations": [LanggraphIntegration()], "traces_sample_rate": 1.0, "send_default_pii": send_default_pii, - "stream_gen_ai_spans": span_streaming, - "trace_lifecycle": "stream" if span_streaming else "static", } if data_collection is not None: init_kwargs["data_collection"] = data_collection @@ -2313,13 +837,12 @@ def original_invoke(self, *args, **kwargs): ] } - captured = capture_items("span") if span_streaming else capture_events() + captured = capture_items("span") - with start_transaction(): - wrapped_invoke = _wrap_pregel_invoke(original_invoke) - wrapped_invoke(pregel, test_state) + wrapped_invoke = _wrap_pregel_invoke(original_invoke) + wrapped_invoke(pregel, test_state) - data = _invoke_span_data(captured, span_streaming) + data = _invoke_span_data(captured) if expect_outputs: assert data[SPANDATA.GEN_AI_RESPONSE_TEXT] == expected_assistant_response @@ -2331,7 +854,6 @@ def original_invoke(self, *args, **kwargs): assert SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS not in data -@pytest.mark.parametrize("span_streaming", [True, False]) @pytest.mark.parametrize( "data_collection, send_default_pii, expect_inputs, expect_outputs", [ @@ -2367,20 +889,16 @@ def original_invoke(self, *args, **kwargs): ) def test_pregel_ainvoke_gates_inputs_and_outputs_independently( sentry_init, - capture_events, capture_items, data_collection, send_default_pii, expect_inputs, expect_outputs, - span_streaming, ): init_kwargs = { "integrations": [LanggraphIntegration()], "traces_sample_rate": 1.0, "send_default_pii": send_default_pii, - "stream_gen_ai_spans": span_streaming, - "trace_lifecycle": "stream" if span_streaming else "static", } if data_collection is not None: init_kwargs["data_collection"] = data_collection @@ -2411,15 +929,14 @@ async def original_ainvoke(self, *args, **kwargs): } async def run_test(): - with start_transaction(): - wrapped_ainvoke = _wrap_pregel_ainvoke(original_ainvoke) - return await wrapped_ainvoke(pregel, test_state) + wrapped_ainvoke = _wrap_pregel_ainvoke(original_ainvoke) + return await wrapped_ainvoke(pregel, test_state) - captured = capture_items("span") if span_streaming else capture_events() + captured = capture_items("span") asyncio.run(run_test()) - data = _invoke_span_data(captured, span_streaming) + data = _invoke_span_data(captured) if expect_inputs: assert SPANDATA.GEN_AI_REQUEST_MESSAGES in data @@ -2434,224 +951,3 @@ async def run_test(): else: assert SPANDATA.GEN_AI_RESPONSE_TEXT not in data assert SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS not in data - - -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_pregel_invoke_message_delta_ignores_gen_ai_inputs_setting( - sentry_init, - capture_events, - capture_items, - span_streaming, -): - sentry_init( - integrations=[LanggraphIntegration()], - traces_sample_rate=1.0, - stream_gen_ai_spans=span_streaming, - trace_lifecycle="stream" if span_streaming else "static", - data_collection={"gen_ai": {"inputs": False, "outputs": True}}, - ) - - prior_response = "Of course! How can I assist you?" - test_state = { - "messages": [ - MockMessage("Hello, can you help me?", name="user"), - MockMessage( - prior_response, - name="assistant", - response_metadata={ - "token_usage": { - "total_tokens": 300, - "prompt_tokens": 100, - "completion_tokens": 200, - }, - "model_name": "gpt-3.5-turbo", - }, - ), - ] - } - pregel = MockPregelInstance("test_graph") - expected_assistant_response = "I'll help you with that task!" - - def original_invoke(self, *args, **kwargs): - return { - "messages": args[0].get("messages", []) - + [ - MockMessage( - content=expected_assistant_response, - name="assistant", - response_metadata={ - "token_usage": { - "total_tokens": 30, - "prompt_tokens": 10, - "completion_tokens": 20, - }, - "model_name": "gpt-4.1-2025-04-14", - }, - ) - ] - } - - captured = capture_items("span") if span_streaming else capture_events() - - with start_transaction(): - wrapped_invoke = _wrap_pregel_invoke(original_invoke) - wrapped_invoke(pregel, test_state) - - data = _invoke_span_data(captured, span_streaming) - - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in data - assert data[SPANDATA.GEN_AI_RESPONSE_TEXT] == expected_assistant_response - assert prior_response not in data[SPANDATA.GEN_AI_RESPONSE_TEXT] - assert data[SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert data[SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 20 - assert data[SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 - assert data[SPANDATA.GEN_AI_RESPONSE_MODEL] == "gpt-4.1-2025-04-14" - - -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_pregel_ainvoke_message_delta_ignores_gen_ai_inputs_setting( - sentry_init, - capture_events, - capture_items, - span_streaming, -): - sentry_init( - integrations=[LanggraphIntegration()], - traces_sample_rate=1.0, - stream_gen_ai_spans=span_streaming, - trace_lifecycle="stream" if span_streaming else "static", - data_collection={"gen_ai": {"inputs": False, "outputs": True}}, - ) - - prior_response = "It is sunny in Berlin." - test_state = { - "messages": [ - MockMessage("What is the weather?", name="user"), - MockMessage( - prior_response, - name="assistant", - response_metadata={ - "token_usage": { - "total_tokens": 300, - "prompt_tokens": 100, - "completion_tokens": 200, - }, - "model_name": "gpt-3.5-turbo", - }, - ), - ] - } - pregel = MockPregelInstance("async_graph") - expected_assistant_response = "Let me check the weather for you!" - - async def original_ainvoke(self, *args, **kwargs): - return { - "messages": args[0].get("messages", []) - + [ - MockMessage( - content=expected_assistant_response, - name="assistant", - response_metadata={ - "token_usage": { - "total_tokens": 30, - "prompt_tokens": 10, - "completion_tokens": 20, - }, - "model_name": "gpt-4.1-2025-04-14", - }, - ) - ] - } - - async def run_test(): - with start_transaction(): - wrapped_ainvoke = _wrap_pregel_ainvoke(original_ainvoke) - return await wrapped_ainvoke(pregel, test_state) - - captured = capture_items("span") if span_streaming else capture_events() - - asyncio.run(run_test()) - - data = _invoke_span_data(captured, span_streaming) - - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in data - assert data[SPANDATA.GEN_AI_RESPONSE_TEXT] == expected_assistant_response - assert prior_response not in data[SPANDATA.GEN_AI_RESPONSE_TEXT] - assert data[SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert data[SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 20 - assert data[SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 - assert data[SPANDATA.GEN_AI_RESPONSE_MODEL] == "gpt-4.1-2025-04-14" - - -@pytest.mark.parametrize( - "data_collection, send_default_pii, expect_available_tools", - [ - pytest.param( - {"gen_ai": {"inputs": True}}, - False, - True, - id="gen-ai-inputs-enabled-overrides-pii-disabled", - ), - pytest.param( - {"gen_ai": {"inputs": False}}, - True, - False, - id="gen-ai-inputs-disabled-overrides-pii-enabled", - ), - pytest.param( - {}, - False, - True, - id="gen-ai-omitted-defaults-to-enabled", - ), - pytest.param( - None, - False, - True, - id="no-data-collection-collects-regardless-of-pii", - ), - ], -) -def test_state_graph_compile_gates_available_tools_only_when_data_collection_configured( - sentry_init, - capture_events, - data_collection, - send_default_pii, - expect_available_tools, -): - init_kwargs = { - "integrations": [LanggraphIntegration()], - "traces_sample_rate": 1.0, - "send_default_pii": send_default_pii, - "stream_gen_ai_spans": False, - } - if data_collection is not None: - init_kwargs["data_collection"] = data_collection - - sentry_init(**init_kwargs) - - graph = MockStateGraph() - - def original_compile(self, *args, **kwargs): - return MockCompiledGraph(self.name) - - events = capture_events() - - with patch("sentry_sdk.integrations.langgraph.StateGraph"), start_transaction(): - wrapped_compile = _wrap_state_graph_compile(original_compile) - wrapped_compile(graph, model="test-model", checkpointer=None) - - tx = events[0] - agent_spans = [span for span in tx["spans"] if span["op"] == OP.GEN_AI_CREATE_AGENT] - assert len(agent_spans) == 1 - data = agent_spans[0]["data"] - - if expect_available_tools: - assert data[SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS] == [ - "search_tool", - "calculator", - ] - else: - assert SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS not in data - - assert data[SPANDATA.GEN_AI_AGENT_NAME] == "test_graph" diff --git a/tests/integrations/launchdarkly/test_launchdarkly.py b/tests/integrations/launchdarkly/test_launchdarkly.py index 0c24ccc112..5a9048becc 100644 --- a/tests/integrations/launchdarkly/test_launchdarkly.py +++ b/tests/integrations/launchdarkly/test_launchdarkly.py @@ -1,43 +1,28 @@ import concurrent.futures as cf -import sys import ldclient import pytest -from ldclient import LDClient from ldclient.config import Config from ldclient.context import Context from ldclient.integrations.test_data import TestData import sentry_sdk -from sentry_sdk import start_span, start_transaction from sentry_sdk.integrations import DidNotEnable from sentry_sdk.integrations.launchdarkly import LaunchDarklyIntegration -from tests.conftest import ApproxDict -@pytest.mark.parametrize( - "use_global_client", - (False, True), -) -def test_launchdarkly_integration( - sentry_init, use_global_client, capture_events, uninstall_integration -): +def test_launchdarkly_integration(sentry_init, capture_events, uninstall_integration): td = TestData.data_source() td.update(td.flag("hello").variation_for_all(True)) td.update(td.flag("world").variation_for_all(True)) - # Disable background requests as we aren't using a server. config = Config( "sdk-key", update_processor_class=td, diagnostic_opt_out=True, send_events=False ) uninstall_integration(LaunchDarklyIntegration.identifier) - if use_global_client: - ldclient.set_config(config) - sentry_init(integrations=[LaunchDarklyIntegration()]) - client = ldclient.get() - else: - client = LDClient(config=config) - sentry_init(integrations=[LaunchDarklyIntegration(ld_client=client)]) + ldclient.set_config(config) + sentry_init(integrations=[LaunchDarklyIntegration()]) + client = ldclient.get() # Evaluate client.variation("hello", Context.create("my-org", "organization"), False) @@ -63,18 +48,18 @@ def test_launchdarkly_integration_threaded( td = TestData.data_source() td.update(td.flag("hello").variation_for_all(True)) td.update(td.flag("world").variation_for_all(True)) - client = LDClient( - config=Config( - "sdk-key", - update_processor_class=td, - diagnostic_opt_out=True, # Disable background requests as we aren't using a server. - send_events=False, - ) + config = Config( + "sdk-key", + update_processor_class=td, + diagnostic_opt_out=True, # Disable background requests as we aren't using a server. + send_events=False, ) + ldclient.set_config(config) + client = ldclient.get() context = Context.create("user1") uninstall_integration(LaunchDarklyIntegration.identifier) - sentry_init(integrations=[LaunchDarklyIntegration(ld_client=client)]) + sentry_init(integrations=[LaunchDarklyIntegration()]) events = capture_events() def task(flag_key): @@ -118,29 +103,29 @@ def task(flag_key): } -@pytest.mark.skipif(sys.version_info < (3, 7), reason="requires python3.7 or higher") def test_launchdarkly_integration_asyncio( sentry_init, capture_events, uninstall_integration ): """Assert concurrently evaluated flags do not pollute one another.""" + uninstall_integration(LaunchDarklyIntegration.identifier) + asyncio = pytest.importorskip("asyncio") td = TestData.data_source() td.update(td.flag("hello").variation_for_all(True)) td.update(td.flag("world").variation_for_all(True)) - client = LDClient( - config=Config( - "sdk-key", - update_processor_class=td, - diagnostic_opt_out=True, # Disable background requests as we aren't using a server. - send_events=False, - ) + config = Config( + "sdk-key", + update_processor_class=td, + diagnostic_opt_out=True, # Disable background requests as we aren't using a server. + send_events=False, ) + ldclient.set_config(config) + client = ldclient.get() context = Context.create("user1") - uninstall_integration(LaunchDarklyIntegration.identifier) - sentry_init(integrations=[LaunchDarklyIntegration(ld_client=client)]) + sentry_init(integrations=[LaunchDarklyIntegration()]) events = capture_events() async def task(flag_key): @@ -184,10 +169,8 @@ async def runner(): } -def test_launchdarkly_integration_did_not_enable(monkeypatch): - # Client is not passed in and set_config wasn't called. - # TODO: Bad practice to access internals like this. We can skip this test, or remove this - # case entirely (force user to pass in a client instance). +def test_launchdarkly_integration_did_not_enable(uninstall_integration): + # set_config wasn't called. ldclient._reset_client() try: ldclient.__lock.lock() @@ -195,89 +178,43 @@ def test_launchdarkly_integration_did_not_enable(monkeypatch): finally: ldclient.__lock.unlock() - with pytest.raises(DidNotEnable): - LaunchDarklyIntegration() + uninstall_integration(LaunchDarklyIntegration.identifier) - td = TestData.data_source() - # Disable background requests as we aren't using a server. - # Required because we corrupt the internal state above. - config = Config( - "sdk-key", update_processor_class=td, diagnostic_opt_out=True, send_events=False - ) - # Client not initialized. - client = LDClient(config=config) - monkeypatch.setattr(client, "is_initialized", lambda: False) with pytest.raises(DidNotEnable): - LaunchDarklyIntegration(ld_client=client) + sentry_sdk.init( + integrations=[LaunchDarklyIntegration()], + ) -@pytest.mark.parametrize( - "use_global_client", - (False, True), -) -@pytest.mark.parametrize( - "span_streaming", - [True, False], -) def test_launchdarkly_span_integration( sentry_init, - use_global_client, capture_events, capture_items, uninstall_integration, - span_streaming, ): td = TestData.data_source() td.update(td.flag("hello").variation_for_all(True)) - # Disable background requests as we aren't using a server. config = Config( "sdk-key", update_processor_class=td, diagnostic_opt_out=True, send_events=False ) uninstall_integration(LaunchDarklyIntegration.identifier) - if use_global_client: - ldclient.set_config(config) - sentry_init( - traces_sample_rate=1.0, - integrations=[LaunchDarklyIntegration()], - trace_lifecycle="stream" if span_streaming else "static", - ) - client = ldclient.get() - else: - client = LDClient(config=config) - sentry_init( - traces_sample_rate=1.0, - integrations=[LaunchDarklyIntegration(ld_client=client)], - trace_lifecycle="stream" if span_streaming else "static", - ) - - if span_streaming: - items = capture_items("span") - - with sentry_sdk.traces.start_span(name="bar"): - client.variation("hello", Context.create("my-org", "organization"), False) - client.variation("other", Context.create("my-org", "organization"), False) - - sentry_sdk.flush() + ldclient.set_config(config) + sentry_init( + traces_sample_rate=1.0, + integrations=[LaunchDarklyIntegration()], + ) + client = ldclient.get() - assert len(items) == 1 - span = items[0].payload - assert span["attributes"]["flag.evaluation.hello"] is True - assert span["attributes"]["flag.evaluation.other"] is False + items = capture_items("span") - else: - events = capture_events() + with sentry_sdk.start_span(name="bar"): + client.variation("hello", Context.create("my-org", "organization"), False) + client.variation("other", Context.create("my-org", "organization"), False) - with start_transaction(name="hi"): - with start_span(op="foo", name="bar"): - client.variation( - "hello", Context.create("my-org", "organization"), False - ) - client.variation( - "other", Context.create("my-org", "organization"), False - ) + sentry_sdk.flush() - (event,) = events - assert event["spans"][0]["data"] == ApproxDict( - {"flag.evaluation.hello": True, "flag.evaluation.other": False} - ) + assert len(items) == 1 + span = items[0].payload + assert span["attributes"]["flag.evaluation.hello"] is True + assert span["attributes"]["flag.evaluation.other"] is False diff --git a/tests/integrations/litellm/test_litellm.py b/tests/integrations/litellm/test_litellm.py index a5d5c2ae9f..145ddaa6e3 100644 --- a/tests/integrations/litellm/test_litellm.py +++ b/tests/integrations/litellm/test_litellm.py @@ -36,7 +36,6 @@ async def __call__(self, *args, **kwargs): from openai import AsyncOpenAI, OpenAI from openai.types import CompletionUsage -from sentry_sdk import start_transaction from sentry_sdk._types import BLOB_DATA_SUBSTITUTE from sentry_sdk.consts import OP, SPANDATA from sentry_sdk.integrations.litellm import ( @@ -135,36 +134,23 @@ def __init__( self.created = 1234567890 -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize( - "send_default_pii, include_prompts", - [ - (True, True), - (True, False), - (False, True), - (False, False), - ], + "send_default_pii", + [True, False], ) def test_nonstreaming_chat_completion( reset_litellm_executor, sentry_init, - capture_events, capture_items, send_default_pii, - include_prompts, get_model_response, nonstreaming_chat_completions_model_response, - stream_gen_ai_spans, - span_streaming, ): sentry_init( - integrations=[LiteLLMIntegration(include_prompts=include_prompts)], + integrations=[LiteLLMIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) messages = [ @@ -189,190 +175,74 @@ def test_nonstreaming_chat_completion( serialize_pydantic=True, request_headers={"X-Stainless-Raw-Response": "true"}, ) + items = capture_items("span") - if span_streaming: - items = capture_items("transaction", "span") - - with mock.patch.object( - client.completions._client._client, - "send", - return_value=model_response, - ), sentry_sdk.traces.start_span(name="litellm test"): - litellm.completion( - model="gpt-3.5-turbo", - messages=messages, - client=client, - ) - - litellm_utils.executor.shutdown(wait=True) - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert spans[2]["name"] == "litellm test" - chat_spans = list( - x - for x in spans - if x["attributes"].get("sentry.op") == OP.GEN_AI_CHAT - and x["attributes"].get("sentry.origin") == "auto.ai.litellm" - ) - assert len(chat_spans) == 1 - span = chat_spans[0] - - assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - assert span["name"] == "chat gpt-3.5-turbo" - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "gpt-3.5-turbo" - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_MODEL] == "gpt-3.5-turbo" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "openai" - assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - - if send_default_pii and include_prompts: - assert json.loads(span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) == [ - { - "role": "user", - "content": "Message demonstrating the absence of truncation.", - }, - {"role": "user", "content": "Hello!"}, - ] - assert SPANDATA.GEN_AI_RESPONSE_TEXT in span["attributes"] - else: - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] - - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 20 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 - elif stream_gen_ai_spans: - items = capture_items("transaction", "span") - - with mock.patch.object( - client.completions._client._client, - "send", - return_value=model_response, - ), start_transaction(name="litellm test"): - litellm.completion( - model="gpt-3.5-turbo", - messages=messages, - client=client, - ) - - litellm_utils.executor.shutdown(wait=True) - - (event,) = (item.payload for item in items if item.type == "transaction") - assert event["transaction"] == "litellm test" - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - chat_spans = list( - x - for x in spans - if x["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - and x["attributes"]["sentry.origin"] == "auto.ai.litellm" + with mock.patch.object( + client.completions._client._client, + "send", + return_value=model_response, + ): + litellm.completion( + model="gpt-3.5-turbo", + messages=messages, + client=client, ) - assert len(chat_spans) == 1 - span = chat_spans[0] - - assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - assert span["name"] == "chat gpt-3.5-turbo" - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "gpt-3.5-turbo" - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_MODEL] == "gpt-3.5-turbo" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "openai" - assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - - if send_default_pii and include_prompts: - assert json.loads(span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) == [ - { - "role": "user", - "content": "Message demonstrating the absence of truncation.", - }, - {"role": "user", "content": "Hello!"}, - ] - assert SPANDATA.GEN_AI_RESPONSE_TEXT in span["attributes"] - else: - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] - - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 20 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 - else: - events = capture_events() - with mock.patch.object( - client.completions._client._client, - "send", - return_value=model_response, - ), start_transaction(name="litellm test"): - litellm.completion( - model="gpt-3.5-turbo", - messages=messages, - client=client, - ) + litellm_utils.executor.shutdown(wait=True) - litellm_utils.executor.shutdown(wait=True) + sentry_sdk.flush() + spans = [item.payload for item in items] + chat_spans = list( + x + for x in spans + if x["attributes"].get("sentry.op") == OP.GEN_AI_CHAT + and x["attributes"].get("sentry.origin") == "auto.ai.litellm" + ) + assert len(chat_spans) == 1 + span = chat_spans[0] + + assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT + assert span["name"] == "chat gpt-3.5-turbo" + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "gpt-3.5-turbo" + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_MODEL] == "gpt-3.5-turbo" + assert span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "openai" + assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" + + if send_default_pii: + assert json.loads(span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) == [ + { + "role": "user", + "content": "Message demonstrating the absence of truncation.", + }, + {"role": "user", "content": "Hello!"}, + ] + assert SPANDATA.GEN_AI_RESPONSE_TEXT in span["attributes"] + else: + assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] + assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] - assert len(events) == 1 - (event,) = events + assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 20 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 - assert event["type"] == "transaction" - assert event["transaction"] == "litellm test" - chat_spans = list( - x - for x in event["spans"] - if x["op"] == OP.GEN_AI_CHAT and x["origin"] == "auto.ai.litellm" - ) - assert len(chat_spans) == 1 - span = chat_spans[0] - - assert span["op"] == OP.GEN_AI_CHAT - assert span["description"] == "chat gpt-3.5-turbo" - assert span["data"][SPANDATA.GEN_AI_REQUEST_MODEL] == "gpt-3.5-turbo" - assert span["data"][SPANDATA.GEN_AI_RESPONSE_MODEL] == "gpt-3.5-turbo" - assert span["data"][SPANDATA.GEN_AI_SYSTEM] == "openai" - assert span["data"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - - if send_default_pii and include_prompts: - assert SPANDATA.GEN_AI_REQUEST_MESSAGES in span["data"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT in span["data"] - else: - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["data"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["data"] - - assert span["data"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["data"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 20 - assert span["data"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio(loop_scope="session") @pytest.mark.parametrize( - "send_default_pii, include_prompts", - [ - (True, True), - (True, False), - (False, True), - (False, False), - ], + "send_default_pii", + [True, False], ) async def test_async_nonstreaming_chat_completion( sentry_init, - capture_events, capture_items, send_default_pii, - include_prompts, get_model_response, nonstreaming_chat_completions_model_response, - stream_gen_ai_spans, - span_streaming, ): sentry_init( - integrations=[LiteLLMIntegration(include_prompts=include_prompts)], + integrations=[LiteLLMIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) messages = [ @@ -397,194 +267,76 @@ async def test_async_nonstreaming_chat_completion( serialize_pydantic=True, request_headers={"X-Stainless-Raw-Response": "true"}, ) + items = capture_items("span") - if span_streaming: - items = capture_items("transaction", "span") - - with mock.patch.object( - client.completions._client._client, - "send", - return_value=model_response, - ), sentry_sdk.traces.start_span(name="litellm test"): - await litellm.acompletion( - model="gpt-3.5-turbo", - messages=messages, - client=client, - ) - - await GLOBAL_LOGGING_WORKER.flush() - await asyncio.sleep(0.5) - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert spans[2]["name"] == "litellm test" - chat_spans = list( - x - for x in spans - if x["attributes"].get("sentry.op") == OP.GEN_AI_CHAT - and x["attributes"].get("sentry.origin") == "auto.ai.litellm" - ) - assert len(chat_spans) == 1 - span = chat_spans[0] - - assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - assert span["name"] == "chat gpt-3.5-turbo" - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "gpt-3.5-turbo" - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_MODEL] == "gpt-3.5-turbo" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "openai" - assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - - if send_default_pii and include_prompts: - assert json.loads(span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) == [ - { - "role": "user", - "content": "Message demonstrating the absence of truncation.", - }, - {"role": "user", "content": "Hello!"}, - ] - assert SPANDATA.GEN_AI_RESPONSE_TEXT in span["attributes"] - else: - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] - - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 20 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 - elif stream_gen_ai_spans: - items = capture_items("transaction", "span") - - with mock.patch.object( - client.completions._client._client, - "send", - return_value=model_response, - ), start_transaction(name="litellm test"): - await litellm.acompletion( - model="gpt-3.5-turbo", - messages=messages, - client=client, - ) - - await GLOBAL_LOGGING_WORKER.flush() - await asyncio.sleep(0.5) - - (event,) = (item.payload for item in items if item.type == "transaction") - assert event["transaction"] == "litellm test" - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - chat_spans = list( - x - for x in spans - if x["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - and x["attributes"]["sentry.origin"] == "auto.ai.litellm" + with mock.patch.object( + client.completions._client._client, + "send", + return_value=model_response, + ): + await litellm.acompletion( + model="gpt-3.5-turbo", + messages=messages, + client=client, ) - assert len(chat_spans) == 1 - span = chat_spans[0] - - assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - assert span["name"] == "chat gpt-3.5-turbo" - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "gpt-3.5-turbo" - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_MODEL] == "gpt-3.5-turbo" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "openai" - assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - - if send_default_pii and include_prompts: - assert json.loads(span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) == [ - { - "role": "user", - "content": "Message demonstrating the absence of truncation.", - }, - {"role": "user", "content": "Hello!"}, - ] - assert SPANDATA.GEN_AI_RESPONSE_TEXT in span["attributes"] - else: - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] - - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 20 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 - else: - events = capture_events() - with mock.patch.object( - client.completions._client._client, - "send", - return_value=model_response, - ), start_transaction(name="litellm test"): - await litellm.acompletion( - model="gpt-3.5-turbo", - messages=messages, - client=client, - ) + await GLOBAL_LOGGING_WORKER.flush() + await asyncio.sleep(0.5) - await GLOBAL_LOGGING_WORKER.flush() - await asyncio.sleep(0.5) + sentry_sdk.flush() + spans = [item.payload for item in items] + chat_spans = list( + x + for x in spans + if x["attributes"].get("sentry.op") == OP.GEN_AI_CHAT + and x["attributes"].get("sentry.origin") == "auto.ai.litellm" + ) + assert len(chat_spans) == 1 + span = chat_spans[0] + + assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT + assert span["name"] == "chat gpt-3.5-turbo" + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "gpt-3.5-turbo" + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_MODEL] == "gpt-3.5-turbo" + assert span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "openai" + assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" + + if send_default_pii: + assert json.loads(span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) == [ + { + "role": "user", + "content": "Message demonstrating the absence of truncation.", + }, + {"role": "user", "content": "Hello!"}, + ] + assert SPANDATA.GEN_AI_RESPONSE_TEXT in span["attributes"] + else: + assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] + assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] - assert len(events) == 1 - (event,) = events + assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 20 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 - assert event["type"] == "transaction" - assert event["transaction"] == "litellm test" - chat_spans = list( - x - for x in event["spans"] - if x["op"] == OP.GEN_AI_CHAT and x["origin"] == "auto.ai.litellm" - ) - assert len(chat_spans) == 1 - span = chat_spans[0] - - assert span["op"] == OP.GEN_AI_CHAT - assert span["description"] == "chat gpt-3.5-turbo" - assert span["data"][SPANDATA.GEN_AI_REQUEST_MODEL] == "gpt-3.5-turbo" - assert span["data"][SPANDATA.GEN_AI_RESPONSE_MODEL] == "gpt-3.5-turbo" - assert span["data"][SPANDATA.GEN_AI_SYSTEM] == "openai" - assert span["data"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - - if send_default_pii and include_prompts: - assert SPANDATA.GEN_AI_REQUEST_MESSAGES in span["data"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT in span["data"] - else: - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["data"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["data"] - - assert span["data"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["data"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 20 - assert span["data"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize( - "send_default_pii, include_prompts", - [ - (True, True), - (True, False), - (False, True), - (False, False), - ], + "send_default_pii", + [True, False], ) def test_streaming_chat_completion( reset_litellm_executor, sentry_init, - capture_events, capture_items, send_default_pii, - include_prompts, get_model_response, server_side_event_chunks, streaming_chat_completions_model_response, - stream_gen_ai_spans, - span_streaming, ): sentry_init( - integrations=[LiteLLMIntegration(include_prompts=include_prompts)], + integrations=[LiteLLMIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) messages = [ @@ -601,106 +353,58 @@ def test_streaming_chat_completion( ), request_headers={"X-Stainless-Raw-Response": "true"}, ) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with mock.patch.object( - client.completions._client._client, - "send", - return_value=model_response, - ), start_transaction(name="litellm test"): - response = litellm.completion( - model="gpt-3.5-turbo", - messages=messages, - client=client, - stream=True, - ) - for _ in response: - pass - - streaming_handler.executor.shutdown(wait=True) - - sentry_sdk.flush() - spans = [item.payload for item in items] - chat_spans = list( - x - for x in spans - if x["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - and x["attributes"]["sentry.origin"] == "auto.ai.litellm" + with mock.patch.object( + client.completions._client._client, + "send", + return_value=model_response, + ): + response = litellm.completion( + model="gpt-3.5-turbo", + messages=messages, + client=client, + stream=True, ) - assert len(chat_spans) == 1 - span = chat_spans[0] + for _ in response: + pass - assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True - else: - events = capture_events() - - with mock.patch.object( - client.completions._client._client, - "send", - return_value=model_response, - ), start_transaction(name="litellm test"): - response = litellm.completion( - model="gpt-3.5-turbo", - messages=messages, - client=client, - stream=True, - ) - for _ in response: - pass - - streaming_handler.executor.shutdown(wait=True) - - assert len(events) == 1 - (event,) = events - - assert event["type"] == "transaction" - chat_spans = list( - x - for x in event["spans"] - if x["op"] == OP.GEN_AI_CHAT and x["origin"] == "auto.ai.litellm" - ) - assert len(chat_spans) == 1 - span = chat_spans[0] + streaming_handler.executor.shutdown(wait=True) - assert span["op"] == OP.GEN_AI_CHAT - assert span["data"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True + sentry_sdk.flush() + spans = [item.payload for item in items] + chat_spans = list( + x + for x in spans + if x["attributes"]["sentry.op"] == OP.GEN_AI_CHAT + and x["attributes"]["sentry.origin"] == "auto.ai.litellm" + ) + assert len(chat_spans) == 1 + span = chat_spans[0] + + assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio(loop_scope="session") @pytest.mark.parametrize( - "send_default_pii, include_prompts", - [ - (True, True), - (True, False), - (False, True), - (False, False), - ], + "send_default_pii", + [True, False], ) async def test_async_streaming_chat_completion( sentry_init, - capture_events, capture_items, send_default_pii, - include_prompts, get_model_response, async_iterator, server_side_event_chunks, streaming_chat_completions_model_response, - stream_gen_ai_spans, - span_streaming, ): sentry_init( - integrations=[LiteLLMIntegration(include_prompts=include_prompts)], + integrations=[LiteLLMIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) messages = [ @@ -719,87 +423,46 @@ async def test_async_streaming_chat_completion( ), request_headers={"X-Stainless-Raw-Response": "true"}, ) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with mock.patch.object( - client.completions._client._client, - "send", - return_value=model_response, - ), start_transaction(name="litellm test"): - response = await litellm.acompletion( - model="gpt-3.5-turbo", - messages=messages, - client=client, - stream=True, - ) - async for _ in response: - pass - - await GLOBAL_LOGGING_WORKER.flush() - await asyncio.sleep(0.5) - - sentry_sdk.flush() - spans = [item.payload for item in items] - chat_spans = list( - x - for x in spans - if x["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - and x["attributes"]["sentry.origin"] == "auto.ai.litellm" + with mock.patch.object( + client.completions._client._client, + "send", + return_value=model_response, + ): + response = await litellm.acompletion( + model="gpt-3.5-turbo", + messages=messages, + client=client, + stream=True, ) - assert len(chat_spans) == 1 - span = chat_spans[0] + async for _ in response: + pass - assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True - else: - events = capture_events() - - with mock.patch.object( - client.completions._client._client, - "send", - return_value=model_response, - ), start_transaction(name="litellm test"): - response = await litellm.acompletion( - model="gpt-3.5-turbo", - messages=messages, - client=client, - stream=True, - ) - async for _ in response: - pass - - await GLOBAL_LOGGING_WORKER.flush() - await asyncio.sleep(0.5) - - assert len(events) == 1 - (event,) = events - - assert event["type"] == "transaction" - chat_spans = list( - x - for x in event["spans"] - if x["op"] == OP.GEN_AI_CHAT and x["origin"] == "auto.ai.litellm" - ) - assert len(chat_spans) == 1 - span = chat_spans[0] + await GLOBAL_LOGGING_WORKER.flush() + await asyncio.sleep(0.5) + + sentry_sdk.flush() + spans = [item.payload for item in items] + chat_spans = list( + x + for x in spans + if x["attributes"]["sentry.op"] == OP.GEN_AI_CHAT + and x["attributes"]["sentry.origin"] == "auto.ai.litellm" + ) + assert len(chat_spans) == 1 + span = chat_spans[0] - assert span["op"] == OP.GEN_AI_CHAT - assert span["data"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True + assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_embeddings_create( sentry_init, - capture_events, capture_items, get_model_response, openai_embedding_model_response, clear_litellm_cache, - stream_gen_ai_spans, - span_streaming, ): """ Test that litellm.embedding() calls are properly instrumented. @@ -808,12 +471,10 @@ def test_embeddings_create( to ensure proper integration testing. """ sentry_init( - integrations=[LiteLLMIntegration(include_prompts=True)], + integrations=[LiteLLMIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = OpenAI(api_key="test-key") @@ -823,104 +484,55 @@ def test_embeddings_create( serialize_pydantic=True, request_headers={"X-Stainless-Raw-Response": "true"}, ) + items = capture_items("span") + + with mock.patch.object( + client.embeddings._client._client, + "send", + return_value=model_response, + ): + response = litellm.embedding( + model="text-embedding-ada-002", + input="Hello, world!", + client=client, + ) + # Allow time for callbacks to complete (they may run in separate threads) + time.sleep(0.1) + + # Response is processed by litellm, so just check it exists + assert response is not None + sentry_sdk.flush() + spans = [item.payload for item in items] + spans = list( + x + for x in spans + if x["attributes"]["sentry.op"] == OP.GEN_AI_EMBEDDINGS + and x["attributes"]["sentry.origin"] == "auto.ai.litellm" + ) + + assert len(spans) == 1 + span = spans[0] + + assert span["attributes"]["sentry.op"] == OP.GEN_AI_EMBEDDINGS + assert span["name"] == "embeddings text-embedding-ada-002" + assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "embeddings" + assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 5 + assert ( + span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] + == "text-embedding-ada-002" + ) + # Check that embeddings input is captured (it's JSON serialized) + embeddings_input = span["attributes"][SPANDATA.GEN_AI_EMBEDDINGS_INPUT] + assert json.loads(embeddings_input) == ["Hello, world!"] + - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with mock.patch.object( - client.embeddings._client._client, - "send", - return_value=model_response, - ): - with start_transaction(name="litellm test"): - response = litellm.embedding( - model="text-embedding-ada-002", - input="Hello, world!", - client=client, - ) - # Allow time for callbacks to complete (they may run in separate threads) - time.sleep(0.1) - - # Response is processed by litellm, so just check it exists - assert response is not None - sentry_sdk.flush() - spans = [item.payload for item in items] - spans = list( - x - for x in spans - if x["attributes"]["sentry.op"] == OP.GEN_AI_EMBEDDINGS - and x["attributes"]["sentry.origin"] == "auto.ai.litellm" - ) - - assert len(spans) == 1 - span = spans[0] - - assert span["attributes"]["sentry.op"] == OP.GEN_AI_EMBEDDINGS - assert span["name"] == "embeddings text-embedding-ada-002" - assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "embeddings" - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 5 - assert ( - span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] - == "text-embedding-ada-002" - ) - # Check that embeddings input is captured (it's JSON serialized) - embeddings_input = span["attributes"][SPANDATA.GEN_AI_EMBEDDINGS_INPUT] - assert json.loads(embeddings_input) == ["Hello, world!"] - else: - events = capture_events() - - with mock.patch.object( - client.embeddings._client._client, - "send", - return_value=model_response, - ): - with start_transaction(name="litellm test"): - response = litellm.embedding( - model="text-embedding-ada-002", - input="Hello, world!", - client=client, - ) - # Allow time for callbacks to complete (they may run in separate threads) - time.sleep(0.1) - - # Response is processed by litellm, so just check it exists - assert response is not None - assert len(events) == 1 - (event,) = events - - assert event["type"] == "transaction" - spans = list( - x - for x in event["spans"] - if x["op"] == OP.GEN_AI_EMBEDDINGS and x["origin"] == "auto.ai.litellm" - ) - assert len(spans) == 1 - span = spans[0] - - assert span["op"] == OP.GEN_AI_EMBEDDINGS - assert span["description"] == "embeddings text-embedding-ada-002" - assert span["data"][SPANDATA.GEN_AI_OPERATION_NAME] == "embeddings" - assert span["data"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 5 - assert ( - span["data"][SPANDATA.GEN_AI_REQUEST_MODEL] == "text-embedding-ada-002" - ) - # Check that embeddings input is captured (it's JSON serialized) - embeddings_input = span["data"][SPANDATA.GEN_AI_EMBEDDINGS_INPUT] - assert json.loads(embeddings_input) == ["Hello, world!"] - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio(loop_scope="session") async def test_async_embeddings_create( sentry_init, - capture_events, capture_items, get_model_response, openai_embedding_model_response, clear_litellm_cache, - stream_gen_ai_spans, - span_streaming, ): """ Test that litellm.embedding() calls are properly instrumented. @@ -929,12 +541,10 @@ async def test_async_embeddings_create( to ensure proper integration testing. """ sentry_init( - integrations=[LiteLLMIntegration(include_prompts=True)], + integrations=[LiteLLMIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = AsyncOpenAI(api_key="test-key") @@ -944,114 +554,62 @@ async def test_async_embeddings_create( serialize_pydantic=True, request_headers={"X-Stainless-Raw-Response": "true"}, ) + items = capture_items("span") + + with mock.patch.object( + client.embeddings._client._client, + "send", + return_value=model_response, + ): + response = await litellm.aembedding( + model="text-embedding-ada-002", + input="Hello, world!", + client=client, + ) + + await GLOBAL_LOGGING_WORKER.flush() + await asyncio.sleep(0.5) + + # Response is processed by litellm, so just check it exists + assert response is not None + sentry_sdk.flush() + spans = [item.payload for item in items] + spans = list( + x + for x in spans + if x["attributes"]["sentry.op"] == OP.GEN_AI_EMBEDDINGS + and x["attributes"]["sentry.origin"] == "auto.ai.litellm" + ) + assert len(spans) == 1 + span = spans[0] + + assert span["attributes"]["sentry.op"] == OP.GEN_AI_EMBEDDINGS + assert span["name"] == "embeddings text-embedding-ada-002" + assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "embeddings" + assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 5 + assert ( + span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] + == "text-embedding-ada-002" + ) + # Check that embeddings input is captured (it's JSON serialized) + embeddings_input = span["attributes"][SPANDATA.GEN_AI_EMBEDDINGS_INPUT] + + assert json.loads(embeddings_input) == ["Hello, world!"] + - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with mock.patch.object( - client.embeddings._client._client, - "send", - return_value=model_response, - ): - with start_transaction(name="litellm test"): - response = await litellm.aembedding( - model="text-embedding-ada-002", - input="Hello, world!", - client=client, - ) - - await GLOBAL_LOGGING_WORKER.flush() - await asyncio.sleep(0.5) - - # Response is processed by litellm, so just check it exists - assert response is not None - sentry_sdk.flush() - spans = [item.payload for item in items] - spans = list( - x - for x in spans - if x["attributes"]["sentry.op"] == OP.GEN_AI_EMBEDDINGS - and x["attributes"]["sentry.origin"] == "auto.ai.litellm" - ) - assert len(spans) == 1 - span = spans[0] - - assert span["attributes"]["sentry.op"] == OP.GEN_AI_EMBEDDINGS - assert span["name"] == "embeddings text-embedding-ada-002" - assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "embeddings" - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 5 - assert ( - span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] - == "text-embedding-ada-002" - ) - # Check that embeddings input is captured (it's JSON serialized) - embeddings_input = span["attributes"][SPANDATA.GEN_AI_EMBEDDINGS_INPUT] - - assert json.loads(embeddings_input) == ["Hello, world!"] - else: - events = capture_events() - - with mock.patch.object( - client.embeddings._client._client, - "send", - return_value=model_response, - ): - with start_transaction(name="litellm test"): - response = await litellm.aembedding( - model="text-embedding-ada-002", - input="Hello, world!", - client=client, - ) - - await GLOBAL_LOGGING_WORKER.flush() - await asyncio.sleep(0.5) - - # Response is processed by litellm, so just check it exists - assert response is not None - assert len(events) == 1 - (event,) = events - - assert event["type"] == "transaction" - spans = list( - x - for x in event["spans"] - if x["op"] == OP.GEN_AI_EMBEDDINGS and x["origin"] == "auto.ai.litellm" - ) - assert len(spans) == 1 - span = spans[0] - - assert span["op"] == OP.GEN_AI_EMBEDDINGS - assert span["description"] == "embeddings text-embedding-ada-002" - assert span["data"][SPANDATA.GEN_AI_OPERATION_NAME] == "embeddings" - assert span["data"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 5 - assert ( - span["data"][SPANDATA.GEN_AI_REQUEST_MODEL] == "text-embedding-ada-002" - ) - # Check that embeddings input is captured (it's JSON serialized) - embeddings_input = span["data"][SPANDATA.GEN_AI_EMBEDDINGS_INPUT] - assert json.loads(embeddings_input) == ["Hello, world!"] - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_embeddings_create_with_list_input( sentry_init, - capture_events, capture_items, get_model_response, openai_embedding_model_response, clear_litellm_cache, - stream_gen_ai_spans, - span_streaming, ): """Test embedding with list input.""" sentry_init( - integrations=[LiteLLMIntegration(include_prompts=True)], + integrations=[LiteLLMIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = OpenAI(api_key="test-key") @@ -1061,111 +619,61 @@ def test_embeddings_create_with_list_input( serialize_pydantic=True, request_headers={"X-Stainless-Raw-Response": "true"}, ) + items = capture_items("span") + + with mock.patch.object( + client.embeddings._client._client, + "send", + return_value=model_response, + ): + response = litellm.embedding( + model="text-embedding-ada-002", + input=["First text", "Second text", "Third text"], + client=client, + ) + # Allow time for callbacks to complete (they may run in separate threads) + time.sleep(0.1) + + # Response is processed by litellm, so just check it exists + assert response is not None + + sentry_sdk.flush() + spans = [item.payload for item in items] + spans = list( + x + for x in spans + if x["attributes"]["sentry.op"] == OP.GEN_AI_EMBEDDINGS + and x["attributes"]["sentry.origin"] == "auto.ai.litellm" + ) + assert len(spans) == 1 + span = spans[0] + + assert span["attributes"]["sentry.op"] == OP.GEN_AI_EMBEDDINGS + assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "embeddings" + # Check that list of embeddings input is captured (it's JSON serialized) + embeddings_input = span["attributes"][SPANDATA.GEN_AI_EMBEDDINGS_INPUT] + + assert json.loads(embeddings_input) == [ + "First text", + "Second text", + "Third text", + ] + - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with mock.patch.object( - client.embeddings._client._client, - "send", - return_value=model_response, - ): - with start_transaction(name="litellm test"): - response = litellm.embedding( - model="text-embedding-ada-002", - input=["First text", "Second text", "Third text"], - client=client, - ) - # Allow time for callbacks to complete (they may run in separate threads) - time.sleep(0.1) - - # Response is processed by litellm, so just check it exists - assert response is not None - - sentry_sdk.flush() - spans = [item.payload for item in items] - spans = list( - x - for x in spans - if x["attributes"]["sentry.op"] == OP.GEN_AI_EMBEDDINGS - and x["attributes"]["sentry.origin"] == "auto.ai.litellm" - ) - assert len(spans) == 1 - span = spans[0] - - assert span["attributes"]["sentry.op"] == OP.GEN_AI_EMBEDDINGS - assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "embeddings" - # Check that list of embeddings input is captured (it's JSON serialized) - embeddings_input = span["attributes"][SPANDATA.GEN_AI_EMBEDDINGS_INPUT] - - assert json.loads(embeddings_input) == [ - "First text", - "Second text", - "Third text", - ] - else: - events = capture_events() - - with mock.patch.object( - client.embeddings._client._client, - "send", - return_value=model_response, - ): - with start_transaction(name="litellm test"): - response = litellm.embedding( - model="text-embedding-ada-002", - input=["First text", "Second text", "Third text"], - client=client, - ) - # Allow time for callbacks to complete (they may run in separate threads) - time.sleep(0.1) - - # Response is processed by litellm, so just check it exists - assert response is not None - assert len(events) == 1 - (event,) = events - - assert event["type"] == "transaction" - spans = list( - x - for x in event["spans"] - if x["op"] == OP.GEN_AI_EMBEDDINGS and x["origin"] == "auto.ai.litellm" - ) - assert len(spans) == 1 - span = spans[0] - - assert span["op"] == OP.GEN_AI_EMBEDDINGS - assert span["data"][SPANDATA.GEN_AI_OPERATION_NAME] == "embeddings" - # Check that list of embeddings input is captured (it's JSON serialized) - embeddings_input = span["data"][SPANDATA.GEN_AI_EMBEDDINGS_INPUT] - assert json.loads(embeddings_input) == [ - "First text", - "Second text", - "Third text", - ] - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio(loop_scope="session") async def test_async_embeddings_create_with_list_input( sentry_init, - capture_events, capture_items, get_model_response, openai_embedding_model_response, clear_litellm_cache, - stream_gen_ai_spans, - span_streaming, ): """Test embedding with list input.""" sentry_init( - integrations=[LiteLLMIntegration(include_prompts=True)], + integrations=[LiteLLMIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = AsyncOpenAI(api_key="test-key") @@ -1175,111 +683,60 @@ async def test_async_embeddings_create_with_list_input( serialize_pydantic=True, request_headers={"X-Stainless-Raw-Response": "true"}, ) + items = capture_items("span") + + with mock.patch.object( + client.embeddings._client._client, + "send", + return_value=model_response, + ): + response = await litellm.aembedding( + model="text-embedding-ada-002", + input=["First text", "Second text", "Third text"], + client=client, + ) + + await GLOBAL_LOGGING_WORKER.flush() + await asyncio.sleep(0.5) + + # Response is processed by litellm, so just check it exists + assert response is not None + sentry_sdk.flush() + spans = [item.payload for item in items] + spans = list( + x + for x in spans + if x["attributes"]["sentry.op"] == OP.GEN_AI_EMBEDDINGS + and x["attributes"]["sentry.origin"] == "auto.ai.litellm" + ) + assert len(spans) == 1 + span = spans[0] + + assert span["attributes"]["sentry.op"] == OP.GEN_AI_EMBEDDINGS + assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "embeddings" + # Check that list of embeddings input is captured (it's JSON serialized) + embeddings_input = span["attributes"][SPANDATA.GEN_AI_EMBEDDINGS_INPUT] + + assert json.loads(embeddings_input) == [ + "First text", + "Second text", + "Third text", + ] + - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with mock.patch.object( - client.embeddings._client._client, - "send", - return_value=model_response, - ): - with start_transaction(name="litellm test"): - response = await litellm.aembedding( - model="text-embedding-ada-002", - input=["First text", "Second text", "Third text"], - client=client, - ) - - await GLOBAL_LOGGING_WORKER.flush() - await asyncio.sleep(0.5) - - # Response is processed by litellm, so just check it exists - assert response is not None - sentry_sdk.flush() - spans = [item.payload for item in items] - spans = list( - x - for x in spans - if x["attributes"]["sentry.op"] == OP.GEN_AI_EMBEDDINGS - and x["attributes"]["sentry.origin"] == "auto.ai.litellm" - ) - assert len(spans) == 1 - span = spans[0] - - assert span["attributes"]["sentry.op"] == OP.GEN_AI_EMBEDDINGS - assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "embeddings" - # Check that list of embeddings input is captured (it's JSON serialized) - embeddings_input = span["attributes"][SPANDATA.GEN_AI_EMBEDDINGS_INPUT] - - assert json.loads(embeddings_input) == [ - "First text", - "Second text", - "Third text", - ] - else: - events = capture_events() - - with mock.patch.object( - client.embeddings._client._client, - "send", - return_value=model_response, - ): - with start_transaction(name="litellm test"): - response = await litellm.aembedding( - model="text-embedding-ada-002", - input=["First text", "Second text", "Third text"], - client=client, - ) - - await GLOBAL_LOGGING_WORKER.flush() - await asyncio.sleep(0.5) - - # Response is processed by litellm, so just check it exists - assert response is not None - assert len(events) == 1 - (event,) = events - - assert event["type"] == "transaction" - spans = list( - x - for x in event["spans"] - if x["op"] == OP.GEN_AI_EMBEDDINGS and x["origin"] == "auto.ai.litellm" - ) - assert len(spans) == 1 - span = spans[0] - - assert span["op"] == OP.GEN_AI_EMBEDDINGS - assert span["data"][SPANDATA.GEN_AI_OPERATION_NAME] == "embeddings" - # Check that list of embeddings input is captured (it's JSON serialized) - embeddings_input = span["data"][SPANDATA.GEN_AI_EMBEDDINGS_INPUT] - assert json.loads(embeddings_input) == [ - "First text", - "Second text", - "Third text", - ] - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_embeddings_no_pii( sentry_init, - capture_events, capture_items, get_model_response, openai_embedding_model_response, clear_litellm_cache, - stream_gen_ai_spans, - span_streaming, ): """Test that PII is not captured when disabled.""" sentry_init( - integrations=[LiteLLMIntegration(include_prompts=True)], + integrations=[LiteLLMIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=False, # PII disabled - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = OpenAI(api_key="test-key") @@ -1289,97 +746,53 @@ def test_embeddings_no_pii( serialize_pydantic=True, request_headers={"X-Stainless-Raw-Response": "true"}, ) + items = capture_items("span") + + with mock.patch.object( + client.embeddings._client._client, + "send", + return_value=model_response, + ): + response = litellm.embedding( + model="text-embedding-ada-002", + input="Hello, world!", + client=client, + ) + # Allow time for callbacks to complete (they may run in separate threads) + time.sleep(0.1) + + # Response is processed by litellm, so just check it exists + assert response is not None + sentry_sdk.flush() + spans = [item.payload for item in items] + spans = list( + x + for x in spans + if x["attributes"]["sentry.op"] == OP.GEN_AI_EMBEDDINGS + and x["attributes"]["sentry.origin"] == "auto.ai.litellm" + ) + assert len(spans) == 1 + span = spans[0] + + assert span["attributes"]["sentry.op"] == OP.GEN_AI_EMBEDDINGS + # Check that embeddings input is NOT captured when PII is disabled + assert SPANDATA.GEN_AI_EMBEDDINGS_INPUT not in span["attributes"] + - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with mock.patch.object( - client.embeddings._client._client, - "send", - return_value=model_response, - ): - with start_transaction(name="litellm test"): - response = litellm.embedding( - model="text-embedding-ada-002", - input="Hello, world!", - client=client, - ) - # Allow time for callbacks to complete (they may run in separate threads) - time.sleep(0.1) - - # Response is processed by litellm, so just check it exists - assert response is not None - sentry_sdk.flush() - spans = [item.payload for item in items] - spans = list( - x - for x in spans - if x["attributes"]["sentry.op"] == OP.GEN_AI_EMBEDDINGS - and x["attributes"]["sentry.origin"] == "auto.ai.litellm" - ) - assert len(spans) == 1 - span = spans[0] - - assert span["attributes"]["sentry.op"] == OP.GEN_AI_EMBEDDINGS - # Check that embeddings input is NOT captured when PII is disabled - assert SPANDATA.GEN_AI_EMBEDDINGS_INPUT not in span["attributes"] - else: - events = capture_events() - - with mock.patch.object( - client.embeddings._client._client, - "send", - return_value=model_response, - ): - with start_transaction(name="litellm test"): - response = litellm.embedding( - model="text-embedding-ada-002", - input="Hello, world!", - client=client, - ) - # Allow time for callbacks to complete (they may run in separate threads) - time.sleep(0.1) - - # Response is processed by litellm, so just check it exists - assert response is not None - assert len(events) == 1 - (event,) = events - - assert event["type"] == "transaction" - spans = list( - x - for x in event["spans"] - if x["op"] == OP.GEN_AI_EMBEDDINGS and x["origin"] == "auto.ai.litellm" - ) - assert len(spans) == 1 - span = spans[0] - - assert span["op"] == OP.GEN_AI_EMBEDDINGS - # Check that embeddings input is NOT captured when PII is disabled - assert SPANDATA.GEN_AI_EMBEDDINGS_INPUT not in span["data"] - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio(loop_scope="session") async def test_async_embeddings_no_pii( sentry_init, - capture_events, capture_items, get_model_response, openai_embedding_model_response, clear_litellm_cache, - stream_gen_ai_spans, - span_streaming, ): """Test that PII is not captured when disabled.""" sentry_init( - integrations=[LiteLLMIntegration(include_prompts=True)], + integrations=[LiteLLMIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=False, # PII disabled - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = AsyncOpenAI(api_key="test-key") @@ -1389,95 +802,50 @@ async def test_async_embeddings_no_pii( serialize_pydantic=True, request_headers={"X-Stainless-Raw-Response": "true"}, ) + items = capture_items("span") + + with mock.patch.object( + client.embeddings._client._client, + "send", + return_value=model_response, + ): + response = await litellm.aembedding( + model="text-embedding-ada-002", + input="Hello, world!", + client=client, + ) + + await GLOBAL_LOGGING_WORKER.flush() + await asyncio.sleep(0.5) + + # Response is processed by litellm, so just check it exists + assert response is not None + sentry_sdk.flush() + spans = [item.payload for item in items] + spans = list( + x + for x in spans + if x["attributes"]["sentry.op"] == OP.GEN_AI_EMBEDDINGS + and x["attributes"]["sentry.origin"] == "auto.ai.litellm" + ) + assert len(spans) == 1 + span = spans[0] + + assert span["attributes"]["sentry.op"] == OP.GEN_AI_EMBEDDINGS + # Check that embeddings input is NOT captured when PII is disabled + assert SPANDATA.GEN_AI_EMBEDDINGS_INPUT not in span["attributes"] + - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with mock.patch.object( - client.embeddings._client._client, - "send", - return_value=model_response, - ): - with start_transaction(name="litellm test"): - response = await litellm.aembedding( - model="text-embedding-ada-002", - input="Hello, world!", - client=client, - ) - - await GLOBAL_LOGGING_WORKER.flush() - await asyncio.sleep(0.5) - - # Response is processed by litellm, so just check it exists - assert response is not None - sentry_sdk.flush() - spans = [item.payload for item in items] - spans = list( - x - for x in spans - if x["attributes"]["sentry.op"] == OP.GEN_AI_EMBEDDINGS - and x["attributes"]["sentry.origin"] == "auto.ai.litellm" - ) - assert len(spans) == 1 - span = spans[0] - - assert span["attributes"]["sentry.op"] == OP.GEN_AI_EMBEDDINGS - # Check that embeddings input is NOT captured when PII is disabled - assert SPANDATA.GEN_AI_EMBEDDINGS_INPUT not in span["attributes"] - else: - events = capture_events() - - with mock.patch.object( - client.embeddings._client._client, - "send", - return_value=model_response, - ): - with start_transaction(name="litellm test"): - response = await litellm.aembedding( - model="text-embedding-ada-002", - input="Hello, world!", - client=client, - ) - - await GLOBAL_LOGGING_WORKER.flush() - await asyncio.sleep(0.5) - - # Response is processed by litellm, so just check it exists - assert response is not None - assert len(events) == 1 - (event,) = events - - assert event["type"] == "transaction" - spans = list( - x - for x in event["spans"] - if x["op"] == OP.GEN_AI_EMBEDDINGS and x["origin"] == "auto.ai.litellm" - ) - assert len(spans) == 1 - span = spans[0] - - assert span["op"] == OP.GEN_AI_EMBEDDINGS - # Check that embeddings input is NOT captured when PII is disabled - assert SPANDATA.GEN_AI_EMBEDDINGS_INPUT not in span["data"] - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_exception_handling( reset_litellm_executor, sentry_init, - capture_events, capture_items, get_rate_limit_model_response, - stream_gen_ai_spans, - span_streaming, ): sentry_init( integrations=[LiteLLMIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) messages = [{"role": "user", "content": "Hello!"}] @@ -1485,65 +853,34 @@ def test_exception_handling( client = OpenAI(api_key="test-key") model_response = get_rate_limit_model_response() + items = capture_items("event") - if span_streaming or stream_gen_ai_spans: - items = capture_items("event") - - with mock.patch.object( - client.completions._client._client, - "send", - return_value=model_response, - ), start_transaction(name="litellm test"), pytest.raises( - litellm.RateLimitError - ): - litellm.completion( - model="gpt-3.5-turbo", - messages=messages, - client=client, - ) - - # Find the error event - error_events = [item.payload for item in items] - else: - events = capture_events() - - with mock.patch.object( - client.completions._client._client, - "send", - return_value=model_response, - ), start_transaction(name="litellm test"), pytest.raises( - litellm.RateLimitError - ): - litellm.completion( - model="gpt-3.5-turbo", - messages=messages, - client=client, - ) - - # Should have error event and transaction - assert len(events) >= 1 - # Find the error event - error_events = [e for e in events if e.get("level") == "error"] + with mock.patch.object( + client.completions._client._client, + "send", + return_value=model_response, + ), pytest.raises(litellm.RateLimitError): + litellm.completion( + model="gpt-3.5-turbo", + messages=messages, + client=client, + ) + + # Find the error event + error_events = [item.payload for item in items] assert len(error_events) == 1 -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio(loop_scope="session") async def test_async_exception_handling( sentry_init, - capture_events, capture_items, get_rate_limit_model_response, - stream_gen_ai_spans, - span_streaming, ): sentry_init( integrations=[LiteLLMIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) messages = [{"role": "user", "content": "Hello!"}] @@ -1551,66 +888,35 @@ async def test_async_exception_handling( client = AsyncOpenAI(api_key="test-key") model_response = get_rate_limit_model_response() + items = capture_items("event") - if span_streaming or stream_gen_ai_spans: - items = capture_items("event") - - with mock.patch.object( - client.embeddings._client._client, - "send", - return_value=model_response, - ), start_transaction(name="litellm test"), pytest.raises( - litellm.RateLimitError - ): - await litellm.acompletion( - model="gpt-3.5-turbo", - messages=messages, - client=client, - ) - - # Find the error event - error_events = [item.payload for item in items] - else: - events = capture_events() - - with mock.patch.object( - client.embeddings._client._client, - "send", - return_value=model_response, - ), start_transaction(name="litellm test"), pytest.raises( - litellm.RateLimitError - ): - await litellm.acompletion( - model="gpt-3.5-turbo", - messages=messages, - client=client, - ) - - # Should have error event and transaction - assert len(events) >= 1 - # Find the error event - error_events = [e for e in events if e.get("level") == "error"] + with mock.patch.object( + client.embeddings._client._client, + "send", + return_value=model_response, + ), pytest.raises(litellm.RateLimitError): + await litellm.acompletion( + model="gpt-3.5-turbo", + messages=messages, + client=client, + ) + + # Find the error event + error_events = [item.payload for item in items] assert len(error_events) == 1 -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_span_origin( reset_litellm_executor, sentry_init, - capture_events, capture_items, get_model_response, nonstreaming_chat_completions_model_response, - stream_gen_ai_spans, - span_streaming, ): sentry_init( integrations=[LiteLLMIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) messages = [{"role": "user", "content": "Hello!"}] @@ -1632,92 +938,40 @@ def test_span_origin( serialize_pydantic=True, request_headers={"X-Stainless-Raw-Response": "true"}, ) - if span_streaming: - items = capture_items("span") - - with mock.patch.object( - client.completions._client._client, - "send", - return_value=model_response, - ), sentry_sdk.traces.start_span(name="litellm test"): - litellm.completion( - model="gpt-3.5-turbo", - messages=messages, - client=client, - ) + items = capture_items("span") - litellm_utils.executor.shutdown(wait=True) - - sentry_sdk.flush() - spans = [item.payload for item in items] - assert spans[2]["is_segment"] is True - assert spans[2]["attributes"]["sentry.origin"] == "manual" - assert spans[1]["attributes"]["sentry.origin"] == "auto.ai.litellm" - elif stream_gen_ai_spans: - items = capture_items("transaction", "span") - - with mock.patch.object( - client.completions._client._client, - "send", - return_value=model_response, - ), start_transaction(name="litellm test"): - litellm.completion( - model="gpt-3.5-turbo", - messages=messages, - client=client, - ) - - litellm_utils.executor.shutdown(wait=True) - - (event,) = (item.payload for item in items if item.type == "transaction") - assert event["contexts"]["trace"]["origin"] == "manual" - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert spans[0]["attributes"]["sentry.origin"] == "auto.ai.litellm" - else: - events = capture_events() - - with mock.patch.object( - client.completions._client._client, - "send", - return_value=model_response, - ), start_transaction(name="litellm test"): - litellm.completion( - model="gpt-3.5-turbo", - messages=messages, - client=client, - ) - - litellm_utils.executor.shutdown(wait=True) + with mock.patch.object( + client.completions._client._client, + "send", + return_value=model_response, + ): + litellm.completion( + model="gpt-3.5-turbo", + messages=messages, + client=client, + ) - (event,) = events + litellm_utils.executor.shutdown(wait=True) - assert event["contexts"]["trace"]["origin"] == "manual" - assert event["spans"][0]["origin"] == "auto.ai.litellm" + sentry_sdk.flush() + spans = [item.payload for item in items] + assert spans[1]["attributes"]["sentry.origin"] == "auto.ai.litellm" -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_multiple_providers( reset_litellm_executor, sentry_init, - capture_events, capture_items, get_model_response, nonstreaming_chat_completions_model_response, nonstreaming_anthropic_model_response, nonstreaming_google_genai_model_response, - stream_gen_ai_spans, - span_streaming, ): """Test that the integration correctly identifies different providers.""" sentry_init( integrations=[LiteLLMIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) messages = [{"role": "user", "content": "Hello!"}] @@ -1738,234 +992,87 @@ def test_multiple_providers( serialize_pydantic=True, request_headers={"X-Stainless-Raw-Response": "true"}, ) + items = capture_items("span") - if span_streaming: - items = capture_items("span") - - with mock.patch.object( - openai_client.completions._client._client, - "send", - return_value=openai_model_response, - ), sentry_sdk.traces.start_span(name="test gpt-3.5-turbo"): - litellm.completion( - model="gpt-3.5-turbo", - messages=messages, - client=openai_client, - ) - - litellm_utils.executor.shutdown(wait=True) - - _reset_litellm_executor() - - anthropic_client = HTTPHandler() - anthropic_model_response = get_model_response( - nonstreaming_anthropic_model_response, - serialize_pydantic=True, - request_headers={"X-Stainless-Raw-Response": "true"}, - ) - - with mock.patch.object( - anthropic_client, - "post", - return_value=anthropic_model_response, - ), sentry_sdk.traces.start_span(name="test claude-3-opus-20240229"): - litellm.completion( - model="claude-3-opus-20240229", - messages=messages, - client=anthropic_client, - api_key="test-key", - ) - - litellm_utils.executor.shutdown(wait=True) - - _reset_litellm_executor() - - gemini_client = HTTPHandler() - gemini_model_response = get_model_response( - nonstreaming_google_genai_model_response, - serialize_pydantic=True, + with mock.patch.object( + openai_client.completions._client._client, + "send", + return_value=openai_model_response, + ): + litellm.completion( + model="gpt-3.5-turbo", + messages=messages, + client=openai_client, ) - with mock.patch.object( - gemini_client, - "post", - return_value=gemini_model_response, - ), sentry_sdk.traces.start_span(name="test gemini/gemini-pro"): - litellm.completion( - model="gemini/gemini-pro", - messages=messages, - client=gemini_client, - api_key="test-key", - ) + litellm_utils.executor.shutdown(wait=True) - litellm_utils.executor.shutdown(wait=True) + _reset_litellm_executor() - sentry_sdk.flush() - spans = [item.payload for item in items] - for span in spans: - if span["is_segment"] is True: - continue - # The provider should be detected by litellm.get_llm_provider - assert SPANDATA.GEN_AI_SYSTEM in span["attributes"] - elif stream_gen_ai_spans: - items = capture_items("span", "transaction") - - with mock.patch.object( - openai_client.completions._client._client, - "send", - return_value=openai_model_response, - ), start_transaction(name="test gpt-3.5-turbo"): - litellm.completion( - model="gpt-3.5-turbo", - messages=messages, - client=openai_client, - ) - - litellm_utils.executor.shutdown(wait=True) - - _reset_litellm_executor() - - anthropic_client = HTTPHandler() - anthropic_model_response = get_model_response( - nonstreaming_anthropic_model_response, - serialize_pydantic=True, - request_headers={"X-Stainless-Raw-Response": "true"}, - ) + anthropic_client = HTTPHandler() + anthropic_model_response = get_model_response( + nonstreaming_anthropic_model_response, + serialize_pydantic=True, + request_headers={"X-Stainless-Raw-Response": "true"}, + ) - with mock.patch.object( - anthropic_client, - "post", - return_value=anthropic_model_response, - ), start_transaction(name="test claude-3-opus-20240229"): - litellm.completion( - model="claude-3-opus-20240229", - messages=messages, - client=anthropic_client, - api_key="test-key", - ) - - litellm_utils.executor.shutdown(wait=True) - - _reset_litellm_executor() - - gemini_client = HTTPHandler() - gemini_model_response = get_model_response( - nonstreaming_google_genai_model_response, - serialize_pydantic=True, + with mock.patch.object( + anthropic_client, + "post", + return_value=anthropic_model_response, + ): + litellm.completion( + model="claude-3-opus-20240229", + messages=messages, + client=anthropic_client, + api_key="test-key", ) - with mock.patch.object( - gemini_client, - "post", - return_value=gemini_model_response, - ), start_transaction(name="test gemini/gemini-pro"): - litellm.completion( - model="gemini/gemini-pro", - messages=messages, - client=gemini_client, - api_key="test-key", - ) - - litellm_utils.executor.shutdown(wait=True) + litellm_utils.executor.shutdown(wait=True) - events = [item.payload for item in items if item.type == "transaction"] - assert len(events) == 3 + _reset_litellm_executor() - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - for span in spans: - # The provider should be detected by litellm.get_llm_provider - assert SPANDATA.GEN_AI_SYSTEM in span["attributes"] - else: - events = capture_events() - - with mock.patch.object( - openai_client.completions._client._client, - "send", - return_value=openai_model_response, - ), start_transaction(name="test gpt-3.5-turbo"): - litellm.completion( - model="gpt-3.5-turbo", - messages=messages, - client=openai_client, - ) - - litellm_utils.executor.shutdown(wait=True) - - _reset_litellm_executor() - - anthropic_client = HTTPHandler() - anthropic_model_response = get_model_response( - nonstreaming_anthropic_model_response, - serialize_pydantic=True, - request_headers={"X-Stainless-Raw-Response": "true"}, - ) + gemini_client = HTTPHandler() + gemini_model_response = get_model_response( + nonstreaming_google_genai_model_response, + serialize_pydantic=True, + ) - with mock.patch.object( - anthropic_client, - "post", - return_value=anthropic_model_response, - ), start_transaction(name="test claude-3-opus-20240229"): - litellm.completion( - model="claude-3-opus-20240229", - messages=messages, - client=anthropic_client, - api_key="test-key", - ) - - litellm_utils.executor.shutdown(wait=True) - - _reset_litellm_executor() - - gemini_client = HTTPHandler() - gemini_model_response = get_model_response( - nonstreaming_google_genai_model_response, - serialize_pydantic=True, + with mock.patch.object( + gemini_client, + "post", + return_value=gemini_model_response, + ): + litellm.completion( + model="gemini/gemini-pro", + messages=messages, + client=gemini_client, + api_key="test-key", ) - with mock.patch.object( - gemini_client, - "post", - return_value=gemini_model_response, - ), start_transaction(name="test gemini/gemini-pro"): - litellm.completion( - model="gemini/gemini-pro", - messages=messages, - client=gemini_client, - api_key="test-key", - ) - - litellm_utils.executor.shutdown(wait=True) - - assert len(events) == 3 + litellm_utils.executor.shutdown(wait=True) - for i in range(3): - span = events[i]["spans"][0] - # The provider should be detected by litellm.get_llm_provider - assert SPANDATA.GEN_AI_SYSTEM in span["data"] + sentry_sdk.flush() + spans = [item.payload for item in items] + for span in spans: + # The provider should be detected by litellm.get_llm_provider + assert SPANDATA.GEN_AI_PROVIDER_NAME in span["attributes"] -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio(loop_scope="session") async def test_async_multiple_providers( sentry_init, - capture_events, capture_items, get_model_response, nonstreaming_chat_completions_model_response, nonstreaming_anthropic_model_response, nonstreaming_google_genai_model_response, - stream_gen_ai_spans, - span_streaming, ): """Test that the integration correctly identifies different providers.""" sentry_init( integrations=[LiteLLMIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) messages = [{"role": "user", "content": "Hello!"}] @@ -1986,241 +1093,88 @@ async def test_async_multiple_providers( serialize_pydantic=True, request_headers={"X-Stainless-Raw-Response": "true"}, ) + items = capture_items("span") - if span_streaming: - items = capture_items("transaction", "span") - - with mock.patch.object( - openai_client.completions._client._client, - "send", - return_value=openai_model_response, - ), sentry_sdk.traces.start_span(name="test gpt-3.5-turbo"): - await litellm.acompletion( - model="gpt-3.5-turbo", - messages=messages, - client=openai_client, - ) - - await GLOBAL_LOGGING_WORKER.flush() - await asyncio.sleep(0.5) - - _reset_litellm_executor() - - anthropic_client = AsyncHTTPHandler() - anthropic_model_response = get_model_response( - nonstreaming_anthropic_model_response, - serialize_pydantic=True, - request_headers={"X-Stainless-Raw-Response": "True"}, + with mock.patch.object( + openai_client.completions._client._client, + "send", + return_value=openai_model_response, + ): + await litellm.acompletion( + model="gpt-3.5-turbo", + messages=messages, + client=openai_client, ) - with mock.patch.object( - anthropic_client, - "post", - return_value=anthropic_model_response, - ), sentry_sdk.traces.start_span(name="test claude-3-opus-20240229"): - await litellm.acompletion( - model="claude-3-opus-20240229", - messages=messages, - client=anthropic_client, - api_key="test-key", - ) - - await GLOBAL_LOGGING_WORKER.flush() - await asyncio.sleep(0.5) - - _reset_litellm_executor() - - gemini_client = AsyncHTTPHandler() - gemini_model_response = get_model_response( - nonstreaming_google_genai_model_response, - serialize_pydantic=True, - ) + await GLOBAL_LOGGING_WORKER.flush() + await asyncio.sleep(0.5) - with mock.patch.object( - gemini_client, - "post", - return_value=gemini_model_response, - ), sentry_sdk.traces.start_span(name="test gemini/gemini-pro"): - await litellm.acompletion( - model="gemini/gemini-pro", - messages=messages, - client=gemini_client, - api_key="test-key", - ) - - await GLOBAL_LOGGING_WORKER.flush() - await asyncio.sleep(0.5) + _reset_litellm_executor() - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - for span in spans: - if span["is_segment"] is True: - continue - # The provider should be detected by litellm.get_llm_provider - assert SPANDATA.GEN_AI_SYSTEM in span["attributes"] - elif stream_gen_ai_spans: - items = capture_items("transaction", "span") - - with mock.patch.object( - openai_client.completions._client._client, - "send", - return_value=openai_model_response, - ), start_transaction(name="test gpt-3.5-turbo"): - await litellm.acompletion( - model="gpt-3.5-turbo", - messages=messages, - client=openai_client, - ) - - await GLOBAL_LOGGING_WORKER.flush() - await asyncio.sleep(0.5) - - _reset_litellm_executor() - - anthropic_client = AsyncHTTPHandler() - anthropic_model_response = get_model_response( - nonstreaming_anthropic_model_response, - serialize_pydantic=True, - request_headers={"X-Stainless-Raw-Response": "True"}, - ) + anthropic_client = AsyncHTTPHandler() + anthropic_model_response = get_model_response( + nonstreaming_anthropic_model_response, + serialize_pydantic=True, + request_headers={"X-Stainless-Raw-Response": "True"}, + ) - with mock.patch.object( - anthropic_client, - "post", - return_value=anthropic_model_response, - ), start_transaction(name="test claude-3-opus-20240229"): - await litellm.acompletion( - model="claude-3-opus-20240229", - messages=messages, - client=anthropic_client, - api_key="test-key", - ) - - await GLOBAL_LOGGING_WORKER.flush() - await asyncio.sleep(0.5) - - _reset_litellm_executor() - - gemini_client = AsyncHTTPHandler() - gemini_model_response = get_model_response( - nonstreaming_google_genai_model_response, - serialize_pydantic=True, + with mock.patch.object( + anthropic_client, + "post", + return_value=anthropic_model_response, + ): + await litellm.acompletion( + model="claude-3-opus-20240229", + messages=messages, + client=anthropic_client, + api_key="test-key", ) - with mock.patch.object( - gemini_client, - "post", - return_value=gemini_model_response, - ), start_transaction(name="test gemini/gemini-pro"): - await litellm.acompletion( - model="gemini/gemini-pro", - messages=messages, - client=gemini_client, - api_key="test-key", - ) - - await GLOBAL_LOGGING_WORKER.flush() - await asyncio.sleep(0.5) + await GLOBAL_LOGGING_WORKER.flush() + await asyncio.sleep(0.5) - events = [item.payload for item in items if item.type == "transaction"] - assert len(events) == 3 + _reset_litellm_executor() - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - for span in spans: - # The provider should be detected by litellm.get_llm_provider - assert SPANDATA.GEN_AI_SYSTEM in span["attributes"] - else: - events = capture_events() - - with mock.patch.object( - openai_client.completions._client._client, - "send", - return_value=openai_model_response, - ), start_transaction(name="test gpt-3.5-turbo"): - await litellm.acompletion( - model="gpt-3.5-turbo", - messages=messages, - client=openai_client, - ) - - await GLOBAL_LOGGING_WORKER.flush() - await asyncio.sleep(0.5) - - _reset_litellm_executor() - - anthropic_client = AsyncHTTPHandler() - anthropic_model_response = get_model_response( - nonstreaming_anthropic_model_response, - serialize_pydantic=True, - request_headers={"X-Stainless-Raw-Response": "True"}, - ) + gemini_client = AsyncHTTPHandler() + gemini_model_response = get_model_response( + nonstreaming_google_genai_model_response, + serialize_pydantic=True, + ) - with mock.patch.object( - anthropic_client, - "post", - return_value=anthropic_model_response, - ), start_transaction(name="test claude-3-opus-20240229"): - await litellm.acompletion( - model="claude-3-opus-20240229", - messages=messages, - client=anthropic_client, - api_key="test-key", - ) - - await GLOBAL_LOGGING_WORKER.flush() - await asyncio.sleep(0.5) - - _reset_litellm_executor() - - gemini_client = AsyncHTTPHandler() - gemini_model_response = get_model_response( - nonstreaming_google_genai_model_response, - serialize_pydantic=True, + with mock.patch.object( + gemini_client, + "post", + return_value=gemini_model_response, + ): + await litellm.acompletion( + model="gemini/gemini-pro", + messages=messages, + client=gemini_client, + api_key="test-key", ) - with mock.patch.object( - gemini_client, - "post", - return_value=gemini_model_response, - ), start_transaction(name="test gemini/gemini-pro"): - await litellm.acompletion( - model="gemini/gemini-pro", - messages=messages, - client=gemini_client, - api_key="test-key", - ) + await GLOBAL_LOGGING_WORKER.flush() + await asyncio.sleep(0.5) - await GLOBAL_LOGGING_WORKER.flush() - await asyncio.sleep(0.5) + sentry_sdk.flush() + spans = [item.payload for item in items] + for span in spans: + # The provider should be detected by litellm.get_llm_provider + assert SPANDATA.GEN_AI_PROVIDER_NAME in span["attributes"] - assert len(events) == 3 - for i in range(3): - span = events[i]["spans"][0] - # The provider should be detected by litellm.get_llm_provider - assert SPANDATA.GEN_AI_SYSTEM in span["data"] - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_additional_parameters( reset_litellm_executor, sentry_init, - capture_events, capture_items, get_model_response, nonstreaming_chat_completions_model_response, - stream_gen_ai_spans, - span_streaming, ): """Test that additional parameters are captured.""" sentry_init( integrations=[LiteLLMIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) messages = [{"role": "user", "content": "Hello!"}] @@ -2241,100 +1195,56 @@ def test_additional_parameters( serialize_pydantic=True, request_headers={"X-Stainless-Raw-Response": "true"}, ) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with mock.patch.object( - client.completions._client._client, - "send", - return_value=model_response, - ), start_transaction(name="litellm test"): - litellm.completion( - model="gpt-3.5-turbo", - messages=messages, - client=client, - temperature=0.7, - max_tokens=100, - top_p=0.9, - frequency_penalty=0.5, - presence_penalty=0.5, - ) - - litellm_utils.executor.shutdown(wait=True) - - sentry_sdk.flush() - spans = [item.payload for item in items] - chat_spans = list( - x - for x in spans - if x["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - and x["attributes"]["sentry.origin"] == "auto.ai.litellm" - ) - assert len(chat_spans) == 1 - span = chat_spans[0] - - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TEMPERATURE] == 0.7 - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 100 - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TOP_P] == 0.9 - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_FREQUENCY_PENALTY] == 0.5 - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_PRESENCE_PENALTY] == 0.5 - else: - events = capture_events() - - with mock.patch.object( - client.completions._client._client, - "send", - return_value=model_response, - ), start_transaction(name="litellm test"): - litellm.completion( - model="gpt-3.5-turbo", - messages=messages, - client=client, - temperature=0.7, - max_tokens=100, - top_p=0.9, - frequency_penalty=0.5, - presence_penalty=0.5, - ) - - litellm_utils.executor.shutdown(wait=True) - - (event,) = events - chat_spans = list( - x - for x in event["spans"] - if x["op"] == OP.GEN_AI_CHAT and x["origin"] == "auto.ai.litellm" + with mock.patch.object( + client.completions._client._client, + "send", + return_value=model_response, + ): + litellm.completion( + model="gpt-3.5-turbo", + messages=messages, + client=client, + temperature=0.7, + max_tokens=100, + top_p=0.9, + frequency_penalty=0.5, + presence_penalty=0.5, ) - assert len(chat_spans) == 1 - span = chat_spans[0] - assert span["data"][SPANDATA.GEN_AI_REQUEST_TEMPERATURE] == 0.7 - assert span["data"][SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 100 - assert span["data"][SPANDATA.GEN_AI_REQUEST_TOP_P] == 0.9 - assert span["data"][SPANDATA.GEN_AI_REQUEST_FREQUENCY_PENALTY] == 0.5 - assert span["data"][SPANDATA.GEN_AI_REQUEST_PRESENCE_PENALTY] == 0.5 + litellm_utils.executor.shutdown(wait=True) + + sentry_sdk.flush() + spans = [item.payload for item in items] + chat_spans = list( + x + for x in spans + if x["attributes"]["sentry.op"] == OP.GEN_AI_CHAT + and x["attributes"]["sentry.origin"] == "auto.ai.litellm" + ) + assert len(chat_spans) == 1 + span = chat_spans[0] + + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TEMPERATURE] == 0.7 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 100 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TOP_P] == 0.9 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_FREQUENCY_PENALTY] == 0.5 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_PRESENCE_PENALTY] == 0.5 -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio(loop_scope="session") async def test_async_additional_parameters( sentry_init, - capture_events, capture_items, get_model_response, nonstreaming_chat_completions_model_response, - stream_gen_ai_spans, - span_streaming, ): """Test that additional parameters are captured.""" sentry_init( integrations=[LiteLLMIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) messages = [{"role": "user", "content": "Hello!"}] @@ -2355,101 +1265,56 @@ async def test_async_additional_parameters( serialize_pydantic=True, request_headers={"X-Stainless-Raw-Response": "true"}, ) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with mock.patch.object( - client.completions._client._client, - "send", - return_value=model_response, - ), start_transaction(name="litellm test"): - await litellm.acompletion( - model="gpt-3.5-turbo", - messages=messages, - client=client, - temperature=0.7, - max_tokens=100, - top_p=0.9, - frequency_penalty=0.5, - presence_penalty=0.5, - ) - - await GLOBAL_LOGGING_WORKER.flush() - await asyncio.sleep(0.5) - - sentry_sdk.flush() - spans = [item.payload for item in items] - chat_spans = list( - x - for x in spans - if x["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - and x["attributes"]["sentry.origin"] == "auto.ai.litellm" - ) - assert len(chat_spans) == 1 - span = chat_spans[0] - - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TEMPERATURE] == 0.7 - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 100 - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TOP_P] == 0.9 - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_FREQUENCY_PENALTY] == 0.5 - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_PRESENCE_PENALTY] == 0.5 - else: - events = capture_events() - - with mock.patch.object( - client.completions._client._client, - "send", - return_value=model_response, - ), start_transaction(name="litellm test"): - await litellm.acompletion( - model="gpt-3.5-turbo", - messages=messages, - client=client, - temperature=0.7, - max_tokens=100, - top_p=0.9, - frequency_penalty=0.5, - presence_penalty=0.5, - ) - - await GLOBAL_LOGGING_WORKER.flush() - await asyncio.sleep(0.5) - - (event,) = events - chat_spans = list( - x - for x in event["spans"] - if x["op"] == OP.GEN_AI_CHAT and x["origin"] == "auto.ai.litellm" + with mock.patch.object( + client.completions._client._client, + "send", + return_value=model_response, + ): + await litellm.acompletion( + model="gpt-3.5-turbo", + messages=messages, + client=client, + temperature=0.7, + max_tokens=100, + top_p=0.9, + frequency_penalty=0.5, + presence_penalty=0.5, ) - assert len(chat_spans) == 1 - span = chat_spans[0] - assert span["data"][SPANDATA.GEN_AI_REQUEST_TEMPERATURE] == 0.7 - assert span["data"][SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 100 - assert span["data"][SPANDATA.GEN_AI_REQUEST_TOP_P] == 0.9 - assert span["data"][SPANDATA.GEN_AI_REQUEST_FREQUENCY_PENALTY] == 0.5 - assert span["data"][SPANDATA.GEN_AI_REQUEST_PRESENCE_PENALTY] == 0.5 + await GLOBAL_LOGGING_WORKER.flush() + await asyncio.sleep(0.5) + + sentry_sdk.flush() + spans = [item.payload for item in items] + chat_spans = list( + x + for x in spans + if x["attributes"]["sentry.op"] == OP.GEN_AI_CHAT + and x["attributes"]["sentry.origin"] == "auto.ai.litellm" + ) + assert len(chat_spans) == 1 + span = chat_spans[0] + + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TEMPERATURE] == 0.7 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 100 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TOP_P] == 0.9 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_FREQUENCY_PENALTY] == 0.5 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_PRESENCE_PENALTY] == 0.5 -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_no_integration( reset_litellm_executor, sentry_init, - capture_events, capture_items, get_model_response, nonstreaming_chat_completions_model_response, - stream_gen_ai_spans, - span_streaming, ): """Test that when integration is not enabled, callbacks don't break.""" sentry_init( disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) messages = [{"role": "user", "content": "Hello!"}] @@ -2470,76 +1335,43 @@ def test_no_integration( serialize_pydantic=True, request_headers={"X-Stainless-Raw-Response": "true"}, ) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with mock.patch.object( - client.completions._client._client, - "send", - return_value=model_response, - ), start_transaction(name="litellm test"): - litellm.completion( - model="gpt-3.5-turbo", - messages=messages, - client=client, - ) + with mock.patch.object( + client.completions._client._client, + "send", + return_value=model_response, + ): + litellm.completion( + model="gpt-3.5-turbo", + messages=messages, + client=client, + ) - litellm_utils.executor.shutdown(wait=True) + litellm_utils.executor.shutdown(wait=True) - sentry_sdk.flush() - spans = [item.payload for item in items] - chat_spans = list( - x - for x in spans - if x["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - and x["attributes"]["sentry.origin"] == "auto.ai.litellm" - ) - else: - events = capture_events() - - with mock.patch.object( - client.completions._client._client, - "send", - return_value=model_response, - ), start_transaction(name="litellm test"): - litellm.completion( - model="gpt-3.5-turbo", - messages=messages, - client=client, - ) - - litellm_utils.executor.shutdown(wait=True) - - (event,) = events - # Should still have the transaction, but no child spans since integration is off - assert event["type"] == "transaction" - chat_spans = list( - x - for x in event["spans"] - if x["op"] == OP.GEN_AI_CHAT and x["origin"] == "auto.ai.litellm" - ) + sentry_sdk.flush() + spans = [item.payload for item in items] + chat_spans = list( + x + for x in spans + if x["attributes"]["sentry.op"] == OP.GEN_AI_CHAT + and x["attributes"]["sentry.origin"] == "auto.ai.litellm" + ) assert len(chat_spans) == 0 -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio(loop_scope="session") async def test_async_no_integration( sentry_init, - capture_events, capture_items, get_model_response, nonstreaming_chat_completions_model_response, - stream_gen_ai_spans, - span_streaming, ): """Test that when integration is not enabled, callbacks don't break.""" sentry_init( disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) messages = [{"role": "user", "content": "Hello!"}] @@ -2560,76 +1392,42 @@ async def test_async_no_integration( serialize_pydantic=True, request_headers={"X-Stainless-Raw-Response": "true"}, ) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with mock.patch.object( - client.completions._client._client, - "send", - return_value=model_response, - ), start_transaction(name="litellm test"): - await litellm.acompletion( - model="gpt-3.5-turbo", - messages=messages, - client=client, - ) + with mock.patch.object( + client.completions._client._client, + "send", + return_value=model_response, + ): + await litellm.acompletion( + model="gpt-3.5-turbo", + messages=messages, + client=client, + ) - await GLOBAL_LOGGING_WORKER.flush() - await asyncio.sleep(0.5) + await GLOBAL_LOGGING_WORKER.flush() + await asyncio.sleep(0.5) - sentry_sdk.flush() - spans = [item.payload for item in items] - chat_spans = list( - x - for x in spans - if x["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - and x["attributes"]["sentry.origin"] == "auto.ai.litellm" - ) - else: - events = capture_events() - - with mock.patch.object( - client.completions._client._client, - "send", - return_value=model_response, - ), start_transaction(name="litellm test"): - await litellm.acompletion( - model="gpt-3.5-turbo", - messages=messages, - client=client, - ) - - await GLOBAL_LOGGING_WORKER.flush() - await asyncio.sleep(0.5) - - (event,) = events - # Should still have the transaction, but no child spans since integration is off - assert event["type"] == "transaction" - chat_spans = list( - x - for x in event["spans"] - if x["op"] == OP.GEN_AI_CHAT and x["origin"] == "auto.ai.litellm" - ) + sentry_sdk.flush() + spans = [item.payload for item in items] + chat_spans = list( + x + for x in spans + if x["attributes"]["sentry.op"] == OP.GEN_AI_CHAT + and x["attributes"]["sentry.origin"] == "auto.ai.litellm" + ) assert len(chat_spans) == 0 -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_response_without_usage( sentry_init, - capture_events, capture_items, - stream_gen_ai_spans, - span_streaming, ): """Test handling of responses without usage information.""" sentry_init( integrations=[LiteLLMIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) messages = [{"role": "user", "content": "Hello!"}] @@ -2643,53 +1441,27 @@ def test_response_without_usage( "choices": [MockChoice()], }, )() + items = capture_items("span") + + kwargs = { + "model": "gpt-3.5-turbo", + "messages": messages, + } + + _input_callback(kwargs) + _success_callback( + kwargs, + mock_response, + datetime.now(), + datetime.now(), + ) - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with start_transaction(name="litellm test"): - kwargs = { - "model": "gpt-3.5-turbo", - "messages": messages, - } - - _input_callback(kwargs) - _success_callback( - kwargs, - mock_response, - datetime.now(), - datetime.now(), - ) - - sentry_sdk.flush() - (span,) = (item.payload for item in items) - - # Span should still be created even without usage info - assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - assert span["name"] == "chat gpt-3.5-turbo" - else: - events = capture_events() - - with start_transaction(name="litellm test"): - kwargs = { - "model": "gpt-3.5-turbo", - "messages": messages, - } - - _input_callback(kwargs) - _success_callback( - kwargs, - mock_response, - datetime.now(), - datetime.now(), - ) - - (event,) = events - (span,) = event["spans"] + sentry_sdk.flush() + (span,) = (item.payload for item in items) - # Span should still be created even without usage info - assert span["op"] == OP.GEN_AI_CHAT - assert span["description"] == "chat gpt-3.5-turbo" + # Span should still be created even without usage info + assert span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT + assert span["name"] == "chat gpt-3.5-turbo" def test_integration_setup(sentry_init): @@ -2706,89 +1478,23 @@ def test_integration_setup(sentry_init): assert _failure_callback in (litellm.failure_callback or []) -def test_litellm_message_truncation(sentry_init, capture_events): - """Test that large messages are truncated properly in LiteLLM integration.""" - sentry_init( - integrations=[LiteLLMIntegration(include_prompts=True)], - disabled_integrations=[StdlibIntegration], - traces_sample_rate=1.0, - send_default_pii=True, - stream_gen_ai_spans=False, - ) - events = capture_events() - - large_content = ( - "This is a very long message that will exceed our size limits. " * 1000 - ) - messages = [ - {"role": "user", "content": "small message 1"}, - {"role": "assistant", "content": large_content}, - {"role": "user", "content": large_content}, - {"role": "assistant", "content": "small message 4"}, - {"role": "user", "content": "small message 5"}, - ] - mock_response = MockCompletionResponse() - - with start_transaction(name="litellm test"): - kwargs = { - "model": "gpt-3.5-turbo", - "messages": messages, - } - - _input_callback(kwargs) - _success_callback( - kwargs, - mock_response, - datetime.now(), - datetime.now(), - ) - - assert len(events) > 0 - tx = events[0] - assert tx["type"] == "transaction" - - chat_spans = [ - span for span in tx.get("spans", []) if span.get("op") == OP.GEN_AI_CHAT - ] - assert len(chat_spans) > 0 - - chat_span = chat_spans[0] - assert SPANDATA.GEN_AI_REQUEST_MESSAGES in chat_span["data"] - - messages_data = chat_span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - assert isinstance(messages_data, str) - - parsed_messages = json.loads(messages_data) - assert isinstance(parsed_messages, list) - assert len(parsed_messages) == 1 - assert "small message 5" in str(parsed_messages[0]) - assert tx["_meta"]["spans"]["0"]["data"]["gen_ai.request.messages"][""]["len"] == 5 - - IMAGE_DATA = b"fake_image_data_12345" IMAGE_B64 = base64.b64encode(IMAGE_DATA).decode("utf-8") IMAGE_DATA_URI = f"data:image/png;base64,{IMAGE_B64}" -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_binary_content_encoding_image_url( reset_litellm_executor, sentry_init, - capture_events, capture_items, get_model_response, nonstreaming_chat_completions_model_response, - stream_gen_ai_spans, - span_streaming, ): sentry_init( - integrations=[LiteLLMIntegration(include_prompts=True)], + integrations=[LiteLLMIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) messages = [ @@ -2820,61 +1526,33 @@ def test_binary_content_encoding_image_url( serialize_pydantic=True, request_headers={"X-Stainless-Raw-Response": "true"}, ) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with mock.patch.object( - client.completions._client._client, - "send", - return_value=model_response, - ), start_transaction(name="litellm test"): - litellm.completion( - model="gpt-4-vision-preview", - messages=messages, - client=client, - custom_llm_provider="openai", - ) + with mock.patch.object( + client.completions._client._client, + "send", + return_value=model_response, + ): + litellm.completion( + model="gpt-4-vision-preview", + messages=messages, + client=client, + custom_llm_provider="openai", + ) - litellm_utils.executor.shutdown(wait=True) + litellm_utils.executor.shutdown(wait=True) - sentry_sdk.flush() - spans = [item.payload for item in items] - chat_spans = list( - x - for x in spans - if x["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - and x["attributes"]["sentry.origin"] == "auto.ai.litellm" - ) - assert len(chat_spans) == 1 - span = chat_spans[0] - messages_data = json.loads(span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) - else: - events = capture_events() - - with mock.patch.object( - client.completions._client._client, - "send", - return_value=model_response, - ), start_transaction(name="litellm test"): - litellm.completion( - model="gpt-4-vision-preview", - messages=messages, - client=client, - custom_llm_provider="openai", - ) - - litellm_utils.executor.shutdown(wait=True) - - (event,) = events - chat_spans = list( - x - for x in event["spans"] - if x["op"] == OP.GEN_AI_CHAT and x["origin"] == "auto.ai.litellm" - ) - assert len(chat_spans) == 1 - span = chat_spans[0] - messages_data = json.loads(span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) + sentry_sdk.flush() + spans = [item.payload for item in items] + chat_spans = list( + x + for x in spans + if x["attributes"]["sentry.op"] == OP.GEN_AI_CHAT + and x["attributes"]["sentry.origin"] == "auto.ai.litellm" + ) + assert len(chat_spans) == 1 + span = chat_spans[0] + messages_data = json.loads(span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) blob_item = next( ( @@ -2895,25 +1573,18 @@ def test_binary_content_encoding_image_url( ) -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio(loop_scope="session") async def test_async_binary_content_encoding_image_url( sentry_init, - capture_events, capture_items, get_model_response, nonstreaming_chat_completions_model_response, - stream_gen_ai_spans, - span_streaming, ): sentry_init( - integrations=[LiteLLMIntegration(include_prompts=True)], + integrations=[LiteLLMIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) messages = [ @@ -2945,63 +1616,34 @@ async def test_async_binary_content_encoding_image_url( serialize_pydantic=True, request_headers={"X-Stainless-Raw-Response": "true"}, ) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with mock.patch.object( - client.completions._client._client, - "send", - return_value=model_response, - ), start_transaction(name="litellm test"): - await litellm.acompletion( - model="gpt-4-vision-preview", - messages=messages, - client=client, - custom_llm_provider="openai", - ) + with mock.patch.object( + client.completions._client._client, + "send", + return_value=model_response, + ): + await litellm.acompletion( + model="gpt-4-vision-preview", + messages=messages, + client=client, + custom_llm_provider="openai", + ) - await GLOBAL_LOGGING_WORKER.flush() - await asyncio.sleep(0.5) + await GLOBAL_LOGGING_WORKER.flush() + await asyncio.sleep(0.5) - sentry_sdk.flush() - spans = [item.payload for item in items] - chat_spans = list( - x - for x in spans - if x["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - and x["attributes"]["sentry.origin"] == "auto.ai.litellm" - ) - assert len(chat_spans) == 1 - span = chat_spans[0] - messages_data = json.loads(span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) - else: - events = capture_events() - - with mock.patch.object( - client.completions._client._client, - "send", - return_value=model_response, - ), start_transaction(name="litellm test"): - await litellm.acompletion( - model="gpt-4-vision-preview", - messages=messages, - client=client, - custom_llm_provider="openai", - ) - - await GLOBAL_LOGGING_WORKER.flush() - await asyncio.sleep(0.5) - - (event,) = events - chat_spans = list( - x - for x in event["spans"] - if x["op"] == OP.GEN_AI_CHAT and x["origin"] == "auto.ai.litellm" - ) - assert len(chat_spans) == 1 - span = chat_spans[0] - messages_data = json.loads(span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) + sentry_sdk.flush() + spans = [item.payload for item in items] + chat_spans = list( + x + for x in spans + if x["attributes"]["sentry.op"] == OP.GEN_AI_CHAT + and x["attributes"]["sentry.origin"] == "auto.ai.litellm" + ) + assert len(chat_spans) == 1 + span = chat_spans[0] + messages_data = json.loads(span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) blob_item = next( ( @@ -3022,25 +1664,18 @@ async def test_async_binary_content_encoding_image_url( ) -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_binary_content_encoding_mixed_content( reset_litellm_executor, sentry_init, - capture_events, capture_items, get_model_response, nonstreaming_chat_completions_model_response, - stream_gen_ai_spans, - span_streaming, ): sentry_init( - integrations=[LiteLLMIntegration(include_prompts=True)], + integrations=[LiteLLMIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) messages = [ @@ -3073,61 +1708,33 @@ def test_binary_content_encoding_mixed_content( serialize_pydantic=True, request_headers={"X-Stainless-Raw-Response": "true"}, ) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with mock.patch.object( - client.completions._client._client, - "send", - return_value=model_response, - ), start_transaction(name="litellm test"): - litellm.completion( - model="gpt-4-vision-preview", - messages=messages, - client=client, - custom_llm_provider="openai", - ) + with mock.patch.object( + client.completions._client._client, + "send", + return_value=model_response, + ): + litellm.completion( + model="gpt-4-vision-preview", + messages=messages, + client=client, + custom_llm_provider="openai", + ) - litellm_utils.executor.shutdown(wait=True) + litellm_utils.executor.shutdown(wait=True) - sentry_sdk.flush() - spans = [item.payload for item in items] - chat_spans = list( - x - for x in spans - if x["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - and x["attributes"]["sentry.origin"] == "auto.ai.litellm" - ) - assert len(chat_spans) == 1 - span = chat_spans[0] - messages_data = json.loads(span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) - else: - events = capture_events() - - with mock.patch.object( - client.completions._client._client, - "send", - return_value=model_response, - ), start_transaction(name="litellm test"): - litellm.completion( - model="gpt-4-vision-preview", - messages=messages, - client=client, - custom_llm_provider="openai", - ) - - litellm_utils.executor.shutdown(wait=True) - - (event,) = events - chat_spans = list( - x - for x in event["spans"] - if x["op"] == OP.GEN_AI_CHAT and x["origin"] == "auto.ai.litellm" - ) - assert len(chat_spans) == 1 - span = chat_spans[0] - messages_data = json.loads(span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) + sentry_sdk.flush() + spans = [item.payload for item in items] + chat_spans = list( + x + for x in spans + if x["attributes"]["sentry.op"] == OP.GEN_AI_CHAT + and x["attributes"]["sentry.origin"] == "auto.ai.litellm" + ) + assert len(chat_spans) == 1 + span = chat_spans[0] + messages_data = json.loads(span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) content_items = [ item for msg in messages_data if "content" in msg for item in msg["content"] @@ -3136,25 +1743,18 @@ def test_binary_content_encoding_mixed_content( assert any(item.get("type") == "blob" for item in content_items) -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio(loop_scope="session") async def test_async_binary_content_encoding_mixed_content( sentry_init, - capture_events, capture_items, get_model_response, nonstreaming_chat_completions_model_response, - stream_gen_ai_spans, - span_streaming, ): sentry_init( - integrations=[LiteLLMIntegration(include_prompts=True)], + integrations=[LiteLLMIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) messages = [ @@ -3187,63 +1787,34 @@ async def test_async_binary_content_encoding_mixed_content( serialize_pydantic=True, request_headers={"X-Stainless-Raw-Response": "true"}, ) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with mock.patch.object( - client.completions._client._client, - "send", - return_value=model_response, - ), start_transaction(name="litellm test"): - await litellm.acompletion( - model="gpt-4-vision-preview", - messages=messages, - client=client, - custom_llm_provider="openai", - ) + with mock.patch.object( + client.completions._client._client, + "send", + return_value=model_response, + ): + await litellm.acompletion( + model="gpt-4-vision-preview", + messages=messages, + client=client, + custom_llm_provider="openai", + ) - await GLOBAL_LOGGING_WORKER.flush() - await asyncio.sleep(0.5) + await GLOBAL_LOGGING_WORKER.flush() + await asyncio.sleep(0.5) - sentry_sdk.flush() - spans = [item.payload for item in items] - chat_spans = list( - x - for x in spans - if x["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - and x["attributes"]["sentry.origin"] == "auto.ai.litellm" - ) - assert len(chat_spans) == 1 - span = chat_spans[0] - messages_data = json.loads(span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) - else: - events = capture_events() - - with mock.patch.object( - client.completions._client._client, - "send", - return_value=model_response, - ), start_transaction(name="litellm test"): - await litellm.acompletion( - model="gpt-4-vision-preview", - messages=messages, - client=client, - custom_llm_provider="openai", - ) - - await GLOBAL_LOGGING_WORKER.flush() - await asyncio.sleep(0.5) - - (event,) = events - chat_spans = list( - x - for x in event["spans"] - if x["op"] == OP.GEN_AI_CHAT and x["origin"] == "auto.ai.litellm" - ) - assert len(chat_spans) == 1 - span = chat_spans[0] - messages_data = json.loads(span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) + sentry_sdk.flush() + spans = [item.payload for item in items] + chat_spans = list( + x + for x in spans + if x["attributes"]["sentry.op"] == OP.GEN_AI_CHAT + and x["attributes"]["sentry.origin"] == "auto.ai.litellm" + ) + assert len(chat_spans) == 1 + span = chat_spans[0] + messages_data = json.loads(span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) content_items = [ item for msg in messages_data if "content" in msg for item in msg["content"] @@ -3252,25 +1823,18 @@ async def test_async_binary_content_encoding_mixed_content( assert any(item.get("type") == "blob" for item in content_items) -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_binary_content_encoding_uri_type( reset_litellm_executor, sentry_init, - capture_events, capture_items, get_model_response, nonstreaming_chat_completions_model_response, - stream_gen_ai_spans, - span_streaming, ): sentry_init( - integrations=[LiteLLMIntegration(include_prompts=True)], + integrations=[LiteLLMIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) messages = [ @@ -3301,60 +1865,32 @@ def test_binary_content_encoding_uri_type( serialize_pydantic=True, request_headers={"X-Stainless-Raw-Response": "true"}, ) + items = capture_items("span") + with mock.patch.object( + client.completions._client._client, + "send", + return_value=model_response, + ): + litellm.completion( + model="gpt-4-vision-preview", + messages=messages, + client=client, + custom_llm_provider="openai", + ) - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - with mock.patch.object( - client.completions._client._client, - "send", - return_value=model_response, - ), start_transaction(name="litellm test"): - litellm.completion( - model="gpt-4-vision-preview", - messages=messages, - client=client, - custom_llm_provider="openai", - ) - - litellm_utils.executor.shutdown(wait=True) + litellm_utils.executor.shutdown(wait=True) - sentry_sdk.flush() - spans = [item.payload for item in items] - chat_spans = list( - x - for x in spans - if x["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - and x["attributes"]["sentry.origin"] == "auto.ai.litellm" - ) - assert len(chat_spans) == 1 - span = chat_spans[0] - messages_data = json.loads(span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) - else: - events = capture_events() - - with mock.patch.object( - client.completions._client._client, - "send", - return_value=model_response, - ), start_transaction(name="litellm test"): - litellm.completion( - model="gpt-4-vision-preview", - messages=messages, - client=client, - custom_llm_provider="openai", - ) - - litellm_utils.executor.shutdown(wait=True) - - (event,) = events - chat_spans = list( - x - for x in event["spans"] - if x["op"] == OP.GEN_AI_CHAT and x["origin"] == "auto.ai.litellm" - ) - assert len(chat_spans) == 1 - span = chat_spans[0] - messages_data = json.loads(span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) + sentry_sdk.flush() + spans = [item.payload for item in items] + chat_spans = list( + x + for x in spans + if x["attributes"]["sentry.op"] == OP.GEN_AI_CHAT + and x["attributes"]["sentry.origin"] == "auto.ai.litellm" + ) + assert len(chat_spans) == 1 + span = chat_spans[0] + messages_data = json.loads(span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) uri_item = next( ( @@ -3370,25 +1906,18 @@ def test_binary_content_encoding_uri_type( assert uri_item["uri"] == "https://example.com/image.jpg" -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio(loop_scope="session") async def test_async_binary_content_encoding_uri_type( sentry_init, - capture_events, capture_items, get_model_response, nonstreaming_chat_completions_model_response, - stream_gen_ai_spans, - span_streaming, ): sentry_init( - integrations=[LiteLLMIntegration(include_prompts=True)], + integrations=[LiteLLMIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) messages = [ @@ -3419,63 +1948,34 @@ async def test_async_binary_content_encoding_uri_type( serialize_pydantic=True, request_headers={"X-Stainless-Raw-Response": "true"}, ) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with mock.patch.object( - client.completions._client._client, - "send", - return_value=model_response, - ), start_transaction(name="litellm test"): - await litellm.acompletion( - model="gpt-4-vision-preview", - messages=messages, - client=client, - custom_llm_provider="openai", - ) + with mock.patch.object( + client.completions._client._client, + "send", + return_value=model_response, + ): + await litellm.acompletion( + model="gpt-4-vision-preview", + messages=messages, + client=client, + custom_llm_provider="openai", + ) - await GLOBAL_LOGGING_WORKER.flush() - await asyncio.sleep(0.5) + await GLOBAL_LOGGING_WORKER.flush() + await asyncio.sleep(0.5) - sentry_sdk.flush() - spans = [item.payload for item in items] - chat_spans = list( - x - for x in spans - if x["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - and x["attributes"]["sentry.origin"] == "auto.ai.litellm" - ) - assert len(chat_spans) == 1 - span = chat_spans[0] - messages_data = json.loads(span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) - else: - events = capture_events() - - with mock.patch.object( - client.completions._client._client, - "send", - return_value=model_response, - ), start_transaction(name="litellm test"): - await litellm.acompletion( - model="gpt-4-vision-preview", - messages=messages, - client=client, - custom_llm_provider="openai", - ) - - await GLOBAL_LOGGING_WORKER.flush() - await asyncio.sleep(0.5) - - (event,) = events - chat_spans = list( - x - for x in event["spans"] - if x["op"] == OP.GEN_AI_CHAT and x["origin"] == "auto.ai.litellm" - ) - assert len(chat_spans) == 1 - span = chat_spans[0] - messages_data = json.loads(span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) + sentry_sdk.flush() + spans = [item.payload for item in items] + chat_spans = list( + x + for x in spans + if x["attributes"]["sentry.op"] == OP.GEN_AI_CHAT + and x["attributes"]["sentry.origin"] == "auto.ai.litellm" + ) + assert len(chat_spans) == 1 + span = chat_spans[0] + messages_data = json.loads(span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) uri_item = next( ( @@ -3592,12 +2092,11 @@ def test_convert_message_parts_image_url_missing_url(): @pytest.mark.parametrize( - "data_collection, send_default_pii, include_prompts, expected_present, expected_absent", + "data_collection, send_default_pii, expected_present, expected_absent", [ pytest.param( {"gen_ai": {"inputs": True, "outputs": True}}, False, - False, [SPANDATA.GEN_AI_REQUEST_MESSAGES, SPANDATA.GEN_AI_RESPONSE_TEXT], [], id="gen-ai-inputs-and-outputs-enabled-override-legacy-off", @@ -3605,7 +2104,6 @@ def test_convert_message_parts_image_url_missing_url(): pytest.param( {"gen_ai": {"inputs": False, "outputs": False}}, True, - True, [], [SPANDATA.GEN_AI_REQUEST_MESSAGES, SPANDATA.GEN_AI_RESPONSE_TEXT], id="gen-ai-inputs-and-outputs-disabled-override-legacy-on", @@ -3613,7 +2111,6 @@ def test_convert_message_parts_image_url_missing_url(): pytest.param( {"gen_ai": {"inputs": True, "outputs": False}}, False, - False, [SPANDATA.GEN_AI_REQUEST_MESSAGES], [SPANDATA.GEN_AI_RESPONSE_TEXT], id="gen-ai-inputs-enabled-outputs-disabled", @@ -3621,7 +2118,6 @@ def test_convert_message_parts_image_url_missing_url(): pytest.param( {"gen_ai": {"inputs": False, "outputs": True}}, False, - False, [SPANDATA.GEN_AI_RESPONSE_TEXT], [SPANDATA.GEN_AI_REQUEST_MESSAGES], id="gen-ai-outputs-enabled-inputs-disabled", @@ -3629,7 +2125,6 @@ def test_convert_message_parts_image_url_missing_url(): pytest.param( {"gen_ai": {}}, False, - False, [SPANDATA.GEN_AI_REQUEST_MESSAGES, SPANDATA.GEN_AI_RESPONSE_TEXT], [], id="gen-ai-inputs-and-outputs-omitted-default-to-enabled", @@ -3637,15 +2132,13 @@ def test_convert_message_parts_image_url_missing_url(): pytest.param( None, True, - True, [SPANDATA.GEN_AI_REQUEST_MESSAGES, SPANDATA.GEN_AI_RESPONSE_TEXT], [], - id="no-gen-ai-config-legacy-pii-and-include-prompts-enabled", + id="no-gen-ai-config-legacy-pii", ), pytest.param( None, False, - True, [], [SPANDATA.GEN_AI_REQUEST_MESSAGES, SPANDATA.GEN_AI_RESPONSE_TEXT], id="no-gen-ai-config-legacy-pii-disabled", @@ -3655,22 +2148,19 @@ def test_convert_message_parts_image_url_missing_url(): def test_chat_completion_data_collection( reset_litellm_executor, sentry_init, - capture_events, + capture_items, get_model_response, nonstreaming_chat_completions_model_response, data_collection, send_default_pii, - include_prompts, expected_present, expected_absent, ): sentry_init_kwargs = dict( - integrations=[LiteLLMIntegration(include_prompts=include_prompts)], + integrations=[LiteLLMIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=send_default_pii, - stream_gen_ai_spans=False, - trace_lifecycle="static", ) if data_collection is not None: sentry_init_kwargs["data_collection"] = data_collection @@ -3697,13 +2187,13 @@ def test_chat_completion_data_collection( request_headers={"X-Stainless-Raw-Response": "true"}, ) - events = capture_events() + items = capture_items("span") with mock.patch.object( client.completions._client._client, "send", return_value=model_response, - ), start_transaction(name="litellm test"): + ): litellm.completion( model="gpt-3.5-turbo", messages=messages, @@ -3712,13 +2202,15 @@ def test_chat_completion_data_collection( litellm_utils.executor.shutdown(wait=True) - (event,) = events + sentry_sdk.flush() + spans = [item.payload for item in items] (span,) = [ x - for x in event["spans"] - if x["op"] == OP.GEN_AI_CHAT and x["origin"] == "auto.ai.litellm" + for x in spans + if x["attributes"].get("sentry.op") == OP.GEN_AI_CHAT + and x["attributes"].get("sentry.origin") == "auto.ai.litellm" ] - span_data = span["data"] + span_data = span["attributes"] for key in expected_present: assert key in span_data, f"{key} should have been collected" @@ -3742,26 +2234,23 @@ def test_chat_completion_data_collection( @pytest.mark.parametrize( - "data_collection, send_default_pii, include_prompts, should_collect_input", + "data_collection, send_default_pii, should_collect_input", [ pytest.param( {"gen_ai": {"inputs": True}}, False, - False, True, id="gen-ai-inputs-enabled-override-legacy-off", ), pytest.param( {"gen_ai": {"inputs": False}}, True, - True, False, id="gen-ai-inputs-disabled-override-legacy-on", ), pytest.param( {"gen_ai": {}}, False, - False, True, id="gen-ai-inputs-omitted-default-to-enabled", ), @@ -3769,13 +2258,11 @@ def test_chat_completion_data_collection( None, True, True, - True, - id="no-gen-ai-config-legacy-pii-and-include-prompts-enabled", + id="no-gen-ai-config-legacy-pii", ), pytest.param( None, False, - True, False, id="no-gen-ai-config-legacy-pii-disabled", ), @@ -3783,21 +2270,18 @@ def test_chat_completion_data_collection( ) def test_embeddings_data_collection( sentry_init, - capture_events, + capture_items, get_model_response, openai_embedding_model_response, data_collection, send_default_pii, - include_prompts, should_collect_input, ): sentry_init_kwargs = dict( - integrations=[LiteLLMIntegration(include_prompts=include_prompts)], + integrations=[LiteLLMIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=send_default_pii, - stream_gen_ai_spans=False, - trace_lifecycle="static", ) if data_collection is not None: sentry_init_kwargs["data_collection"] = data_collection @@ -3812,29 +2296,29 @@ def test_embeddings_data_collection( request_headers={"X-Stainless-Raw-Response": "true"}, ) - events = capture_events() + items = capture_items("span") with mock.patch.object( client.embeddings._client._client, "send", return_value=model_response, ): - with start_transaction(name="litellm test"): - litellm.embedding( - model="text-embedding-ada-002", - input="Hello, world!", - client=client, - ) - # Allow time for callbacks to complete (they may run in separate threads) - time.sleep(0.1) - - (event,) = events + litellm.embedding( + model="text-embedding-ada-002", + input="Hello, world!", + client=client, + ) + # Allow time for callbacks to complete (they may run in separate threads) + time.sleep(0.1) + + spans = [item.payload for item in items] (span,) = [ x - for x in event["spans"] - if x["op"] == OP.GEN_AI_EMBEDDINGS and x["origin"] == "auto.ai.litellm" + for x in spans + if x["attributes"].get("sentry.op") == OP.GEN_AI_EMBEDDINGS + and x["attributes"].get("sentry.origin") == "auto.ai.litellm" ] - span_data = span["data"] + span_data = span["attributes"] if should_collect_input: assert json.loads(span_data[SPANDATA.GEN_AI_EMBEDDINGS_INPUT]) == [ diff --git a/tests/integrations/litestar/test_litestar.py b/tests/integrations/litestar/test_litestar.py index 7e59e65864..363b83fdab 100644 --- a/tests/integrations/litestar/test_litestar.py +++ b/tests/integrations/litestar/test_litestar.py @@ -15,8 +15,8 @@ import sentry_sdk from sentry_sdk import capture_message -from sentry_sdk._types import SENSITIVE_DATA_SUBSTITUTE from sentry_sdk.integrations.litestar import LitestarIntegration +from sentry_sdk.utils import SENSITIVE_DATA_SUBSTITUTE from tests.conftest import ApproxDict from tests.integrations.conftest import parametrize_test_configurable_status_codes from tests.integrations.utils import DATA_COLLECTION_USER_INFO_CASES @@ -97,51 +97,33 @@ async def body_json(data: "dict[str, Any]") -> "dict[str, Any]": ), ], ) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_catch_exceptions( sentry_init, capture_exceptions, - capture_events, capture_items, test_url, expected_error, expected_message, expected_tx_name, - span_streaming, ): sentry_init( integrations=[LitestarIntegration()], - trace_lifecycle="stream" if span_streaming else "static", ) litestar_app = litestar_app_factory() client = TestClient(litestar_app) exceptions = capture_exceptions() - if span_streaming: - items = capture_items("event") + items = capture_items("event") - try: - client.get(test_url) - except Exception: - pass + try: + client.get(test_url) + except Exception: + pass - (exc,) = exceptions - assert isinstance(exc, expected_error) - assert str(exc) == expected_message + (exc,) = exceptions + assert isinstance(exc, expected_error) + assert str(exc) == expected_message - (event,) = (item.payload for item in items) - else: - events = capture_events() - - try: - client.get(test_url) - except Exception: - pass - - (exc,) = exceptions - assert isinstance(exc, expected_error) - assert str(exc) == expected_message - - (event,) = events + (event,) = (item.payload for item in items) assert expected_tx_name in event["transaction"] assert event["exception"]["values"][0]["mechanism"]["type"] == "litestar" @@ -163,61 +145,40 @@ def test_catch_exceptions( ), ], ) -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_transaction_name_and_source( +def test_segment_name_and_source( sentry_init, - capture_events, test_url, expected_tx_name, capture_items, - span_streaming, ): sentry_init( traces_sample_rate=1.0, integrations=[LitestarIntegration()], - trace_lifecycle="stream" if span_streaming else "static", ) litestar_app = litestar_app_factory() client = TestClient(litestar_app) + items = capture_items("span") - if span_streaming: - items = capture_items("span") + try: + client.get(test_url) + except Exception: + pass - try: - client.get(test_url) - except Exception: - pass - - sentry_sdk.flush() - spans = [item.payload for item in items] - - spans = [span for span in spans if expected_tx_name in span["name"]] - assert len(spans) == 1 - assert spans[0]["attributes"]["sentry.segment.name.source"] == "component" - else: - events = capture_events() + sentry_sdk.flush() + spans = [item.payload for item in items] - try: - client.get(test_url) - except Exception: - pass + spans = [span for span in spans if expected_tx_name in span["name"]] + assert len(spans) == 1 + assert spans[0]["attributes"]["sentry.segment.name.source"] == "component" - (_, transaction) = events - assert expected_tx_name in transaction["transaction"] - assert transaction["transaction_info"] == {"source": "component"} - -@pytest.mark.parametrize("span_streaming", [True, False]) def test_middleware_spans( sentry_init, - capture_events, capture_items, - span_streaming, ): sentry_init( traces_sample_rate=1.0, integrations=[LitestarIntegration()], - trace_lifecycle="stream" if span_streaming else "static", ) logging_config = LoggingMiddlewareConfig() @@ -234,57 +195,32 @@ def test_middleware_spans( client = TestClient( litestar_app, raise_server_exceptions=False, base_url="http://testserver.local" ) - if span_streaming: - items = capture_items("span") - - client.get("/message") - - sentry_sdk.flush() - spans = [item.payload for item in items] - - expected = {"SessionMiddleware", "LoggingMiddleware", "RateLimitMiddleware"} - found = set() - - litestar_spans = ( - span - for span in spans - if span["attributes"]["sentry.op"] == "middleware.litestar" - ) + items = capture_items("span") - for span in litestar_spans: - assert span["name"] in expected - assert span["name"] not in found - found.add(span["name"]) - assert span["name"] == span["attributes"]["middleware.name"] - else: - events = capture_events() - - client.get("/message") + client.get("/message") - (_, transaction_event) = events + sentry_sdk.flush() + spans = [item.payload for item in items] - expected = {"SessionMiddleware", "LoggingMiddleware", "RateLimitMiddleware"} - found = set() + expected = {"SessionMiddleware", "LoggingMiddleware", "RateLimitMiddleware"} + found = set() - litestar_spans = ( - span - for span in transaction_event["spans"] - if span["op"] == "middleware.litestar" - ) + litestar_spans = ( + span + for span in spans + if span["attributes"]["sentry.op"] == "middleware.litestar" + ) - for span in litestar_spans: - assert span["description"] in expected - assert span["description"] not in found - found.add(span["description"]) - assert span["description"] == span["tags"]["litestar.middleware_name"] + for span in litestar_spans: + assert span["name"] in expected + assert span["name"] not in found + found.add(span["name"]) + assert span["name"] == span["attributes"]["middleware.name"] -@pytest.mark.parametrize("span_streaming", [True, False]) def test_middleware_callback_spans( sentry_init, - capture_events, capture_items, - span_streaming, ): class SampleMiddleware(AbstractMiddleware): async def __call__(self, scope, receive, send) -> None: @@ -299,98 +235,59 @@ async def do_stuff(message): sentry_init( traces_sample_rate=1.0, integrations=[LitestarIntegration()], - trace_lifecycle="stream" if span_streaming else "static", ) litestar_app = litestar_app_factory(middleware=[SampleMiddleware]) client = TestClient(litestar_app, raise_server_exceptions=False) - if span_streaming: - items = capture_items("span") + items = capture_items("span") - client.get("/message") + client.get("/message") - spans = [item.payload for item in items] + spans = [item.payload for item in items] - expected_litestar_spans = [ - { - "name": "SampleMiddleware", - "attributes": ApproxDict( - { - "middleware.name": "SampleMiddleware", - "sentry.op": "middleware.litestar", - }, - ), - }, - { - "name": "SentryAsgiMiddleware._run_app.._sentry_wrapped_send", - "attributes": ApproxDict( - { - "middleware.name": "SampleMiddleware", - "sentry.op": "middleware.litestar.send", - } - ), - }, - { - "name": "SentryAsgiMiddleware._run_app.._sentry_wrapped_send", - "attributes": ApproxDict( - { - "middleware.name": "SampleMiddleware", - "sentry.op": "middleware.litestar.send", - } - ), - }, - ] - - def is_matching_span(expected_span, actual_span): - return ( - expected_span["name"] == actual_span["name"] - and expected_span["attributes"] == actual_span["attributes"] - ) - - sentry_sdk.flush() - spans = [item.payload for item in items] - actual_litestar_spans = list( - span - for span in spans - if "middleware.litestar" in span["attributes"].get("sentry.op") + expected_litestar_spans = [ + { + "name": "SampleMiddleware", + "attributes": ApproxDict( + { + "middleware.name": "SampleMiddleware", + "sentry.op": "middleware.litestar", + }, + ), + }, + { + "name": "SentryAsgiMiddleware._run_app.._sentry_wrapped_send", + "attributes": ApproxDict( + { + "middleware.name": "SampleMiddleware", + "sentry.op": "middleware.litestar.send", + } + ), + }, + { + "name": "SentryAsgiMiddleware._run_app.._sentry_wrapped_send", + "attributes": ApproxDict( + { + "middleware.name": "SampleMiddleware", + "sentry.op": "middleware.litestar.send", + } + ), + }, + ] + + def is_matching_span(expected_span, actual_span): + return ( + expected_span["name"] == actual_span["name"] + and expected_span["attributes"] == actual_span["attributes"] ) - else: - events = capture_events() - - client.get("/message") - - (_, transaction_events) = events - - expected_litestar_spans = [ - { - "op": "middleware.litestar", - "description": "SampleMiddleware", - "tags": {"litestar.middleware_name": "SampleMiddleware"}, - }, - { - "op": "middleware.litestar.send", - "description": "SentryAsgiMiddleware._run_app.._sentry_wrapped_send", - "tags": {"litestar.middleware_name": "SampleMiddleware"}, - }, - { - "op": "middleware.litestar.send", - "description": "SentryAsgiMiddleware._run_app.._sentry_wrapped_send", - "tags": {"litestar.middleware_name": "SampleMiddleware"}, - }, - ] - def is_matching_span(expected_span, actual_span): - return ( - expected_span["op"] == actual_span["op"] - and expected_span["description"] == actual_span["description"] - and expected_span["tags"] == actual_span["tags"] - ) - - actual_litestar_spans = list( - span - for span in transaction_events["spans"] - if "middleware.litestar" in span["op"] - ) + sentry_sdk.flush() + spans = [item.payload for item in items] + actual_litestar_spans = list( + span + for span in spans + if "middleware.litestar" in span["attributes"].get("sentry.op") + ) assert len(actual_litestar_spans) == 3 @@ -401,8 +298,9 @@ def is_matching_span(expected_span, actual_span): ) -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_middleware_receive_send(sentry_init, capture_items, span_streaming): +def test_middleware_receive_send( + sentry_init, +): class SampleReceiveSendMiddleware(AbstractMiddleware): async def __call__(self, scope, receive, send): message = await receive() @@ -417,7 +315,6 @@ async def __call__(self, scope, receive, send): sentry_init( traces_sample_rate=1.0, integrations=[LitestarIntegration()], - trace_lifecycle="stream" if span_streaming else "static", ) litestar_app = litestar_app_factory(middleware=[SampleReceiveSendMiddleware]) @@ -426,12 +323,9 @@ async def __call__(self, scope, receive, send): client.get("/message") -@pytest.mark.parametrize("span_streaming", [True, False]) def test_middleware_partial_receive_send( sentry_init, - capture_events, capture_items, - span_streaming, ): class SamplePartialReceiveSendMiddleware(AbstractMiddleware): async def __call__(self, scope, receive, send): @@ -456,106 +350,59 @@ async def my_send(*args, **kwargs): sentry_init( traces_sample_rate=1.0, integrations=[LitestarIntegration()], - trace_lifecycle="stream" if span_streaming else "static", ) litestar_app = litestar_app_factory(middleware=[SamplePartialReceiveSendMiddleware]) client = TestClient(litestar_app, raise_server_exceptions=False) + items = capture_items("span") - if span_streaming: - items = capture_items("span") - - # See SamplePartialReceiveSendMiddleware.__call__ above for assertions of correct behavior - client.get("/message") - - sentry_sdk.flush() - spans = [item.payload for item in items] - - expected_litestar_spans = [ - { - "name": "SamplePartialReceiveSendMiddleware", - "attributes": ApproxDict( - { - "middleware.name": "SamplePartialReceiveSendMiddleware", - "sentry.op": "middleware.litestar", - } - ), - }, - { - "name": "TestClientTransport.create_receive..receive", - "attributes": ApproxDict( - { - "middleware.name": "SamplePartialReceiveSendMiddleware", - "sentry.op": "middleware.litestar.receive", - } - ), - }, - { - "name": "SentryAsgiMiddleware._run_app.._sentry_wrapped_send", - "attributes": ApproxDict( - { - "middleware.name": "SamplePartialReceiveSendMiddleware", - "sentry.op": "middleware.litestar.send", - } - ), - }, - ] + # See SamplePartialReceiveSendMiddleware.__call__ above for assertions of correct behavior + client.get("/message") - def is_matching_span(expected_span, actual_span): - return ( - actual_span["name"].startswith(expected_span["name"]) - and expected_span["attributes"] == actual_span["attributes"] - ) + sentry_sdk.flush() + spans = [item.payload for item in items] - actual_litestar_spans = list( - span - for span in spans - if "middleware.litestar" in span["attributes"].get("sentry.op") + expected_litestar_spans = [ + { + "name": "SamplePartialReceiveSendMiddleware", + "attributes": ApproxDict( + { + "middleware.name": "SamplePartialReceiveSendMiddleware", + "sentry.op": "middleware.litestar", + } + ), + }, + { + "name": "TestClientTransport.create_receive..receive", + "attributes": ApproxDict( + { + "middleware.name": "SamplePartialReceiveSendMiddleware", + "sentry.op": "middleware.litestar.receive", + } + ), + }, + { + "name": "SentryAsgiMiddleware._run_app.._sentry_wrapped_send", + "attributes": ApproxDict( + { + "middleware.name": "SamplePartialReceiveSendMiddleware", + "sentry.op": "middleware.litestar.send", + } + ), + }, + ] + + def is_matching_span(expected_span, actual_span): + return ( + actual_span["name"].startswith(expected_span["name"]) + and expected_span["attributes"] == actual_span["attributes"] ) - else: - events = capture_events() - - # See SamplePartialReceiveSendMiddleware.__call__ above for assertions of correct behavior - client.get("/message") - - (_, transaction_events) = events - - expected_litestar_spans = [ - { - "op": "middleware.litestar", - "description": "SamplePartialReceiveSendMiddleware", - "tags": { - "litestar.middleware_name": "SamplePartialReceiveSendMiddleware" - }, - }, - { - "op": "middleware.litestar.receive", - "description": "TestClientTransport.create_receive..receive", - "tags": { - "litestar.middleware_name": "SamplePartialReceiveSendMiddleware" - }, - }, - { - "op": "middleware.litestar.send", - "description": "SentryAsgiMiddleware._run_app.._sentry_wrapped_send", - "tags": { - "litestar.middleware_name": "SamplePartialReceiveSendMiddleware" - }, - }, - ] - def is_matching_span(expected_span, actual_span): - return ( - expected_span["op"] == actual_span["op"] - and actual_span["description"].startswith(expected_span["description"]) - and expected_span["tags"] == actual_span["tags"] - ) - - actual_litestar_spans = list( - span - for span in transaction_events["spans"] - if "middleware.litestar" in span["op"] - ) + actual_litestar_spans = list( + span + for span in spans + if "middleware.litestar" in span["attributes"].get("sentry.op") + ) assert len(actual_litestar_spans) == 3 for expected_span in expected_litestar_spans: @@ -565,17 +412,13 @@ def is_matching_span(expected_span, actual_span): ) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_span_origin( sentry_init, - capture_events, capture_items, - span_streaming, ): sentry_init( integrations=[LitestarIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) logging_config = LoggingMiddlewareConfig() @@ -592,40 +435,26 @@ def test_span_origin( client = TestClient( litestar_app, raise_server_exceptions=False, base_url="http://testserver.local" ) - if span_streaming: - items = capture_items("span") - - client.get("/message") - - sentry_sdk.flush() - spans = [item.payload for item in items] - - for span in spans: - if span["attributes"]["sentry.origin"] == "auto.http.httpx": - continue - assert span["attributes"]["sentry.origin"] == "auto.http.litestar" - else: - events = capture_events() + items = capture_items("span") - client.get("/message") + client.get("/message") - (_, event) = events + sentry_sdk.flush() + spans = [item.payload for item in items] - assert event["contexts"]["trace"]["origin"] == "auto.http.litestar" - for span in event["spans"]: - assert span["origin"] == "auto.http.litestar" + for span in spans: + if span["attributes"]["sentry.origin"] == "auto.http.httpx": + continue + assert span["attributes"]["sentry.origin"] == "auto.http.litestar" @pytest.mark.parametrize("init_kwargs, expect_user", DATA_COLLECTION_USER_INFO_CASES) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_litestar_scope_user_on_exception_event( sentry_init, capture_exceptions, - capture_events, capture_items, init_kwargs, expect_user, - span_streaming, ): class TestUserMiddleware(AbstractMiddleware): async def __call__(self, scope, receive, send): @@ -638,36 +467,22 @@ async def __call__(self, scope, receive, send): sentry_init( integrations=[LitestarIntegration()], - trace_lifecycle="stream" if span_streaming else "static", **init_kwargs, ) litestar_app = litestar_app_factory(middleware=[TestUserMiddleware]) client = TestClient(litestar_app) exceptions = capture_exceptions() - if span_streaming: - items = capture_items("event") - - # This request intentionally raises an exception - try: - client.get("/some_url") - except Exception: - pass - - assert len(exceptions) == 1 - (event,) = (item.payload for item in items) - else: - events = capture_events() + items = capture_items("event") - # This request intentionally raises an exception - try: - client.get("/some_url") - except Exception: - pass + # This request intentionally raises an exception + try: + client.get("/some_url") + except Exception: + pass - assert len(exceptions) == 1 - assert len(events) == 1 - (event,) = events + assert len(exceptions) == 1 + (event,) = (item.payload for item in items) if expect_user: assert "user" in event @@ -715,14 +530,12 @@ def test_request_body_data_collection( client = TestClient(litestar_app) client.post("/body/json", json=body) - (event, transaction_event) = events + (event,) = events if expect_body: assert event["request"]["data"] == body - assert transaction_event["request"]["data"] == body else: assert "data" not in event["request"] - assert "data" not in transaction_event["request"] def test_request_body_data_collection_wins_over_send_default_pii( @@ -741,10 +554,9 @@ def test_request_body_data_collection_wins_over_send_default_pii( client = TestClient(litestar_app) client.post("/body/json", json={"foo": {"bar": "baz", "qux": ["1", "2", "3"]}}) - (event, transaction_event) = events + (event,) = events assert "data" not in event["request"] - assert "data" not in transaction_event["request"] @pytest.mark.parametrize( @@ -849,26 +661,21 @@ def test_cookie_data_collection( client = TestClient(litestar_app) client.get("/message", headers={"cookie": COOKIE_HEADER}) - (event, transaction_event) = events + (event,) = events if expected_cookies is None: assert "cookies" not in event["request"] - assert "cookies" not in transaction_event["request"] else: assert event["request"]["cookies"] == expected_cookies - assert transaction_event["request"]["cookies"] == expected_cookies @parametrize_test_configurable_status_codes -@pytest.mark.parametrize("span_streaming", [True, False]) def test_configurable_status_codes_handler( sentry_init, - capture_events, capture_items, failed_request_status_codes, status_code, expected_error, - span_streaming, ): integration_kwargs = ( {"failed_request_status_codes": failed_request_status_codes} @@ -877,7 +684,6 @@ def test_configurable_status_codes_handler( ) sentry_init( integrations=[LitestarIntegration(**integration_kwargs)], - trace_lifecycle="stream" if span_streaming else "static", ) @get("/error") @@ -886,31 +692,22 @@ async def error() -> None: app = Litestar([error]) client = TestClient(app) + items = capture_items("event") - if span_streaming: - items = capture_items("event") - - client.get("/error") - - events = [item.payload for item in items] - else: - events = capture_events() + client.get("/error") - client.get("/error") + events = [item.payload for item in items] assert len(events) == int(expected_error) @parametrize_test_configurable_status_codes -@pytest.mark.parametrize("span_streaming", [True, False]) def test_configurable_status_codes_middleware( sentry_init, - capture_events, capture_items, failed_request_status_codes, status_code, expected_error, - span_streaming, ): integration_kwargs = ( {"failed_request_status_codes": failed_request_status_codes} @@ -920,7 +717,6 @@ def test_configurable_status_codes_middleware( sentry_init( integrations=[LitestarIntegration(**integration_kwargs)], - trace_lifecycle="stream" if span_streaming else "static", ) def create_raising_middleware(app): @@ -934,31 +730,21 @@ async def error() -> None: ... app = Litestar([error], middleware=[create_raising_middleware]) client = TestClient(app) + items = capture_items("event") - if span_streaming: - items = capture_items("event") - - client.get("/error") - - events = [item.payload for item in items] - else: - events = capture_events() + client.get("/error") - client.get("/error") + events = [item.payload for item in items] assert len(events) == int(expected_error) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_catch_non_http_exceptions_in_middleware( sentry_init, - capture_events, capture_items, - span_streaming, ): sentry_init( integrations=[LitestarIntegration()], - trace_lifecycle="stream" if span_streaming else "static", ) def create_raising_middleware(app): @@ -972,23 +758,14 @@ async def error() -> None: ... app = Litestar([error], middleware=[create_raising_middleware]) client = TestClient(app) + items = capture_items("event") - if span_streaming: - items = capture_items("event") - - try: - client.get("/error") - except RuntimeError: - pass - - events = [item.payload for item in items] - else: - events = capture_events() + try: + client.get("/error") + except RuntimeError: + pass - try: - client.get("/error") - except RuntimeError: - pass + events = [item.payload for item in items] assert len(events) == 1 event_exception = events[0]["exception"]["values"][0] diff --git a/tests/integrations/logging/test_logging.py b/tests/integrations/logging/test_logging.py index 15ceb8dd65..e86b529948 100644 --- a/tests/integrations/logging/test_logging.py +++ b/tests/integrations/logging/test_logging.py @@ -4,15 +4,15 @@ import pytest +import sentry_sdk from sentry_sdk import get_client from sentry_sdk.consts import VERSION from sentry_sdk.integrations.logging import ( LoggingIntegration, - SentryLogsHandler, ignore_logger, - ignore_logger_for_sentry_logs, + ignore_logger_for_events, unignore_logger, - unignore_logger_for_sentry_logs, + unignore_logger_for_events, ) other_logger = logging.getLogger("testfoo") @@ -25,9 +25,71 @@ def reset_level(): logger.setLevel(logging.DEBUG) +def test_logging_defaults(sentry_init, capture_events): + sentry_init() + + events = capture_events() + + logger.info("bread", extra=dict(foo=42)) + logger.critical("lol", extra=dict(bar=69)) + + sentry_sdk.capture_message("hello") + + sentry_sdk.flush() + + # Without adding the integration explicitly, only the message should be + # captured (no logs), and it shouldn't have any breadcrumbs + assert len(events) == 1 + (event,) = events + assert not event["breadcrumbs"]["values"] + + +def test_logging_defaults_enabled(sentry_init, capture_items): + sentry_init( + integrations=[LoggingIntegration()], + ) + + items = capture_items() + + logger.info("bread", extra=dict(foo=42)) + logger.critical("lol", extra=dict(bar=69)) + + sentry_sdk.capture_message("hello") + + sentry_sdk.flush() + + assert len(items) == 3 + message, log1, log2 = [item.payload for item in items] + + assert len(message["breadcrumbs"]["values"]) == 2 + crumb1, crumb2 = message["breadcrumbs"]["values"] + + assert crumb1["type"] == "log" + assert crumb1["message"] == "bread" + assert crumb1["data"] == {"foo": 42} + + assert crumb2["type"] == "log" + assert crumb2["message"] == "lol" + assert crumb2["data"] == {"bar": 69} + + assert log1["level"] == "info" + assert log1["attributes"]["sentry.severity_number"] == 9 + assert log1["attributes"]["sentry.severity_text"] == "info" + assert log1["attributes"]["foo"] == 42 + + assert log2["level"] == "fatal" + assert log2["attributes"]["sentry.severity_number"] == 21 + assert log2["attributes"]["sentry.severity_text"] == "fatal" + assert log2["attributes"]["bar"] == 69 + + @pytest.mark.parametrize("logger", [logger, other_logger]) -def test_logging_works_with_many_loggers(sentry_init, capture_events, logger): - sentry_init(integrations=[LoggingIntegration(event_level="ERROR")]) +def test_event_logging_works_with_many_loggers(sentry_init, capture_events, logger): + sentry_init( + integrations=[ + LoggingIntegration(event_level=logging.ERROR, breadcrumb_level=logging.INFO) + ] + ) events = capture_events() logger.info("bread") @@ -40,28 +102,13 @@ def test_logging_works_with_many_loggers(sentry_init, capture_events, logger): assert any(crumb["message"] == "bread" for crumb in event["breadcrumbs"]["values"]) -@pytest.mark.parametrize("integrations", [None, [], [LoggingIntegration()]]) -@pytest.mark.parametrize( - "kwargs", [{"exc_info": None}, {}, {"exc_info": 0}, {"exc_info": False}] -) -def test_logging_defaults(integrations, sentry_init, capture_events, kwargs): - sentry_init(integrations=integrations) - events = capture_events() - - logger.info("bread") - logger.critical("LOL", **kwargs) - (event,) = events - - assert event["level"] == "fatal" - assert any(crumb["message"] == "bread" for crumb in event["breadcrumbs"]["values"]) - assert not any( - crumb["message"] == "LOL" for crumb in event["breadcrumbs"]["values"] +def test_event_logging_extra_data(sentry_init, capture_events): + sentry_init( + integrations=[ + LoggingIntegration(breadcrumb_level=logging.INFO, event_level=logging.ERROR) + ], + default_integrations=False, ) - assert "threads" not in event - - -def test_logging_extra_data(sentry_init, capture_events): - sentry_init(integrations=[LoggingIntegration()], default_integrations=False) events = capture_events() logger.info("bread", extra=dict(foo=42)) @@ -77,8 +124,15 @@ def test_logging_extra_data(sentry_init, capture_events): ) -def test_logging_extra_data_integer_keys(sentry_init, capture_events): - sentry_init(integrations=[LoggingIntegration()], default_integrations=False) +def test_event_logging_extra_data_integer_keys(sentry_init, capture_events): + sentry_init( + integrations=[ + LoggingIntegration( + breadcrumb_level=logging.INFO, event_level=logging.ERROR + ), + ], + default_integrations=False, + ) events = capture_events() logger.critical("integer in extra keys", extra={1: 1}) @@ -95,8 +149,15 @@ def test_logging_extra_data_integer_keys(sentry_init, capture_events): pytest.param({"stack_info": True}, id="stack_info"), ), ) -def test_logging_stack_trace(sentry_init, capture_events, enable_stack_trace_kwarg): - sentry_init(integrations=[LoggingIntegration()], default_integrations=False) +def test_event_logging_stack_trace( + sentry_init, capture_events, enable_stack_trace_kwarg +): + sentry_init( + integrations=[ + LoggingIntegration(breadcrumb_level=logging.INFO, event_level=logging.ERROR) + ], + attach_stacktrace=False, + ) events = capture_events() logger.error("first", **enable_stack_trace_kwarg) @@ -114,8 +175,12 @@ def test_logging_stack_trace(sentry_init, capture_events, enable_stack_trace_kwa assert "threads" not in event_without -def test_logging_level(sentry_init, capture_events): - sentry_init(integrations=[LoggingIntegration()], default_integrations=False) +def test_event_logging_level(sentry_init, capture_events): + sentry_init( + integrations=[ + LoggingIntegration(breadcrumb_level=logging.INFO, event_level=logging.ERROR) + ], + ) events = capture_events() logger.setLevel(logging.WARNING) @@ -132,7 +197,7 @@ def test_logging_level(sentry_init, capture_events): assert not events -def test_custom_log_level_names(sentry_init, capture_events): +def test_event_logging_custom_level_names(sentry_init, capture_events): levels = { logging.DEBUG: "debug", logging.INFO: "info", @@ -156,7 +221,6 @@ def test_custom_log_level_names(sentry_init, capture_events): logger.setLevel(logging_level) sentry_init( integrations=[LoggingIntegration(event_level=logging_level)], - default_integrations=False, ) events = capture_events() @@ -170,8 +234,12 @@ def test_custom_log_level_names(sentry_init, capture_events): del events[:] -def test_logging_filters(sentry_init, capture_events): - sentry_init(integrations=[LoggingIntegration()], default_integrations=False) +def test_event_logging_filters(sentry_init, capture_events): + sentry_init( + integrations=[ + LoggingIntegration(breadcrumb_level=logging.INFO, event_level=logging.ERROR) + ], + ) events = capture_events() should_log = False @@ -193,10 +261,9 @@ def filter(self, record): assert event["logentry"]["formatted"] == "hi" -def test_logging_captured_warnings(sentry_init, capture_events, recwarn): +def test_event_logging_captured_warnings(sentry_init, capture_events, recwarn): sentry_init( integrations=[LoggingIntegration(event_level="WARNING")], - default_integrations=False, ) events = capture_events() @@ -233,44 +300,27 @@ def test_logging_captured_warnings(sentry_init, capture_events, recwarn): def test_sentry_logs_collection_off_by_default(sentry_init, capture_items, request): - """Automatic logs capture by Sentry logs needs explicit opt-in via capture_sentry_logs.""" + """Automatic logs capture by Sentry logs needs explicit opt-in to the integration.""" sentry_init() items = capture_items("log") python_logger = logging.Logger("test-logger") python_logger.warning("this is %s a template %s", "1", "2") - get_client().flush() + sentry_sdk.flush() assert not items -def test_sentry_logs_handler_skips_format_when_disabled(sentry_init): - sentry_init(integrations=[LoggingIntegration(capture_sentry_logs=False)]) - handler = SentryLogsHandler() - record = logging.LogRecord( - name="test-logger", - level=logging.INFO, - pathname=__file__, - lineno=1, - msg="hello %s", - args=("world",), - exc_info=None, - ) - with mock.patch.object(handler, "format") as formatted: - handler.emit(record) - formatted.assert_not_called() - - def test_sentry_logs_collection_opt_in(sentry_init, capture_items, request): - """Automatic logs capture by Sentry logs needs explicit opt-in via capture_sentry_logs.""" - sentry_init(integrations=[LoggingIntegration(capture_sentry_logs=True)]) + """Automatic logs capture by Sentry logs needs explicit opt-in to the integration.""" + sentry_init(integrations=[LoggingIntegration()]) items = capture_items("log") python_logger = logging.Logger("test-logger") python_logger.warning("this is %s a template %s", "1", "2") - get_client().flush() + sentry_sdk.flush() assert len(items) == 1 @@ -280,73 +330,45 @@ def test_sentry_logs_collection_opt_in(sentry_init, capture_items, request): assert log["attributes"]["sentry.severity_text"] == "warn" -def test_sentry_logs_collection_opt_in_compat(sentry_init, capture_items, request): - """Automatic logs capture by Sentry logs needs explicit opt-in via enable_logs.""" - # This should be removed in the next major. - sentry_init(enable_logs=True) - items = capture_items("log") - - python_logger = logging.Logger("test-logger") - python_logger.warning("this is %s a template %s", "1", "2") - - get_client().flush() - - assert len(items) == 1 - - log = items[0].payload - assert log["attributes"]["sentry.message.template"] == "this is %s a template %s" - assert log["attributes"]["sentry.severity_number"] == 13 - assert log["attributes"]["sentry.severity_text"] == "warn" - - -def test_sentry_logs_collection_opt_in_compat_does_not_override_explicit_opt_out( - sentry_init, capture_items, request -): - # This should be removed in the next major. +def test_ignore_logger_for_events(sentry_init, capture_events, request): sentry_init( - enable_logs=True, integrations=[LoggingIntegration(capture_sentry_logs=False)] + integrations=[LoggingIntegration(event_level=logging.DEBUG)], ) - items = capture_items("log") - - python_logger = logging.Logger("test-logger") - python_logger.warning("this is %s a template %s", "1", "2") - - get_client().flush() - - assert len(items) == 0 - - -def test_ignore_logger(sentry_init, capture_events, request): - sentry_init(integrations=[LoggingIntegration()], default_integrations=False) events = capture_events() - ignore_logger("testfoo") - request.addfinalizer(lambda: unignore_logger("testfoo")) + ignore_logger_for_events("testfoo") + request.addfinalizer(lambda: unignore_logger_for_events("testfoo")) other_logger.error("hi") assert not events -def test_ignore_logger_whitespace_padding(sentry_init, capture_events, request): +def test_ignore_logger_for_events_whitespace_padding( + sentry_init, capture_events, request +): """Here we test insensitivity to whitespace padding of ignored loggers""" - sentry_init(integrations=[LoggingIntegration()], default_integrations=False) + sentry_init( + integrations=[LoggingIntegration(event_level=logging.DEBUG)], + ) events = capture_events() - ignore_logger("testfoo") - request.addfinalizer(lambda: unignore_logger("testfoo")) + ignore_logger_for_events("testfoo") + request.addfinalizer(lambda: unignore_logger_for_events("testfoo")) padded_logger = logging.getLogger(" testfoo ") padded_logger.error("hi") assert not events -def test_ignore_logger_wildcard(sentry_init, capture_events, request): - sentry_init(integrations=[LoggingIntegration()], default_integrations=False) +def test_ignore_logger_for_events_wildcard(sentry_init, capture_events, request): + sentry_init( + integrations=[LoggingIntegration(event_level=logging.DEBUG)], + ) events = capture_events() - ignore_logger("testfoo.*") - request.addfinalizer(lambda: unignore_logger("testfoo.*")) + ignore_logger_for_events("testfoo.*") + request.addfinalizer(lambda: unignore_logger_for_events("testfoo.*")) nested_logger = logging.getLogger("testfoo.submodule") @@ -359,13 +381,15 @@ def test_ignore_logger_wildcard(sentry_init, capture_events, request): assert event["logentry"]["formatted"] == "hi" -def test_ignore_logger_does_not_affect_sentry_logs(sentry_init, capture_items, request): - """ignore_logger should suppress events/breadcrumbs but not Sentry Logs.""" - sentry_init(integrations=[LoggingIntegration(capture_sentry_logs=True)]) +def test_ignore_logger_for_events_does_not_affect_sentry_logs( + sentry_init, capture_items, request +): + """ignore_logger_for_events should suppress events/breadcrumbs but not Sentry Logs.""" + sentry_init(integrations=[LoggingIntegration(event_level=logging.DEBUG)]) items = capture_items("log") - ignore_logger("testfoo") - request.addfinalizer(lambda: unignore_logger("testfoo")) + ignore_logger_for_events("testfoo") + request.addfinalizer(lambda: unignore_logger_for_events("testfoo")) other_logger.error("hi") get_client().flush() @@ -375,19 +399,17 @@ def test_ignore_logger_does_not_affect_sentry_logs(sentry_init, capture_items, r assert logs[0]["body"] == "hi" -def test_ignore_logger_for_sentry_logs( - sentry_init, capture_envelopes, capture_items, request -): - """ignore_logger_for_sentry_logs should suppress Sentry Logs but not events.""" - sentry_init(integrations=[LoggingIntegration(capture_sentry_logs=True)]) +def test_ignore_logger(sentry_init, capture_envelopes, capture_items, request): + """ignore_logger should suppress Sentry Logs but not events.""" + sentry_init(integrations=[LoggingIntegration(event_level=logging.ERROR)]) envelopes = capture_envelopes() items = capture_items("log") - ignore_logger_for_sentry_logs("testfoo") - request.addfinalizer(lambda: unignore_logger_for_sentry_logs("testfoo")) + ignore_logger("testfoo") + request.addfinalizer(lambda: unignore_logger("testfoo")) other_logger.error("hi") - get_client().flush() + sentry_sdk.flush() # Event should still be captured event_envelopes = [e for e in envelopes if e.items[0].type == "event"] @@ -398,9 +420,11 @@ def test_ignore_logger_for_sentry_logs( assert len(logs) == 0 -def test_logging_dictionary_interpolation(sentry_init, capture_events): +def test_event_logging_dictionary_interpolation(sentry_init, capture_events): """Here we test an entire dictionary being interpolated into the log message.""" - sentry_init(integrations=[LoggingIntegration()], default_integrations=False) + sentry_init( + integrations=[LoggingIntegration(event_level=logging.ERROR)], + ) events = capture_events() logger.error("this is a log with a dictionary %s", {"foo": "bar"}) @@ -414,9 +438,11 @@ def test_logging_dictionary_interpolation(sentry_init, capture_events): assert event["logentry"]["params"] == {"foo": "bar"} -def test_logging_dictionary_args(sentry_init, capture_events): +def test_event_logging_dictionary_args(sentry_init, capture_events): """Here we test items from a dictionary being interpolated into the log message.""" - sentry_init(integrations=[LoggingIntegration()], default_integrations=False) + sentry_init( + integrations=[LoggingIntegration(event_level=logging.ERROR)], + ) events = capture_events() logger.error( @@ -440,13 +466,13 @@ def test_sentry_logs_warning(sentry_init, capture_items): """ The python logger module should create 'warn' sentry logs if the flag is on. """ - sentry_init(integrations=[LoggingIntegration(capture_sentry_logs=True)]) + sentry_init(integrations=[LoggingIntegration()]) items = capture_items("log") python_logger = logging.Logger("test-logger") python_logger.warning("this is %s a template %s", "1", "2") - get_client().flush() + sentry_sdk.flush() logs = [item.payload for item in items] attrs = logs[0]["attributes"] assert attrs["sentry.message.template"] == "this is %s a template %s" @@ -465,12 +491,12 @@ def test_sentry_logs_debug(sentry_init, capture_envelopes): """ The python logger module should not create 'debug' sentry logs if the flag is on by default """ - sentry_init(integrations=[LoggingIntegration(capture_sentry_logs=True)]) + sentry_init(integrations=[LoggingIntegration()]) envelopes = capture_envelopes() python_logger = logging.Logger("test-logger") python_logger.debug("this is %s a template %s", "1", "2") - get_client().flush() + sentry_sdk.flush() assert len(envelopes) == 0 @@ -480,18 +506,14 @@ def test_no_log_infinite_loop(sentry_init, capture_envelopes): If 'debug' mode is true, and you set a low log level in the logging integration, there should be no infinite loops. """ sentry_init( - integrations=[ - LoggingIntegration( - capture_sentry_logs=True, sentry_logs_level=logging.DEBUG - ) - ], + integrations=[LoggingIntegration(level=logging.DEBUG)], debug=True, ) envelopes = capture_envelopes() python_logger = logging.Logger("test-logger") python_logger.debug("this is %s a template %s", "1", "2") - get_client().flush() + sentry_sdk.flush() assert len(envelopes) == 1 @@ -500,14 +522,15 @@ def test_logging_errors(sentry_init, capture_envelopes, capture_items): """ The python logger module should be able to log errors without erroring """ - sentry_init(integrations=[LoggingIntegration(capture_sentry_logs=True)]) + sentry_init(integrations=[LoggingIntegration(event_level=logging.ERROR)]) envelopes = capture_envelopes() items = capture_items("log") python_logger = logging.Logger("test-logger") python_logger.error(Exception("test exc 1")) python_logger.error("error is %s", Exception("test exc 2")) - get_client().flush() + + sentry_sdk.flush() error_event_1 = envelopes[0].items[0].payload.json assert error_event_1["level"] == "error" @@ -522,9 +545,8 @@ def test_logging_errors(sentry_init, capture_envelopes, capture_items): assert logs[1]["attributes"]["sentry.severity_text"] == "error" assert logs[1]["attributes"]["sentry.message.template"] == "error is %s" - assert logs[1]["attributes"]["sentry.message.parameter.0"] in ( - "Exception('test exc 2')", - "Exception('test exc 2',)", # py3.6 + assert ( + logs[1]["attributes"]["sentry.message.parameter.0"] == "Exception('test exc 2')" ) assert "code.line.number" in logs[1]["attributes"] @@ -537,7 +559,7 @@ def test_log_strips_project_root(sentry_init, capture_items): """ sentry_init( project_root="/custom/test", - integrations=[LoggingIntegration(capture_sentry_logs=True)], + integrations=[LoggingIntegration()], ) items = capture_items("log") @@ -553,7 +575,7 @@ def test_log_strips_project_root(sentry_init, capture_items): exc_info=None, ) ) - get_client().flush() + sentry_sdk.flush() logs = [item.payload for item in items] assert len(logs) == 1 @@ -565,7 +587,7 @@ def test_logger_with_all_attributes(sentry_init, capture_items): """ The python logger should be able to log all attributes, including extra data. """ - sentry_init(integrations=[LoggingIntegration(capture_sentry_logs=True)]) + sentry_init(integrations=[LoggingIntegration()]) items = capture_items("log") python_logger = logging.Logger("test-logger") @@ -574,7 +596,7 @@ def test_logger_with_all_attributes(sentry_init, capture_items): 1, extra={"foo": "bar", "numeric": 42, "more_complex": {"nested": "data"}}, ) - get_client().flush() + sentry_sdk.flush() logs = [item.payload for item in items] @@ -642,7 +664,7 @@ def test_sentry_logs_named_parameters(sentry_init, capture_items): """ The python logger module should capture named parameters from dictionary arguments in Sentry logs. """ - sentry_init(integrations=[LoggingIntegration(capture_sentry_logs=True)]) + sentry_init(integrations=[LoggingIntegration()]) items = capture_items("log") python_logger = logging.Logger("test-logger") @@ -657,7 +679,7 @@ def test_sentry_logs_named_parameters(sentry_init, capture_items): }, ) - get_client().flush() + sentry_sdk.flush() logs = [item.payload for item in items] assert len(logs) == 1 @@ -687,7 +709,7 @@ def test_sentry_logs_named_parameters_complex_values(sentry_init, capture_items) """ The python logger module should handle complex values in named parameters using safe_repr. """ - sentry_init(integrations=[LoggingIntegration(capture_sentry_logs=True)]) + sentry_init(integrations=[LoggingIntegration()]) items = capture_items("log") python_logger = logging.Logger("test-logger") @@ -700,7 +722,7 @@ def test_sentry_logs_named_parameters_complex_values(sentry_init, capture_items) }, ) - get_client().flush() + sentry_sdk.flush() logs = [item.payload for item in items] assert len(logs) == 1 @@ -721,13 +743,13 @@ def test_sentry_logs_no_parameters_no_template(sentry_init, capture_items): """ There shouldn't be a template if there are no parameters. """ - sentry_init(integrations=[LoggingIntegration(capture_sentry_logs=True)]) + sentry_init(integrations=[LoggingIntegration()]) items = capture_items("log") python_logger = logging.Logger("test-logger") python_logger.warning("Warning about something without any parameters.") - get_client().flush() + sentry_sdk.flush() logs = [item.payload for item in items] assert len(logs) == 1 diff --git a/tests/integrations/loguru/test_loguru.py b/tests/integrations/loguru/test_loguru.py index 2db777d3c3..20e90cffcf 100644 --- a/tests/integrations/loguru/test_loguru.py +++ b/tests/integrations/loguru/test_loguru.py @@ -12,31 +12,72 @@ logger.remove(0) # don't print to console +def test_defaults(sentry_init, capture_events): + """No logs, events, breadcrumbs captured by default.""" + sentry_init() + + events = capture_events() + + logger.error("test") + + assert not events + + +def test_defaults_enabled(sentry_init, capture_items): + """Logs and breadcrumbs captured by default if integration is enabled.""" + sentry_init(integrations=[LoguruIntegration()]) + + items = capture_items() + + logger.error("test") + sentry_sdk.capture_message("oh no") + + sentry_sdk.flush() + + events = [item for item in items if item.type == "event"] + logs = [item for item in items if item.type == "log"] + + assert len(events) == 1 + assert events[0].payload["message"] == "oh no" + + breadcrumbs = events[0].payload["breadcrumbs"]["values"] + assert len(breadcrumbs) == 1 + assert breadcrumbs[0]["level"] == "error" + assert breadcrumbs[0]["category"] == "tests.integrations.loguru.test_loguru" + + assert len(logs) == 1 + assert logs[0].payload["body"] == "test" + assert logs[0].payload["level"] == "error" + assert logs[0].payload["attributes"]["sentry.origin"] == "auto.log.loguru" + + @pytest.mark.parametrize( - "level,created_event,expected_sentry_level", + "level,created_event,created_breadcrumb,created_log,expected_event_level,expected_log_level", [ - # None - no breadcrumb - # False - no event - # True - event created - (LoggingLevels.TRACE, None, "debug"), - (LoggingLevels.DEBUG, None, "debug"), - (LoggingLevels.INFO, False, "info"), - (LoggingLevels.SUCCESS, False, "info"), - (LoggingLevels.WARNING, False, "warning"), - (LoggingLevels.ERROR, True, "error"), - (LoggingLevels.CRITICAL, True, "critical"), + (LoggingLevels.TRACE, False, False, False, "debug", "trace"), + (LoggingLevels.DEBUG, False, False, False, "debug", "debug"), + (LoggingLevels.INFO, False, True, True, "info", "info"), + (LoggingLevels.SUCCESS, False, True, True, "info", "info"), + (LoggingLevels.WARNING, False, True, True, "warning", "warn"), + (LoggingLevels.ERROR, True, True, True, "error", "error"), + (LoggingLevels.CRITICAL, True, True, True, "critical", "fatal"), ], ) @pytest.mark.parametrize("disable_breadcrumbs", [True, False]) @pytest.mark.parametrize("disable_events", [True, False]) -def test_just_log( +@pytest.mark.parametrize("disable_logs", [True, False]) +def test_levels( sentry_init, - capture_events, + capture_items, level, created_event, - expected_sentry_level, + created_breadcrumb, + created_log, + expected_event_level, + expected_log_level, disable_breadcrumbs, disable_events, + disable_logs, uninstall_integration, request, ): @@ -46,46 +87,52 @@ def test_just_log( sentry_init( integrations=[ LoguruIntegration( - level=None if disable_breadcrumbs else LoggingLevels.INFO.value, + breadcrumb_level=None + if disable_breadcrumbs + else LoggingLevels.INFO.value, event_level=None if disable_events else LoggingLevels.ERROR.value, + level=None if disable_logs else LoggingLevels.INFO.value, ) ], - default_integrations=False, ) - events = capture_events() + items = capture_items() getattr(logger, level.name.lower())("test") + sentry_sdk.flush() + expected_pattern = ( r" \| " + r"{:9}".format(level.name.upper()) - + r"\| tests\.integrations\.loguru\.test_loguru:test_just_log:\d+ - test" + + r"\| tests\.integrations\.loguru\.test_loguru:test_levels:\d+ - test" ) - if not created_event: + breadcrumbs = sentry_sdk.get_isolation_scope()._breadcrumbs + if not disable_breadcrumbs and created_breadcrumb: + (breadcrumb,) = breadcrumbs + assert breadcrumb["level"] == expected_event_level + assert breadcrumb["category"] == "tests.integrations.loguru.test_loguru" + assert re.fullmatch(expected_pattern, breadcrumb["message"][23:]) + else: + assert not breadcrumbs + + events = [item for item in items if item.type == "event"] + if disable_events or not created_event: assert not events - breadcrumbs = sentry_sdk.get_isolation_scope()._breadcrumbs - if ( - not disable_breadcrumbs and created_event is not None - ): # not None == not TRACE or DEBUG level - (breadcrumb,) = breadcrumbs - assert breadcrumb["level"] == expected_sentry_level - assert breadcrumb["category"] == "tests.integrations.loguru.test_loguru" - assert re.fullmatch(expected_pattern, breadcrumb["message"][23:]) - else: - assert not breadcrumbs - - return + logs = [item for item in items if item.type == "log"] + if disable_logs or not created_log: + assert not logs - if disable_events: - assert not events - return + for event in events: + assert event.payload["level"] == expected_event_level + assert event.payload["logger"] == "tests.integrations.loguru.test_loguru" + assert re.fullmatch(expected_pattern, event.payload["logentry"]["message"][23:]) - (event,) = events - assert event["level"] == expected_sentry_level - assert event["logger"] == "tests.integrations.loguru.test_loguru" - assert re.fullmatch(expected_pattern, event["logentry"]["message"][23:]) + for log in logs: + assert log.payload["level"] == expected_log_level + assert log.payload["body"] == "test" + assert log.payload["attributes"]["sentry.origin"] == "auto.log.loguru" def test_breadcrumb_format(sentry_init, capture_events, uninstall_integration, request): @@ -95,12 +142,12 @@ def test_breadcrumb_format(sentry_init, capture_events, uninstall_integration, r sentry_init( integrations=[ LoguruIntegration( - level=LoggingLevels.INFO.value, - event_level=None, + breadcrumb_level=LoggingLevels.INFO.value, breadcrumb_format="{message}", + level=None, + event_level=None, ) ], - default_integrations=False, ) logger.info("test") @@ -119,11 +166,11 @@ def test_event_format(sentry_init, capture_events, uninstall_integration, reques integrations=[ LoguruIntegration( level=None, + breadcrumb_level=None, event_level=LoggingLevels.ERROR.value, event_format="{message}", ) ], - default_integrations=False, ) events = capture_events() @@ -140,7 +187,7 @@ def test_sentry_logs_warning( uninstall_integration("loguru") request.addfinalizer(logger.remove) - sentry_init(integrations=[LoguruIntegration(capture_sentry_logs=True)]) + sentry_init(integrations=[LoguruIntegration()]) items = capture_items("log") logger.warning("this is {} a {}", "just", "template") @@ -164,7 +211,7 @@ def test_sentry_logs_debug( uninstall_integration("loguru") request.addfinalizer(logger.remove) - sentry_init(integrations=[LoguruIntegration(capture_sentry_logs=True)]) + sentry_init(integrations=[LoguruIntegration()]) envelopes = capture_envelopes() logger.debug("this is %s a template %s", "1", "2") @@ -178,11 +225,7 @@ def test_sentry_log_levels(sentry_init, capture_items, uninstall_integration, re request.addfinalizer(logger.remove) sentry_init( - integrations=[ - LoguruIntegration( - capture_sentry_logs=True, sentry_logs_level=LoggingLevels.SUCCESS - ) - ], + integrations=[LoguruIntegration(level=LoggingLevels.SUCCESS)], ) items = capture_items("log") @@ -215,9 +258,7 @@ def test_disable_loguru_logs( request.addfinalizer(logger.remove) sentry_init( - integrations=[ - LoguruIntegration(capture_sentry_logs=True, sentry_logs_level=None) - ], + integrations=[LoguruIntegration(level=None)], ) items = capture_items("log") @@ -256,78 +297,6 @@ def test_disable_sentry_logs_by_default( assert len(logs) == 0 -def test_enable_sentry_logs_if_enable_logs_is_true( - sentry_init, capture_items, uninstall_integration, request -): - # This should be removed in the next major. - uninstall_integration("loguru") - request.addfinalizer(logger.remove) - - sentry_init(enable_logs=True) - items = capture_items("log") - - logger.trace("this is a log") - logger.debug("this is a log") - logger.info("this is a log") - logger.success("this is a log") - logger.warning("this is a log") - logger.error("this is a log") - logger.critical("this is a log") - - sentry_sdk.get_client().flush() - logs = [item.payload for item in items] - assert len(logs) == 5 - - -def test_disable_sentry_logs_if_enable_logs_is_true_but_integration_option_is_false( - sentry_init, capture_items, uninstall_integration, request -): - # This should be removed in the next major. - uninstall_integration("loguru") - request.addfinalizer(logger.remove) - - sentry_init( - enable_logs=True, integrations=[LoguruIntegration(capture_sentry_logs=False)] - ) - items = capture_items("log") - - logger.trace("this is a log") - logger.debug("this is a log") - logger.info("this is a log") - logger.success("this is a log") - logger.warning("this is a log") - logger.error("this is a log") - logger.critical("this is a log") - - sentry_sdk.get_client().flush() - logs = [item.payload for item in items] - assert not logs - - -def test_disable_sentry_logs_explicitly( - sentry_init, capture_items, uninstall_integration, request -): - uninstall_integration("loguru") - request.addfinalizer(logger.remove) - - sentry_init( - integrations=[LoguruIntegration(capture_sentry_logs=False)], - ) - items = capture_items("log") - - logger.trace("this is a log") - logger.debug("this is a log") - logger.info("this is a log") - logger.success("this is a log") - logger.warning("this is a log") - logger.error("this is a log") - logger.critical("this is a log") - - sentry_sdk.get_client().flush() - logs = [item.payload for item in items] - assert len(logs) == 0 - - def test_no_log_infinite_loop( sentry_init, capture_envelopes, uninstall_integration, request ): @@ -338,11 +307,7 @@ def test_no_log_infinite_loop( request.addfinalizer(logger.remove) sentry_init( - integrations=[ - LoguruIntegration( - capture_sentry_logs=True, sentry_logs_level=LoggingLevels.DEBUG - ) - ], + integrations=[LoguruIntegration(level=LoggingLevels.DEBUG)], debug=True, ) envelopes = capture_envelopes() @@ -360,7 +325,13 @@ def test_logging_errors( uninstall_integration("loguru") request.addfinalizer(logger.remove) - sentry_init(integrations=[LoguruIntegration(capture_sentry_logs=True)]) + sentry_init( + integrations=[ + LoguruIntegration( + level=LoggingLevels.INFO.value, event_level=LoggingLevels.ERROR.value + ) + ] + ) envelopes = capture_envelopes() items = capture_items("log") @@ -390,7 +361,7 @@ def test_log_strips_project_root( request.addfinalizer(logger.remove) sentry_init( - integrations=[LoguruIntegration(capture_sentry_logs=True)], + integrations=[LoguruIntegration()], project_root="/custom/test", ) items = capture_items("log") @@ -439,7 +410,7 @@ def test_log_keeps_full_path_if_not_in_project_root( request.addfinalizer(logger.remove) sentry_init( - integrations=[LoguruIntegration(capture_sentry_logs=True)], + integrations=[LoguruIntegration()], project_root="/custom/test", ) items = capture_items("log") @@ -487,7 +458,7 @@ def test_logger_with_all_attributes( uninstall_integration("loguru") request.addfinalizer(logger.remove) - sentry_init(integrations=[LoguruIntegration(capture_sentry_logs=True)]) + sentry_init(integrations=[LoguruIntegration()]) items = capture_items("log") logger.warning("log #{}", 1) @@ -559,7 +530,7 @@ def test_logger_capture_parameters_from_args( uninstall_integration("loguru") request.addfinalizer(logger.remove) - sentry_init(integrations=[LoguruIntegration(capture_sentry_logs=True)]) + sentry_init(integrations=[LoguruIntegration()]) items = capture_items("log") logger.warning("Task ID: {}", 123) @@ -578,7 +549,7 @@ def test_logger_capture_parameters_from_kwargs( uninstall_integration("loguru") request.addfinalizer(logger.remove) - sentry_init(integrations=[LoguruIntegration(capture_sentry_logs=True)]) + sentry_init(integrations=[LoguruIntegration()]) items = capture_items("log") logger.warning("Task ID: {task_id}", task_id=123) @@ -597,7 +568,7 @@ def test_logger_capture_parameters_from_contextualize( uninstall_integration("loguru") request.addfinalizer(logger.remove) - sentry_init(integrations=[LoguruIntegration(capture_sentry_logs=True)]) + sentry_init(integrations=[LoguruIntegration()]) items = capture_items("log") with logger.contextualize(task_id=123): @@ -617,7 +588,7 @@ def test_logger_capture_parameters_from_bind( uninstall_integration("loguru") request.addfinalizer(logger.remove) - sentry_init(integrations=[LoguruIntegration(capture_sentry_logs=True)]) + sentry_init(integrations=[LoguruIntegration()]) items = capture_items("log") logger.bind(task_id=123).warning("Log") @@ -635,7 +606,7 @@ def test_logger_capture_parameters_from_patch( uninstall_integration("loguru") request.addfinalizer(logger.remove) - sentry_init(integrations=[LoguruIntegration(capture_sentry_logs=True)]) + sentry_init(integrations=[LoguruIntegration()]) items = capture_items("log") logger.patch(lambda record: record["extra"].update(task_id=123)).warning("Log") @@ -653,7 +624,7 @@ def test_no_parameters_no_template( uninstall_integration("loguru") request.addfinalizer(logger.remove) - sentry_init(integrations=[LoguruIntegration(capture_sentry_logs=True)]) + sentry_init(integrations=[LoguruIntegration()]) items = capture_items("log") logger.warning("Logging a hardcoded warning") diff --git a/tests/integrations/mcp/test_mcp.py b/tests/integrations/mcp/test_mcp.py index 15432d8d84..982d25c71f 100644 --- a/tests/integrations/mcp/test_mcp.py +++ b/tests/integrations/mcp/test_mcp.py @@ -35,45 +35,35 @@ async def __call__(self, *args, **kwargs): from mcp.server.lowlevel import Server -from mcp.server.lowlevel.helper_types import ReadResourceContents MCP_PACKAGE_VERSION = package_version("mcp") -IS_MCP_V2 = MCP_PACKAGE_VERSION is not None and MCP_PACKAGE_VERSION >= (2, 0, 0) try: - if not IS_MCP_V2: - from mcp.server.lowlevel.server import ( # type: ignore[import-not-found] - request_ctx, - ) - else: - request_ctx = None + from mcp.server.lowlevel.server import ( # type: ignore[import-not-found] + request_ctx, + ) except ImportError: request_ctx = None -if IS_MCP_V2: - from mcp_types import ( - CallToolRequestParams, - CallToolResult, - GetPromptRequestParams, - GetPromptResult, - PromptMessage, - ReadResourceRequestParams, - ReadResourceResult, - TextContent, - TextResourceContents, - ) -else: - from mcp.types import GetPromptResult, PromptMessage, TextContent - from mcp.server.sse import SseServerTransport from mcp.server.streamable_http_manager import StreamableHTTPSessionManager +from mcp_types import ( + CallToolRequestParams, + CallToolResult, + GetPromptRequestParams, + GetPromptResult, + PromptMessage, + ReadResourceRequestParams, + ReadResourceResult, + TextContent, + TextResourceContents, +) from starlette.applications import Starlette from starlette.responses import Response from starlette.routing import Mount, Route from starlette.testclient import TestClient import sentry_sdk -from sentry_sdk import start_transaction from sentry_sdk.consts import OP, SPANDATA from sentry_sdk.integrations.mcp import MCPIntegration @@ -142,31 +132,8 @@ def __init__(self, text): self.text = text -def test_integration_patches_server(sentry_init): - """Test that MCPIntegration patches the Server class""" - if not IS_MCP_V2: - original_call_tool = Server.call_tool - original_get_prompt = Server.get_prompt - original_read_resource = Server.read_resource - - sentry_init( - integrations=[MCPIntegration()], - traces_sample_rate=1.0, - ) - - assert Server.call_tool is not original_call_tool - assert Server.get_prompt is not original_get_prompt - assert Server.read_resource is not original_read_resource - - @pytest.mark.asyncio -@pytest.mark.skipif( - not IS_MCP_V2, reason="Constructor handler registration is MCP v2 only" -) -@pytest.mark.parametrize("span_streaming", [True, False]) -async def test_tool_handler_constructor_registration( - sentry_init, capture_events, capture_items, span_streaming, stdio -): +async def test_tool_handler_constructor_registration(sentry_init, capture_items, stdio): """v2 handlers registered via the Server(...) constructor are instrumented. This is the dominant v2 registration path (used by lowlevel examples and by @@ -175,7 +142,6 @@ async def test_tool_handler_constructor_registration( sentry_init( integrations=[MCPIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) async def test_tool(ctx, params): @@ -190,34 +156,17 @@ async def test_tool(ctx, params): ) server = Server("test-server", on_call_tool=test_tool) - - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="mcp tx"): - await stdio( - server, - method="tools/call", - params={"name": "calculate", "arguments": {"x": 10}}, - request_id="req-ctor", - ) - sentry_sdk.flush() - span = _find_mcp_span(items, method_name="tools/call") - assert span is not None - data = span["attributes"] - else: - events = capture_events() - with start_transaction(name="mcp tx"): - await stdio( - server, - method="tools/call", - params={"name": "calculate", "arguments": {"x": 10}}, - request_id="req-ctor", - ) - (tx,) = events - assert len(tx["spans"]) == 1 - span = tx["spans"][0] - assert span["description"] == "tools/call calculate" - data = span["data"] + items = capture_items("span") + await stdio( + server, + method="tools/call", + params={"name": "calculate", "arguments": {"x": 10}}, + request_id="req-ctor", + ) + sentry_sdk.flush() + span = _find_mcp_span(items, method_name="tools/call") + assert span is not None + data = span["attributes"] assert data[SPANDATA.MCP_TOOL_NAME] == "calculate" assert data[SPANDATA.MCP_METHOD_NAME] == "tools/call" @@ -226,10 +175,8 @@ async def test_tool(ctx, params): @pytest.mark.asyncio -@pytest.mark.skipif(not IS_MCP_V2, reason="MCPServer is MCP v2 only") -@pytest.mark.parametrize("span_streaming", [True, False]) async def test_mcpserver_high_level_tool_instrumented( - sentry_init, capture_events, capture_items, span_streaming, stdio + sentry_init, capture_items, stdio ): """The in-tree high-level MCPServer wires its handlers through the lowlevel Server(...) constructor, so its tool calls are instrumented too.""" @@ -238,7 +185,6 @@ async def test_mcpserver_high_level_tool_instrumented( sentry_init( integrations=[MCPIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) mcp_server = MCPServer("test-server") @@ -247,54 +193,29 @@ async def test_mcpserver_high_level_tool_instrumented( def add(a: int, b: int) -> int: return a + b - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="mcp tx"): - await stdio( - mcp_server._lowlevel_server, - method="tools/call", - params={"name": "add", "arguments": {"a": 2, "b": 3}}, - request_id="req-mcpserver", - ) - - sentry_sdk.flush() - span = _find_mcp_span(items, method_name="tools/call") - assert span is not None - assert span["attributes"]["sentry.op"] == OP.MCP_SERVER - assert span["name"] == "tools/call add" - assert span["attributes"][SPANDATA.MCP_METHOD_NAME] == "tools/call" - else: - events = capture_events() - with start_transaction(name="mcp tx"): - await stdio( - mcp_server._lowlevel_server, - method="tools/call", - params={"name": "add", "arguments": {"a": 2, "b": 3}}, - request_id="req-mcpserver", - ) - - (tx,) = events - assert len(tx["spans"]) == 1 - span = tx["spans"][0] - assert span["op"] == OP.MCP_SERVER - assert span["description"] == "tools/call add" - assert span["data"][SPANDATA.MCP_METHOD_NAME] == "tools/call" + items = capture_items("span") + await stdio( + mcp_server._lowlevel_server, + method="tools/call", + params={"name": "add", "arguments": {"a": 2, "b": 3}}, + request_id="req-mcpserver", + ) + + sentry_sdk.flush() + span = _find_mcp_span(items, method_name="tools/call") + assert span is not None + assert span["attributes"]["sentry.op"] == OP.MCP_SERVER + assert span["name"] == "tools/call add" + assert span["attributes"][SPANDATA.MCP_METHOD_NAME] == "tools/call" @pytest.mark.asyncio -@pytest.mark.skipif( - not IS_MCP_V2, reason="Constructor handler registration is MCP v2 only" -) -@pytest.mark.parametrize("span_streaming", [True, False]) -async def test_wrapping_handler_is_idempotent( - sentry_init, capture_events, capture_items, span_streaming, stdio -): +async def test_wrapping_handler_is_idempotent(sentry_init, capture_items, stdio): """Re-registering an already-wrapped handler via add_request_handler must not double-wrap — invoking it should produce exactly one MCP span.""" sentry_init( integrations=[MCPIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) async def test_tool(ctx, params): @@ -306,137 +227,80 @@ async def test_tool(ctx, params): server = Server("test-server", on_call_tool=test_tool) entry = server.get_request_handler("tools/call") server.add_request_handler("tools/call", CallToolRequestParams, entry.handler) - - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="mcp tx"): - await stdio( - server, - method="tools/call", - params={"name": "add", "arguments": {}}, - request_id="req-idempotent", - ) - sentry_sdk.flush() - mcp_spans = [ - item.payload - for item in items - if item.type == "span" - and item.payload.get("attributes", {}).get("sentry.op") == OP.MCP_SERVER - ] - else: - events = capture_events() - with start_transaction(name="mcp tx"): - await stdio( - server, - method="tools/call", - params={"name": "add", "arguments": {}}, - request_id="req-idempotent", - ) - (tx,) = events - mcp_spans = [s for s in tx["spans"] if s["op"] == OP.MCP_SERVER] + items = capture_items("span") + await stdio( + server, + method="tools/call", + params={"name": "add", "arguments": {}}, + request_id="req-idempotent", + ) + sentry_sdk.flush() + mcp_spans = [ + item.payload + for item in items + if item.type == "span" + and item.payload.get("attributes", {}).get("sentry.op") == OP.MCP_SERVER + ] assert len(mcp_spans) == 1 @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) @pytest.mark.parametrize( - "send_default_pii, include_prompts", - [(True, True), (True, False), (False, True), (False, False)], + "send_default_pii", + [True, False], ) async def test_tool_handler_stdio( sentry_init, - capture_events, capture_items, send_default_pii, - include_prompts, - span_streaming, stdio, ): """Test that synchronous tool handlers create proper spans""" sentry_init( - integrations=[MCPIntegration(include_prompts=include_prompts)], + integrations=[MCPIntegration()], traces_sample_rate=1.0, send_default_pii=send_default_pii, - trace_lifecycle="stream" if span_streaming else "static", ) server = Server("test-server") - if IS_MCP_V2: - - async def test_tool(ctx, params): - return CallToolResult( - content=[ - TextContent( - type="text", - text=json.dumps({"result": "success", "value": 42}), - ) - ], - structured_content={"result": "success", "value": 42}, - ) + async def test_tool(ctx, params): + return CallToolResult( + content=[ + TextContent( + type="text", + text=json.dumps({"result": "success", "value": 42}), + ) + ], + structured_content={"result": "success", "value": 42}, + ) - server.add_request_handler("tools/call", CallToolRequestParams, test_tool) - else: + server.add_request_handler("tools/call", CallToolRequestParams, test_tool) - @server.call_tool() - async def test_tool(tool_name, arguments): - return {"result": "success", "value": 42} - - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="mcp tx"): - result = await stdio( - server, - method="tools/call", - params={ - "name": "calculate", - "arguments": {"x": 10, "y": 5}, - }, - request_id="req-123", - ) - sentry_sdk.flush() - else: - events = capture_events() - with start_transaction(name="mcp tx"): - result = await stdio( - server, - method="tools/call", - params={ - "name": "calculate", - "arguments": {"x": 10, "y": 5}, - }, - request_id="req-123", - ) - - if IS_MCP_V2: - assert _get_response(result).result["structuredContent"] == { - "result": "success", - "value": 42, - } - else: - assert _get_response(result).result["content"][0]["text"] == json.dumps( - {"result": "success", "value": 42}, - indent=2, - ) + items = capture_items("span") + result = await stdio( + server, + method="tools/call", + params={ + "name": "calculate", + "arguments": {"x": 10, "y": 5}, + }, + request_id="req-123", + ) + sentry_sdk.flush() - if span_streaming: - span = _find_mcp_span(items, method_name="tools/call") - assert span is not None - assert span["name"] == "tools/call calculate" - data = span["attributes"] - assert data["sentry.op"] == OP.MCP_SERVER - assert data["sentry.origin"] == "auto.ai.mcp" - else: - (tx,) = events - assert tx["type"] == "transaction" - assert len(tx["spans"]) == 1 + assert _get_response(result).result["structuredContent"] == { + "result": "success", + "value": 42, + } - span = tx["spans"][0] - assert span["op"] == OP.MCP_SERVER - assert span["description"] == "tools/call calculate" - assert span["origin"] == "auto.ai.mcp" - data = span["data"] + span = _find_mcp_span(items, method_name="tools/call") + assert span is not None + assert span["name"] == "tools/call calculate" + data = span["attributes"] + assert data["sentry.op"] == OP.MCP_SERVER + assert data["sentry.origin"] == "auto.ai.mcp" # Check span data assert data[SPANDATA.MCP_TOOL_NAME] == "calculate" @@ -449,7 +313,7 @@ async def test_tool(tool_name, arguments): assert data["mcp.request.argument.y"] == "5" # Check PII-sensitive data is only present when both flags are True - if send_default_pii and include_prompts: + if send_default_pii: assert data[SPANDATA.MCP_TOOL_RESULT_CONTENT] == json.dumps( { "result": "success", @@ -463,54 +327,33 @@ async def test_tool(tool_name, arguments): @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) @pytest.mark.parametrize( - "send_default_pii, include_prompts", - [(True, True), (True, False), (False, True), (False, False)], + "send_default_pii", + [True, False], ) async def test_tool_handler_streamable_http( - sentry_init, - capture_events, - capture_items, - send_default_pii, - include_prompts, - span_streaming, - json_rpc, - select_transactions_with_mcp_spans, + sentry_init, capture_items, send_default_pii, json_rpc ): """Test that async tool handlers create proper spans""" sentry_init( - integrations=[MCPIntegration(include_prompts=include_prompts)], + integrations=[MCPIntegration()], traces_sample_rate=1.0, send_default_pii=send_default_pii, - trace_lifecycle="stream" if span_streaming else "static", ) server = Server("test-server") - if IS_MCP_V2: - - async def test_tool_async(ctx, params): - return CallToolResult( - content=[ - TextContent( - type="text", - text=json.dumps({"status": "completed"}), - ) - ] - ) - - server.add_request_handler("tools/call", CallToolRequestParams, test_tool_async) - else: - - @server.call_tool() - async def test_tool_async(tool_name, arguments): - return [ + async def test_tool_async(ctx, params): + return CallToolResult( + content=[ TextContent( type="text", text=json.dumps({"status": "completed"}), ) ] + ) + + server.add_request_handler("tools/call", CallToolRequestParams, test_tool_async) session_manager = StreamableHTTPSessionManager( app=server, @@ -523,60 +366,29 @@ async def test_tool_async(tool_name, arguments): ], lifespan=lambda app: session_manager.run(), ) - - if span_streaming: - items = capture_items("span") - session_id, result = json_rpc( - app, - method="tools/call", - params={ - "name": "process", - "arguments": { - "data": "test", - }, - }, - request_id="req-456", - ) - sentry_sdk.flush() - else: - events = capture_events() - session_id, result = json_rpc( - app, - method="tools/call", - params={ - "name": "process", - "arguments": { - "data": "test", - }, + items = capture_items("span") + session_id, result = json_rpc( + app, + method="tools/call", + params={ + "name": "process", + "arguments": { + "data": "test", }, - request_id="req-456", - ) + }, + request_id="req-456", + ) + sentry_sdk.flush() assert result.json()["result"]["content"][0]["text"] == json.dumps( {"status": "completed"} ) - - if span_streaming: - span = _find_mcp_span(items, method_name="tools/call") - assert span is not None - assert span["name"] == "tools/call process" - data = span["attributes"] - assert data["sentry.op"] == OP.MCP_SERVER - assert data["sentry.origin"] == "auto.ai.mcp" - else: - transactions = select_transactions_with_mcp_spans( - events, method_name="tools/call" - ) - assert len(transactions) == 1 - tx = transactions[0] - assert tx["type"] == "transaction" - assert len(tx["spans"]) == 1 - span = tx["spans"][0] - - assert span["op"] == OP.MCP_SERVER - assert span["description"] == "tools/call process" - assert span["origin"] == "auto.ai.mcp" - data = span["data"] + span = _find_mcp_span(items, method_name="tools/call") + assert span is not None + assert span["name"] == "tools/call process" + data = span["attributes"] + assert data["sentry.op"] == OP.MCP_SERVER + assert data["sentry.origin"] == "auto.ai.mcp" # Check span data assert data[SPANDATA.MCP_TOOL_NAME] == "process" @@ -588,7 +400,7 @@ async def test_tool_async(tool_name, arguments): assert data["mcp.request.argument.data"] == "test" # Check PII-sensitive data - if send_default_pii and include_prompts: + if send_default_pii: assert data[SPANDATA.MCP_TOOL_RESULT_CONTENT] == json.dumps( {"status": "completed"} ) @@ -597,13 +409,9 @@ async def test_tool_async(tool_name, arguments): @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) async def test_tool_handler_stateless_streamable_http( sentry_init, - capture_events, capture_items, - select_transactions_with_mcp_spans, - span_streaming, ): """A stateless StreamableHTTP server is still reported as the http transport. @@ -613,76 +421,40 @@ async def test_tool_handler_stateless_streamable_http( sentry_init( integrations=[MCPIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) server = Server("test-server") - if IS_MCP_V2: + async def test_tool_async(ctx, params): + return CallToolResult(content=[TextContent(type="text", text="ok")]) - async def test_tool_async(ctx, params): - return CallToolResult(content=[TextContent(type="text", text="ok")]) + server.add_request_handler("tools/call", CallToolRequestParams, test_tool_async) - server.add_request_handler("tools/call", CallToolRequestParams, test_tool_async) - else: + items = capture_items("span") - @server.call_tool() - async def test_tool_async(tool_name, arguments): - return [TextContent(type="text", text="ok")] - - if span_streaming: - items = capture_items("span") - - # A stateless server accepts each request on its own, so there is no - # handshake to replay and no session id to echo back. - with TestClient(_streamable_http_app(server, stateless=True)) as client: - response = client.post( - "/mcp/", - headers={ - "Accept": "application/json, text/event-stream", - "Content-Type": "application/json", - }, - json={ - "jsonrpc": "2.0", - "method": "tools/call", - "params": {"name": "process", "arguments": {}}, - "id": "req-789", - }, - ) - - assert "mcp-session-id" not in response.headers - - sentry_sdk.flush() - span = _find_mcp_span(items, method_name="tools/call") - assert span is not None - data = span["attributes"] - else: - events = capture_events() - - # A stateless server accepts each request on its own, so there is no - # handshake to replay and no session id to echo back. - with TestClient(_streamable_http_app(server, stateless=True)) as client: - response = client.post( - "/mcp/", - headers={ - "Accept": "application/json, text/event-stream", - "Content-Type": "application/json", - }, - json={ - "jsonrpc": "2.0", - "method": "tools/call", - "params": {"name": "process", "arguments": {}}, - "id": "req-789", - }, - ) - - assert "mcp-session-id" not in response.headers - - transactions = select_transactions_with_mcp_spans( - events, method_name="tools/call" + # A stateless server accepts each request on its own, so there is no + # handshake to replay and no session id to echo back. + with TestClient(_streamable_http_app(server, stateless=True)) as client: + response = client.post( + "/mcp/", + headers={ + "Accept": "application/json, text/event-stream", + "Content-Type": "application/json", + }, + json={ + "jsonrpc": "2.0", + "method": "tools/call", + "params": {"name": "process", "arguments": {}}, + "id": "req-789", + }, ) - assert len(transactions) == 1 - data = transactions[0]["spans"][0]["data"] + + assert "mcp-session-id" not in response.headers + + sentry_sdk.flush() + span = _find_mcp_span(items, method_name="tools/call") + assert span is not None + data = span["attributes"] assert data[SPANDATA.MCP_TRANSPORT] == "http" assert data[SPANDATA.NETWORK_TRANSPORT] == "tcp" @@ -691,124 +463,65 @@ async def test_tool_async(tool_name, arguments): @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) -async def test_tool_handler_with_error( - sentry_init, capture_events, capture_items, span_streaming, stdio -): +async def test_tool_handler_with_error(sentry_init, capture_items, stdio): """Test that tool handler errors are captured properly""" sentry_init( integrations=[MCPIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) server = Server("test-server") - if IS_MCP_V2: + async def failing_tool(ctx, params): + raise ValueError("Tool execution failed") - async def failing_tool(ctx, params): - raise ValueError("Tool execution failed") + server.add_request_handler("tools/call", CallToolRequestParams, failing_tool) - server.add_request_handler("tools/call", CallToolRequestParams, failing_tool) - else: + items = capture_items("event", "span") + result = await stdio( + server, + method="tools/call", + params={ + "name": "bad_tool", + "arguments": {}, + }, + request_id="req-error", + ) + sentry_sdk.flush() - @server.call_tool() - def failing_tool(tool_name, arguments): - raise ValueError("Tool execution failed") - - if span_streaming: - items = capture_items("event", "span") - with sentry_sdk.traces.start_span(name="mcp tx"): - result = await stdio( - server, - method="tools/call", - params={ - "name": "bad_tool", - "arguments": {}, - }, - request_id="req-error", - ) - sentry_sdk.flush() - - resp = _get_response(result) - if IS_MCP_V2: - assert "Tool execution failed" in resp.error.message - else: - assert resp.result["content"][0]["text"] == "Tool execution failed" - - error_payload = next(item.payload for item in items if item.type == "event") - span = _find_mcp_span(items, method_name="tools/call") - assert span is not None - - assert error_payload["level"] == "error" - assert error_payload["exception"]["values"][0]["type"] == "ValueError" - assert ( - error_payload["exception"]["values"][0]["value"] == "Tool execution failed" - ) - assert error_payload["exception"]["values"][0]["mechanism"]["type"] == "mcp" - assert not error_payload["exception"]["values"][0]["mechanism"]["handled"] + resp = _get_response(result) - assert span["status"] == "error" - else: - events = capture_events() - with start_transaction(name="mcp tx"): - result = await stdio( - server, - method="tools/call", - params={ - "name": "bad_tool", - "arguments": {}, - }, - request_id="req-error", - ) - - resp = _get_response(result) - if IS_MCP_V2: - assert "Tool execution failed" in resp.error.message - else: - assert resp.result["content"][0]["text"] == "Tool execution failed" - - # Should have error event and transaction - assert len(events) == 2 - error_event, tx = events - - # Check error event - assert error_event["level"] == "error" - assert error_event["exception"]["values"][0]["type"] == "ValueError" - assert error_event["exception"]["values"][0]["value"] == "Tool execution failed" - assert error_event["exception"]["values"][0]["mechanism"]["type"] == "mcp" - assert not error_event["exception"]["values"][0]["mechanism"]["handled"] - - # Check transaction and span - assert tx["type"] == "transaction" - assert len(tx["spans"]) == 1 - span = tx["spans"][0] - - assert span["status"] == "internal_error" - assert span["tags"]["status"] == "internal_error" + assert "Tool execution failed" in resp.error.message + + error_payload = next(item.payload for item in items if item.type == "event") + span = _find_mcp_span(items, method_name="tools/call") + assert span is not None + + assert error_payload["level"] == "error" + assert error_payload["exception"]["values"][0]["type"] == "ValueError" + assert error_payload["exception"]["values"][0]["value"] == "Tool execution failed" + assert error_payload["exception"]["values"][0]["mechanism"]["type"] == "mcp" + assert not error_payload["exception"]["values"][0]["mechanism"]["handled"] + + assert span["status"] == "error" @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) @pytest.mark.parametrize( - "send_default_pii, include_prompts", - [(True, True), (True, False), (False, True), (False, False)], + "send_default_pii", + [True, False], ) async def test_prompt_handler_stdio( sentry_init, - capture_events, capture_items, send_default_pii, - include_prompts, - span_streaming, stdio, ): """Test that synchronous prompt handlers create proper spans""" sentry_init( - integrations=[MCPIntegration(include_prompts=include_prompts)], + integrations=[MCPIntegration()], traces_sample_rate=1.0, send_default_pii=send_default_pii, - trace_lifecycle="stream" if span_streaming else "static", ) server = Server("test-server") @@ -823,67 +536,34 @@ async def test_prompt_handler_stdio( ], ) - if IS_MCP_V2: + async def test_prompt(ctx, params): + return prompt_result - async def test_prompt(ctx, params): - return prompt_result + server.add_request_handler("prompts/get", GetPromptRequestParams, test_prompt) - server.add_request_handler("prompts/get", GetPromptRequestParams, test_prompt) - else: - - @server.get_prompt() - async def test_prompt(name, arguments): - return prompt_result - - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="mcp tx"): - result = await stdio( - server, - method="prompts/get", - params={ - "name": "code_help", - "arguments": {"language": "python"}, - }, - request_id="req-prompt", - ) - sentry_sdk.flush() - else: - events = capture_events() - with start_transaction(name="mcp tx"): - result = await stdio( - server, - method="prompts/get", - params={ - "name": "code_help", - "arguments": {"language": "python"}, - }, - request_id="req-prompt", - ) + items = capture_items("span") + result = await stdio( + server, + method="prompts/get", + params={ + "name": "code_help", + "arguments": {"language": "python"}, + }, + request_id="req-prompt", + ) + sentry_sdk.flush() assert _get_response(result).result["messages"][0]["role"] == "user" assert ( _get_response(result).result["messages"][0]["content"]["text"] == "Tell me about Python" ) - - if span_streaming: - span = _find_mcp_span(items, method_name="prompts/get") - assert span is not None - assert span["name"] == "prompts/get code_help" - data = span["attributes"] - assert data["sentry.op"] == OP.MCP_SERVER - assert data["sentry.origin"] == "auto.ai.mcp" - else: - (tx,) = events - assert tx["type"] == "transaction" - assert len(tx["spans"]) == 1 - - span = tx["spans"][0] - assert span["op"] == OP.MCP_SERVER - assert span["description"] == "prompts/get code_help" - assert span["origin"] == "auto.ai.mcp" - data = span["data"] + span = _find_mcp_span(items, method_name="prompts/get") + assert span is not None + assert span["name"] == "prompts/get code_help" + data = span["attributes"] + assert data["sentry.op"] == OP.MCP_SERVER + assert data["sentry.origin"] == "auto.ai.mcp" # Check span data assert data[SPANDATA.MCP_PROMPT_NAME] == "code_help" @@ -896,7 +576,7 @@ async def test_prompt(name, arguments): assert data[SPANDATA.MCP_PROMPT_RESULT_MESSAGE_COUNT] == 1 # For single message prompts, role and content should be captured only with PII - if send_default_pii and include_prompts: + if send_default_pii: assert data[SPANDATA.MCP_PROMPT_RESULT_MESSAGE_ROLE] == "user" assert ( data[SPANDATA.MCP_PROMPT_RESULT_MESSAGE_CONTENT] == "Tell me about Python" @@ -907,27 +587,18 @@ async def test_prompt(name, arguments): @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) @pytest.mark.parametrize( - "send_default_pii, include_prompts", - [(True, True), (True, False), (False, True), (False, False)], + "send_default_pii", + [True, False], ) async def test_prompt_handler_streamable_http( - sentry_init, - capture_events, - capture_items, - send_default_pii, - include_prompts, - span_streaming, - json_rpc, - select_transactions_with_mcp_spans, + sentry_init, capture_items, send_default_pii, json_rpc ): """Test that async prompt handlers create proper spans""" sentry_init( - integrations=[MCPIntegration(include_prompts=include_prompts)], + integrations=[MCPIntegration()], traces_sample_rate=1.0, send_default_pii=send_default_pii, - trace_lifecycle="stream" if span_streaming else "static", ) server = Server("test-server") @@ -945,19 +616,10 @@ async def test_prompt_handler_streamable_http( ], ) - if IS_MCP_V2: - - async def test_prompt_async(ctx, params): - return prompt_result - - server.add_request_handler( - "prompts/get", GetPromptRequestParams, test_prompt_async - ) - else: + async def test_prompt_async(ctx, params): + return prompt_result - @server.get_prompt() - async def test_prompt_async(name, arguments): - return prompt_result + server.add_request_handler("prompts/get", GetPromptRequestParams, test_prompt_async) session_manager = StreamableHTTPSessionManager( app=server, @@ -970,53 +632,25 @@ async def test_prompt_async(name, arguments): ], lifespan=lambda app: session_manager.run(), ) - - if span_streaming: - items = capture_items("span") - _, result = json_rpc( - app, - method="prompts/get", - params={ - "name": "mcp_info", - "arguments": {}, - }, - request_id="req-async-prompt", - ) - sentry_sdk.flush() - else: - events = capture_events() - _, result = json_rpc( - app, - method="prompts/get", - params={ - "name": "mcp_info", - "arguments": {}, - }, - request_id="req-async-prompt", - ) + items = capture_items("span") + _, result = json_rpc( + app, + method="prompts/get", + params={ + "name": "mcp_info", + "arguments": {}, + }, + request_id="req-async-prompt", + ) + sentry_sdk.flush() assert len(result.json()["result"]["messages"]) == 2 - - if span_streaming: - span = _find_mcp_span(items, method_name="prompts/get") - assert span is not None - assert span["name"] == "prompts/get mcp_info" - data = span["attributes"] - assert data["sentry.op"] == OP.MCP_SERVER - assert data["sentry.origin"] == "auto.ai.mcp" - else: - transactions = select_transactions_with_mcp_spans( - events, method_name="prompts/get" - ) - assert len(transactions) == 1 - tx = transactions[0] - assert tx["type"] == "transaction" - assert len(tx["spans"]) == 1 - span = tx["spans"][0] - - assert span["op"] == OP.MCP_SERVER - assert span["description"] == "prompts/get mcp_info" - data = span["data"] + span = _find_mcp_span(items, method_name="prompts/get") + assert span is not None + assert span["name"] == "prompts/get mcp_info" + data = span["attributes"] + assert data["sentry.op"] == OP.MCP_SERVER + assert data["sentry.origin"] == "auto.ai.mcp" # For multi-message prompts, count is always captured assert data[SPANDATA.MCP_PROMPT_RESULT_MESSAGE_COUNT] == 2 @@ -1026,176 +660,90 @@ async def test_prompt_async(name, arguments): @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) -async def test_prompt_handler_with_error( - sentry_init, capture_events, capture_items, span_streaming, stdio -): +async def test_prompt_handler_with_error(sentry_init, capture_items, stdio): """Test that prompt handler errors are captured""" sentry_init( integrations=[MCPIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) server = Server("test-server") - if IS_MCP_V2: + async def failing_prompt(ctx, params): + raise RuntimeError("Prompt not found") - async def failing_prompt(ctx, params): - raise RuntimeError("Prompt not found") - - server.add_request_handler( - "prompts/get", GetPromptRequestParams, failing_prompt - ) - else: + server.add_request_handler("prompts/get", GetPromptRequestParams, failing_prompt) - @server.get_prompt() - async def failing_prompt(name, arguments): - raise RuntimeError("Prompt not found") - - if span_streaming: - items = capture_items("event", "span") - with sentry_sdk.traces.start_span(name="mcp tx"): - response = await stdio( - server, - method="prompts/get", - params={ - "name": "code_help", - "arguments": {"language": "python"}, - }, - request_id="req-error-prompt", - ) - sentry_sdk.flush() - - assert _get_response(response).error.message == "Prompt not found" - - error_payload = next(item.payload for item in items if item.type == "event") - span = _find_mcp_span(items, method_name="prompts/get") - assert span is not None - - assert error_payload["level"] == "error" - assert error_payload["exception"]["values"][0]["type"] == "RuntimeError" - assert error_payload["exception"]["values"][0]["mechanism"]["type"] == "mcp" - assert not error_payload["exception"]["values"][0]["mechanism"]["handled"] - assert span["status"] == "error" - else: - events = capture_events() - with start_transaction(name="mcp tx"): - response = await stdio( - server, - method="prompts/get", - params={ - "name": "code_help", - "arguments": {"language": "python"}, - }, - request_id="req-error-prompt", - ) - - assert _get_response(response).error.message == "Prompt not found" - - # Should have error event and transaction - assert len(events) == 2 - error_event, tx = events + items = capture_items("event", "span") + response = await stdio( + server, + method="prompts/get", + params={ + "name": "code_help", + "arguments": {"language": "python"}, + }, + request_id="req-error-prompt", + ) + sentry_sdk.flush() - assert error_event["level"] == "error" - assert error_event["exception"]["values"][0]["type"] == "RuntimeError" - assert error_event["exception"]["values"][0]["mechanism"]["type"] == "mcp" - assert not error_event["exception"]["values"][0]["mechanism"]["handled"] + assert _get_response(response).error.message == "Prompt not found" - # Check transaction and span - assert tx["type"] == "transaction" - assert len(tx["spans"]) == 1 - span = tx["spans"][0] + error_payload = next(item.payload for item in items if item.type == "event") + span = _find_mcp_span(items, method_name="prompts/get") + assert span is not None - assert span["status"] == "internal_error" + assert error_payload["level"] == "error" + assert error_payload["exception"]["values"][0]["type"] == "RuntimeError" + assert error_payload["exception"]["values"][0]["mechanism"]["type"] == "mcp" + assert not error_payload["exception"]["values"][0]["mechanism"]["handled"] + assert span["status"] == "error" @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) -async def test_resource_handler_stdio( - sentry_init, capture_events, capture_items, span_streaming, stdio -): +async def test_resource_handler_stdio(sentry_init, capture_items, stdio): """Test that synchronous resource handlers create proper spans""" sentry_init( integrations=[MCPIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) server = Server("test-server") - if IS_MCP_V2: - - async def test_resource(ctx, params): - return ReadResourceResult( - contents=[ - TextResourceContents( - uri=str(params.uri), - text=json.dumps({"content": "file contents"}), - mime_type="text/plain", - ) - ] - ) - - server.add_request_handler( - "resources/read", ReadResourceRequestParams, test_resource - ) - else: - - @server.read_resource() - async def test_resource(uri): - return [ - ReadResourceContents( - content=json.dumps({"content": "file contents"}), + async def test_resource(ctx, params): + return ReadResourceResult( + contents=[ + TextResourceContents( + uri=str(params.uri), + text=json.dumps({"content": "file contents"}), mime_type="text/plain", ) ] + ) - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="mcp tx"): - result = await stdio( - server, - method="resources/read", - params={ - "uri": "file:///path/to/file.txt", - }, - request_id="req-resource", - ) - sentry_sdk.flush() - else: - events = capture_events() - with start_transaction(name="mcp tx"): - result = await stdio( - server, - method="resources/read", - params={ - "uri": "file:///path/to/file.txt", - }, - request_id="req-resource", - ) + server.add_request_handler( + "resources/read", ReadResourceRequestParams, test_resource + ) + + items = capture_items("span") + result = await stdio( + server, + method="resources/read", + params={ + "uri": "file:///path/to/file.txt", + }, + request_id="req-resource", + ) + sentry_sdk.flush() assert _get_response(result).result["contents"][0]["text"] == json.dumps( {"content": "file contents"}, ) - - if span_streaming: - span = _find_mcp_span(items, method_name="resources/read") - assert span is not None - assert span["name"] == "resources/read file:///path/to/file.txt" - data = span["attributes"] - assert data["sentry.op"] == OP.MCP_SERVER - assert data["sentry.origin"] == "auto.ai.mcp" - else: - (tx,) = events - assert tx["type"] == "transaction" - assert len(tx["spans"]) == 1 - - span = tx["spans"][0] - assert span["op"] == OP.MCP_SERVER - assert span["description"] == "resources/read file:///path/to/file.txt" - assert span["origin"] == "auto.ai.mcp" - data = span["data"] + span = _find_mcp_span(items, method_name="resources/read") + assert span is not None + assert span["name"] == "resources/read file:///path/to/file.txt" + data = span["attributes"] + assert data["sentry.op"] == OP.MCP_SERVER + assert data["sentry.origin"] == "auto.ai.mcp" # Check span data assert data[SPANDATA.MCP_RESOURCE_URI] == "file:///path/to/file.txt" @@ -1208,50 +756,29 @@ async def test_resource(uri): @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) -async def test_resource_handler_streamable_http( - sentry_init, - capture_events, - capture_items, - span_streaming, - json_rpc, - select_transactions_with_mcp_spans, -): +async def test_resource_handler_streamable_http(sentry_init, capture_items, json_rpc): """Test that async resource handlers create proper spans""" sentry_init( integrations=[MCPIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) server = Server("test-server") - if IS_MCP_V2: - - async def test_resource_async(ctx, params): - return ReadResourceResult( - contents=[ - TextResourceContents( - uri=str(params.uri), - text=json.dumps({"data": "resource data"}), - mime_type="text/plain", - ) - ] - ) - - server.add_request_handler( - "resources/read", ReadResourceRequestParams, test_resource_async - ) - else: - - @server.read_resource() - async def test_resource_async(uri): - return [ - ReadResourceContents( - content=json.dumps({"data": "resource data"}), + async def test_resource_async(ctx, params): + return ReadResourceResult( + contents=[ + TextResourceContents( + uri=str(params.uri), + text=json.dumps({"data": "resource data"}), mime_type="text/plain", ) ] + ) + + server.add_request_handler( + "resources/read", ReadResourceRequestParams, test_resource_async + ) session_manager = StreamableHTTPSessionManager( app=server, @@ -1264,53 +791,26 @@ async def test_resource_async(uri): ], lifespan=lambda app: session_manager.run(), ) - - if span_streaming: - items = capture_items("span") - session_id, result = json_rpc( - app, - method="resources/read", - params={ - "uri": "https://example.com/resource", - }, - request_id="req-async-resource", - ) - sentry_sdk.flush() - else: - events = capture_events() - session_id, result = json_rpc( - app, - method="resources/read", - params={ - "uri": "https://example.com/resource", - }, - request_id="req-async-resource", - ) + items = capture_items("span") + session_id, result = json_rpc( + app, + method="resources/read", + params={ + "uri": "https://example.com/resource", + }, + request_id="req-async-resource", + ) + sentry_sdk.flush() assert result.json()["result"]["contents"][0]["text"] == json.dumps( {"data": "resource data"} ) - - if span_streaming: - span = _find_mcp_span(items, method_name="resources/read") - assert span is not None - assert span["name"] == "resources/read https://example.com/resource" - data = span["attributes"] - assert data["sentry.op"] == OP.MCP_SERVER - assert data["sentry.origin"] == "auto.ai.mcp" - else: - transactions = select_transactions_with_mcp_spans( - events, method_name="resources/read" - ) - assert len(transactions) == 1 - tx = transactions[0] - assert tx["type"] == "transaction" - assert len(tx["spans"]) == 1 - span = tx["spans"][0] - - assert span["op"] == OP.MCP_SERVER - assert span["description"] == "resources/read https://example.com/resource" - data = span["data"] + span = _find_mcp_span(items, method_name="resources/read") + assert span is not None + assert span["name"] == "resources/read https://example.com/resource" + data = span["attributes"] + assert data["sentry.op"] == OP.MCP_SERVER + assert data["sentry.origin"] == "auto.ai.mcp" assert data[SPANDATA.MCP_RESOURCE_URI] == "https://example.com/resource" assert data[SPANDATA.MCP_RESOURCE_PROTOCOL] == "https" @@ -1318,160 +818,89 @@ async def test_resource_async(uri): @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) -async def test_resource_handler_with_error( - sentry_init, capture_events, capture_items, span_streaming, stdio -): +async def test_resource_handler_with_error(sentry_init, capture_items, stdio): """Test that resource handler errors are captured""" sentry_init( integrations=[MCPIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) server = Server("test-server") - if IS_MCP_V2: + async def failing_resource(ctx, params): + raise FileNotFoundError("Resource not found") - async def failing_resource(ctx, params): - raise FileNotFoundError("Resource not found") + server.add_request_handler( + "resources/read", ReadResourceRequestParams, failing_resource + ) - server.add_request_handler( - "resources/read", ReadResourceRequestParams, failing_resource - ) - else: + items = capture_items("event", "span") + await stdio( + server, + method="resources/read", + params={ + "uri": "file:///missing.txt", + }, + request_id="req-error-resource", + ) + sentry_sdk.flush() - @server.read_resource() - def failing_resource(uri): - raise FileNotFoundError("Resource not found") - - if span_streaming: - items = capture_items("event", "span") - with sentry_sdk.traces.start_span(name="mcp tx"): - await stdio( - server, - method="resources/read", - params={ - "uri": "file:///missing.txt", - }, - request_id="req-error-resource", - ) - sentry_sdk.flush() - - error_payload = next(item.payload for item in items if item.type == "event") - span = _find_mcp_span(items, method_name="resources/read") - assert span is not None - - assert error_payload["level"] == "error" - assert error_payload["exception"]["values"][0]["type"] == "FileNotFoundError" - assert error_payload["exception"]["values"][0]["mechanism"]["type"] == "mcp" - assert not error_payload["exception"]["values"][0]["mechanism"]["handled"] - assert span["status"] == "error" - else: - events = capture_events() - with start_transaction(name="mcp tx"): - await stdio( - server, - method="resources/read", - params={ - "uri": "file:///missing.txt", - }, - request_id="req-error-resource", - ) - - # Should have error event and transaction - assert len(events) == 2 - error_event, tx = events - - assert error_event["level"] == "error" - assert error_event["exception"]["values"][0]["type"] == "FileNotFoundError" - assert error_event["exception"]["values"][0]["mechanism"]["type"] == "mcp" - assert not error_event["exception"]["values"][0]["mechanism"]["handled"] - - # Check transaction and span - assert tx["type"] == "transaction" - assert len(tx["spans"]) == 1 - span = tx["spans"][0] - - assert span["status"] == "internal_error" + error_payload = next(item.payload for item in items if item.type == "event") + span = _find_mcp_span(items, method_name="resources/read") + assert span is not None + + assert error_payload["level"] == "error" + assert error_payload["exception"]["values"][0]["type"] == "FileNotFoundError" + assert error_payload["exception"]["values"][0]["mechanism"]["type"] == "mcp" + assert not error_payload["exception"]["values"][0]["mechanism"]["handled"] + assert span["status"] == "error" @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) @pytest.mark.parametrize( - "send_default_pii, include_prompts", - [(True, True), (False, False)], + "send_default_pii", + [True, False], ) async def test_tool_result_extraction_tuple( sentry_init, - capture_events, capture_items, send_default_pii, - include_prompts, - span_streaming, stdio, ): """Test extraction of tool results from tuple format (UnstructuredContent, StructuredContent)""" sentry_init( - integrations=[MCPIntegration(include_prompts=include_prompts)], + integrations=[MCPIntegration()], traces_sample_rate=1.0, send_default_pii=send_default_pii, - trace_lifecycle="stream" if span_streaming else "static", ) server = Server("test-server") - if IS_MCP_V2: + async def test_tool_tuple(ctx, params): + return CallToolResult( + content=[TextContent(type="text", text="Result text")], + structured_content={"key": "value", "count": 5}, + ) + + server.add_request_handler("tools/call", CallToolRequestParams, test_tool_tuple) - async def test_tool_tuple(ctx, params): - return CallToolResult( - content=[TextContent(type="text", text="Result text")], - structured_content={"key": "value", "count": 5}, - ) + items = capture_items("span") + await stdio( + server, + method="tools/call", + params={ + "name": "calculate", + "arguments": {}, + }, + request_id="req-tuple", + ) + sentry_sdk.flush() - server.add_request_handler("tools/call", CallToolRequestParams, test_tool_tuple) - else: + span = _find_mcp_span(items, method_name="tools/call") + assert span is not None + data = span["attributes"] - @server.call_tool() - def test_tool_tuple(tool_name, arguments): - unstructured = [MockTextContent("Result text")] - structured = {"key": "value", "count": 5} - return (unstructured, structured) - - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="mcp tx"): - await stdio( - server, - method="tools/call", - params={ - "name": "calculate", - "arguments": {}, - }, - request_id="req-tuple", - ) - sentry_sdk.flush() - - span = _find_mcp_span(items, method_name="tools/call") - assert span is not None - data = span["attributes"] - else: - events = capture_events() - with start_transaction(name="mcp tx"): - await stdio( - server, - method="tools/call", - params={ - "name": "calculate", - "arguments": {}, - }, - request_id="req-tuple", - ) - - (tx,) = events - data = tx["spans"][0]["data"] - - if send_default_pii and include_prompts: + if send_default_pii: assert data[SPANDATA.MCP_TOOL_RESULT_CONTENT] == json.dumps( { "key": "value", @@ -1485,161 +914,96 @@ def test_tool_tuple(tool_name, arguments): @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) @pytest.mark.parametrize( - "send_default_pii, include_prompts", - [(True, True), (False, False)], + "send_default_pii", + [True, False], ) async def test_tool_result_extraction_unstructured( sentry_init, - capture_events, capture_items, send_default_pii, - include_prompts, - span_streaming, stdio, ): """Test extraction of tool results from UnstructuredContent (list of content blocks)""" sentry_init( - integrations=[MCPIntegration(include_prompts=include_prompts)], + integrations=[MCPIntegration()], traces_sample_rate=1.0, send_default_pii=send_default_pii, - trace_lifecycle="stream" if span_streaming else "static", ) server = Server("test-server") - if IS_MCP_V2: - - async def test_tool_unstructured(ctx, params): - return CallToolResult( - content=[ - TextContent(type="text", text="First part"), - TextContent(type="text", text="Second part"), - ] - ) - - server.add_request_handler( - "tools/call", CallToolRequestParams, test_tool_unstructured + async def test_tool_unstructured(ctx, params): + return CallToolResult( + content=[ + TextContent(type="text", text="First part"), + TextContent(type="text", text="Second part"), + ] ) - else: - @server.call_tool() - def test_tool_unstructured(tool_name, arguments): - return [ - MockTextContent("First part"), - MockTextContent("Second part"), - ] + server.add_request_handler( + "tools/call", CallToolRequestParams, test_tool_unstructured + ) - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="mcp tx"): - await stdio( - server, - method="tools/call", - params={ - "name": "text_tool", - "arguments": {}, - }, - request_id="req-unstructured", - ) - sentry_sdk.flush() - - span = _find_mcp_span(items, method_name="tools/call") - assert span is not None - data = span["attributes"] - else: - events = capture_events() - with start_transaction(name="mcp tx"): - await stdio( - server, - method="tools/call", - params={ - "name": "text_tool", - "arguments": {}, - }, - request_id="req-unstructured", - ) - - (tx,) = events - data = tx["spans"][0]["data"] + items = capture_items("span") + await stdio( + server, + method="tools/call", + params={ + "name": "text_tool", + "arguments": {}, + }, + request_id="req-unstructured", + ) + sentry_sdk.flush() + + span = _find_mcp_span(items, method_name="tools/call") + assert span is not None + data = span["attributes"] # Should extract and join text from content blocks only with PII - if send_default_pii and include_prompts: + if send_default_pii: assert data[SPANDATA.MCP_TOOL_RESULT_CONTENT] == "First part Second part" else: assert SPANDATA.MCP_TOOL_RESULT_CONTENT not in data @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) -async def test_multiple_handlers( - sentry_init, capture_events, capture_items, span_streaming, stdio -): +async def test_multiple_handlers(sentry_init, capture_items, stdio): """Test that multiple handler calls create multiple spans""" sentry_init( integrations=[MCPIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) server = Server("test-server") - if IS_MCP_V2: - - async def tool_handler(ctx, params): - return CallToolResult( - content=[ - TextContent( - type="text", - text=json.dumps({"result": params.name}), - ) - ] - ) - - async def prompt_handler(ctx, params): - return GetPromptResult( - description="A test prompt", - messages=[ - PromptMessage( - role="user", - content=TextContent(type="text", text="Test prompt"), - ) - ], - ) + async def tool_handler(ctx, params): + return CallToolResult( + content=[ + TextContent( + type="text", + text=json.dumps({"result": params.name}), + ) + ] + ) - server.add_request_handler("tools/call", CallToolRequestParams, tool_handler) - server.add_request_handler( - "prompts/get", GetPromptRequestParams, prompt_handler + async def prompt_handler(ctx, params): + return GetPromptResult( + description="A test prompt", + messages=[ + PromptMessage( + role="user", + content=TextContent(type="text", text="Test prompt"), + ) + ], ) - else: - @server.call_tool() - def tool1(tool_name, arguments): - return {"result": "tool1"} - - @server.call_tool() - def tool2(tool_name, arguments): - return {"result": "tool2"} - - @server.get_prompt() - def prompt1(name, arguments): - return GetPromptResult( - description="A test prompt", - messages=[ - PromptMessage( - role="user", - content=TextContent(type="text", text="Test prompt"), - ) - ], - ) + server.add_request_handler("tools/call", CallToolRequestParams, tool_handler) + server.add_request_handler("prompts/get", GetPromptRequestParams, prompt_handler) - if span_streaming: - items = capture_items("span") - tx_ctx = sentry_sdk.traces.start_span(name="mcp tx") - else: - events = capture_events() - tx_ctx = start_transaction(name="mcp tx") + items = capture_items("span") + tx_ctx = sentry_sdk.start_span(name="mcp tx") with tx_ctx: await stdio( @@ -1671,123 +1035,74 @@ def prompt1(name, arguments): }, request_id="req-multi", ) - - if span_streaming: - sentry_sdk.flush() - mcp_spans = [ - item.payload - for item in items - if item.type == "span" - and item.payload.get("attributes", {}).get("sentry.op") == OP.MCP_SERVER - ] - assert len(mcp_spans) == 3 - assert all(s["attributes"]["sentry.op"] == OP.MCP_SERVER for s in mcp_spans) - span_names = [s["name"] for s in mcp_spans] - assert "tools/call tool_a" in span_names - assert "tools/call tool_b" in span_names - assert "prompts/get prompt_a" in span_names - else: - (tx,) = events - assert tx["type"] == "transaction" - assert len(tx["spans"]) == 3 - - span_ops = [span["op"] for span in tx["spans"]] - assert all(op == OP.MCP_SERVER for op in span_ops) - - span_descriptions = [span["description"] for span in tx["spans"]] - assert "tools/call tool_a" in span_descriptions - assert "tools/call tool_b" in span_descriptions - assert "prompts/get prompt_a" in span_descriptions + sentry_sdk.flush() + mcp_spans = [ + item.payload + for item in items + if item.type == "span" + and item.payload.get("attributes", {}).get("sentry.op") == OP.MCP_SERVER + ] + assert len(mcp_spans) == 3 + assert all(s["attributes"]["sentry.op"] == OP.MCP_SERVER for s in mcp_spans) + span_names = [s["name"] for s in mcp_spans] + assert "tools/call tool_a" in span_names + assert "tools/call tool_b" in span_names + assert "prompts/get prompt_a" in span_names @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) @pytest.mark.parametrize( - "send_default_pii, include_prompts", - [(True, True), (False, False)], + "send_default_pii", + [True, False], ) async def test_prompt_with_dict_result( sentry_init, - capture_events, capture_items, send_default_pii, - include_prompts, - span_streaming, stdio, ): """Test prompt handler with dict result instead of GetPromptResult object""" sentry_init( - integrations=[MCPIntegration(include_prompts=include_prompts)], + integrations=[MCPIntegration()], traces_sample_rate=1.0, send_default_pii=send_default_pii, - trace_lifecycle="stream" if span_streaming else "static", ) server = Server("test-server") - if IS_MCP_V2: - - async def test_prompt_dict(ctx, params): - return GetPromptResult( - messages=[ - PromptMessage( - role="user", - content=TextContent(type="text", text="Hello from dict"), - ) - ] - ) - - server.add_request_handler( - "prompts/get", GetPromptRequestParams, test_prompt_dict + async def test_prompt_dict(ctx, params): + return GetPromptResult( + messages=[ + PromptMessage( + role="user", + content=TextContent(type="text", text="Hello from dict"), + ) + ] ) - else: - @server.get_prompt() - def test_prompt_dict(name, arguments): - return { - "messages": [ - {"role": "user", "content": {"text": "Hello from dict"}}, - ] - } + server.add_request_handler("prompts/get", GetPromptRequestParams, test_prompt_dict) - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="mcp tx"): - await stdio( - server, - method="prompts/get", - params={ - "name": "dict_prompt", - "arguments": {}, - }, - request_id="req-dict-prompt", - ) - sentry_sdk.flush() - - span = _find_mcp_span(items, method_name="prompts/get") - assert span is not None - data = span["attributes"] - else: - events = capture_events() - with start_transaction(name="mcp tx"): - await stdio( - server, - method="prompts/get", - params={ - "name": "dict_prompt", - "arguments": {}, - }, - request_id="req-dict-prompt", - ) - - (tx,) = events - data = tx["spans"][0]["data"] + items = capture_items("span") + await stdio( + server, + method="prompts/get", + params={ + "name": "dict_prompt", + "arguments": {}, + }, + request_id="req-dict-prompt", + ) + sentry_sdk.flush() + + span = _find_mcp_span(items, method_name="prompts/get") + assert span is not None + data = span["attributes"] # Message count is always captured assert data[SPANDATA.MCP_PROMPT_RESULT_MESSAGE_COUNT] == 1 # Role and content only captured with PII - if send_default_pii and include_prompts: + if send_default_pii: assert data[SPANDATA.MCP_PROMPT_RESULT_MESSAGE_ROLE] == "user" assert data[SPANDATA.MCP_PROMPT_RESULT_MESSAGE_CONTENT] == "Hello from dict" else: @@ -1796,71 +1111,40 @@ def test_prompt_dict(name, arguments): @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) -async def test_tool_with_complex_arguments( - sentry_init, capture_events, capture_items, span_streaming, stdio -): +async def test_tool_with_complex_arguments(sentry_init, capture_items, stdio): """Test tool handler with complex nested arguments""" sentry_init( integrations=[MCPIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) server = Server("test-server") - if IS_MCP_V2: + async def test_tool_complex(ctx, params): + return CallToolResult(content=[TextContent(type="text", text="processed")]) - async def test_tool_complex(ctx, params): - return CallToolResult(content=[TextContent(type="text", text="processed")]) - - server.add_request_handler( - "tools/call", CallToolRequestParams, test_tool_complex - ) - else: - - @server.call_tool() - def test_tool_complex(tool_name, arguments): - return {"processed": True} + server.add_request_handler("tools/call", CallToolRequestParams, test_tool_complex) complex_args = { "nested": {"key": "value", "list": [1, 2, 3]}, "string": "test", "number": 42, } + items = capture_items("span") + await stdio( + server, + method="tools/call", + params={ + "name": "complex_tool", + "arguments": complex_args, + }, + request_id="req-complex", + ) + sentry_sdk.flush() - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="mcp tx"): - await stdio( - server, - method="tools/call", - params={ - "name": "complex_tool", - "arguments": complex_args, - }, - request_id="req-complex", - ) - sentry_sdk.flush() - - span = _find_mcp_span(items, method_name="tools/call") - assert span is not None - data = span["attributes"] - else: - events = capture_events() - with start_transaction(name="mcp tx"): - await stdio( - server, - method="tools/call", - params={ - "name": "complex_tool", - "arguments": complex_args, - }, - request_id="req-complex", - ) - - (tx,) = events - data = tx["spans"][0]["data"] + span = _find_mcp_span(items, method_name="tools/call") + assert span is not None + data = span["attributes"] # Complex arguments should be serialized assert data["mcp.request.argument.nested"] == json.dumps( @@ -1871,110 +1155,7 @@ def test_tool_complex(tool_name, arguments): @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.skipif(IS_MCP_V2, reason="SSE scope propagation not supported in MCP v2") -async def test_sse_transport_detection( - sentry_init, capture_events, capture_items, span_streaming, json_rpc_sse -): - """Test that SSE transport is correctly detected via query parameter""" - sentry_init( - integrations=[MCPIntegration()], - traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", - ) - - server = Server("test-server") - sse = SseServerTransport("/messages/") - - sse_connection_closed = asyncio.Event() - - async def handle_sse(request): - async with sse.connect_sse( - request.scope, request.receive, request._send - ) as streams: - async with anyio.create_task_group() as tg: - - async def run_server(): - await server.run( - streams[0], streams[1], server.create_initialization_options() - ) - - tg.start_soon(run_server) - - sse_connection_closed.set() - return Response() - - app = Starlette( - routes=[ - Route("/sse", endpoint=handle_sse, methods=["GET"]), - Mount("/messages/", app=sse.handle_post_message), - ], - ) - - if IS_MCP_V2: - - async def test_tool(ctx, params): - return CallToolResult( - content=[TextContent(type="text", text="success")], - structured_content={"result": "success"}, - ) - - server.add_request_handler("tools/call", CallToolRequestParams, test_tool) - else: - - @server.call_tool() - async def test_tool(tool_name, arguments): - return {"result": "success"} - - if span_streaming: - items = capture_items("span") - else: - events = capture_events() - - keep_sse_alive = asyncio.Event() - app_task, session_id, result = await json_rpc_sse( - app, - method="tools/call", - params={ - "name": "sse_tool", - "arguments": {}, - }, - request_id="req-sse", - keep_sse_alive=keep_sse_alive, - ) - - await sse_connection_closed.wait() - await app_task - - assert result["result"]["structuredContent"] == {"result": "success"} - - if span_streaming: - sentry_sdk.flush() - span = _find_mcp_span(items, method_name="tools/call") - assert span is not None - data = span["attributes"] - else: - transactions = [ - event - for event in events - if event["type"] == "transaction" and event["transaction"] == "/sse" - ] - assert len(transactions) == 1 - tx = transactions[0] - data = tx["spans"][0]["data"] - - # Check that SSE transport is detected - assert data[SPANDATA.MCP_TRANSPORT] == "sse" - assert data[SPANDATA.NETWORK_TRANSPORT] == "tcp" - assert data[SPANDATA.MCP_SESSION_ID] == session_id - - -@pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.skipif(not IS_MCP_V2, reason="MCP v2 SSE transport detection") -async def test_sse_transport_detection_v2( - sentry_init, capture_events, capture_items, span_streaming, json_rpc_sse -): +async def test_sse_transport_detection_v2(sentry_init, capture_items, json_rpc_sse): """Test that SSE transport is detected on MCP v2. In v2 the request context is carried by the ServerRequestContext built per @@ -1988,7 +1169,6 @@ async def test_sse_transport_detection_v2( sentry_init( integrations=[MCPIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) server = Server("test-server") @@ -2026,11 +1206,7 @@ async def test_tool(ctx, params): ) server.add_request_handler("tools/call", CallToolRequestParams, test_tool) - - if span_streaming: - items = capture_items("span") - else: - events = capture_events() + items = capture_items("span") keep_sse_alive = asyncio.Event() app_task, session_id, result = await json_rpc_sse( @@ -2048,35 +1224,10 @@ async def test_tool(ctx, params): await app_task assert result["result"]["structuredContent"] == {"result": "success"} - - if span_streaming: - sentry_sdk.flush() - span = _find_mcp_span(items, method_name="tools/call") - assert span is not None - data = span["attributes"] - else: - # v2 SSE does not propagate Sentry scopes (only StreamableHTTP does), so - # the handler runs without an active transaction and the MCP span becomes - # its own root transaction (data lives on the trace context) rather than a - # child span of the "/sse" request transaction. Accept either shape. - data = None - for event in events: - if event.get("type") != "transaction": - continue - trace = event["contexts"]["trace"] - if ( - trace.get("op") == OP.MCP_SERVER - and trace.get("data", {}).get(SPANDATA.MCP_METHOD_NAME) == "tools/call" - ): - data = trace["data"] - break - for span in event.get("spans", []): - if span["data"].get(SPANDATA.MCP_METHOD_NAME) == "tools/call": - data = span["data"] - break - if data is not None: - break - assert data is not None + sentry_sdk.flush() + span = _find_mcp_span(items, method_name="tools/call") + assert span is not None + data = span["attributes"] assert data[SPANDATA.MCP_TRANSPORT] == "sse" assert data[SPANDATA.NETWORK_TRANSPORT] == "tcp" @@ -2084,10 +1235,7 @@ async def test_tool(ctx, params): @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) -async def test_streamable_http_scope_propagation( - sentry_init, capture_events, capture_items, span_streaming, json_rpc -): +async def test_streamable_http_scope_propagation(sentry_init, capture_items, json_rpc): """Errors raised inside an HTTP handler attach to the MCP transaction's trace. StreamableHTTPServerTransport.handle_request stashes the active isolation and @@ -2098,22 +1246,14 @@ async def test_streamable_http_scope_propagation( sentry_init( integrations=[MCPIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) server = Server("test-server") - if IS_MCP_V2: - - async def failing_tool(ctx, params): - raise ValueError("Tool execution failed") + async def failing_tool(ctx, params): + raise ValueError("Tool execution failed") - server.add_request_handler("tools/call", CallToolRequestParams, failing_tool) - else: - - @server.call_tool() - def failing_tool(tool_name, arguments): - raise ValueError("Tool execution failed") + server.add_request_handler("tools/call", CallToolRequestParams, failing_tool) session_manager = StreamableHTTPSessionManager( app=server, @@ -2127,68 +1267,30 @@ def failing_tool(tool_name, arguments): lifespan=lambda app: session_manager.run(), ) - if span_streaming: - items = capture_items("event", "span") - - json_rpc( - app, - method="tools/call", - params={"name": "bad_tool", "arguments": {}}, - request_id="req-scope", - ) - - (error_event,) = (item.payload for item in items if item.type == "event") - assert error_event["exception"]["values"][0]["type"] == "ValueError" - assert error_event["exception"]["values"][0]["mechanism"]["type"] == "mcp" - assert not error_event["exception"]["values"][0]["mechanism"]["handled"] - - sentry_sdk.flush() + items = capture_items("event", "span") + json_rpc( + app, + method="tools/call", + params={"name": "bad_tool", "arguments": {}}, + request_id="req-scope", + ) - span = _find_mcp_span(items, method_name="tools/call") - assert span is not None + (error_event,) = (item.payload for item in items if item.type == "event") + assert error_event["exception"]["values"][0]["type"] == "ValueError" + assert error_event["exception"]["values"][0]["mechanism"]["type"] == "mcp" + assert not error_event["exception"]["values"][0]["mechanism"]["handled"] - # The captured error shares the trace of the MCP span, proving the - # handler executed under the propagated request scope. - assert error_event["contexts"]["trace"]["trace_id"] == span["trace_id"] - else: - events = capture_events() + sentry_sdk.flush() - json_rpc( - app, - method="tools/call", - params={"name": "bad_tool", "arguments": {}}, - request_id="req-scope", - ) + span = _find_mcp_span(items, method_name="tools/call") + assert span is not None - error_events = [e for e in events if e.get("type") != "transaction"] - mcp_transactions = [ - e - for e in events - if e.get("type") == "transaction" - and any( - span["data"].get(SPANDATA.MCP_METHOD_NAME) == "tools/call" - for span in e.get("spans", []) - ) - ] - - assert len(error_events) == 1 - assert len(mcp_transactions) == 1 - - error_event = error_events[0] - assert error_event["exception"]["values"][0]["type"] == "ValueError" - assert error_event["exception"]["values"][0]["mechanism"]["type"] == "mcp" - assert not error_event["exception"]["values"][0]["mechanism"]["handled"] - - # The captured error shares the trace of the MCP transaction, proving the - # handler executed under the propagated request scope. - assert ( - error_event["contexts"]["trace"]["trace_id"] - == mcp_transactions[0]["contexts"]["trace"]["trace_id"] - ) + # The captured error shares the trace of the MCP span, proving the + # handler executed under the propagated request scope. + assert error_event["contexts"]["trace"]["trace_id"] == span["trace_id"] @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) @pytest.mark.parametrize( "data_collection, send_default_pii, expect_input", [ @@ -2232,19 +1334,16 @@ def failing_tool(tool_name, arguments): ) async def test_tool_data_collection_inputs( sentry_init, - capture_events, capture_items, data_collection, send_default_pii, expect_input, - span_streaming, stdio, ): init_kwargs = { "integrations": [MCPIntegration()], "traces_sample_rate": 1.0, "send_default_pii": send_default_pii, - "trace_lifecycle": "stream" if span_streaming else "static", } if data_collection is not None: init_kwargs["data_collection"] = data_collection @@ -2253,40 +1352,24 @@ async def test_tool_data_collection_inputs( server = Server("test-server") - if IS_MCP_V2: - - async def test_tool(ctx, params): - return CallToolResult( - content=[TextContent(type="text", text="ok")], - structured_content={"result": "success"}, - ) - - server.add_request_handler("tools/call", CallToolRequestParams, test_tool) - else: + async def test_tool(ctx, params): + return CallToolResult( + content=[TextContent(type="text", text="ok")], + structured_content={"result": "success"}, + ) - @server.call_tool() - async def test_tool(tool_name, arguments): - return {"result": "success"} + server.add_request_handler("tools/call", CallToolRequestParams, test_tool) params = { "name": "calculate", "arguments": {"x": 10, "y": 5}, } - - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="mcp tx"): - await stdio(server, method="tools/call", params=params, request_id="req-1") - sentry_sdk.flush() - span = _find_mcp_span(items, method_name="tools/call") - assert span is not None - data = span["attributes"] - else: - events = capture_events() - with start_transaction(name="mcp tx"): - await stdio(server, method="tools/call", params=params, request_id="req-1") - (tx,) = events - data = tx["spans"][0]["data"] + items = capture_items("span") + await stdio(server, method="tools/call", params=params, request_id="req-1") + sentry_sdk.flush() + span = _find_mcp_span(items, method_name="tools/call") + assert span is not None + data = span["attributes"] # Arguments are only gated once data_collection is configured; without it they # are set unconditionally, as they were before data_collection existed. @@ -2305,7 +1388,6 @@ async def test_tool(tool_name, arguments): @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) @pytest.mark.parametrize( "data_collection, send_default_pii, expect_output", [ @@ -2349,12 +1431,10 @@ async def test_tool(tool_name, arguments): ) async def test_tool_data_collection_outputs( sentry_init, - capture_events, capture_items, data_collection, send_default_pii, expect_output, - span_streaming, stdio, ): """Tool result content is gated on data_collection.gen_ai.outputs""" @@ -2362,7 +1442,6 @@ async def test_tool_data_collection_outputs( "integrations": [MCPIntegration()], "traces_sample_rate": 1.0, "send_default_pii": send_default_pii, - "trace_lifecycle": "stream" if span_streaming else "static", } if data_collection is not None: init_kwargs["data_collection"] = data_collection @@ -2371,45 +1450,29 @@ async def test_tool_data_collection_outputs( server = Server("test-server") - if IS_MCP_V2: - - async def test_tool(ctx, params): - return CallToolResult( - content=[ - TextContent( - type="text", - text=json.dumps({"result": "success", "value": 42}), - ) - ], - structured_content={"result": "success", "value": 42}, - ) - - server.add_request_handler("tools/call", CallToolRequestParams, test_tool) - else: + async def test_tool(ctx, params): + return CallToolResult( + content=[ + TextContent( + type="text", + text=json.dumps({"result": "success", "value": 42}), + ) + ], + structured_content={"result": "success", "value": 42}, + ) - @server.call_tool() - async def test_tool(tool_name, arguments): - return {"result": "success", "value": 42} + server.add_request_handler("tools/call", CallToolRequestParams, test_tool) params = { "name": "calculate", "arguments": {"x": 10, "y": 5}, } - - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="mcp tx"): - await stdio(server, method="tools/call", params=params, request_id="req-1") - sentry_sdk.flush() - span = _find_mcp_span(items, method_name="tools/call") - assert span is not None - data = span["attributes"] - else: - events = capture_events() - with start_transaction(name="mcp tx"): - await stdio(server, method="tools/call", params=params, request_id="req-1") - (tx,) = events - data = tx["spans"][0]["data"] + items = capture_items("span") + await stdio(server, method="tools/call", params=params, request_id="req-1") + sentry_sdk.flush() + span = _find_mcp_span(items, method_name="tools/call") + assert span is not None + data = span["attributes"] if expect_output: assert data[SPANDATA.MCP_TOOL_RESULT_CONTENT] == json.dumps( @@ -2422,7 +1485,6 @@ async def test_tool(tool_name, arguments): @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) @pytest.mark.parametrize( "data_collection, send_default_pii, expect_input", [ @@ -2466,12 +1528,10 @@ async def test_tool(tool_name, arguments): ) async def test_prompt_data_collection_inputs( sentry_init, - capture_events, capture_items, data_collection, send_default_pii, expect_input, - span_streaming, stdio, ): """Prompt arguments and message content are gated on data_collection.gen_ai.inputs. @@ -2483,7 +1543,6 @@ async def test_prompt_data_collection_inputs( "integrations": [MCPIntegration()], "traces_sample_rate": 1.0, "send_default_pii": send_default_pii, - "trace_lifecycle": "stream" if span_streaming else "static", } if data_collection is not None: init_kwargs["data_collection"] = data_collection @@ -2502,41 +1561,21 @@ async def test_prompt_data_collection_inputs( ], ) - if IS_MCP_V2: + async def test_prompt(ctx, params): + return prompt_result - async def test_prompt(ctx, params): - return prompt_result - - server.add_request_handler("prompts/get", GetPromptRequestParams, test_prompt) - else: - - @server.get_prompt() - async def test_prompt(name, arguments): - return prompt_result + server.add_request_handler("prompts/get", GetPromptRequestParams, test_prompt) params = { "name": "code_help", "arguments": {"language": "python"}, } - - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="mcp tx"): - await stdio( - server, method="prompts/get", params=params, request_id="req-prompt" - ) - sentry_sdk.flush() - span = _find_mcp_span(items, method_name="prompts/get") - assert span is not None - data = span["attributes"] - else: - events = capture_events() - with start_transaction(name="mcp tx"): - await stdio( - server, method="prompts/get", params=params, request_id="req-prompt" - ) - (tx,) = events - data = tx["spans"][0]["data"] + items = capture_items("span") + await stdio(server, method="prompts/get", params=params, request_id="req-prompt") + sentry_sdk.flush() + span = _find_mcp_span(items, method_name="prompts/get") + assert span is not None + data = span["attributes"] # Arguments are only gated once data_collection is configured; without it they # are set unconditionally, as they were before data_collection existed. @@ -2556,58 +1595,3 @@ async def test_prompt(name, arguments): # The message count carries no prompt content, so it is never gated assert data[SPANDATA.MCP_PROMPT_RESULT_MESSAGE_COUNT] == 1 - - -@pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) -async def test_include_prompts_ignored_when_data_collection_set( - sentry_init, - capture_events, - capture_items, - span_streaming, - stdio, -): - sentry_init( - integrations=[MCPIntegration(include_prompts=False)], - traces_sample_rate=1.0, - send_default_pii=True, - trace_lifecycle="stream" if span_streaming else "static", - data_collection={"gen_ai": {"outputs": True}}, - ) - - server = Server("test-server") - - if IS_MCP_V2: - - async def test_tool(ctx, params): - return CallToolResult( - content=[TextContent(type="text", text=json.dumps({"value": 42}))], - structured_content={"value": 42}, - ) - - server.add_request_handler("tools/call", CallToolRequestParams, test_tool) - else: - - @server.call_tool() - async def test_tool(tool_name, arguments): - return {"value": 42} - - params = {"name": "calculate", "arguments": {"x": 10}} - - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="mcp tx"): - await stdio(server, method="tools/call", params=params, request_id="req-1") - sentry_sdk.flush() - span = _find_mcp_span(items, method_name="tools/call") - assert span is not None - data = span["attributes"] - else: - events = capture_events() - with start_transaction(name="mcp tx"): - await stdio(server, method="tools/call", params=params, request_id="req-1") - (tx,) = events - data = tx["spans"][0]["data"] - - assert data[SPANDATA.MCP_TOOL_RESULT_CONTENT] == json.dumps({"value": 42}) - assert data[SPANDATA.MCP_TOOL_RESULT_CONTENT_COUNT] == 1 diff --git a/tests/integrations/mistral/test_mistral.py b/tests/integrations/mistral/test_mistral.py index 21808020c4..c336125a4a 100644 --- a/tests/integrations/mistral/test_mistral.py +++ b/tests/integrations/mistral/test_mistral.py @@ -51,21 +51,15 @@ def mistral_response(): ) -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_nonstreaming_chat( sentry_init, capture_items, get_model_response, mistral_response, - stream_gen_ai_spans, - span_streaming, ): sentry_init( integrations=[MistralIntegration()], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = Mistral(api_key="z") @@ -75,110 +69,58 @@ def test_nonstreaming_chat( serialize_pydantic=True, ) - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with mock.patch.object( - Chat, - "do_request", - return_value=model_response, - ), sentry_sdk.start_transaction(name="mistral"): - client.chat.complete( - model="mistral-medium-latest", - messages=[ - {"role": "user", "content": "What is the best French cheese?"} - ], - max_tokens=1024, - presence_penalty=0.1, - frequency_penalty=0.2, - temperature=0.7, - top_p=0.9, - reasoning_effort="high", - ) - sentry_sdk.flush() - spans = [item.payload for item in items] - (span,) = ( - span - for span in spans - if span["attributes"].get("sentry.op") == OP.GEN_AI_CHAT - ) - - assert span["name"] == "chat mistral-medium-latest" - assert span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "mistral" - assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - - assert ( - span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "mistral-medium-latest" + items = capture_items("span") + + with mock.patch.object( + Chat, + "do_request", + return_value=model_response, + ): + client.chat.complete( + model="mistral-medium-latest", + messages=[{"role": "user", "content": "What is the best French cheese?"}], + max_tokens=1024, + presence_penalty=0.1, + frequency_penalty=0.2, + temperature=0.7, + top_p=0.9, + reasoning_effort="high", ) - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is False - - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TEMPERATURE] == 0.7 - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TOP_P] == 0.9 - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_FREQUENCY_PENALTY] == 0.2 - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_PRESENCE_PENALTY] == 0.1 - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 1024 - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_REASONING_LEVEL] == "high" - - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 20 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 - else: - items = capture_items("transaction") - - with mock.patch.object( - Chat, - "do_request", - return_value=model_response, - ), sentry_sdk.start_transaction(name="mistral"): - client.chat.complete( - model="open-mistral", - messages=[{"role": "user", "content": "Hello, Mistral"}], - max_tokens=1024, - presence_penalty=0.1, - frequency_penalty=0.2, - temperature=0.7, - top_p=0.9, - reasoning_effort="high", - ) - - (transaction,) = [item.payload for item in items] - (span,) = transaction["spans"] + sentry_sdk.flush() + spans = [item.payload for item in items] + (span,) = ( + span for span in spans if span["attributes"].get("sentry.op") == OP.GEN_AI_CHAT + ) - assert span["description"] == "chat open-mistral" - assert span["data"][SPANDATA.GEN_AI_PROVIDER_NAME] == "mistral" - assert span["data"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" + assert span["name"] == "chat mistral-medium-latest" + assert span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "mistral" + assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["data"][SPANDATA.GEN_AI_REQUEST_MODEL] == "open-mistral" - assert span["data"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is False + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "mistral-medium-latest" + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is False - assert span["data"][SPANDATA.GEN_AI_REQUEST_TEMPERATURE] == 0.7 - assert span["data"][SPANDATA.GEN_AI_REQUEST_TOP_P] == 0.9 - assert span["data"][SPANDATA.GEN_AI_REQUEST_FREQUENCY_PENALTY] == 0.2 - assert span["data"][SPANDATA.GEN_AI_REQUEST_PRESENCE_PENALTY] == 0.1 - assert span["data"][SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 1024 - assert span["data"][SPANDATA.GEN_AI_REQUEST_REASONING_LEVEL] == "high" + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TEMPERATURE] == 0.7 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TOP_P] == 0.9 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_FREQUENCY_PENALTY] == 0.2 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_PRESENCE_PENALTY] == 0.1 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 1024 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_REASONING_LEVEL] == "high" - assert span["data"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["data"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 20 - assert span["data"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 20 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) async def test_nonstreaming_chat_async( sentry_init, capture_items, get_model_response, mistral_response, - stream_gen_ai_spans, - span_streaming, ): sentry_init( integrations=[MistralIntegration()], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = Mistral(api_key="z") @@ -188,93 +130,47 @@ async def test_nonstreaming_chat_async( serialize_pydantic=True, ) - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with mock.patch.object( - Chat, - "do_request_async", - return_value=model_response, - ), sentry_sdk.start_transaction(name="mistral"): - await client.chat.complete_async( - model="mistral-medium-latest", - messages=[ - {"role": "user", "content": "What is the best French cheese?"} - ], - max_tokens=1024, - presence_penalty=0.1, - frequency_penalty=0.2, - temperature=0.7, - top_p=0.9, - reasoning_effort="high", - ) - - sentry_sdk.flush() - spans = [item.payload for item in items] - (span,) = ( - span - for span in spans - if span["attributes"].get("sentry.op") == OP.GEN_AI_CHAT - ) - - assert span["name"] == "chat mistral-medium-latest" - assert span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "mistral" - assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - - assert ( - span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "mistral-medium-latest" + items = capture_items("span") + + with mock.patch.object( + Chat, + "do_request_async", + return_value=model_response, + ): + await client.chat.complete_async( + model="mistral-medium-latest", + messages=[{"role": "user", "content": "What is the best French cheese?"}], + max_tokens=1024, + presence_penalty=0.1, + frequency_penalty=0.2, + temperature=0.7, + top_p=0.9, + reasoning_effort="high", ) - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is False - - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TEMPERATURE] == 0.7 - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TOP_P] == 0.9 - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_FREQUENCY_PENALTY] == 0.2 - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_PRESENCE_PENALTY] == 0.1 - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 1024 - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_REASONING_LEVEL] == "high" - - assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 20 - assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 - else: - items = capture_items("transaction") - with mock.patch.object( - Chat, - "do_request_async", - return_value=model_response, - ), sentry_sdk.start_transaction(name="mistral"): - await client.chat.complete_async( - model="mistral-medium-latest", - messages=[{"role": "user", "content": "Hello, Mistral"}], - max_tokens=1024, - presence_penalty=0.1, - frequency_penalty=0.2, - temperature=0.7, - top_p=0.9, - reasoning_effort="high", - ) - - (transaction,) = [item.payload for item in items] - (span,) = transaction["spans"] + sentry_sdk.flush() + spans = [item.payload for item in items] + (span,) = ( + span for span in spans if span["attributes"].get("sentry.op") == OP.GEN_AI_CHAT + ) - assert span["description"] == "chat mistral-medium-latest" - assert span["data"][SPANDATA.GEN_AI_PROVIDER_NAME] == "mistral" - assert span["data"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" + assert span["name"] == "chat mistral-medium-latest" + assert span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "mistral" + assert span["attributes"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" - assert span["data"][SPANDATA.GEN_AI_REQUEST_MODEL] == "mistral-medium-latest" - assert span["data"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is False + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "mistral-medium-latest" + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is False - assert span["data"][SPANDATA.GEN_AI_REQUEST_TEMPERATURE] == 0.7 - assert span["data"][SPANDATA.GEN_AI_REQUEST_TOP_P] == 0.9 - assert span["data"][SPANDATA.GEN_AI_REQUEST_FREQUENCY_PENALTY] == 0.2 - assert span["data"][SPANDATA.GEN_AI_REQUEST_PRESENCE_PENALTY] == 0.1 - assert span["data"][SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 1024 - assert span["data"][SPANDATA.GEN_AI_REQUEST_REASONING_LEVEL] == "high" + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TEMPERATURE] == 0.7 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TOP_P] == 0.9 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_FREQUENCY_PENALTY] == 0.2 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_PRESENCE_PENALTY] == 0.1 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 1024 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_REASONING_LEVEL] == "high" - assert span["data"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 - assert span["data"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 20 - assert span["data"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 20 + assert span["attributes"][SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS] == 30 @pytest.mark.parametrize( @@ -470,8 +366,6 @@ async def test_nonstreaming_chat_async( ), ) @pytest.mark.parametrize("data_collection", [True, False]) -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_input_attributes_nonstreaming_chat( sentry_init, capture_items, @@ -481,23 +375,17 @@ def test_input_attributes_nonstreaming_chat( expected_system_instructions, expected_input_messages, data_collection, - stream_gen_ai_spans, - span_streaming, ): if data_collection: sentry_init( integrations=[MistralIntegration()], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", data_collection={}, ) else: sentry_init( integrations=[MistralIntegration()], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", send_default_pii=True, ) @@ -508,61 +396,33 @@ def test_input_attributes_nonstreaming_chat( serialize_pydantic=True, ) - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with mock.patch.object( - Chat, - "do_request", - return_value=model_response, - ), sentry_sdk.start_transaction(name="mistral"): - client.chat.complete( - model="mistral-medium-latest", - messages=messages, - ) + items = capture_items("span") - sentry_sdk.flush() - spans = [item.payload for item in items] - (span,) = ( - span - for span in spans - if span["attributes"].get("sentry.op") == OP.GEN_AI_CHAT + with mock.patch.object( + Chat, + "do_request", + return_value=model_response, + ): + client.chat.complete( + model="mistral-medium-latest", + messages=messages, ) - assert span["name"] == "chat mistral-medium-latest" - assert ( - json.loads(span["attributes"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS]) - == expected_system_instructions - ) - assert ( - json.loads(span["attributes"][SPANDATA.GEN_AI_INPUT_MESSAGES]) - == expected_input_messages - ) - else: - items = capture_items("transaction") - - with mock.patch.object( - Chat, - "do_request", - return_value=model_response, - ), sentry_sdk.start_transaction(name="mistral"): - client.chat.complete( - model="open-mistral", - messages=messages, - ) - - (transaction,) = [item.payload for item in items] - (span,) = transaction["spans"] + sentry_sdk.flush() + spans = [item.payload for item in items] + (span,) = ( + span for span in spans if span["attributes"].get("sentry.op") == OP.GEN_AI_CHAT + ) - assert span["description"] == "chat open-mistral" - assert ( - json.loads(span["data"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS]) - == expected_system_instructions - ) - assert ( - json.loads(span["data"][SPANDATA.GEN_AI_INPUT_MESSAGES]) - == expected_input_messages - ) + assert span["name"] == "chat mistral-medium-latest" + assert ( + json.loads(span["attributes"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS]) + == expected_system_instructions + ) + assert ( + json.loads(span["attributes"][SPANDATA.GEN_AI_INPUT_MESSAGES]) + == expected_input_messages + ) @pytest.mark.parametrize( @@ -759,8 +619,6 @@ def test_input_attributes_nonstreaming_chat( ) @pytest.mark.asyncio @pytest.mark.parametrize("data_collection", [True, False]) -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) async def test_input_attributes_nonstreaming_chat_async( sentry_init, capture_items, @@ -770,23 +628,17 @@ async def test_input_attributes_nonstreaming_chat_async( expected_system_instructions, expected_input_messages, data_collection, - stream_gen_ai_spans, - span_streaming, ): if data_collection: sentry_init( integrations=[MistralIntegration()], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", data_collection={}, ) else: sentry_init( integrations=[MistralIntegration()], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", send_default_pii=True, ) client = Mistral(api_key="z") @@ -796,89 +648,53 @@ async def test_input_attributes_nonstreaming_chat_async( serialize_pydantic=True, ) - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with mock.patch.object( - Chat, - "do_request_async", - return_value=model_response, - ), sentry_sdk.start_transaction(name="mistral"): - await client.chat.complete_async( - model="mistral-medium-latest", - messages=messages, - ) + items = capture_items("span") - sentry_sdk.flush() - spans = [item.payload for item in items] - (span,) = ( - span - for span in spans - if span["attributes"].get("sentry.op") == OP.GEN_AI_CHAT - ) - - assert span["name"] == "chat mistral-medium-latest" - assert ( - json.loads(span["attributes"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS]) - == expected_system_instructions - ) - assert ( - json.loads(span["attributes"][SPANDATA.GEN_AI_INPUT_MESSAGES]) - == expected_input_messages + with mock.patch.object( + Chat, + "do_request_async", + return_value=model_response, + ): + await client.chat.complete_async( + model="mistral-medium-latest", + messages=messages, ) - else: - items = capture_items("transaction") - - with mock.patch.object( - Chat, - "do_request_async", - return_value=model_response, - ), sentry_sdk.start_transaction(name="mistral"): - await client.chat.complete_async( - model="mistral-medium-latest", - messages=messages, - ) - (transaction,) = [item.payload for item in items] - (span,) = transaction["spans"] + sentry_sdk.flush() + spans = [item.payload for item in items] + (span,) = ( + span for span in spans if span["attributes"].get("sentry.op") == OP.GEN_AI_CHAT + ) - assert span["description"] == "chat mistral-medium-latest" - assert ( - json.loads(span["data"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS]) - == expected_system_instructions - ) - assert ( - json.loads(span["data"][SPANDATA.GEN_AI_INPUT_MESSAGES]) - == expected_input_messages - ) + assert span["name"] == "chat mistral-medium-latest" + assert ( + json.loads(span["attributes"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS]) + == expected_system_instructions + ) + assert ( + json.loads(span["attributes"][SPANDATA.GEN_AI_INPUT_MESSAGES]) + == expected_input_messages + ) @pytest.mark.parametrize("data_collection", [True, False]) -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_output_attributes_nonstreaming_chat( sentry_init, capture_items, get_model_response, mistral_response, data_collection, - stream_gen_ai_spans, - span_streaming, ): if data_collection: sentry_init( integrations=[MistralIntegration()], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", data_collection={}, ) else: sentry_init( integrations=[MistralIntegration()], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", send_default_pii=True, ) @@ -889,106 +705,61 @@ def test_output_attributes_nonstreaming_chat( serialize_pydantic=True, ) - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") + items = capture_items("span") - with mock.patch.object( - Chat, - "do_request", - return_value=model_response, - ), sentry_sdk.start_transaction(name="mistral"): - client.chat.complete( - model="mistral-medium-latest", - messages=[ - {"role": "user", "content": "What is the best French cheese?"} - ], - ) - - sentry_sdk.flush() - spans = [item.payload for item in items] - (span,) = ( - span - for span in spans - if span["attributes"].get("sentry.op") == OP.GEN_AI_CHAT + with mock.patch.object( + Chat, + "do_request", + return_value=model_response, + ): + client.chat.complete( + model="mistral-medium-latest", + messages=[{"role": "user", "content": "What is the best French cheese?"}], ) - assert span["name"] == "chat mistral-medium-latest" - assert json.loads(span["attributes"][SPANDATA.GEN_AI_OUTPUT_MESSAGES]) == [ - { - "role": "assistant", - "parts": [ - {"type": "text", "content": "Hello, how can I help you?"}, - ], - }, - { - "role": "assistant", - "parts": [ - {"type": "text", "content": "Response 1"}, - {"type": "text", "content": "Response 2"}, - ], - }, - ] - else: - items = capture_items("transaction") - - with mock.patch.object( - Chat, - "do_request", - return_value=model_response, - ), sentry_sdk.start_transaction(name="mistral"): - client.chat.complete( - model="open-mistral", - messages=[{"role": "user", "content": "Hello, Mistral"}], - ) - - (transaction,) = [item.payload for item in items] - (span,) = transaction["spans"] + sentry_sdk.flush() + spans = [item.payload for item in items] + (span,) = ( + span for span in spans if span["attributes"].get("sentry.op") == OP.GEN_AI_CHAT + ) - assert span["description"] == "chat open-mistral" - assert json.loads(span["data"][SPANDATA.GEN_AI_OUTPUT_MESSAGES]) == [ - { - "role": "assistant", - "parts": [ - {"type": "text", "content": "Hello, how can I help you?"}, - ], - }, - { - "role": "assistant", - "parts": [ - {"type": "text", "content": "Response 1"}, - {"type": "text", "content": "Response 2"}, - ], - }, - ] + assert span["name"] == "chat mistral-medium-latest" + assert json.loads(span["attributes"][SPANDATA.GEN_AI_OUTPUT_MESSAGES]) == [ + { + "role": "assistant", + "parts": [ + {"type": "text", "content": "Hello, how can I help you?"}, + ], + }, + { + "role": "assistant", + "parts": [ + {"type": "text", "content": "Response 1"}, + {"type": "text", "content": "Response 2"}, + ], + }, + ] @pytest.mark.asyncio @pytest.mark.parametrize("data_collection", [True, False]) -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) async def test_output_attributes_nonstreaming_chat_async( sentry_init, capture_items, get_model_response, mistral_response, data_collection, - stream_gen_ai_spans, - span_streaming, ): if data_collection: sentry_init( integrations=[MistralIntegration()], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", data_collection={}, ) else: sentry_init( integrations=[MistralIntegration()], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", send_default_pii=True, ) @@ -999,74 +770,37 @@ async def test_output_attributes_nonstreaming_chat_async( serialize_pydantic=True, ) - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") + items = capture_items("span") - with mock.patch.object( - Chat, - "do_request_async", - return_value=model_response, - ), sentry_sdk.start_transaction(name="mistral"): - await client.chat.complete_async( - model="mistral-medium-latest", - messages=[ - {"role": "user", "content": "What is the best French cheese?"} - ], - ) - - sentry_sdk.flush() - spans = [item.payload for item in items] - (span,) = ( - span - for span in spans - if span["attributes"].get("sentry.op") == OP.GEN_AI_CHAT + with mock.patch.object( + Chat, + "do_request_async", + return_value=model_response, + ): + await client.chat.complete_async( + model="mistral-medium-latest", + messages=[{"role": "user", "content": "What is the best French cheese?"}], ) - assert span["name"] == "chat mistral-medium-latest" - assert json.loads(span["attributes"][SPANDATA.GEN_AI_OUTPUT_MESSAGES]) == [ - { - "role": "assistant", - "parts": [ - {"type": "text", "content": "Hello, how can I help you?"}, - ], - }, - { - "role": "assistant", - "parts": [ - {"type": "text", "content": "Response 1"}, - {"type": "text", "content": "Response 2"}, - ], - }, - ] - else: - items = capture_items("transaction") - - with mock.patch.object( - Chat, - "do_request_async", - return_value=model_response, - ), sentry_sdk.start_transaction(name="mistral"): - await client.chat.complete_async( - model="mistral-medium-latest", - messages=[{"role": "user", "content": "Hello, Mistral"}], - ) - - (transaction,) = [item.payload for item in items] - (span,) = transaction["spans"] + sentry_sdk.flush() + spans = [item.payload for item in items] + (span,) = ( + span for span in spans if span["attributes"].get("sentry.op") == OP.GEN_AI_CHAT + ) - assert span["description"] == "chat mistral-medium-latest" - assert json.loads(span["data"][SPANDATA.GEN_AI_OUTPUT_MESSAGES]) == [ - { - "role": "assistant", - "parts": [ - {"type": "text", "content": "Hello, how can I help you?"}, - ], - }, - { - "role": "assistant", - "parts": [ - {"type": "text", "content": "Response 1"}, - {"type": "text", "content": "Response 2"}, - ], - }, - ] + assert span["name"] == "chat mistral-medium-latest" + assert json.loads(span["attributes"][SPANDATA.GEN_AI_OUTPUT_MESSAGES]) == [ + { + "role": "assistant", + "parts": [ + {"type": "text", "content": "Hello, how can I help you?"}, + ], + }, + { + "role": "assistant", + "parts": [ + {"type": "text", "content": "Response 1"}, + {"type": "text", "content": "Response 2"}, + ], + }, + ] diff --git a/tests/integrations/openai/test_openai.py b/tests/integrations/openai/test_openai.py index 96866886ec..5d2c8d090f 100644 --- a/tests/integrations/openai/test_openai.py +++ b/tests/integrations/openai/test_openai.py @@ -63,7 +63,6 @@ from unittest import mock # python 3.3 and above -from sentry_sdk import start_transaction from sentry_sdk.consts import OP, SPANDATA from sentry_sdk.integrations.openai import ( OpenAIIntegration, @@ -168,22 +167,15 @@ async def __call__(self, *args, **kwargs): OPENAI_VERSION <= (2, 10, 0), reason="ChatCompletionCustomToolParam is unavailable before.", ) -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_chat_completion_tool_definitions( sentry_init, - capture_events, capture_items, nonstreaming_chat_completions_model_response, - stream_gen_ai_spans, - span_streaming, ): sentry_init( integrations=[OpenAIIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = OpenAI(api_key="z") @@ -200,160 +192,78 @@ def test_chat_completion_tool_definitions( ), ) ) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with start_transaction(name="openai tx"): - client.chat.completions.create( - model="some-model", - messages=[ - {"role": "system", "content": "You are a helpful assistant."}, - {"role": "user", "content": "hello"}, - ], - tools=[ - ChatCompletionFunctionToolParam( - type="function", - function=FunctionDefinition( - name="name", - description="description", - parameters={ - "type": "object", - "properties": { - "city": {"type": "string"}, - "state": {"type": "string"}, - }, - "required": ["city", "state"], - "additionalProperties": False, - }, - strict=True, - ), - ), - ChatCompletionCustomToolParam( - type="custom", - custom=Custom( - name="name", - description="description", - ), - ), - ], - ) - - sentry_sdk.flush() - span = next(item.payload for item in items) - - assert json.loads(span["attributes"][SPANDATA.GEN_AI_TOOL_DEFINITIONS]) == [ - { - "type": "function", - "name": "name", - "description": "description", - "parameters": { - "type": "object", - "properties": { - "city": {"type": "string"}, - "state": {"type": "string"}, + client.chat.completions.create( + model="some-model", + messages=[ + {"role": "system", "content": "You are a helpful assistant."}, + {"role": "user", "content": "hello"}, + ], + tools=[ + ChatCompletionFunctionToolParam( + type="function", + function=FunctionDefinition( + name="name", + description="description", + parameters={ + "type": "object", + "properties": { + "city": {"type": "string"}, + "state": {"type": "string"}, + }, + "required": ["city", "state"], + "additionalProperties": False, }, - "required": ["city", "state"], - "additionalProperties": False, - }, - }, - { - "type": "custom", - "name": "name", - "description": "description", - }, - ] - else: - events = capture_events() - - with start_transaction(name="openai tx"): - client.chat.completions.create( - model="some-model", - messages=[ - {"role": "system", "content": "You are a helpful assistant."}, - {"role": "user", "content": "hello"}, - ], - tools=[ - ChatCompletionFunctionToolParam( - type="function", - function=FunctionDefinition( - name="name", - description="description", - parameters={ - "type": "object", - "properties": { - "city": {"type": "string"}, - "state": {"type": "string"}, - }, - "required": ["city", "state"], - "additionalProperties": False, - }, - strict=True, - ), - ), - ChatCompletionCustomToolParam( - type="custom", - custom=Custom( - name="name", - description="description", - ), - ), - ], - ) + strict=True, + ), + ), + ChatCompletionCustomToolParam( + type="custom", + custom=Custom( + name="name", + description="description", + ), + ), + ], + ) - tx = events[0] - assert tx["type"] == "transaction" + sentry_sdk.flush() + span = next(item.payload for item in items) - assert json.loads(tx["spans"][0]["data"][SPANDATA.GEN_AI_TOOL_DEFINITIONS]) == [ - { - "type": "function", - "name": "name", - "description": "description", - "parameters": { - "type": "object", - "properties": { - "city": {"type": "string"}, - "state": {"type": "string"}, - }, - "required": ["city", "state"], - "additionalProperties": False, + assert json.loads(span["attributes"][SPANDATA.GEN_AI_TOOL_DEFINITIONS]) == [ + { + "type": "function", + "name": "name", + "description": "description", + "parameters": { + "type": "object", + "properties": { + "city": {"type": "string"}, + "state": {"type": "string"}, }, + "required": ["city", "state"], + "additionalProperties": False, }, - { - "type": "custom", - "name": "name", - "description": "description", - }, - ] + }, + { + "type": "custom", + "name": "name", + "description": "description", + }, + ] -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) -@pytest.mark.parametrize( - "send_default_pii, include_prompts", - [ - (True, False), - (False, True), - (False, False), - ], -) -def test_nonstreaming_chat_completion_no_prompts( +def test_nonstreaming_chat_completion_no_sensitive_data( sentry_init, - capture_events, capture_items, - send_default_pii, - include_prompts, nonstreaming_chat_completions_model_response, - stream_gen_ai_spans, - span_streaming, ): sentry_init( - integrations=[OpenAIIntegration(include_prompts=include_prompts)], + integrations=[OpenAIIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, - send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", + send_default_pii=False, ) client = OpenAI(api_key="z") @@ -370,96 +280,48 @@ def test_nonstreaming_chat_completion_no_prompts( ), ) ) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with start_transaction(name="openai tx"): - response = ( - client.chat.completions.create( - model="some-model", - messages=[ - {"role": "system", "content": "You are a helpful assistant."}, - {"role": "user", "content": "hello"}, - ], - max_tokens=100, - presence_penalty=0.1, - frequency_penalty=0.2, - temperature=0.7, - top_p=0.9, - ) - .choices[0] - .message.content - ) - - assert response == "the model response" - sentry_sdk.flush() - span = next(item.payload for item in items) - assert span["attributes"]["sentry.op"] == "gen_ai.chat" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "openai" - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is False - - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "some-model" - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 100 - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_PRESENCE_PENALTY] == 0.1 - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_FREQUENCY_PENALTY] == 0.2 - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TEMPERATURE] == 0.7 - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TOP_P] == 0.9 - - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in span["attributes"] - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] - - assert span["attributes"]["gen_ai.usage.output_tokens"] == 10 - assert span["attributes"]["gen_ai.usage.input_tokens"] == 20 - assert span["attributes"]["gen_ai.usage.total_tokens"] == 30 - else: - events = capture_events() - - with start_transaction(name="openai tx"): - response = ( - client.chat.completions.create( - model="some-model", - messages=[ - {"role": "system", "content": "You are a helpful assistant."}, - {"role": "user", "content": "hello"}, - ], - max_tokens=100, - presence_penalty=0.1, - frequency_penalty=0.2, - temperature=0.7, - top_p=0.9, - ) - .choices[0] - .message.content - ) + response = ( + client.chat.completions.create( + model="some-model", + messages=[ + {"role": "system", "content": "You are a helpful assistant."}, + {"role": "user", "content": "hello"}, + ], + max_tokens=100, + presence_penalty=0.1, + frequency_penalty=0.2, + temperature=0.7, + top_p=0.9, + ) + .choices[0] + .message.content + ) - assert response == "the model response" - tx = events[0] - assert tx["type"] == "transaction" - span = tx["spans"][0] - assert span["op"] == "gen_ai.chat" - assert span["data"][SPANDATA.GEN_AI_SYSTEM] == "openai" - assert span["data"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is False + assert response == "the model response" + sentry_sdk.flush() + span = next(item.payload for item in items) + assert span["attributes"]["sentry.op"] == "gen_ai.chat" + assert span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "openai" + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is False - assert span["data"][SPANDATA.GEN_AI_REQUEST_MODEL] == "some-model" - assert span["data"][SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 100 - assert span["data"][SPANDATA.GEN_AI_REQUEST_PRESENCE_PENALTY] == 0.1 - assert span["data"][SPANDATA.GEN_AI_REQUEST_FREQUENCY_PENALTY] == 0.2 - assert span["data"][SPANDATA.GEN_AI_REQUEST_TEMPERATURE] == 0.7 - assert span["data"][SPANDATA.GEN_AI_REQUEST_TOP_P] == 0.9 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "some-model" + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 100 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_PRESENCE_PENALTY] == 0.1 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_FREQUENCY_PENALTY] == 0.2 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TEMPERATURE] == 0.7 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TOP_P] == 0.9 - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in span["data"] - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["data"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["data"] + assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in span["attributes"] + assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] + assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] - assert span["data"]["gen_ai.usage.output_tokens"] == 10 - assert span["data"]["gen_ai.usage.input_tokens"] == 20 - assert span["data"]["gen_ai.usage.total_tokens"] == 30 + assert span["attributes"]["gen_ai.usage.output_tokens"] == 10 + assert span["attributes"]["gen_ai.usage.input_tokens"] == 20 + assert span["attributes"]["gen_ai.usage.total_tokens"] == 30 -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize( "get_messages,expected_system_instructions", [ @@ -540,21 +402,16 @@ def test_nonstreaming_chat_completion_no_prompts( ) def test_nonstreaming_chat_completion( sentry_init, - capture_events, capture_items, get_messages, expected_system_instructions, nonstreaming_chat_completions_model_response, - stream_gen_ai_spans, - span_streaming, ): sentry_init( - integrations=[OpenAIIntegration(include_prompts=True)], + integrations=[OpenAIIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = OpenAI(api_key="z") @@ -571,106 +428,57 @@ def test_nonstreaming_chat_completion( ), ) ) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with start_transaction(name="openai tx"): - response = ( - client.chat.completions.create( - model="some-model", - messages=get_messages(), - max_tokens=100, - presence_penalty=0.1, - frequency_penalty=0.2, - temperature=0.7, - top_p=0.9, - ) - .choices[0] - .message.content - ) - - assert response == "the model response" - sentry_sdk.flush() - span = next(item.payload for item in items) - assert span["attributes"]["sentry.op"] == "gen_ai.chat" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "openai" - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is False - - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "some-model" - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 100 - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_PRESENCE_PENALTY] == 0.1 - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_FREQUENCY_PENALTY] == 0.2 - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TEMPERATURE] == 0.7 - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TOP_P] == 0.9 - - assert ( - json.loads(span["attributes"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS]) - == expected_system_instructions - ) - - assert "hello" in span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - assert ( - "Message demonstrating the absence of truncation." - in span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] + response = ( + client.chat.completions.create( + model="some-model", + messages=get_messages(), + max_tokens=100, + presence_penalty=0.1, + frequency_penalty=0.2, + temperature=0.7, + top_p=0.9, ) - assert "the model response" in span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] - - assert span["attributes"]["gen_ai.usage.output_tokens"] == 10 - assert span["attributes"]["gen_ai.usage.input_tokens"] == 20 - assert span["attributes"]["gen_ai.usage.total_tokens"] == 30 - else: - events = capture_events() - - with start_transaction(name="openai tx"): - response = ( - client.chat.completions.create( - model="some-model", - messages=get_messages(), - max_tokens=100, - presence_penalty=0.1, - frequency_penalty=0.2, - temperature=0.7, - top_p=0.9, - ) - .choices[0] - .message.content - ) - - assert response == "the model response" - tx = events[0] - assert tx["type"] == "transaction" - span = tx["spans"][0] - assert span["op"] == "gen_ai.chat" - assert span["data"][SPANDATA.GEN_AI_SYSTEM] == "openai" - assert span["data"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is False - - assert span["data"][SPANDATA.GEN_AI_REQUEST_MODEL] == "some-model" - assert span["data"][SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 100 - assert span["data"][SPANDATA.GEN_AI_REQUEST_PRESENCE_PENALTY] == 0.1 - assert span["data"][SPANDATA.GEN_AI_REQUEST_FREQUENCY_PENALTY] == 0.2 - assert span["data"][SPANDATA.GEN_AI_REQUEST_TEMPERATURE] == 0.7 - assert span["data"][SPANDATA.GEN_AI_REQUEST_TOP_P] == 0.9 + .choices[0] + .message.content + ) - assert ( - json.loads(span["data"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS]) - == expected_system_instructions - ) + assert response == "the model response" + sentry_sdk.flush() + span = next(item.payload for item in items) + assert span["attributes"]["sentry.op"] == "gen_ai.chat" + assert span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "openai" + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is False + + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "some-model" + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 100 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_PRESENCE_PENALTY] == 0.1 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_FREQUENCY_PENALTY] == 0.2 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TEMPERATURE] == 0.7 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TOP_P] == 0.9 + + assert ( + json.loads(span["attributes"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS]) + == expected_system_instructions + ) - assert "hello" in span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - assert "the model response" in span["data"][SPANDATA.GEN_AI_RESPONSE_TEXT] + assert "hello" in span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] + assert ( + "Message demonstrating the absence of truncation." + in span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] + ) + assert "the model response" in span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] - assert span["data"]["gen_ai.usage.output_tokens"] == 10 - assert span["data"]["gen_ai.usage.input_tokens"] == 20 - assert span["data"]["gen_ai.usage.total_tokens"] == 30 + assert span["attributes"]["gen_ai.usage.output_tokens"] == 10 + assert span["attributes"]["gen_ai.usage.input_tokens"] == 20 + assert span["attributes"]["gen_ai.usage.total_tokens"] == 30 @pytest.mark.skipif( OPENAI_VERSION <= (1, 1, 0), reason="OpenAI versions <=1.1.0 do not support the tools parameter.", ) -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize( "data_collection,expected_present,expected_absent", [ @@ -716,22 +524,17 @@ def test_nonstreaming_chat_completion( ) def test_completions_api_data_collection( sentry_init, - capture_events, capture_items, data_collection, expected_present, expected_absent, nonstreaming_chat_completions_model_response, - stream_gen_ai_spans, - span_streaming, ): sentry_init( integrations=[OpenAIIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, data_collection=data_collection, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = OpenAI(api_key="z") @@ -762,25 +565,13 @@ def test_completions_api_data_collection( "top_p": 0.9, "tools": EXAMPLE_COMPLETIONS_TOOLS, } + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with start_transaction(name="openai tx"): - client.chat.completions.create(**create_kwargs) - - sentry_sdk.flush() - (span,) = (item.payload for item in items) - span_data = span["attributes"] - else: - events = capture_events() - - with start_transaction(name="openai tx"): - client.chat.completions.create(**create_kwargs) + client.chat.completions.create(**create_kwargs) - (transaction,) = events - (span,) = transaction["spans"] - span_data = span["data"] + sentry_sdk.flush() + (span,) = (item.payload for item in items) + span_data = span["attributes"] assert span_data[SPANDATA.GEN_AI_OPERATION_NAME] == "chat" assert span_data[SPANDATA.GEN_AI_REQUEST_MODEL] == "some-model" @@ -789,7 +580,7 @@ def test_completions_api_data_collection( assert span_data[SPANDATA.GEN_AI_REQUEST_FREQUENCY_PENALTY] == 0.2 assert span_data[SPANDATA.GEN_AI_REQUEST_TEMPERATURE] == 0.7 assert span_data[SPANDATA.GEN_AI_REQUEST_TOP_P] == 0.9 - assert span_data[SPANDATA.GEN_AI_SYSTEM] == "openai" + assert span_data[SPANDATA.GEN_AI_PROVIDER_NAME] == "openai" for key, value in expected_present.items(): assert span_data[key] == value @@ -798,8 +589,6 @@ def test_completions_api_data_collection( assert key not in span_data -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize( "data_collection,send_default_pii,expect_output", [ @@ -843,22 +632,17 @@ def test_completions_api_data_collection( ) def test_completions_api_data_collection_outputs( sentry_init, - capture_events, capture_items, data_collection, send_default_pii, expect_output, nonstreaming_chat_completions_model_response, - stream_gen_ai_spans, - span_streaming, ): init_kwargs = { "integrations": [OpenAIIntegration()], "disabled_integrations": [StdlibIntegration], "traces_sample_rate": 1.0, "send_default_pii": send_default_pii, - "stream_gen_ai_spans": stream_gen_ai_spans, - "trace_lifecycle": "stream" if span_streaming else "static", } if data_collection is not None: init_kwargs["data_collection"] = data_collection @@ -879,31 +663,16 @@ def test_completions_api_data_collection_outputs( ), ) ) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with start_transaction(name="openai tx"): - client.chat.completions.create( - model="some-model", - messages=[{"role": "user", "content": "hello"}], - ) - - sentry_sdk.flush() - (span,) = (item.payload for item in items) - span_data = span["attributes"] - else: - events = capture_events() - - with start_transaction(name="openai tx"): - client.chat.completions.create( - model="some-model", - messages=[{"role": "user", "content": "hello"}], - ) + client.chat.completions.create( + model="some-model", + messages=[{"role": "user", "content": "hello"}], + ) - (transaction,) = events - (span,) = transaction["spans"] - span_data = span["data"] + sentry_sdk.flush() + (span,) = (item.payload for item in items) + span_data = span["attributes"] assert span_data[SPANDATA.GEN_AI_RESPONSE_MODEL] == "gpt-3.5-turbo" @@ -913,8 +682,6 @@ def test_completions_api_data_collection_outputs( assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span_data -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio @pytest.mark.parametrize( "data_collection,send_default_pii,expect_output", @@ -959,22 +726,17 @@ def test_completions_api_data_collection_outputs( ) async def test_completions_api_data_collection_outputs_async( sentry_init, - capture_events, capture_items, data_collection, send_default_pii, expect_output, nonstreaming_chat_completions_model_response, - stream_gen_ai_spans, - span_streaming, ): init_kwargs = { "integrations": [OpenAIIntegration()], "disabled_integrations": [StdlibIntegration], "traces_sample_rate": 1.0, "send_default_pii": send_default_pii, - "stream_gen_ai_spans": stream_gen_ai_spans, - "trace_lifecycle": "stream" if span_streaming else "static", } if data_collection is not None: init_kwargs["data_collection"] = data_collection @@ -995,31 +757,16 @@ async def test_completions_api_data_collection_outputs_async( ), ) ) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with start_transaction(name="openai tx"): - await client.chat.completions.create( - model="some-model", - messages=[{"role": "user", "content": "hello"}], - ) - - sentry_sdk.flush() - (span,) = (item.payload for item in items) - span_data = span["attributes"] - else: - events = capture_events() - - with start_transaction(name="openai tx"): - await client.chat.completions.create( - model="some-model", - messages=[{"role": "user", "content": "hello"}], - ) + await client.chat.completions.create( + model="some-model", + messages=[{"role": "user", "content": "hello"}], + ) - (transaction,) = events - (span,) = transaction["spans"] - span_data = span["data"] + sentry_sdk.flush() + (span,) = (item.payload for item in items) + span_data = span["attributes"] assert span_data[SPANDATA.GEN_AI_RESPONSE_MODEL] == "gpt-3.5-turbo" @@ -1029,22 +776,15 @@ async def test_completions_api_data_collection_outputs_async( assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span_data -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_completions_api_data_collection_outputs_empty_choices( sentry_init, - capture_events, capture_items, - stream_gen_ai_spans, - span_streaming, ): sentry_init( integrations=[OpenAIIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, data_collection={"gen_ai": {"outputs": True}}, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = OpenAI(api_key="z") @@ -1062,38 +802,21 @@ def test_completions_api_data_collection_outputs_empty_choices( ), ) ) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with start_transaction(name="openai tx"): - client.chat.completions.create( - model="some-model", - messages=[{"role": "user", "content": "hello"}], - ) - - sentry_sdk.flush() - (span,) = (item.payload for item in items) - span_data = span["attributes"] - else: - events = capture_events() - - with start_transaction(name="openai tx"): - client.chat.completions.create( - model="some-model", - messages=[{"role": "user", "content": "hello"}], - ) + client.chat.completions.create( + model="some-model", + messages=[{"role": "user", "content": "hello"}], + ) - (transaction,) = events - (span,) = transaction["spans"] - span_data = span["data"] + sentry_sdk.flush() + (span,) = (item.payload for item in items) + span_data = span["attributes"] # No choices means no output data, even with outputs collection enabled assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span_data -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize( "data_collection,expect_output", [ @@ -1116,14 +839,11 @@ def test_completions_api_data_collection_outputs_empty_choices( ) def test_streaming_chat_completion_data_collection_outputs( sentry_init, - capture_events, capture_items, data_collection, expect_output, get_model_response, server_side_event_chunks, - stream_gen_ai_spans, - span_streaming, ): sentry_init( integrations=[OpenAIIntegration()], @@ -1131,8 +851,6 @@ def test_streaming_chat_completion_data_collection_outputs( traces_sample_rate=1.0, send_default_pii=False, data_collection=data_collection, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = OpenAI(api_key="z") @@ -1156,49 +874,24 @@ def test_streaming_chat_completion_data_collection_outputs( include_event_type=False, ) ) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with mock.patch.object( - client.chat._client._client, - "send", - return_value=returned_stream, - ), start_transaction(name="openai tx"): - response_stream = client.chat.completions.create( - model="some-model", - messages=[{"role": "user", "content": "hello"}], - stream=True, - ) - response_string = "".join( - map(lambda x: x.choices[0].delta.content, response_stream) - ) - - assert response_string == "hello" - sentry_sdk.flush() - (span,) = (item.payload for item in items) - span_data = span["attributes"] - else: - events = capture_events() - - with mock.patch.object( - client.chat._client._client, - "send", - return_value=returned_stream, - ), start_transaction(name="openai tx"): - response_stream = client.chat.completions.create( - model="some-model", - messages=[{"role": "user", "content": "hello"}], - stream=True, - ) - response_string = "".join( - map(lambda x: x.choices[0].delta.content, response_stream) - ) + with mock.patch.object( + client.chat._client._client, "send", return_value=returned_stream + ): + response_stream = client.chat.completions.create( + model="some-model", + messages=[{"role": "user", "content": "hello"}], + stream=True, + ) + response_string = "".join( + map(lambda x: x.choices[0].delta.content, response_stream) + ) - assert response_string == "hello" - (transaction,) = events - (span,) = transaction["spans"] - span_data = span["data"] + assert response_string == "hello" + sentry_sdk.flush() + (span,) = (item.payload for item in items) + span_data = span["attributes"] if expect_output: assert "hello" in span_data[SPANDATA.GEN_AI_RESPONSE_TEXT] @@ -1206,8 +899,6 @@ def test_streaming_chat_completion_data_collection_outputs( assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span_data -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio @pytest.mark.parametrize( "data_collection,expect_output", @@ -1231,15 +922,12 @@ def test_streaming_chat_completion_data_collection_outputs( ) async def test_streaming_chat_completion_data_collection_outputs_async( sentry_init, - capture_events, capture_items, data_collection, expect_output, get_model_response, async_iterator, server_side_event_chunks, - stream_gen_ai_spans, - span_streaming, ): sentry_init( integrations=[OpenAIIntegration()], @@ -1247,8 +935,6 @@ async def test_streaming_chat_completion_data_collection_outputs_async( traces_sample_rate=1.0, send_default_pii=False, data_collection=data_collection, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = AsyncOpenAI(api_key="z") @@ -1274,49 +960,26 @@ async def test_streaming_chat_completion_data_collection_outputs_async( ) ) ) + items = capture_items("span") + + with mock.patch.object( + client.chat._client._client, + "send", + return_value=returned_stream, + ): + response_stream = await client.chat.completions.create( + model="some-model", + messages=[{"role": "user", "content": "hello"}], + stream=True, + ) + response_string = "" + async for x in response_stream: + response_string += x.choices[0].delta.content - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with mock.patch.object( - client.chat._client._client, - "send", - return_value=returned_stream, - ), start_transaction(name="openai tx"): - response_stream = await client.chat.completions.create( - model="some-model", - messages=[{"role": "user", "content": "hello"}], - stream=True, - ) - response_string = "" - async for x in response_stream: - response_string += x.choices[0].delta.content - - assert response_string == "hello" - sentry_sdk.flush() - (span,) = (item.payload for item in items) - span_data = span["attributes"] - else: - events = capture_events() - - with mock.patch.object( - client.chat._client._client, - "send", - return_value=returned_stream, - ), start_transaction(name="openai tx"): - response_stream = await client.chat.completions.create( - model="some-model", - messages=[{"role": "user", "content": "hello"}], - stream=True, - ) - response_string = "" - async for x in response_stream: - response_string += x.choices[0].delta.content - - assert response_string == "hello" - (transaction,) = events - (span,) = transaction["spans"] - span_data = span["data"] + assert response_string == "hello" + sentry_sdk.flush() + (span,) = (item.payload for item in items) + span_data = span["attributes"] if expect_output: assert "hello" in span_data[SPANDATA.GEN_AI_RESPONSE_TEXT] @@ -1324,34 +987,17 @@ async def test_streaming_chat_completion_data_collection_outputs_async( assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span_data -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio -@pytest.mark.parametrize( - "send_default_pii, include_prompts", - [ - (True, False), - (False, True), - (False, False), - ], -) -async def test_nonstreaming_chat_completion_async_no_prompts( +async def test_nonstreaming_chat_completion_async_no_sensitive_data( sentry_init, - capture_events, capture_items, - send_default_pii, - include_prompts, nonstreaming_chat_completions_model_response, - stream_gen_ai_spans, - span_streaming, ): sentry_init( - integrations=[OpenAIIntegration(include_prompts=include_prompts)], + integrations=[OpenAIIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, - send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", + send_default_pii=False, ) client = AsyncOpenAI(api_key="z") @@ -1368,90 +1014,45 @@ async def test_nonstreaming_chat_completion_async_no_prompts( ), ) ) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") + response = await client.chat.completions.create( + model="some-model", + messages=[ + {"role": "system", "content": "You are a helpful assistant."}, + {"role": "user", "content": "hello"}, + ], + max_tokens=100, + presence_penalty=0.1, + frequency_penalty=0.2, + temperature=0.7, + top_p=0.9, + ) + response = response.choices[0].message.content - with start_transaction(name="openai tx"): - response = await client.chat.completions.create( - model="some-model", - messages=[ - {"role": "system", "content": "You are a helpful assistant."}, - {"role": "user", "content": "hello"}, - ], - max_tokens=100, - presence_penalty=0.1, - frequency_penalty=0.2, - temperature=0.7, - top_p=0.9, - ) - response = response.choices[0].message.content - - assert response == "the model response" - sentry_sdk.flush() - span = next(item.payload for item in items) - assert span["attributes"]["sentry.op"] == "gen_ai.chat" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "openai" - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is False - - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "some-model" - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 100 - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_PRESENCE_PENALTY] == 0.1 - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_FREQUENCY_PENALTY] == 0.2 - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TEMPERATURE] == 0.7 - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TOP_P] == 0.9 - - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in span["attributes"] - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] + assert response == "the model response" + sentry_sdk.flush() + span = next(item.payload for item in items) + assert span["attributes"]["sentry.op"] == "gen_ai.chat" + assert span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "openai" + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is False + + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "some-model" + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 100 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_PRESENCE_PENALTY] == 0.1 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_FREQUENCY_PENALTY] == 0.2 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TEMPERATURE] == 0.7 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TOP_P] == 0.9 + + assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in span["attributes"] + assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] + assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] + + assert span["attributes"]["gen_ai.usage.output_tokens"] == 10 + assert span["attributes"]["gen_ai.usage.input_tokens"] == 20 + assert span["attributes"]["gen_ai.usage.total_tokens"] == 30 - assert span["attributes"]["gen_ai.usage.output_tokens"] == 10 - assert span["attributes"]["gen_ai.usage.input_tokens"] == 20 - assert span["attributes"]["gen_ai.usage.total_tokens"] == 30 - else: - events = capture_events() - with start_transaction(name="openai tx"): - response = await client.chat.completions.create( - model="some-model", - messages=[ - {"role": "system", "content": "You are a helpful assistant."}, - {"role": "user", "content": "hello"}, - ], - max_tokens=100, - presence_penalty=0.1, - frequency_penalty=0.2, - temperature=0.7, - top_p=0.9, - ) - response = response.choices[0].message.content - - assert response == "the model response" - tx = events[0] - assert tx["type"] == "transaction" - span = tx["spans"][0] - assert span["op"] == "gen_ai.chat" - assert span["data"][SPANDATA.GEN_AI_SYSTEM] == "openai" - assert span["data"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is False - - assert span["data"][SPANDATA.GEN_AI_REQUEST_MODEL] == "some-model" - assert span["data"][SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 100 - assert span["data"][SPANDATA.GEN_AI_REQUEST_PRESENCE_PENALTY] == 0.1 - assert span["data"][SPANDATA.GEN_AI_REQUEST_FREQUENCY_PENALTY] == 0.2 - assert span["data"][SPANDATA.GEN_AI_REQUEST_TEMPERATURE] == 0.7 - assert span["data"][SPANDATA.GEN_AI_REQUEST_TOP_P] == 0.9 - - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in span["data"] - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["data"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["data"] - - assert span["data"]["gen_ai.usage.output_tokens"] == 10 - assert span["data"]["gen_ai.usage.input_tokens"] == 20 - assert span["data"]["gen_ai.usage.total_tokens"] == 30 - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio @pytest.mark.parametrize( "get_messages,expected_system_instructions", @@ -1533,21 +1134,16 @@ async def test_nonstreaming_chat_completion_async_no_prompts( ) async def test_nonstreaming_chat_completion_async( sentry_init, - capture_events, capture_items, get_messages, expected_system_instructions, nonstreaming_chat_completions_model_response, - stream_gen_ai_spans, - span_streaming, ): sentry_init( - integrations=[OpenAIIntegration(include_prompts=True)], + integrations=[OpenAIIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = AsyncOpenAI(api_key="z") @@ -1564,92 +1160,48 @@ async def test_nonstreaming_chat_completion_async( ), ) ) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with start_transaction(name="openai tx"): - response = await client.chat.completions.create( - model="some-model", - messages=get_messages(), - max_tokens=100, - presence_penalty=0.1, - frequency_penalty=0.2, - temperature=0.7, - top_p=0.9, - ) - response = response.choices[0].message.content - - assert response == "the model response" - sentry_sdk.flush() - span = next(item.payload for item in items) - assert span["attributes"]["sentry.op"] == "gen_ai.chat" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "openai" - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is False - - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "some-model" - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 100 - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_PRESENCE_PENALTY] == 0.1 - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_FREQUENCY_PENALTY] == 0.2 - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TEMPERATURE] == 0.7 - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TOP_P] == 0.9 - - assert ( - json.loads(span["attributes"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS]) - == expected_system_instructions - ) - - assert "hello" in span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - assert ( - "Message demonstrating the absence of truncation." - in span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - ) - assert "the model response" in span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] - - assert span["attributes"]["gen_ai.usage.output_tokens"] == 10 - assert span["attributes"]["gen_ai.usage.input_tokens"] == 20 - assert span["attributes"]["gen_ai.usage.total_tokens"] == 30 - else: - events = capture_events() - - with start_transaction(name="openai tx"): - response = await client.chat.completions.create( - model="some-model", - messages=get_messages(), - max_tokens=100, - presence_penalty=0.1, - frequency_penalty=0.2, - temperature=0.7, - top_p=0.9, - ) - response = response.choices[0].message.content - - assert response == "the model response" - tx = events[0] - assert tx["type"] == "transaction" - span = tx["spans"][0] - assert span["op"] == "gen_ai.chat" - assert span["data"][SPANDATA.GEN_AI_SYSTEM] == "openai" - assert span["data"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is False - - assert span["data"][SPANDATA.GEN_AI_REQUEST_MODEL] == "some-model" - assert span["data"][SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 100 - assert span["data"][SPANDATA.GEN_AI_REQUEST_PRESENCE_PENALTY] == 0.1 - assert span["data"][SPANDATA.GEN_AI_REQUEST_FREQUENCY_PENALTY] == 0.2 - assert span["data"][SPANDATA.GEN_AI_REQUEST_TEMPERATURE] == 0.7 - assert span["data"][SPANDATA.GEN_AI_REQUEST_TOP_P] == 0.9 - - assert ( - json.loads(span["data"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS]) - == expected_system_instructions - ) + response = await client.chat.completions.create( + model="some-model", + messages=get_messages(), + max_tokens=100, + presence_penalty=0.1, + frequency_penalty=0.2, + temperature=0.7, + top_p=0.9, + ) + response = response.choices[0].message.content + + assert response == "the model response" + sentry_sdk.flush() + span = next(item.payload for item in items) + assert span["attributes"]["sentry.op"] == "gen_ai.chat" + assert span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "openai" + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is False + + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "some-model" + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 100 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_PRESENCE_PENALTY] == 0.1 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_FREQUENCY_PENALTY] == 0.2 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TEMPERATURE] == 0.7 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TOP_P] == 0.9 + + assert ( + json.loads(span["attributes"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS]) + == expected_system_instructions + ) - assert "hello" in span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - assert "the model response" in span["data"][SPANDATA.GEN_AI_RESPONSE_TEXT] + assert "hello" in span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] + assert ( + "Message demonstrating the absence of truncation." + in span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] + ) + assert "the model response" in span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] - assert span["data"]["gen_ai.usage.output_tokens"] == 10 - assert span["data"]["gen_ai.usage.input_tokens"] == 20 - assert span["data"]["gen_ai.usage.total_tokens"] == 30 + assert span["attributes"]["gen_ai.usage.output_tokens"] == 10 + assert span["attributes"]["gen_ai.usage.input_tokens"] == 20 + assert span["attributes"]["gen_ai.usage.total_tokens"] == 30 def tiktoken_encoding_if_installed(): @@ -1662,39 +1214,21 @@ def tiktoken_encoding_if_installed(): # noinspection PyTypeChecker -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) -@pytest.mark.parametrize( - "send_default_pii, include_prompts", - [ - (True, False), - (False, True), - (False, False), - ], -) -def test_streaming_chat_completion_no_prompts( +def test_streaming_chat_completion_no_sensitive_data( sentry_init, - capture_events, capture_items, - send_default_pii, - include_prompts, get_model_response, server_side_event_chunks, - stream_gen_ai_spans, - span_streaming, ): sentry_init( integrations=[ OpenAIIntegration( - include_prompts=include_prompts, tiktoken_encoding_name=tiktoken_encoding_if_installed(), ) ], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, - send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", + send_default_pii=False, ) client = OpenAI(api_key="z") @@ -1744,139 +1278,76 @@ def test_streaming_chat_completion_no_prompts( include_event_type=False, ) ) + items = capture_items("span") + + with mock.patch.object( + client.chat._client._client, + "send", + return_value=returned_stream, + ): + response_stream = client.chat.completions.create( + model="some-model", + messages=[ + {"role": "system", "content": "You are a helpful assistant."}, + {"role": "user", "content": "hello"}, + ], + stream=True, + max_tokens=100, + presence_penalty=0.1, + frequency_penalty=0.2, + temperature=0.7, + top_p=0.9, + ) + response_string = "".join( + map(lambda x: x.choices[0].delta.content, response_stream) + ) - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with mock.patch.object( - client.chat._client._client, - "send", - return_value=returned_stream, - ), start_transaction(name="openai tx"): - response_stream = client.chat.completions.create( - model="some-model", - messages=[ - {"role": "system", "content": "You are a helpful assistant."}, - {"role": "user", "content": "hello"}, - ], - stream=True, - max_tokens=100, - presence_penalty=0.1, - frequency_penalty=0.2, - temperature=0.7, - top_p=0.9, - ) - response_string = "".join( - map(lambda x: x.choices[0].delta.content, response_stream) - ) - - assert response_string == "hello world" - sentry_sdk.flush() - span = next(item.payload for item in items) - assert span["attributes"]["sentry.op"] == "gen_ai.chat" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "openai" - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True - - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "some-model" - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 100 - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_PRESENCE_PENALTY] == 0.1 - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_FREQUENCY_PENALTY] == 0.2 - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TEMPERATURE] == 0.7 - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TOP_P] == 0.9 - - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_MODEL] == "model-id" - - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in span["attributes"] - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] - - try: - import tiktoken # type: ignore # noqa # pylint: disable=unused-import - - assert span["attributes"]["gen_ai.usage.output_tokens"] == 2 - assert span["attributes"]["gen_ai.usage.input_tokens"] == 7 - assert span["attributes"]["gen_ai.usage.total_tokens"] == 9 - except ImportError: - pass # if tiktoken is not installed, we can't guarantee token usage will be calculated properly - else: - events = capture_events() - - with mock.patch.object( - client.chat._client._client, - "send", - return_value=returned_stream, - ), start_transaction(name="openai tx"): - response_stream = client.chat.completions.create( - model="some-model", - messages=[ - {"role": "system", "content": "You are a helpful assistant."}, - {"role": "user", "content": "hello"}, - ], - stream=True, - max_tokens=100, - presence_penalty=0.1, - frequency_penalty=0.2, - temperature=0.7, - top_p=0.9, - ) - response_string = "".join( - map(lambda x: x.choices[0].delta.content, response_stream) - ) - - assert response_string == "hello world" - tx = events[0] - assert tx["type"] == "transaction" - span = tx["spans"][0] - assert span["op"] == "gen_ai.chat" - assert span["data"][SPANDATA.GEN_AI_SYSTEM] == "openai" - assert span["data"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True + assert response_string == "hello world" + sentry_sdk.flush() + span = next(item.payload for item in items) + assert span["attributes"]["sentry.op"] == "gen_ai.chat" + assert span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "openai" + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True - assert span["data"][SPANDATA.GEN_AI_REQUEST_MODEL] == "some-model" - assert span["data"][SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 100 - assert span["data"][SPANDATA.GEN_AI_REQUEST_PRESENCE_PENALTY] == 0.1 - assert span["data"][SPANDATA.GEN_AI_REQUEST_FREQUENCY_PENALTY] == 0.2 - assert span["data"][SPANDATA.GEN_AI_REQUEST_TEMPERATURE] == 0.7 - assert span["data"][SPANDATA.GEN_AI_REQUEST_TOP_P] == 0.9 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "some-model" + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 100 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_PRESENCE_PENALTY] == 0.1 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_FREQUENCY_PENALTY] == 0.2 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TEMPERATURE] == 0.7 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TOP_P] == 0.9 - assert span["data"][SPANDATA.GEN_AI_RESPONSE_MODEL] == "model-id" + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_MODEL] == "model-id" - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in span["data"] - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["data"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["data"] + assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in span["attributes"] + assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] + assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] - try: - import tiktoken # type: ignore # noqa # pylint: disable=unused-import + try: + import tiktoken # type: ignore # noqa # pylint: disable=unused-import - assert span["data"]["gen_ai.usage.output_tokens"] == 2 - assert span["data"]["gen_ai.usage.input_tokens"] == 7 - assert span["data"]["gen_ai.usage.total_tokens"] == 9 - except ImportError: - pass # if tiktoken is not installed, we can't guarantee token usage will be calculated properly + assert span["attributes"]["gen_ai.usage.output_tokens"] == 2 + assert span["attributes"]["gen_ai.usage.input_tokens"] == 7 + assert span["attributes"]["gen_ai.usage.total_tokens"] == 9 + except ImportError: + pass # if tiktoken is not installed, we can't guarantee token usage will be calculated properly -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.skipif( OPENAI_VERSION <= (1, 1, 0), reason="OpenAI versions <=1.1.0 do not support the stream_options parameter.", ) def test_streaming_chat_completion_with_usage_in_stream( sentry_init, - capture_events, capture_items, get_model_response, server_side_event_chunks, - stream_gen_ai_spans, - span_streaming, ): """When stream_options=include_usage is set, token usage comes from the final chunk's usage field.""" sentry_init( - integrations=[OpenAIIntegration(include_prompts=False)], + integrations=[OpenAIIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=False, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = OpenAI(api_key="z") @@ -1918,79 +1389,46 @@ def test_streaming_chat_completion_with_usage_in_stream( include_event_type=False, ) ) + items = capture_items("span") + + with mock.patch.object( + client.chat._client._client, + "send", + return_value=returned_stream, + ): + response_stream = client.chat.completions.create( + model="some-model", + messages=[{"role": "user", "content": "hello"}], + stream=True, + stream_options={"include_usage": True}, + ) + for _ in response_stream: + pass - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with mock.patch.object( - client.chat._client._client, - "send", - return_value=returned_stream, - ), start_transaction(name="openai tx"): - response_stream = client.chat.completions.create( - model="some-model", - messages=[{"role": "user", "content": "hello"}], - stream=True, - stream_options={"include_usage": True}, - ) - for _ in response_stream: - pass - - sentry_sdk.flush() - span = next(item.payload for item in items) - assert span["attributes"]["sentry.op"] == "gen_ai.chat" - assert span["attributes"]["gen_ai.usage.input_tokens"] == 20 - assert span["attributes"]["gen_ai.usage.output_tokens"] == 10 - assert span["attributes"]["gen_ai.usage.total_tokens"] == 30 - else: - events = capture_events() - - with mock.patch.object( - client.chat._client._client, - "send", - return_value=returned_stream, - ), start_transaction(name="openai tx"): - response_stream = client.chat.completions.create( - model="some-model", - messages=[{"role": "user", "content": "hello"}], - stream=True, - stream_options={"include_usage": True}, - ) - for _ in response_stream: - pass - - tx = events[0] - assert tx["type"] == "transaction" - span = tx["spans"][0] - assert span["op"] == "gen_ai.chat" - assert span["data"]["gen_ai.usage.input_tokens"] == 20 - assert span["data"]["gen_ai.usage.output_tokens"] == 10 - assert span["data"]["gen_ai.usage.total_tokens"] == 30 + sentry_sdk.flush() + span = next(item.payload for item in items) + assert span["attributes"]["sentry.op"] == "gen_ai.chat" + assert span["attributes"]["gen_ai.usage.input_tokens"] == 20 + assert span["attributes"]["gen_ai.usage.output_tokens"] == 10 + assert span["attributes"]["gen_ai.usage.total_tokens"] == 30 -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.skipif( OPENAI_VERSION <= (1, 1, 0), reason="OpenAI versions <=1.1.0 do not support the stream_options parameter.", ) def test_streaming_chat_completion_empty_content_preserves_token_usage( sentry_init, - capture_events, capture_items, get_model_response, server_side_event_chunks, - stream_gen_ai_spans, - span_streaming, ): """Token usage from the stream is recorded even when no content is produced (e.g. content filter).""" sentry_init( - integrations=[OpenAIIntegration(include_prompts=False)], + integrations=[OpenAIIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=False, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = OpenAI(api_key="z") @@ -2013,58 +1451,30 @@ def test_streaming_chat_completion_empty_content_preserves_token_usage( include_event_type=False, ) ) + items = capture_items("span") + + with mock.patch.object( + client.chat._client._client, + "send", + return_value=returned_stream, + ): + response_stream = client.chat.completions.create( + model="some-model", + messages=[{"role": "user", "content": "hello"}], + stream=True, + stream_options={"include_usage": True}, + ) + for _ in response_stream: + pass - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with mock.patch.object( - client.chat._client._client, - "send", - return_value=returned_stream, - ), start_transaction(name="openai tx"): - response_stream = client.chat.completions.create( - model="some-model", - messages=[{"role": "user", "content": "hello"}], - stream=True, - stream_options={"include_usage": True}, - ) - for _ in response_stream: - pass - - sentry_sdk.flush() - span = next(item.payload for item in items) - assert span["attributes"]["sentry.op"] == "gen_ai.chat" - assert span["attributes"]["gen_ai.usage.input_tokens"] == 20 - assert "gen_ai.usage.output_tokens" not in span["attributes"] - assert span["attributes"]["gen_ai.usage.total_tokens"] == 20 - else: - events = capture_events() - - with mock.patch.object( - client.chat._client._client, - "send", - return_value=returned_stream, - ), start_transaction(name="openai tx"): - response_stream = client.chat.completions.create( - model="some-model", - messages=[{"role": "user", "content": "hello"}], - stream=True, - stream_options={"include_usage": True}, - ) - for _ in response_stream: - pass - - tx = events[0] - assert tx["type"] == "transaction" - span = tx["spans"][0] - assert span["op"] == "gen_ai.chat" - assert span["data"]["gen_ai.usage.input_tokens"] == 20 - assert "gen_ai.usage.output_tokens" not in span["data"] - assert span["data"]["gen_ai.usage.total_tokens"] == 20 + sentry_sdk.flush() + span = next(item.payload for item in items) + assert span["attributes"]["sentry.op"] == "gen_ai.chat" + assert span["attributes"]["gen_ai.usage.input_tokens"] == 20 + assert "gen_ai.usage.output_tokens" not in span["attributes"] + assert span["attributes"]["gen_ai.usage.total_tokens"] == 20 -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.skipif( OPENAI_VERSION <= (1, 1, 0), reason="OpenAI versions <=1.1.0 do not support the stream_options parameter.", @@ -2072,22 +1482,17 @@ def test_streaming_chat_completion_empty_content_preserves_token_usage( @pytest.mark.asyncio async def test_streaming_chat_completion_empty_content_preserves_token_usage_async( sentry_init, - capture_events, capture_items, get_model_response, async_iterator, server_side_event_chunks, - stream_gen_ai_spans, - span_streaming, ): """Token usage from the stream is recorded even when no content is produced - async variant.""" sentry_init( - integrations=[OpenAIIntegration(include_prompts=False)], + integrations=[OpenAIIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=False, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = AsyncOpenAI(api_key="z") @@ -2112,58 +1517,30 @@ async def test_streaming_chat_completion_empty_content_preserves_token_usage_asy ) ) ) + items = capture_items("span") + + with mock.patch.object( + client.chat._client._client, + "send", + return_value=returned_stream, + ): + response_stream = await client.chat.completions.create( + model="some-model", + messages=[{"role": "user", "content": "hello"}], + stream=True, + stream_options={"include_usage": True}, + ) + async for _ in response_stream: + pass - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with mock.patch.object( - client.chat._client._client, - "send", - return_value=returned_stream, - ), start_transaction(name="openai tx"): - response_stream = await client.chat.completions.create( - model="some-model", - messages=[{"role": "user", "content": "hello"}], - stream=True, - stream_options={"include_usage": True}, - ) - async for _ in response_stream: - pass - - sentry_sdk.flush() - span = next(item.payload for item in items) - assert span["attributes"]["sentry.op"] == "gen_ai.chat" - assert span["attributes"]["gen_ai.usage.input_tokens"] == 20 - assert "gen_ai.usage.output_tokens" not in span["attributes"] - assert span["attributes"]["gen_ai.usage.total_tokens"] == 20 - else: - events = capture_events() - - with mock.patch.object( - client.chat._client._client, - "send", - return_value=returned_stream, - ), start_transaction(name="openai tx"): - response_stream = await client.chat.completions.create( - model="some-model", - messages=[{"role": "user", "content": "hello"}], - stream=True, - stream_options={"include_usage": True}, - ) - async for _ in response_stream: - pass - - tx = events[0] - assert tx["type"] == "transaction" - span = tx["spans"][0] - assert span["op"] == "gen_ai.chat" - assert span["data"]["gen_ai.usage.input_tokens"] == 20 - assert "gen_ai.usage.output_tokens" not in span["data"] - assert span["data"]["gen_ai.usage.total_tokens"] == 20 + sentry_sdk.flush() + span = next(item.payload for item in items) + assert span["attributes"]["sentry.op"] == "gen_ai.chat" + assert span["attributes"]["gen_ai.usage.input_tokens"] == 20 + assert "gen_ai.usage.output_tokens" not in span["attributes"] + assert span["attributes"]["gen_ai.usage.total_tokens"] == 20 -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.skipif( OPENAI_VERSION <= (1, 1, 0), reason="OpenAI versions <=1.1.0 do not support the stream_options parameter.", @@ -2171,22 +1548,17 @@ async def test_streaming_chat_completion_empty_content_preserves_token_usage_asy @pytest.mark.asyncio async def test_streaming_chat_completion_async_with_usage_in_stream( sentry_init, - capture_events, capture_items, get_model_response, async_iterator, server_side_event_chunks, - stream_gen_ai_spans, - span_streaming, ): """When stream_options=include_usage is set, token usage comes from the final chunk's usage field (async).""" sentry_init( - integrations=[OpenAIIntegration(include_prompts=False)], + integrations=[OpenAIIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=False, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = AsyncOpenAI(api_key="z") @@ -2230,59 +1602,31 @@ async def test_streaming_chat_completion_async_with_usage_in_stream( ) ) ) + items = capture_items("span") + + with mock.patch.object( + client.chat._client._client, + "send", + return_value=returned_stream, + ): + response_stream = await client.chat.completions.create( + model="some-model", + messages=[{"role": "user", "content": "hello"}], + stream=True, + stream_options={"include_usage": True}, + ) + async for _ in response_stream: + pass - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with mock.patch.object( - client.chat._client._client, - "send", - return_value=returned_stream, - ), start_transaction(name="openai tx"): - response_stream = await client.chat.completions.create( - model="some-model", - messages=[{"role": "user", "content": "hello"}], - stream=True, - stream_options={"include_usage": True}, - ) - async for _ in response_stream: - pass - - sentry_sdk.flush() - span = next(item.payload for item in items) - assert span["attributes"]["sentry.op"] == "gen_ai.chat" - assert span["attributes"]["gen_ai.usage.input_tokens"] == 20 - assert span["attributes"]["gen_ai.usage.output_tokens"] == 10 - assert span["attributes"]["gen_ai.usage.total_tokens"] == 30 - else: - events = capture_events() - - with mock.patch.object( - client.chat._client._client, - "send", - return_value=returned_stream, - ), start_transaction(name="openai tx"): - response_stream = await client.chat.completions.create( - model="some-model", - messages=[{"role": "user", "content": "hello"}], - stream=True, - stream_options={"include_usage": True}, - ) - async for _ in response_stream: - pass - - tx = events[0] - assert tx["type"] == "transaction" - span = tx["spans"][0] - assert span["op"] == "gen_ai.chat" - assert span["data"]["gen_ai.usage.input_tokens"] == 20 - assert span["data"]["gen_ai.usage.output_tokens"] == 10 - assert span["data"]["gen_ai.usage.total_tokens"] == 30 + sentry_sdk.flush() + span = next(item.payload for item in items) + assert span["attributes"]["sentry.op"] == "gen_ai.chat" + assert span["attributes"]["gen_ai.usage.input_tokens"] == 20 + assert span["attributes"]["gen_ai.usage.output_tokens"] == 10 + assert span["attributes"]["gen_ai.usage.total_tokens"] == 30 # noinspection PyTypeChecker -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize( "get_messages,expected_system_instructions,expected_output_tokens,expected_input_tokens", [ @@ -2369,7 +1713,6 @@ async def test_streaming_chat_completion_async_with_usage_in_stream( ) def test_streaming_chat_completion( sentry_init, - capture_events, capture_items, get_messages, expected_system_instructions, @@ -2377,21 +1720,16 @@ def test_streaming_chat_completion( expected_input_tokens, get_model_response, server_side_event_chunks, - stream_gen_ai_spans, - span_streaming, ): sentry_init( integrations=[ OpenAIIntegration( - include_prompts=True, tiktoken_encoding_name=tiktoken_encoding_if_installed(), ) ], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = OpenAI(api_key="z") @@ -2441,169 +1779,88 @@ def test_streaming_chat_completion( include_event_type=False, ) ) - - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with mock.patch.object( - client.chat._client._client, - "send", - return_value=returned_stream, - ), start_transaction(name="openai tx"): - response_stream = client.chat.completions.create( - model="some-model", - messages=get_messages(), - stream=True, - max_tokens=100, - presence_penalty=0.1, - frequency_penalty=0.2, - temperature=0.7, - top_p=0.9, - ) - response_string = "".join( - map(lambda x: x.choices[0].delta.content, response_stream) - ) - assert response_string == "hello world" - sentry_sdk.flush() - span = next(item.payload for item in items) - assert span["attributes"]["sentry.op"] == "gen_ai.chat" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "openai" - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True - - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "some-model" - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 100 - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_PRESENCE_PENALTY] == 0.1 - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_FREQUENCY_PENALTY] == 0.2 - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TEMPERATURE] == 0.7 - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TOP_P] == 0.9 - - assert ( - json.loads(span["attributes"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS]) - == expected_system_instructions + items = capture_items("span") + + with mock.patch.object( + client.chat._client._client, + "send", + return_value=returned_stream, + ): + response_stream = client.chat.completions.create( + model="some-model", + messages=get_messages(), + stream=True, + max_tokens=100, + presence_penalty=0.1, + frequency_penalty=0.2, + temperature=0.7, + top_p=0.9, ) - - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_MODEL] == "model-id" - - assert ( - "Message demonstrating the absence of truncation." - in span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] + response_string = "".join( + map(lambda x: x.choices[0].delta.content, response_stream) ) - assert "hello" in span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - assert "hello world" in span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] + assert response_string == "hello world" + sentry_sdk.flush() + span = next(item.payload for item in items) + assert span["attributes"]["sentry.op"] == "gen_ai.chat" + assert span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "openai" + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True + + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "some-model" + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 100 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_PRESENCE_PENALTY] == 0.1 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_FREQUENCY_PENALTY] == 0.2 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TEMPERATURE] == 0.7 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TOP_P] == 0.9 + + assert ( + json.loads(span["attributes"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS]) + == expected_system_instructions + ) - try: - import tiktoken # type: ignore # noqa # pylint: disable=unused-import + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_MODEL] == "model-id" - assert ( - span["attributes"]["gen_ai.usage.output_tokens"] - == expected_output_tokens - ) - assert ( - span["attributes"]["gen_ai.usage.input_tokens"] == expected_input_tokens - ) - assert ( - span["attributes"]["gen_ai.usage.total_tokens"] - == expected_output_tokens + expected_input_tokens - ) + assert ( + "Message demonstrating the absence of truncation." + in span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] + ) + assert "hello" in span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] + assert "hello world" in span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] - except ImportError: - pass # if tiktoken is not installed, we can't guarantee token usage will be calculated properly - else: - events = capture_events() - - with mock.patch.object( - client.chat._client._client, - "send", - return_value=returned_stream, - ), start_transaction(name="openai tx"): - response_stream = client.chat.completions.create( - model="some-model", - messages=get_messages(), - stream=True, - max_tokens=100, - presence_penalty=0.1, - frequency_penalty=0.2, - temperature=0.7, - top_p=0.9, - ) - response_string = "".join( - map(lambda x: x.choices[0].delta.content, response_stream) - ) - assert response_string == "hello world" - tx = events[0] - assert tx["type"] == "transaction" - span = tx["spans"][0] - assert span["op"] == "gen_ai.chat" - assert span["data"][SPANDATA.GEN_AI_SYSTEM] == "openai" - assert span["data"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True - - assert span["data"][SPANDATA.GEN_AI_REQUEST_MODEL] == "some-model" - assert span["data"][SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 100 - assert span["data"][SPANDATA.GEN_AI_REQUEST_PRESENCE_PENALTY] == 0.1 - assert span["data"][SPANDATA.GEN_AI_REQUEST_FREQUENCY_PENALTY] == 0.2 - assert span["data"][SPANDATA.GEN_AI_REQUEST_TEMPERATURE] == 0.7 - assert span["data"][SPANDATA.GEN_AI_REQUEST_TOP_P] == 0.9 + try: + import tiktoken # type: ignore # noqa # pylint: disable=unused-import assert ( - json.loads(span["data"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS]) - == expected_system_instructions + span["attributes"]["gen_ai.usage.output_tokens"] == expected_output_tokens + ) + assert span["attributes"]["gen_ai.usage.input_tokens"] == expected_input_tokens + assert ( + span["attributes"]["gen_ai.usage.total_tokens"] + == expected_output_tokens + expected_input_tokens ) - assert span["data"][SPANDATA.GEN_AI_RESPONSE_MODEL] == "model-id" - - assert "hello" in span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - assert "hello world" in span["data"][SPANDATA.GEN_AI_RESPONSE_TEXT] - - try: - import tiktoken # type: ignore # noqa # pylint: disable=unused-import - - assert span["data"]["gen_ai.usage.output_tokens"] == expected_output_tokens - assert span["data"]["gen_ai.usage.input_tokens"] == expected_input_tokens - assert ( - span["data"]["gen_ai.usage.total_tokens"] - == expected_output_tokens + expected_input_tokens - ) - - except ImportError: - pass # if tiktoken is not installed, we can't guarantee token usage will be calculated properly + except ImportError: + pass # if tiktoken is not installed, we can't guarantee token usage will be calculated properly # noinspection PyTypeChecker -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio -@pytest.mark.parametrize( - "send_default_pii, include_prompts", - [ - (True, False), - (False, True), - (False, False), - ], -) -async def test_streaming_chat_completion_async_no_prompts( +async def test_streaming_chat_completion_async_no_sensitive_data( sentry_init, - capture_events, capture_items, - send_default_pii, - include_prompts, get_model_response, async_iterator, server_side_event_chunks, - stream_gen_ai_spans, - span_streaming, ): sentry_init( integrations=[ OpenAIIntegration( - include_prompts=include_prompts, tiktoken_encoding_name=tiktoken_encoding_if_installed(), ) ], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, - send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", + send_default_pii=False, ) client = AsyncOpenAI(api_key="z") @@ -2655,123 +1912,63 @@ async def test_streaming_chat_completion_async_no_prompts( ) ) ) + items = capture_items("span") + + with mock.patch.object( + client.chat._client._client, + "send", + return_value=returned_stream, + ): + response_stream = await client.chat.completions.create( + model="some-model", + messages=[ + {"role": "system", "content": "You are a helpful assistant."}, + {"role": "user", "content": "hello"}, + ], + stream=True, + max_tokens=100, + presence_penalty=0.1, + frequency_penalty=0.2, + temperature=0.7, + top_p=0.9, + ) - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with mock.patch.object( - client.chat._client._client, - "send", - return_value=returned_stream, - ), start_transaction(name="openai tx"): - response_stream = await client.chat.completions.create( - model="some-model", - messages=[ - {"role": "system", "content": "You are a helpful assistant."}, - {"role": "user", "content": "hello"}, - ], - stream=True, - max_tokens=100, - presence_penalty=0.1, - frequency_penalty=0.2, - temperature=0.7, - top_p=0.9, - ) - - response_string = "" - async for x in response_stream: - response_string += x.choices[0].delta.content - - assert response_string == "hello world" - sentry_sdk.flush() - span = next(item.payload for item in items) - assert span["attributes"]["sentry.op"] == "gen_ai.chat" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "openai" - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True - - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "some-model" - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 100 - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_PRESENCE_PENALTY] == 0.1 - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_FREQUENCY_PENALTY] == 0.2 - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TEMPERATURE] == 0.7 - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TOP_P] == 0.9 - - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_MODEL] == "model-id" - - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in span["attributes"] - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] - - try: - import tiktoken # type: ignore # noqa # pylint: disable=unused-import - - assert span["attributes"]["gen_ai.usage.output_tokens"] == 2 - assert span["attributes"]["gen_ai.usage.input_tokens"] == 7 - assert span["attributes"]["gen_ai.usage.total_tokens"] == 9 - - except ImportError: - pass # if tiktoken is not installed, we can't guarantee token usage will be calculated properly - else: - events = capture_events() - - with mock.patch.object( - client.chat._client._client, - "send", - return_value=returned_stream, - ), start_transaction(name="openai tx"): - response_stream = await client.chat.completions.create( - model="some-model", - messages=[ - {"role": "system", "content": "You are a helpful assistant."}, - {"role": "user", "content": "hello"}, - ], - stream=True, - max_tokens=100, - presence_penalty=0.1, - frequency_penalty=0.2, - temperature=0.7, - top_p=0.9, - ) - - response_string = "" - async for x in response_stream: - response_string += x.choices[0].delta.content + response_string = "" + async for x in response_stream: + response_string += x.choices[0].delta.content - assert response_string == "hello world" - tx = events[0] - assert tx["type"] == "transaction" - span = tx["spans"][0] - assert span["op"] == "gen_ai.chat" - assert span["data"][SPANDATA.GEN_AI_SYSTEM] == "openai" - assert span["data"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True + assert response_string == "hello world" + sentry_sdk.flush() + span = next(item.payload for item in items) + assert span["attributes"]["sentry.op"] == "gen_ai.chat" + assert span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "openai" + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True - assert span["data"][SPANDATA.GEN_AI_REQUEST_MODEL] == "some-model" - assert span["data"][SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 100 - assert span["data"][SPANDATA.GEN_AI_REQUEST_PRESENCE_PENALTY] == 0.1 - assert span["data"][SPANDATA.GEN_AI_REQUEST_FREQUENCY_PENALTY] == 0.2 - assert span["data"][SPANDATA.GEN_AI_REQUEST_TEMPERATURE] == 0.7 - assert span["data"][SPANDATA.GEN_AI_REQUEST_TOP_P] == 0.9 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "some-model" + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 100 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_PRESENCE_PENALTY] == 0.1 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_FREQUENCY_PENALTY] == 0.2 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TEMPERATURE] == 0.7 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TOP_P] == 0.9 - assert span["data"][SPANDATA.GEN_AI_RESPONSE_MODEL] == "model-id" + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_MODEL] == "model-id" - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in span["data"] - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["data"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["data"] + assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in span["attributes"] + assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] + assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] - try: - import tiktoken # type: ignore # noqa # pylint: disable=unused-import + try: + import tiktoken # type: ignore # noqa # pylint: disable=unused-import - assert span["data"]["gen_ai.usage.output_tokens"] == 2 - assert span["data"]["gen_ai.usage.input_tokens"] == 7 - assert span["data"]["gen_ai.usage.total_tokens"] == 9 + assert span["attributes"]["gen_ai.usage.output_tokens"] == 2 + assert span["attributes"]["gen_ai.usage.input_tokens"] == 7 + assert span["attributes"]["gen_ai.usage.total_tokens"] == 9 - except ImportError: - pass # if tiktoken is not installed, we can't guarantee token usage will be calculated properly + except ImportError: + pass # if tiktoken is not installed, we can't guarantee token usage will be calculated properly # noinspection PyTypeChecker -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio @pytest.mark.parametrize( "get_messages,expected_system_instructions,expected_output_tokens,expected_input_tokens", @@ -2859,7 +2056,6 @@ async def test_streaming_chat_completion_async_no_prompts( ) async def test_streaming_chat_completion_async( sentry_init, - capture_events, capture_items, get_messages, expected_system_instructions, @@ -2868,21 +2064,16 @@ async def test_streaming_chat_completion_async( get_model_response, async_iterator, server_side_event_chunks, - stream_gen_ai_spans, - span_streaming, ): sentry_init( integrations=[ OpenAIIntegration( - include_prompts=True, tiktoken_encoding_name=tiktoken_encoding_if_installed(), ) ], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = AsyncOpenAI(api_key="z") @@ -2935,351 +2126,167 @@ async def test_streaming_chat_completion_async( ) ) ) + items = capture_items("span") + + with mock.patch.object( + client.chat._client._client, + "send", + return_value=returned_stream, + ): + response_stream = await client.chat.completions.create( + model="some-model", + messages=get_messages(), + stream=True, + max_tokens=100, + presence_penalty=0.1, + frequency_penalty=0.2, + temperature=0.7, + top_p=0.9, + ) - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with mock.patch.object( - client.chat._client._client, - "send", - return_value=returned_stream, - ), start_transaction(name="openai tx"): - response_stream = await client.chat.completions.create( - model="some-model", - messages=get_messages(), - stream=True, - max_tokens=100, - presence_penalty=0.1, - frequency_penalty=0.2, - temperature=0.7, - top_p=0.9, - ) - - response_string = "" - async for x in response_stream: - response_string += x.choices[0].delta.content - - assert response_string == "hello world" - sentry_sdk.flush() - span = next(item.payload for item in items) - assert span["attributes"]["sentry.op"] == "gen_ai.chat" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "openai" - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True + response_string = "" + async for x in response_stream: + response_string += x.choices[0].delta.content + + assert response_string == "hello world" + sentry_sdk.flush() + span = next(item.payload for item in items) + assert span["attributes"]["sentry.op"] == "gen_ai.chat" + assert span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "openai" + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True + + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "some-model" + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 100 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_PRESENCE_PENALTY] == 0.1 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_FREQUENCY_PENALTY] == 0.2 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TEMPERATURE] == 0.7 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TOP_P] == 0.9 + + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_MODEL] == "model-id" + + assert ( + json.loads(span["attributes"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS]) + == expected_system_instructions + ) - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "some-model" - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 100 - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_PRESENCE_PENALTY] == 0.1 - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_FREQUENCY_PENALTY] == 0.2 - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TEMPERATURE] == 0.7 - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TOP_P] == 0.9 + assert ( + "Message demonstrating the absence of truncation." + in span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] + ) + assert "hello" in span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] + assert "hello world" in span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_MODEL] == "model-id" + try: + import tiktoken # type: ignore # noqa # pylint: disable=unused-import assert ( - json.loads(span["attributes"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS]) - == expected_system_instructions + span["attributes"]["gen_ai.usage.output_tokens"] == expected_output_tokens ) - + assert span["attributes"]["gen_ai.usage.input_tokens"] == expected_input_tokens assert ( - "Message demonstrating the absence of truncation." - in span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] + span["attributes"]["gen_ai.usage.total_tokens"] + == expected_output_tokens + expected_input_tokens ) - assert "hello" in span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - assert "hello world" in span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] - - try: - import tiktoken # type: ignore # noqa # pylint: disable=unused-import - - assert ( - span["attributes"]["gen_ai.usage.output_tokens"] - == expected_output_tokens - ) - assert ( - span["attributes"]["gen_ai.usage.input_tokens"] == expected_input_tokens - ) - assert ( - span["attributes"]["gen_ai.usage.total_tokens"] - == expected_output_tokens + expected_input_tokens - ) - - except ImportError: - pass # if tiktoken is not installed, we can't guarantee token usage will be calculated properly - else: - events = capture_events() - - with mock.patch.object( - client.chat._client._client, - "send", - return_value=returned_stream, - ), start_transaction(name="openai tx"): - response_stream = await client.chat.completions.create( - model="some-model", - messages=get_messages(), - stream=True, - max_tokens=100, - presence_penalty=0.1, - frequency_penalty=0.2, - temperature=0.7, - top_p=0.9, - ) - - response_string = "" - async for x in response_stream: - response_string += x.choices[0].delta.content - - assert response_string == "hello world" - tx = events[0] - assert tx["type"] == "transaction" - span = tx["spans"][0] - assert span["op"] == "gen_ai.chat" - assert span["data"][SPANDATA.GEN_AI_SYSTEM] == "openai" - assert span["data"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True - - assert span["data"][SPANDATA.GEN_AI_REQUEST_MODEL] == "some-model" - assert span["data"][SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 100 - assert span["data"][SPANDATA.GEN_AI_REQUEST_PRESENCE_PENALTY] == 0.1 - assert span["data"][SPANDATA.GEN_AI_REQUEST_FREQUENCY_PENALTY] == 0.2 - assert span["data"][SPANDATA.GEN_AI_REQUEST_TEMPERATURE] == 0.7 - assert span["data"][SPANDATA.GEN_AI_REQUEST_TOP_P] == 0.9 - assert span["data"][SPANDATA.GEN_AI_RESPONSE_MODEL] == "model-id" - - assert ( - json.loads(span["data"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS]) - == expected_system_instructions - ) - - assert "hello" in span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - assert "hello world" in span["data"][SPANDATA.GEN_AI_RESPONSE_TEXT] - - try: - import tiktoken # type: ignore # noqa # pylint: disable=unused-import - - assert span["data"]["gen_ai.usage.output_tokens"] == expected_output_tokens - assert span["data"]["gen_ai.usage.input_tokens"] == expected_input_tokens - assert ( - span["data"]["gen_ai.usage.total_tokens"] - == expected_output_tokens + expected_input_tokens - ) - - except ImportError: - pass # if tiktoken is not installed, we can't guarantee token usage will be calculated properly + except ImportError: + pass # if tiktoken is not installed, we can't guarantee token usage will be calculated properly -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_bad_chat_completion( sentry_init, - capture_events, capture_items, - stream_gen_ai_spans, - span_streaming, ): sentry_init( integrations=[OpenAIIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) + items = capture_items("event", "span") - if span_streaming: - items = capture_items("event", "span") - - client = OpenAI(api_key="z") - client.chat.completions._post = mock.Mock( - side_effect=OpenAIError("API rate limit reached") - ) - with pytest.raises(OpenAIError): - client.chat.completions.create( - model="some-model", - messages=[{"role": "system", "content": "hello"}], - ) - - (event,) = (item.payload for item in items if item.type == "event") - sentry_sdk.flush() - (span,) = (item.payload for item in items if item.type == "span") - assert event["level"] == "error" - assert span["status"] == "error" - elif stream_gen_ai_spans: - items = capture_items("event", "transaction") - - client = OpenAI(api_key="z") - client.chat.completions._post = mock.Mock( - side_effect=OpenAIError("API rate limit reached") - ) - with pytest.raises(OpenAIError): - client.chat.completions.create( - model="some-model", - messages=[{"role": "system", "content": "hello"}], - ) - - (event,) = (item.payload for item in items if item.type == "event") - (transaction,) = (item.payload for item in items if item.type == "transaction") - assert event["level"] == "error" - assert transaction["contexts"]["trace"]["status"] == "internal_error" - else: - events = capture_events() - - client = OpenAI(api_key="z") - client.chat.completions._post = mock.Mock( - side_effect=OpenAIError("API rate limit reached") + client = OpenAI(api_key="z") + client.chat.completions._post = mock.Mock( + side_effect=OpenAIError("API rate limit reached") + ) + with pytest.raises(OpenAIError): + client.chat.completions.create( + model="some-model", + messages=[{"role": "system", "content": "hello"}], ) - with pytest.raises(OpenAIError): - client.chat.completions.create( - model="some-model", - messages=[{"role": "system", "content": "hello"}], - ) - (event, transaction) = events - assert event["level"] == "error" - assert transaction["contexts"]["trace"]["status"] == "internal_error" + (event,) = (item.payload for item in items if item.type == "event") + sentry_sdk.flush() + (span,) = (item.payload for item in items if item.type == "span") + assert event["level"] == "error" + assert span["status"] == "error" -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_span_status_error( sentry_init, - capture_events, capture_items, - stream_gen_ai_spans, - span_streaming, ): sentry_init( integrations=[OpenAIIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) + items = capture_items("event", "span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("event", "span") - - with start_transaction(name="test"): - client = OpenAI(api_key="z") - client.chat.completions._post = mock.Mock( - side_effect=OpenAIError("API rate limit reached") - ) - with pytest.raises(OpenAIError): - client.chat.completions.create( - model="some-model", - messages=[{"role": "system", "content": "hello"}], - ) + client = OpenAI(api_key="z") + client.chat.completions._post = mock.Mock( + side_effect=OpenAIError("API rate limit reached") + ) + with pytest.raises(OpenAIError): + client.chat.completions.create( + model="some-model", + messages=[{"role": "system", "content": "hello"}], + ) - (error,) = (item.payload for item in items if item.type == "event") - assert error["level"] == "error" + (error,) = (item.payload for item in items if item.type == "event") + assert error["level"] == "error" - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert spans[0]["status"] == "error" - else: - events = capture_events() + sentry_sdk.flush() + spans = [item.payload for item in items if item.type == "span"] + assert spans[0]["status"] == "error" - with start_transaction(name="test"): - client = OpenAI(api_key="z") - client.chat.completions._post = mock.Mock( - side_effect=OpenAIError("API rate limit reached") - ) - with pytest.raises(OpenAIError): - client.chat.completions.create( - model="some-model", - messages=[{"role": "system", "content": "hello"}], - ) - (error, transaction) = events - assert error["level"] == "error" - assert transaction["spans"][0]["status"] == "internal_error" - assert transaction["spans"][0]["tags"]["status"] == "internal_error" - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio async def test_bad_chat_completion_async( sentry_init, - capture_events, capture_items, - stream_gen_ai_spans, - span_streaming, ): sentry_init( integrations=[OpenAIIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", - ) - - client = AsyncOpenAI(api_key="z") - client.chat.completions._post = AsyncMock( - side_effect=OpenAIError("API rate limit reached") ) - if span_streaming: - items = capture_items("event", "span") - - with pytest.raises(OpenAIError): - await client.chat.completions.create( - model="some-model", messages=[{"role": "system", "content": "hello"}] - ) - - (event,) = (item.payload for item in items if item.type == "event") - sentry_sdk.flush() - (span,) = (item.payload for item in items if item.type == "span") - assert event["level"] == "error" - assert span["status"] == "error" - elif stream_gen_ai_spans: - items = capture_items("event", "transaction") - - with pytest.raises(OpenAIError): - await client.chat.completions.create( - model="some-model", messages=[{"role": "system", "content": "hello"}] - ) - - (event,) = (item.payload for item in items if item.type == "event") - (transaction,) = (item.payload for item in items if item.type == "transaction") - assert event["level"] == "error" - assert transaction["contexts"]["trace"]["status"] == "internal_error" - else: - events = capture_events() + client = AsyncOpenAI(api_key="z") + client.chat.completions._post = AsyncMock( + side_effect=OpenAIError("API rate limit reached") + ) + items = capture_items("event", "span") - with pytest.raises(OpenAIError): - await client.chat.completions.create( - model="some-model", messages=[{"role": "system", "content": "hello"}] - ) + with pytest.raises(OpenAIError): + await client.chat.completions.create( + model="some-model", messages=[{"role": "system", "content": "hello"}] + ) - (event, transaction) = events - assert event["level"] == "error" - assert transaction["contexts"]["trace"]["status"] == "internal_error" + (event,) = (item.payload for item in items if item.type == "event") + sentry_sdk.flush() + (span,) = (item.payload for item in items if item.type == "span") + assert event["level"] == "error" + assert span["status"] == "error" -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) -@pytest.mark.parametrize( - "send_default_pii, include_prompts", - [ - (True, False), - (False, True), - (False, False), - ], -) -def test_embeddings_create_no_pii( +def test_embeddings_create_no_sensitive_data( sentry_init, - capture_events, capture_items, - send_default_pii, - include_prompts, - stream_gen_ai_spans, - span_streaming, ): sentry_init( - integrations=[OpenAIIntegration(include_prompts=include_prompts)], + integrations=[OpenAIIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, - send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", + send_default_pii=False, ) client = OpenAI(api_key="z") @@ -3295,55 +2302,24 @@ def test_embeddings_create_no_pii( ) client.embeddings._post = mock.Mock(return_value=returned_embedding) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with start_transaction(name="openai tx"): - response = client.embeddings.create( - input="hello", model="text-embedding-3-large" - ) - - assert len(response.data[0].embedding) == 3 - - sentry_sdk.flush() - span = next(item.payload for item in items) - assert span["attributes"]["sentry.op"] == "gen_ai.embeddings" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "openai" - assert ( - span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] - == "text-embedding-3-large" - ) - - assert SPANDATA.GEN_AI_EMBEDDINGS_INPUT not in span["attributes"] - - assert span["attributes"]["gen_ai.usage.input_tokens"] == 20 - assert span["attributes"]["gen_ai.usage.total_tokens"] == 30 - else: - events = capture_events() + response = client.embeddings.create(input="hello", model="text-embedding-3-large") - with start_transaction(name="openai tx"): - response = client.embeddings.create( - input="hello", model="text-embedding-3-large" - ) - - assert len(response.data[0].embedding) == 3 + assert len(response.data[0].embedding) == 3 - tx = events[0] - assert tx["type"] == "transaction" - span = tx["spans"][0] - assert span["op"] == "gen_ai.embeddings" - assert span["data"][SPANDATA.GEN_AI_SYSTEM] == "openai" - assert span["data"][SPANDATA.GEN_AI_REQUEST_MODEL] == "text-embedding-3-large" + sentry_sdk.flush() + span = next(item.payload for item in items) + assert span["attributes"]["sentry.op"] == "gen_ai.embeddings" + assert span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "openai" + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "text-embedding-3-large" - assert SPANDATA.GEN_AI_EMBEDDINGS_INPUT not in span["data"] + assert SPANDATA.GEN_AI_EMBEDDINGS_INPUT not in span["attributes"] - assert span["data"]["gen_ai.usage.input_tokens"] == 20 - assert span["data"]["gen_ai.usage.total_tokens"] == 30 + assert span["attributes"]["gen_ai.usage.input_tokens"] == 20 + assert span["attributes"]["gen_ai.usage.total_tokens"] == 30 -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize( "get_input,expected_embeddings_input", [ @@ -3415,20 +2391,15 @@ def test_embeddings_create_no_pii( ) def test_embeddings_create( sentry_init, - capture_events, capture_items, get_input, expected_embeddings_input, - stream_gen_ai_spans, - span_streaming, ): sentry_init( - integrations=[OpenAIIntegration(include_prompts=True)], + integrations=[OpenAIIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = OpenAI(api_key="z") @@ -3444,91 +2415,42 @@ def test_embeddings_create( ) client.embeddings._post = mock.Mock(return_value=returned_embedding) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with start_transaction(name="openai tx"): - response = client.embeddings.create( - input=get_input(), model="text-embedding-3-large" - ) - - assert len(response.data[0].embedding) == 3 - - sentry_sdk.flush() - span = next(item.payload for item in items) - assert span["attributes"]["sentry.op"] == "gen_ai.embeddings" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "openai" - assert ( - span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] - == "text-embedding-3-large" - ) - - assert ( - json.loads(span["attributes"][SPANDATA.GEN_AI_EMBEDDINGS_INPUT]) - == expected_embeddings_input - ) - - assert span["attributes"]["gen_ai.usage.input_tokens"] == 20 - assert span["attributes"]["gen_ai.usage.total_tokens"] == 30 - else: - events = capture_events() - - with start_transaction(name="openai tx"): - response = client.embeddings.create( - input=get_input(), model="text-embedding-3-large" - ) - - assert len(response.data[0].embedding) == 3 - - tx = events[0] - assert tx["type"] == "transaction" - span = tx["spans"][0] - assert span["op"] == "gen_ai.embeddings" - assert span["data"][SPANDATA.GEN_AI_SYSTEM] == "openai" - assert span["data"][SPANDATA.GEN_AI_REQUEST_MODEL] == "text-embedding-3-large" - - assert ( - json.loads(span["data"][SPANDATA.GEN_AI_EMBEDDINGS_INPUT]) - == expected_embeddings_input - ) - - assert span["data"]["gen_ai.usage.input_tokens"] == 20 - assert span["data"]["gen_ai.usage.total_tokens"] == 30 + response = client.embeddings.create( + input=get_input(), model="text-embedding-3-large" + ) + assert len(response.data[0].embedding) == 3 -def _collect_embeddings_span_data( - capture_events, capture_items, span_streaming, stream_gen_ai_spans, create -): - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") + sentry_sdk.flush() + span = next(item.payload for item in items) + assert span["attributes"]["sentry.op"] == "gen_ai.embeddings" + assert span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "openai" + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "text-embedding-3-large" - with start_transaction(name="openai tx"): - response = create() + assert ( + json.loads(span["attributes"][SPANDATA.GEN_AI_EMBEDDINGS_INPUT]) + == expected_embeddings_input + ) - assert len(response.data[0].embedding) == 3 + assert span["attributes"]["gen_ai.usage.input_tokens"] == 20 + assert span["attributes"]["gen_ai.usage.total_tokens"] == 30 - sentry_sdk.flush() - span = next(item.payload for item in items) - assert span["attributes"]["sentry.op"] == "gen_ai.embeddings" - return span["attributes"] - events = capture_events() +def _collect_embeddings_span_data(capture_items, create): + items = capture_items("span") - with start_transaction(name="openai tx"): - response = create() + response = create() assert len(response.data[0].embedding) == 3 - tx = events[0] - assert tx["type"] == "transaction" - span = tx["spans"][0] - assert span["op"] == "gen_ai.embeddings" - return span["data"] + sentry_sdk.flush() + span = next(item.payload for item in items) + assert span["attributes"]["sentry.op"] == "gen_ai.embeddings" + return span["attributes"] -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize( "data_collection,send_default_pii,expect_input", [ @@ -3566,21 +2488,16 @@ def _collect_embeddings_span_data( ) def test_embeddings_create_data_collection( sentry_init, - capture_events, capture_items, data_collection, send_default_pii, expect_input, - stream_gen_ai_spans, - span_streaming, ): init_kwargs = { "integrations": [OpenAIIntegration()], "disabled_integrations": [StdlibIntegration], "traces_sample_rate": 1.0, "send_default_pii": send_default_pii, - "stream_gen_ai_spans": stream_gen_ai_spans, - "trace_lifecycle": "stream" if span_streaming else "static", } sentry_init_kwargs = dict(init_kwargs) @@ -3604,14 +2521,11 @@ def test_embeddings_create_data_collection( client.embeddings._post = mock.Mock(return_value=returned_embedding) span_data = _collect_embeddings_span_data( - capture_events, capture_items, - span_streaming, - stream_gen_ai_spans, lambda: client.embeddings.create(input="hello", model="text-embedding-3-large"), ) - assert span_data[SPANDATA.GEN_AI_SYSTEM] == "openai" + assert span_data[SPANDATA.GEN_AI_PROVIDER_NAME] == "openai" assert span_data[SPANDATA.GEN_AI_OPERATION_NAME] == "embeddings" assert span_data[SPANDATA.GEN_AI_REQUEST_MODEL] == "text-embedding-3-large" @@ -3624,8 +2538,6 @@ def test_embeddings_create_data_collection( assert span_data["gen_ai.usage.total_tokens"] == 30 -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize( "get_input", [ @@ -3639,19 +2551,14 @@ def test_embeddings_create_data_collection( ) def test_embeddings_create_data_collection_inputs_disabled_input_shapes( sentry_init, - capture_events, capture_items, get_input, - stream_gen_ai_spans, - span_streaming, ): sentry_init( - integrations=[OpenAIIntegration(include_prompts=True)], + integrations=[OpenAIIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", data_collection={"gen_ai": {"inputs": False}}, ) @@ -3670,10 +2577,7 @@ def test_embeddings_create_data_collection_inputs_disabled_input_shapes( client.embeddings._post = mock.Mock(return_value=returned_embedding) span_data = _collect_embeddings_span_data( - capture_events, capture_items, - span_streaming, - stream_gen_ai_spans, lambda: client.embeddings.create( input=get_input(), model="text-embedding-3-large" ), @@ -3684,33 +2588,16 @@ def test_embeddings_create_data_collection_inputs_disabled_input_shapes( assert SPANDATA.GEN_AI_EMBEDDINGS_INPUT not in span_data -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio -@pytest.mark.parametrize( - "send_default_pii, include_prompts", - [ - (True, False), - (False, True), - (False, False), - ], -) -async def test_embeddings_create_async_no_pii( +async def test_embeddings_create_async_no_sensitive_data( sentry_init, - capture_events, capture_items, - send_default_pii, - include_prompts, - stream_gen_ai_spans, - span_streaming, ): sentry_init( - integrations=[OpenAIIntegration(include_prompts=include_prompts)], + integrations=[OpenAIIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, - send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", + send_default_pii=False, ) client = AsyncOpenAI(api_key="z") @@ -3726,55 +2613,26 @@ async def test_embeddings_create_async_no_pii( ) client.embeddings._post = AsyncMock(return_value=returned_embedding) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with start_transaction(name="openai tx"): - response = await client.embeddings.create( - input="hello", model="text-embedding-3-large" - ) - - assert len(response.data[0].embedding) == 3 - - sentry_sdk.flush() - span = next(item.payload for item in items) - assert span["attributes"]["sentry.op"] == "gen_ai.embeddings" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "openai" - assert ( - span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] - == "text-embedding-3-large" - ) - - assert SPANDATA.GEN_AI_EMBEDDINGS_INPUT not in span["attributes"] - - assert span["attributes"]["gen_ai.usage.input_tokens"] == 20 - assert span["attributes"]["gen_ai.usage.total_tokens"] == 30 - else: - events = capture_events() - - with start_transaction(name="openai tx"): - response = await client.embeddings.create( - input="hello", model="text-embedding-3-large" - ) + response = await client.embeddings.create( + input="hello", model="text-embedding-3-large" + ) - assert len(response.data[0].embedding) == 3 + assert len(response.data[0].embedding) == 3 - tx = events[0] - assert tx["type"] == "transaction" - span = tx["spans"][0] - assert span["op"] == "gen_ai.embeddings" - assert span["data"][SPANDATA.GEN_AI_SYSTEM] == "openai" - assert span["data"][SPANDATA.GEN_AI_REQUEST_MODEL] == "text-embedding-3-large" + sentry_sdk.flush() + span = next(item.payload for item in items) + assert span["attributes"]["sentry.op"] == "gen_ai.embeddings" + assert span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "openai" + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "text-embedding-3-large" - assert SPANDATA.GEN_AI_EMBEDDINGS_INPUT not in span["data"] + assert SPANDATA.GEN_AI_EMBEDDINGS_INPUT not in span["attributes"] - assert span["data"]["gen_ai.usage.input_tokens"] == 20 - assert span["data"]["gen_ai.usage.total_tokens"] == 30 + assert span["attributes"]["gen_ai.usage.input_tokens"] == 20 + assert span["attributes"]["gen_ai.usage.total_tokens"] == 30 -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio @pytest.mark.parametrize( "get_input,expected_embeddings_input", @@ -3847,20 +2705,15 @@ async def test_embeddings_create_async_no_pii( ) async def test_embeddings_create_async( sentry_init, - capture_events, capture_items, get_input, expected_embeddings_input, - stream_gen_ai_spans, - span_streaming, ): sentry_init( - integrations=[OpenAIIntegration(include_prompts=True)], + integrations=[OpenAIIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = AsyncOpenAI(api_key="z") @@ -3876,61 +2729,29 @@ async def test_embeddings_create_async( ) client.embeddings._post = AsyncMock(return_value=returned_embedding) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with start_transaction(name="openai tx"): - response = await client.embeddings.create( - input=get_input(), model="text-embedding-3-large" - ) - - assert len(response.data[0].embedding) == 3 - - sentry_sdk.flush() - span = next(item.payload for item in items) - assert span["attributes"]["sentry.op"] == "gen_ai.embeddings" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "openai" - assert ( - span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] - == "text-embedding-3-large" - ) - - assert ( - json.loads(span["attributes"][SPANDATA.GEN_AI_EMBEDDINGS_INPUT]) - == expected_embeddings_input - ) - - assert span["attributes"]["gen_ai.usage.input_tokens"] == 20 - assert span["attributes"]["gen_ai.usage.total_tokens"] == 30 - else: - events = capture_events() - - with start_transaction(name="openai tx"): - response = await client.embeddings.create( - input=get_input(), model="text-embedding-3-large" - ) + response = await client.embeddings.create( + input=get_input(), model="text-embedding-3-large" + ) - assert len(response.data[0].embedding) == 3 + assert len(response.data[0].embedding) == 3 - tx = events[0] - assert tx["type"] == "transaction" - span = tx["spans"][0] - assert span["op"] == "gen_ai.embeddings" - assert span["data"][SPANDATA.GEN_AI_SYSTEM] == "openai" - assert span["data"][SPANDATA.GEN_AI_REQUEST_MODEL] == "text-embedding-3-large" + sentry_sdk.flush() + span = next(item.payload for item in items) + assert span["attributes"]["sentry.op"] == "gen_ai.embeddings" + assert span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "openai" + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MODEL] == "text-embedding-3-large" - assert ( - json.loads(span["data"][SPANDATA.GEN_AI_EMBEDDINGS_INPUT]) - == expected_embeddings_input - ) + assert ( + json.loads(span["attributes"][SPANDATA.GEN_AI_EMBEDDINGS_INPUT]) + == expected_embeddings_input + ) - assert span["data"]["gen_ai.usage.input_tokens"] == 20 - assert span["data"]["gen_ai.usage.total_tokens"] == 30 + assert span["attributes"]["gen_ai.usage.input_tokens"] == 20 + assert span["attributes"]["gen_ai.usage.total_tokens"] == 30 -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio @pytest.mark.parametrize( "data_collection,send_default_pii,expect_input", @@ -3963,21 +2784,16 @@ async def test_embeddings_create_async( ) async def test_embeddings_create_async_data_collection( sentry_init, - capture_events, capture_items, data_collection, send_default_pii, expect_input, - stream_gen_ai_spans, - span_streaming, ): init_kwargs = { "integrations": [OpenAIIntegration()], "disabled_integrations": [StdlibIntegration], "traces_sample_rate": 1.0, "send_default_pii": send_default_pii, - "stream_gen_ai_spans": stream_gen_ai_spans, - "trace_lifecycle": "stream" if span_streaming else "static", } sentry_init_kwargs = dict(init_kwargs) @@ -3999,38 +2815,20 @@ async def test_embeddings_create_async_data_collection( ) client.embeddings._post = AsyncMock(return_value=returned_embedding) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with start_transaction(name="openai tx"): - response = await client.embeddings.create( - input="hello", model="text-embedding-3-large" - ) - - assert len(response.data[0].embedding) == 3 - - sentry_sdk.flush() - span = next(item.payload for item in items) - assert span["attributes"]["sentry.op"] == "gen_ai.embeddings" - span_data = span["attributes"] - else: - events = capture_events() - - with start_transaction(name="openai tx"): - response = await client.embeddings.create( - input="hello", model="text-embedding-3-large" - ) + response = await client.embeddings.create( + input="hello", model="text-embedding-3-large" + ) - assert len(response.data[0].embedding) == 3 + assert len(response.data[0].embedding) == 3 - tx = events[0] - assert tx["type"] == "transaction" - span = tx["spans"][0] - assert span["op"] == "gen_ai.embeddings" - span_data = span["data"] + sentry_sdk.flush() + span = next(item.payload for item in items) + assert span["attributes"]["sentry.op"] == "gen_ai.embeddings" + span_data = span["attributes"] - assert span_data[SPANDATA.GEN_AI_SYSTEM] == "openai" + assert span_data[SPANDATA.GEN_AI_PROVIDER_NAME] == "openai" assert span_data[SPANDATA.GEN_AI_OPERATION_NAME] == "embeddings" assert span_data[SPANDATA.GEN_AI_REQUEST_MODEL] == "text-embedding-3-large" @@ -4043,28 +2841,20 @@ async def test_embeddings_create_async_data_collection( assert span_data["gen_ai.usage.total_tokens"] == 30 -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize( - "send_default_pii, include_prompts", - [(True, True), (True, False), (False, True), (False, False)], + "send_default_pii", + [True, False], ) def test_embeddings_create_raises_error( sentry_init, - capture_events, capture_items, send_default_pii, - include_prompts, - stream_gen_ai_spans, - span_streaming, ): sentry_init( - integrations=[OpenAIIntegration(include_prompts=include_prompts)], + integrations=[OpenAIIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = OpenAI(api_key="z") @@ -4072,62 +2862,33 @@ def test_embeddings_create_raises_error( client.embeddings._post = mock.Mock( side_effect=OpenAIError("API rate limit reached") ) + items = capture_items("event", "span") - if span_streaming: - items = capture_items("event", "span") - - with pytest.raises(OpenAIError): - client.embeddings.create(input="hello", model="text-embedding-3-large") - - (event,) = (item.payload for item in items if item.type == "event") - sentry_sdk.flush() - (span,) = (item.payload for item in items if item.type == "span") - assert event["level"] == "error" - assert span["status"] == "error" - elif stream_gen_ai_spans: - items = capture_items("event", "transaction") + with pytest.raises(OpenAIError): + client.embeddings.create(input="hello", model="text-embedding-3-large") - with pytest.raises(OpenAIError): - client.embeddings.create(input="hello", model="text-embedding-3-large") - - (event,) = (item.payload for item in items if item.type == "event") - (transaction,) = (item.payload for item in items if item.type == "transaction") - assert event["level"] == "error" - assert transaction["contexts"]["trace"]["status"] == "internal_error" - else: - events = capture_events() - - with pytest.raises(OpenAIError): - client.embeddings.create(input="hello", model="text-embedding-3-large") - - (event, transaction) = events - assert event["level"] == "error" - assert transaction["contexts"]["trace"]["status"] == "internal_error" + (event,) = (item.payload for item in items if item.type == "event") + sentry_sdk.flush() + (span,) = (item.payload for item in items if item.type == "span") + assert event["level"] == "error" + assert span["status"] == "error" -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio @pytest.mark.parametrize( - "send_default_pii, include_prompts", - [(True, True), (True, False), (False, True), (False, False)], + "send_default_pii", + [True, False], ) async def test_embeddings_create_raises_error_async( sentry_init, - capture_events, capture_items, send_default_pii, - include_prompts, - stream_gen_ai_spans, - span_streaming, ): sentry_init( - integrations=[OpenAIIntegration(include_prompts=include_prompts)], + integrations=[OpenAIIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = AsyncOpenAI(api_key="z") @@ -4135,60 +2896,26 @@ async def test_embeddings_create_raises_error_async( client.embeddings._post = AsyncMock( side_effect=OpenAIError("API rate limit reached") ) + items = capture_items("event", "span") - if span_streaming: - items = capture_items("event", "span") - - with pytest.raises(OpenAIError): - await client.embeddings.create( - input="hello", model="text-embedding-3-large" - ) - - (event,) = (item.payload for item in items if item.type == "event") - sentry_sdk.flush() - (span,) = (item.payload for item in items if item.type == "span") - assert event["level"] == "error" - assert span["status"] == "error" - elif stream_gen_ai_spans: - items = capture_items("event", "transaction") - - with pytest.raises(OpenAIError): - await client.embeddings.create( - input="hello", model="text-embedding-3-large" - ) - - (event,) = (item.payload for item in items if item.type == "event") - (transaction,) = (item.payload for item in items if item.type == "transaction") - assert event["level"] == "error" - assert transaction["contexts"]["trace"]["status"] == "internal_error" - else: - events = capture_events() - - with pytest.raises(OpenAIError): - await client.embeddings.create( - input="hello", model="text-embedding-3-large" - ) + with pytest.raises(OpenAIError): + await client.embeddings.create(input="hello", model="text-embedding-3-large") - (event, transaction) = events - assert event["level"] == "error" - assert transaction["contexts"]["trace"]["status"] == "internal_error" + (event,) = (item.payload for item in items if item.type == "event") + sentry_sdk.flush() + (span,) = (item.payload for item in items if item.type == "span") + assert event["level"] == "error" + assert span["status"] == "error" -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_span_origin_nonstreaming_chat( sentry_init, - capture_events, capture_items, nonstreaming_chat_completions_model_response, - stream_gen_ai_spans, - span_streaming, ): sentry_init( integrations=[OpenAIIntegration()], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = OpenAI(api_key="z") @@ -4205,64 +2932,27 @@ def test_span_origin_nonstreaming_chat( ), ) ) + items = capture_items("transaction", "span") - if span_streaming: - items = capture_items("transaction", "span") - - with sentry_sdk.traces.start_span(name="openai tx"): - client.chat.completions.create( - model="some-model", messages=[{"role": "system", "content": "hello"}] - ) - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert spans[1]["attributes"]["sentry.origin"] == "manual" - assert spans[0]["attributes"]["sentry.origin"] == "auto.ai.openai" - elif stream_gen_ai_spans: - items = capture_items("transaction", "span") - - with start_transaction(name="openai tx"): - client.chat.completions.create( - model="some-model", messages=[{"role": "system", "content": "hello"}] - ) - - (event,) = (item.payload for item in items if item.type == "transaction") - assert event["contexts"]["trace"]["origin"] == "manual" - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert spans[0]["attributes"]["sentry.origin"] == "auto.ai.openai" - else: - events = capture_events() - - with start_transaction(name="openai tx"): - client.chat.completions.create( - model="some-model", messages=[{"role": "system", "content": "hello"}] - ) - - (event,) = events + client.chat.completions.create( + model="some-model", messages=[{"role": "system", "content": "hello"}] + ) - assert event["contexts"]["trace"]["origin"] == "manual" - assert event["spans"][0]["origin"] == "auto.ai.openai" + sentry_sdk.flush() + spans = [item.payload for item in items if item.type == "span"] + assert spans[0]["attributes"]["sentry.origin"] == "auto.ai.openai" -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio async def test_span_origin_nonstreaming_chat_async( sentry_init, - capture_events, capture_items, nonstreaming_chat_completions_model_response, - stream_gen_ai_spans, - span_streaming, ): sentry_init( integrations=[OpenAIIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = AsyncOpenAI(api_key="z") @@ -4279,62 +2969,25 @@ async def test_span_origin_nonstreaming_chat_async( ), ) ) + items = capture_items("transaction", "span") - if span_streaming: - items = capture_items("transaction", "span") - - with sentry_sdk.traces.start_span(name="openai tx"): - await client.chat.completions.create( - model="some-model", messages=[{"role": "system", "content": "hello"}] - ) - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert spans[1]["attributes"]["sentry.origin"] == "manual" - assert spans[0]["attributes"]["sentry.origin"] == "auto.ai.openai" - elif stream_gen_ai_spans: - items = capture_items("transaction", "span") - - with start_transaction(name="openai tx"): - await client.chat.completions.create( - model="some-model", messages=[{"role": "system", "content": "hello"}] - ) - - (event,) = (item.payload for item in items if item.type == "transaction") - assert event["contexts"]["trace"]["origin"] == "manual" - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert spans[0]["attributes"]["sentry.origin"] == "auto.ai.openai" - else: - events = capture_events() - - with start_transaction(name="openai tx"): - await client.chat.completions.create( - model="some-model", messages=[{"role": "system", "content": "hello"}] - ) - - (event,) = events + await client.chat.completions.create( + model="some-model", messages=[{"role": "system", "content": "hello"}] + ) - assert event["contexts"]["trace"]["origin"] == "manual" - assert event["spans"][0]["origin"] == "auto.ai.openai" + sentry_sdk.flush() + spans = [item.payload for item in items if item.type == "span"] + assert spans[0]["attributes"]["sentry.origin"] == "auto.ai.openai" -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_span_origin_streaming_chat( sentry_init, - capture_events, capture_items, - stream_gen_ai_spans, - span_streaming, ): sentry_init( integrations=[OpenAIIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = OpenAI(api_key="z") @@ -4374,73 +3027,30 @@ def test_span_origin_streaming_chat( object="chat.completion.chunk", ), ] + items = capture_items("transaction", "span") - if span_streaming: - items = capture_items("transaction", "span") - - client.chat.completions._post = mock.Mock(return_value=returned_stream) - with sentry_sdk.traces.start_span(name="openai tx"): - response_stream = client.chat.completions.create( - model="some-model", messages=[{"role": "system", "content": "hello"}] - ) - - "".join(map(lambda x: x.choices[0].delta.content, response_stream)) - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert spans[1]["attributes"]["sentry.origin"] == "manual" - assert spans[0]["attributes"]["sentry.origin"] == "auto.ai.openai" - elif stream_gen_ai_spans: - items = capture_items("transaction", "span") - - client.chat.completions._post = mock.Mock(return_value=returned_stream) - with start_transaction(name="openai tx"): - response_stream = client.chat.completions.create( - model="some-model", messages=[{"role": "system", "content": "hello"}] - ) - - "".join(map(lambda x: x.choices[0].delta.content, response_stream)) - - (event,) = (item.payload for item in items if item.type == "transaction") - assert event["contexts"]["trace"]["origin"] == "manual" - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert spans[0]["attributes"]["sentry.origin"] == "auto.ai.openai" - else: - events = capture_events() - - client.chat.completions._post = mock.Mock(return_value=returned_stream) - with start_transaction(name="openai tx"): - response_stream = client.chat.completions.create( - model="some-model", messages=[{"role": "system", "content": "hello"}] - ) - - "".join(map(lambda x: x.choices[0].delta.content, response_stream)) + client.chat.completions._post = mock.Mock(return_value=returned_stream) + response_stream = client.chat.completions.create( + model="some-model", messages=[{"role": "system", "content": "hello"}] + ) - (event,) = events + "".join(map(lambda x: x.choices[0].delta.content, response_stream)) - assert event["contexts"]["trace"]["origin"] == "manual" - assert event["spans"][0]["origin"] == "auto.ai.openai" + sentry_sdk.flush() + spans = [item.payload for item in items if item.type == "span"] + assert spans[0]["attributes"]["sentry.origin"] == "auto.ai.openai" -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio async def test_span_origin_streaming_chat_async( sentry_init, - capture_events, capture_items, async_iterator, - stream_gen_ai_spans, - span_streaming, ): sentry_init( integrations=[OpenAIIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = AsyncOpenAI(api_key="z") @@ -4486,74 +3096,29 @@ async def test_span_origin_streaming_chat_async( ) client.chat.completions._post = AsyncMock(return_value=returned_stream) + items = capture_items("transaction", "span") - if span_streaming: - items = capture_items("transaction", "span") - - with sentry_sdk.traces.start_span(name="openai tx"): - response_stream = await client.chat.completions.create( - model="some-model", messages=[{"role": "system", "content": "hello"}] - ) - async for _ in response_stream: - pass - - # "".join(map(lambda x: x.choices[0].delta.content, response_stream)) - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert spans[1]["attributes"]["sentry.origin"] == "manual" - assert spans[0]["attributes"]["sentry.origin"] == "auto.ai.openai" - elif stream_gen_ai_spans: - items = capture_items("transaction", "span") - - with start_transaction(name="openai tx"): - response_stream = await client.chat.completions.create( - model="some-model", messages=[{"role": "system", "content": "hello"}] - ) - async for _ in response_stream: - pass - - # "".join(map(lambda x: x.choices[0].delta.content, response_stream)) - - (event,) = (item.payload for item in items if item.type == "transaction") - assert event["contexts"]["trace"]["origin"] == "manual" - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert spans[0]["attributes"]["sentry.origin"] == "auto.ai.openai" - else: - events = capture_events() - - with start_transaction(name="openai tx"): - response_stream = await client.chat.completions.create( - model="some-model", messages=[{"role": "system", "content": "hello"}] - ) - async for _ in response_stream: - pass - - # "".join(map(lambda x: x.choices[0].delta.content, response_stream)) + response_stream = await client.chat.completions.create( + model="some-model", messages=[{"role": "system", "content": "hello"}] + ) + async for _ in response_stream: + pass - (event,) = events + # "".join(map(lambda x: x.choices[0].delta.content, response_stream)) - assert event["contexts"]["trace"]["origin"] == "manual" - assert event["spans"][0]["origin"] == "auto.ai.openai" + sentry_sdk.flush() + spans = [item.payload for item in items if item.type == "span"] + assert spans[0]["attributes"]["sentry.origin"] == "auto.ai.openai" -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_span_origin_embeddings( sentry_init, - capture_events, capture_items, - stream_gen_ai_spans, - span_streaming, ): sentry_init( integrations=[OpenAIIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = OpenAI(api_key="z") @@ -4569,57 +3134,24 @@ def test_span_origin_embeddings( ) client.embeddings._post = mock.Mock(return_value=returned_embedding) + items = capture_items("transaction", "span") - if span_streaming: - items = capture_items("transaction", "span") - - with sentry_sdk.traces.start_span(name="openai tx"): - client.embeddings.create(input="hello", model="text-embedding-3-large") - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert spans[1]["attributes"]["sentry.origin"] == "manual" - assert spans[0]["attributes"]["sentry.origin"] == "auto.ai.openai" - elif stream_gen_ai_spans: - items = capture_items("transaction", "span") - - with start_transaction(name="openai tx"): - client.embeddings.create(input="hello", model="text-embedding-3-large") - - (event,) = [item.payload for item in items if item.type == "transaction"] - assert event["contexts"]["trace"]["origin"] == "manual" - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert spans[0]["attributes"]["sentry.origin"] == "auto.ai.openai" - else: - events = capture_events() - - with start_transaction(name="openai tx"): - client.embeddings.create(input="hello", model="text-embedding-3-large") + client.embeddings.create(input="hello", model="text-embedding-3-large") - (event,) = events + sentry_sdk.flush() + spans = [item.payload for item in items if item.type == "span"] + assert spans[0]["attributes"]["sentry.origin"] == "auto.ai.openai" - assert event["contexts"]["trace"]["origin"] == "manual" - assert event["spans"][0]["origin"] == "auto.ai.openai" - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio async def test_span_origin_embeddings_async( sentry_init, - capture_events, capture_items, - stream_gen_ai_spans, - span_streaming, ): sentry_init( integrations=[OpenAIIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = AsyncOpenAI(api_key="z") @@ -4635,45 +3167,13 @@ async def test_span_origin_embeddings_async( ) client.embeddings._post = AsyncMock(return_value=returned_embedding) + items = capture_items("transaction", "span") - if span_streaming: - items = capture_items("transaction", "span") - - with sentry_sdk.traces.start_span(name="openai tx"): - await client.embeddings.create( - input="hello", model="text-embedding-3-large" - ) - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert spans[1]["attributes"]["sentry.origin"] == "manual" - assert spans[0]["attributes"]["sentry.origin"] == "auto.ai.openai" - elif stream_gen_ai_spans: - items = capture_items("transaction", "span") - - with start_transaction(name="openai tx"): - await client.embeddings.create( - input="hello", model="text-embedding-3-large" - ) - - (event,) = [item.payload for item in items if item.type == "transaction"] - assert event["contexts"]["trace"]["origin"] == "manual" - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert spans[0]["attributes"]["sentry.origin"] == "auto.ai.openai" - else: - events = capture_events() - - with start_transaction(name="openai tx"): - await client.embeddings.create( - input="hello", model="text-embedding-3-large" - ) - - (event,) = events + await client.embeddings.create(input="hello", model="text-embedding-3-large") - assert event["contexts"]["trace"]["origin"] == "manual" - assert event["spans"][0]["origin"] == "auto.ai.openai" + sentry_sdk.flush() + spans = [item.payload for item in items if item.type == "span"] + assert spans[0]["attributes"]["sentry.origin"] == "auto.ai.openai" def test_completions_token_usage_from_response(): @@ -5038,275 +3538,86 @@ def count_tokens(msg): ) -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.skipif(SKIP_RESPONSES_TESTS, reason="Responses API not available") -def test_ai_client_span_responses_api_no_pii( +def test_ai_client_span_responses_api_no_sensitive_data( sentry_init, - capture_events, capture_items, - stream_gen_ai_spans, - span_streaming, ): sentry_init( integrations=[OpenAIIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = OpenAI(api_key="z") client.responses._post = mock.Mock(return_value=EXAMPLE_RESPONSE) + items = capture_items("span") + + client.responses.create( + model="gpt-4o", + instructions="You are a coding assistant that talks like a pirate.", + input="How do I check if a Python object is an instance of a class?", + max_output_tokens=100, + temperature=0.7, + top_p=0.9, + reasoning={"effort": "high"}, + ) - if span_streaming: - items = capture_items("span") - - with sentry_sdk.traces.start_span(name="openai tx"): - client.responses.create( - model="gpt-4o", - instructions="You are a coding assistant that talks like a pirate.", - input="How do I check if a Python object is an instance of a class?", - max_output_tokens=100, - temperature=0.7, - top_p=0.9, - reasoning={"effort": "high"}, - ) + sentry_sdk.flush() + spans = [item.payload for item in items] + + assert len(spans) == 1 + expected_attributes = { + "gen_ai.operation.name": "responses", + "gen_ai.request.max_tokens": 100, + "gen_ai.request.temperature": 0.7, + "gen_ai.request.top_p": 0.9, + "gen_ai.request.reasoning.level": "high", + "gen_ai.request.model": "gpt-4o", + "gen_ai.response.model": "response-model-id", + "gen_ai.response.streaming": False, + SPANDATA.GEN_AI_PROVIDER_NAME: "openai", + "gen_ai.usage.input_tokens": 20, + SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS: 5, + "gen_ai.usage.output_tokens": 10, + SPANDATA.GEN_AI_USAGE_REASONING_OUTPUT_TOKENS: 8, + "gen_ai.usage.total_tokens": 30, + "sentry.op": "gen_ai.responses", + "sentry.origin": "auto.ai.openai", + } - sentry_sdk.flush() - spans = [item.payload for item in items] - - assert len(spans) == 2 - expected_attributes = { - "gen_ai.operation.name": "responses", - "gen_ai.request.max_tokens": 100, - "gen_ai.request.temperature": 0.7, - "gen_ai.request.top_p": 0.9, - "gen_ai.request.reasoning.level": "high", - "gen_ai.request.model": "gpt-4o", - "gen_ai.response.model": "response-model-id", - "gen_ai.response.streaming": False, - "gen_ai.system": "openai", - "gen_ai.usage.input_tokens": 20, - "gen_ai.usage.input_tokens.cached": 5, - "gen_ai.usage.output_tokens": 10, - "gen_ai.usage.output_tokens.reasoning": 8, - "gen_ai.usage.total_tokens": 30, - "sentry.op": "gen_ai.responses", - "sentry.origin": "auto.ai.openai", - "sentry.segment.name": "openai tx", - } - - for attr, value in expected_attributes.items(): - assert spans[0]["attributes"][attr] == value - - assert "gen_ai.system_instructions" not in spans[0]["attributes"] - assert "gen_ai.request.messages" not in spans[0]["attributes"] - assert "gen_ai.response.text" not in spans[0]["attributes"] - - elif stream_gen_ai_spans: - items = capture_items("span") - - with start_transaction(name="openai tx"): - client.responses.create( - model="gpt-4o", - instructions="You are a coding assistant that talks like a pirate.", - input="How do I check if a Python object is an instance of a class?", - max_output_tokens=100, - temperature=0.7, - top_p=0.9, - reasoning={"effort": "high"}, - tools=EXAMPLE_TOOLS, - ) + for attr, value in expected_attributes.items(): + assert spans[0]["attributes"][attr] == value + + assert "gen_ai.system_instructions" not in spans[0]["attributes"] + assert "gen_ai.request.messages" not in spans[0]["attributes"] + assert "gen_ai.response.text" not in spans[0]["attributes"] - spans = [item.payload for item in items] - - assert len(spans) == 1 - expected_attributes = { - "gen_ai.operation.name": "responses", - "gen_ai.request.max_tokens": 100, - "gen_ai.request.temperature": 0.7, - "gen_ai.request.top_p": 0.9, - "gen_ai.request.reasoning.level": "high", - "gen_ai.request.model": "gpt-4o", - "gen_ai.response.model": "response-model-id", - "gen_ai.response.streaming": False, - "gen_ai.system": "openai", - "gen_ai.usage.input_tokens": 20, - "gen_ai.usage.input_tokens.cached": 5, - "gen_ai.usage.output_tokens": 10, - "gen_ai.usage.output_tokens.reasoning": 8, - "gen_ai.usage.total_tokens": 30, - "sentry.op": "gen_ai.responses", - "sentry.origin": "auto.ai.openai", - "sentry.segment.name": "openai tx", - } - - for attr, value in expected_attributes.items(): - assert spans[0]["attributes"][attr] == value - - assert "gen_ai.system_instructions" not in spans[0]["attributes"] - assert "gen_ai.request.messages" not in spans[0]["attributes"] - assert "gen_ai.response.text" not in spans[0]["attributes"] - else: - events = capture_events() - - with start_transaction(name="openai tx"): - client.responses.create( - model="gpt-4o", - instructions="You are a coding assistant that talks like a pirate.", - input="How do I check if a Python object is an instance of a class?", - max_output_tokens=100, - temperature=0.7, - top_p=0.9, - reasoning={"effort": "high"}, - ) - (transaction,) = events - spans = transaction["spans"] - - assert len(spans) == 1 - assert spans[0]["op"] == "gen_ai.responses" - assert spans[0]["origin"] == "auto.ai.openai" - expected_data = { - "gen_ai.operation.name": "responses", - "gen_ai.request.max_tokens": 100, - "gen_ai.request.temperature": 0.7, - "gen_ai.request.top_p": 0.9, - "gen_ai.request.reasoning.level": "high", - "gen_ai.request.model": "gpt-4o", - "gen_ai.response.model": "response-model-id", - "gen_ai.response.streaming": False, - "gen_ai.system": "openai", - "gen_ai.usage.input_tokens": 20, - "gen_ai.usage.input_tokens.cached": 5, - "gen_ai.usage.output_tokens": 10, - "gen_ai.usage.output_tokens.reasoning": 8, - "gen_ai.usage.total_tokens": 30, - } - - for key, value in expected_data.items(): - assert spans[0]["data"][key] == value - - assert "gen_ai.system_instructions" not in spans[0]["data"] - assert "gen_ai.request.messages" not in spans[0]["data"] - assert "gen_ai.response.text" not in spans[0]["data"] - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.skipif(SKIP_RESPONSES_TESTS, reason="Responses API not available") def test_ai_client_span_responses_tool_definitions( sentry_init, - capture_events, capture_items, - stream_gen_ai_spans, - span_streaming, ): sentry_init( integrations=[OpenAIIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = OpenAI(api_key="z") client.responses._post = mock.Mock(return_value=EXAMPLE_RESPONSE) - - if span_streaming: - items = capture_items("span") - - with sentry_sdk.traces.start_span(name="openai tx"): - client.responses.create( - model="gpt-4o", - input="How do I check if a Python object is an instance of a class?", - tools=[ - FunctionToolParam( - type="function", - name="name", - description="description", - parameters={ - "type": "object", - "properties": { - "city": {"type": "string"}, - "state": {"type": "string"}, - }, - "required": ["city", "state"], - "additionalProperties": False, - }, - strict=True, - ), - CustomToolParam( - type="custom", name="name", description="description" - ), - WebSearchToolParam(type="web_search"), - ], - ) - - sentry_sdk.flush() - spans = [item.payload for item in items] - assert json.loads(spans[0]["attributes"][SPANDATA.GEN_AI_TOOL_DEFINITIONS]) == [ - { - "type": "function", - "name": "name", - "description": "description", - "parameters": { - "type": "object", - "properties": { - "city": {"type": "string"}, - "state": {"type": "string"}, - }, - "required": ["city", "state"], - "additionalProperties": False, - }, - }, - { - "type": "custom", - "name": "name", - "description": "description", - }, - { - "type": "web_search", - }, - ] - elif stream_gen_ai_spans: - items = capture_items("span") - - with start_transaction(name="openai tx"): - client.responses.create( - model="gpt-4o", - input="How do I check if a Python object is an instance of a class?", - tools=[ - FunctionToolParam( - type="function", - name="name", - description="description", - parameters={ - "type": "object", - "properties": { - "city": {"type": "string"}, - "state": {"type": "string"}, - }, - "required": ["city", "state"], - "additionalProperties": False, - }, - strict=True, - ), - CustomToolParam( - type="custom", name="name", description="description" - ), - WebSearchToolParam(type="web_search"), - ], - ) - - spans = [item.payload for item in items] - assert json.loads(spans[0]["attributes"][SPANDATA.GEN_AI_TOOL_DEFINITIONS]) == [ - { - "type": "function", - "name": "name", - "description": "description", - "parameters": { + items = capture_items("span") + + client.responses.create( + model="gpt-4o", + input="How do I check if a Python object is an instance of a class?", + tools=[ + FunctionToolParam( + type="function", + name="name", + description="description", + parameters={ "type": "object", "properties": { "city": {"type": "string"}, @@ -5315,77 +3626,41 @@ def test_ai_client_span_responses_tool_definitions( "required": ["city", "state"], "additionalProperties": False, }, - }, - { - "type": "custom", - "name": "name", - "description": "description", - }, - { - "type": "web_search", - }, - ] - else: - events = capture_events() - - with start_transaction(name="openai tx"): - client.responses.create( - model="gpt-4o", - input="How do I check if a Python object is an instance of a class?", - tools=[ - FunctionToolParam( - type="function", - name="name", - description="description", - parameters={ - "type": "object", - "properties": { - "city": {"type": "string"}, - "state": {"type": "string"}, - }, - "required": ["city", "state"], - "additionalProperties": False, - }, - strict=True, - ), - CustomToolParam( - type="custom", name="name", description="description" - ), - WebSearchToolParam(type="web_search"), - ], - ) - - (transaction,) = events - spans = transaction["spans"] + strict=True, + ), + CustomToolParam(type="custom", name="name", description="description"), + WebSearchToolParam(type="web_search"), + ], + ) - assert json.loads(spans[0]["data"][SPANDATA.GEN_AI_TOOL_DEFINITIONS]) == [ - { - "type": "function", - "name": "name", - "description": "description", - "parameters": { - "type": "object", - "properties": { - "city": {"type": "string"}, - "state": {"type": "string"}, - }, - "required": ["city", "state"], - "additionalProperties": False, + sentry_sdk.flush() + spans = [item.payload for item in items] + assert json.loads(spans[0]["attributes"][SPANDATA.GEN_AI_TOOL_DEFINITIONS]) == [ + { + "type": "function", + "name": "name", + "description": "description", + "parameters": { + "type": "object", + "properties": { + "city": {"type": "string"}, + "state": {"type": "string"}, }, + "required": ["city", "state"], + "additionalProperties": False, }, - { - "type": "custom", - "name": "name", - "description": "description", - }, - { - "type": "web_search", - }, - ] + }, + { + "type": "custom", + "name": "name", + "description": "description", + }, + { + "type": "web_search", + }, + ] -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize( "instructions,input,expected_system_instructions,expected_request_messages", [ @@ -5532,177 +3807,70 @@ def test_ai_client_span_responses_tool_definitions( @pytest.mark.skipif(SKIP_RESPONSES_TESTS, reason="Responses API not available") def test_ai_client_span_responses_api( sentry_init, - capture_events, capture_items, instructions, input, expected_system_instructions, expected_request_messages, - stream_gen_ai_spans, - span_streaming, ): sentry_init( - integrations=[OpenAIIntegration(include_prompts=True)], + integrations=[OpenAIIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = OpenAI(api_key="z") client.responses._post = mock.Mock(return_value=EXAMPLE_RESPONSE) + items = capture_items("span") + + client.responses.create( + model="gpt-4o", + instructions=instructions, + input=input, + max_output_tokens=100, + temperature=0.7, + top_p=0.9, + reasoning={"effort": "high"}, + ) - if span_streaming: - items = capture_items("span") - - with sentry_sdk.traces.start_span(name="openai tx"): - client.responses.create( - model="gpt-4o", - instructions=instructions, - input=input, - max_output_tokens=100, - temperature=0.7, - top_p=0.9, - reasoning={"effort": "high"}, - ) - - sentry_sdk.flush() - spans = [item.payload for item in items] - - assert len(spans) == 2 - - expected_data = { - "gen_ai.operation.name": "responses", - "gen_ai.request.max_tokens": 100, - "gen_ai.request.temperature": 0.7, - "gen_ai.request.top_p": 0.9, - "gen_ai.request.reasoning.level": "high", - "gen_ai.system": "openai", - "gen_ai.response.model": "response-model-id", - "gen_ai.response.streaming": False, - "gen_ai.usage.input_tokens": 20, - "gen_ai.usage.input_tokens.cached": 5, - "gen_ai.usage.output_tokens": 10, - "gen_ai.usage.output_tokens.reasoning": 8, - "gen_ai.usage.total_tokens": 30, - "gen_ai.request.messages": safe_serialize(expected_request_messages), - "gen_ai.request.model": "gpt-4o", - "gen_ai.response.text": "the model response", - "sentry.op": "gen_ai.responses", - "sentry.origin": "auto.ai.openai", - "sentry.segment.name": "openai tx", - } - - if expected_system_instructions is not None: - expected_data["gen_ai.system_instructions"] = safe_serialize( - expected_system_instructions - ) - - for attr, value in expected_data.items(): - assert spans[0]["attributes"][attr] == value - - elif stream_gen_ai_spans: - items = capture_items("span") - - with start_transaction(name="openai tx"): - client.responses.create( - model="gpt-4o", - instructions=instructions, - input=input, - max_output_tokens=100, - temperature=0.7, - top_p=0.9, - reasoning={"effort": "high"}, - ) - - spans = [item.payload for item in items] - - assert len(spans) == 1 - - expected_data = { - "gen_ai.operation.name": "responses", - "gen_ai.request.max_tokens": 100, - "gen_ai.request.temperature": 0.7, - "gen_ai.request.top_p": 0.9, - "gen_ai.request.reasoning.level": "high", - "gen_ai.system": "openai", - "gen_ai.response.model": "response-model-id", - "gen_ai.response.streaming": False, - "gen_ai.usage.input_tokens": 20, - "gen_ai.usage.input_tokens.cached": 5, - "gen_ai.usage.output_tokens": 10, - "gen_ai.usage.output_tokens.reasoning": 8, - "gen_ai.usage.total_tokens": 30, - "gen_ai.request.messages": safe_serialize(expected_request_messages), - "gen_ai.request.model": "gpt-4o", - "gen_ai.response.text": "the model response", - "sentry.op": "gen_ai.responses", - "sentry.origin": "auto.ai.openai", - "sentry.segment.name": "openai tx", - } - - if expected_system_instructions is not None: - expected_data["gen_ai.system_instructions"] = safe_serialize( - expected_system_instructions - ) - - for attr, value in expected_data.items(): - assert spans[0]["attributes"][attr] == value - - else: - events = capture_events() - - with start_transaction(name="openai tx"): - client.responses.create( - model="gpt-4o", - instructions=instructions, - input=input, - max_output_tokens=100, - temperature=0.7, - top_p=0.9, - reasoning={"effort": "high"}, - ) + sentry_sdk.flush() + spans = [item.payload for item in items] + + assert len(spans) == 1 + + expected_data = { + "gen_ai.operation.name": "responses", + "gen_ai.request.max_tokens": 100, + "gen_ai.request.temperature": 0.7, + "gen_ai.request.top_p": 0.9, + "gen_ai.request.reasoning.level": "high", + SPANDATA.GEN_AI_PROVIDER_NAME: "openai", + "gen_ai.response.model": "response-model-id", + "gen_ai.response.streaming": False, + "gen_ai.usage.input_tokens": 20, + SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS: 5, + "gen_ai.usage.output_tokens": 10, + SPANDATA.GEN_AI_USAGE_REASONING_OUTPUT_TOKENS: 8, + "gen_ai.usage.total_tokens": 30, + "gen_ai.request.messages": safe_serialize(expected_request_messages), + "gen_ai.request.model": "gpt-4o", + "gen_ai.response.text": "the model response", + "sentry.op": "gen_ai.responses", + "sentry.origin": "auto.ai.openai", + } - (transaction,) = events - spans = transaction["spans"] - - assert len(spans) == 1 - assert spans[0]["op"] == "gen_ai.responses" - assert spans[0]["origin"] == "auto.ai.openai" - - expected_data = { - "gen_ai.operation.name": "responses", - "gen_ai.request.max_tokens": 100, - "gen_ai.request.temperature": 0.7, - "gen_ai.request.top_p": 0.9, - "gen_ai.request.reasoning.level": "high", - "gen_ai.system": "openai", - "gen_ai.response.model": "response-model-id", - "gen_ai.response.streaming": False, - "gen_ai.usage.input_tokens": 20, - "gen_ai.usage.input_tokens.cached": 5, - "gen_ai.usage.output_tokens": 10, - "gen_ai.usage.output_tokens.reasoning": 8, - "gen_ai.usage.total_tokens": 30, - "gen_ai.request.messages": safe_serialize(expected_request_messages[-1:]), - "gen_ai.request.model": "gpt-4o", - "gen_ai.response.text": "the model response", - } - - if expected_system_instructions is not None: - expected_data["gen_ai.system_instructions"] = safe_serialize( - expected_system_instructions - ) + if expected_system_instructions is not None: + expected_data["gen_ai.system_instructions"] = safe_serialize( + expected_system_instructions + ) - for attr, value in expected_data.items(): - assert spans[0]["data"][attr] == value + for attr, value in expected_data.items(): + assert spans[0]["attributes"][attr] == value -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize( - "data_collection,extra_kwargs,expected_present,expected_absent,include_prompts", + "data_collection,extra_kwargs,expected_present,expected_absent", [ pytest.param( {"gen_ai": {"inputs": True}}, @@ -5726,7 +3894,6 @@ def test_ai_client_span_responses_api( SPANDATA.GEN_AI_TOOL_DEFINITIONS: safe_serialize(EXAMPLE_TOOLS), }, [], - True, id="gen-ai-inputs-enabled-string-input", ), pytest.param( @@ -5748,7 +3915,6 @@ def test_ai_client_span_responses_api( SPANDATA.GEN_AI_REQUEST_MESSAGES, SPANDATA.GEN_AI_TOOL_DEFINITIONS, ], - True, id="gen-ai-inputs-enabled-instructions-only", ), pytest.param( @@ -5775,7 +3941,6 @@ def test_ai_client_span_responses_api( ), }, [SPANDATA.GEN_AI_TOOL_DEFINITIONS], - True, id="gen-ai-inputs-enabled-list-input-with-system-message", ), pytest.param( @@ -5791,7 +3956,6 @@ def test_ai_client_span_responses_api( SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS, SPANDATA.GEN_AI_TOOL_DEFINITIONS, ], - True, id="gen-ai-inputs-disabled", ), pytest.param( @@ -5807,7 +3971,6 @@ def test_ai_client_span_responses_api( SPANDATA.GEN_AI_TOOL_DEFINITIONS: safe_serialize(EXAMPLE_TOOLS), }, [SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS], - True, id="gen-ai-omitted-defaults-to-enabled", ), pytest.param( @@ -5819,7 +3982,6 @@ def test_ai_client_span_responses_api( SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS, SPANDATA.GEN_AI_TOOL_DEFINITIONS, ], - True, id="gen-ai-inputs-enabled-no-input-provided", ), ], @@ -5827,23 +3989,17 @@ def test_ai_client_span_responses_api( @pytest.mark.skipif(SKIP_RESPONSES_TESTS, reason="Responses API not available") def test_responses_api_data_collection( sentry_init, - capture_events, capture_items, data_collection, extra_kwargs, expected_present, expected_absent, - include_prompts, - stream_gen_ai_spans, - span_streaming, ): sentry_init( - integrations=[OpenAIIntegration(include_prompts=include_prompts)], + integrations=[OpenAIIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, data_collection=data_collection, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = OpenAI(api_key="z") @@ -5857,40 +4013,15 @@ def test_responses_api_data_collection( "reasoning": {"effort": "high"}, } create_kwargs.update(extra_kwargs) + items = capture_items("span") - if span_streaming: - items = capture_items("span") - - with sentry_sdk.traces.start_span(name="openai tx"): - client.responses.create(**create_kwargs) - - sentry_sdk.flush() - spans = [item.payload for item in items] - - assert len(spans) == 2 - span_data = spans[0]["attributes"] - elif stream_gen_ai_spans: - items = capture_items("span") - - with start_transaction(name="openai tx"): - client.responses.create(**create_kwargs) - - spans = [item.payload for item in items] + client.responses.create(**create_kwargs) - assert len(spans) == 1 - span_data = spans[0]["attributes"] - else: - events = capture_events() - - with start_transaction(name="openai tx"): - client.responses.create(**create_kwargs) + sentry_sdk.flush() + spans = [item.payload for item in items] - (transaction,) = events - spans = transaction["spans"] - - assert len(spans) == 1 - assert spans[0]["op"] == "gen_ai.responses" - span_data = spans[0]["data"] + assert len(spans) == 1 + span_data = spans[0]["attributes"] # Non-input data is always collected, regardless of data collection config assert span_data["gen_ai.operation.name"] == "responses" @@ -5899,7 +4030,7 @@ def test_responses_api_data_collection( assert span_data["gen_ai.request.temperature"] == 0.7 assert span_data["gen_ai.request.top_p"] == 0.9 assert span_data["gen_ai.request.reasoning.level"] == "high" - assert span_data["gen_ai.system"] == "openai" + assert span_data[SPANDATA.GEN_AI_PROVIDER_NAME] == "openai" for key, value in expected_present.items(): assert span_data[key] == value @@ -5953,32 +4084,16 @@ def _make_responses_api_response(output): ) -def _collect_responses_span_data( - capture_events, capture_items, span_streaming, stream_gen_ai_spans, create -): - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with start_transaction(name="openai tx"): - create() - - sentry_sdk.flush() - (span,) = (item.payload for item in items) - return span["attributes"] +def _collect_responses_span_data(capture_items, create): + items = capture_items("span") - events = capture_events() + create() - with start_transaction(name="openai tx"): - create() + sentry_sdk.flush() + (span,) = (item.payload for item in items) + return span["attributes"] - (transaction,) = events - (span,) = transaction["spans"] - assert span["op"] == "gen_ai.responses" - return span["data"] - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize( "data_collection,send_default_pii,expect_output", [ @@ -6017,21 +4132,16 @@ def _collect_responses_span_data( @pytest.mark.skipif(SKIP_RESPONSES_TESTS, reason="Responses API not available") def test_responses_api_data_collection_outputs( sentry_init, - capture_events, capture_items, data_collection, send_default_pii, expect_output, - stream_gen_ai_spans, - span_streaming, ): init_kwargs = { "integrations": [OpenAIIntegration()], "disabled_integrations": [StdlibIntegration], "traces_sample_rate": 1.0, "send_default_pii": send_default_pii, - "stream_gen_ai_spans": stream_gen_ai_spans, - "trace_lifecycle": "stream" if span_streaming else "static", } if data_collection is not None: init_kwargs["data_collection"] = data_collection @@ -6057,10 +4167,7 @@ def test_responses_api_data_collection_outputs( ) span_data = _collect_responses_span_data( - capture_events, capture_items, - span_streaming, - stream_gen_ai_spans, lambda: client.responses.create(model="gpt-4o", input="hello"), ) @@ -6074,8 +4181,6 @@ def test_responses_api_data_collection_outputs( assert SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS not in span_data -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize( "get_output,expect_text,expect_tool_calls", [ @@ -6121,21 +4226,16 @@ def test_responses_api_data_collection_outputs( @pytest.mark.skipif(SKIP_RESPONSES_TESTS, reason="Responses API not available") def test_responses_api_data_collection_outputs_shapes( sentry_init, - capture_events, capture_items, get_output, expect_text, expect_tool_calls, - stream_gen_ai_spans, - span_streaming, ): sentry_init( integrations=[OpenAIIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, data_collection={"gen_ai": {"outputs": True}}, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = OpenAI(api_key="z") @@ -6144,10 +4244,7 @@ def test_responses_api_data_collection_outputs_shapes( ) span_data = _collect_responses_span_data( - capture_events, capture_items, - span_streaming, - stream_gen_ai_spans, lambda: client.responses.create(model="gpt-4o", input="hello"), ) @@ -6162,8 +4259,6 @@ def test_responses_api_data_collection_outputs_shapes( assert SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS not in span_data -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize( "data_collection,expect_output", [ @@ -6187,14 +4282,11 @@ def test_responses_api_data_collection_outputs_shapes( @pytest.mark.skipif(SKIP_RESPONSES_TESTS, reason="Responses API not available") def test_streaming_responses_api_data_collection_outputs( sentry_init, - capture_events, capture_items, data_collection, expect_output, get_model_response, server_side_event_chunks, - stream_gen_ai_spans, - span_streaming, ): sentry_init( integrations=[OpenAIIntegration()], @@ -6202,8 +4294,6 @@ def test_streaming_responses_api_data_collection_outputs( traces_sample_rate=1.0, send_default_pii=False, data_collection=data_collection, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = OpenAI(api_key="z") @@ -6212,51 +4302,27 @@ def test_streaming_responses_api_data_collection_outputs( EXAMPLE_RESPONSES_STREAM, ) ) + items = capture_items("span") + + with mock.patch.object( + client.responses._client._client, + "send", + return_value=returned_stream, + ): + response_stream = client.responses.create( + model="some-model", + input="hello", + stream=True, + ) + response_string = "" + for item in response_stream: + if hasattr(item, "delta"): + response_string += item.delta - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with mock.patch.object( - client.responses._client._client, - "send", - return_value=returned_stream, - ), start_transaction(name="openai tx"): - response_stream = client.responses.create( - model="some-model", - input="hello", - stream=True, - ) - response_string = "" - for item in response_stream: - if hasattr(item, "delta"): - response_string += item.delta - - assert response_string == "hello world" - sentry_sdk.flush() - (span,) = (item.payload for item in items) - span_data = span["attributes"] - else: - events = capture_events() - - with mock.patch.object( - client.responses._client._client, - "send", - return_value=returned_stream, - ), start_transaction(name="openai tx"): - response_stream = client.responses.create( - model="some-model", - input="hello", - stream=True, - ) - response_string = "" - for item in response_stream: - if hasattr(item, "delta"): - response_string += item.delta - - assert response_string == "hello world" - (transaction,) = events - (span,) = transaction["spans"] - span_data = span["data"] + assert response_string == "hello world" + sentry_sdk.flush() + (span,) = (item.payload for item in items) + span_data = span["attributes"] if expect_output: assert "hello world" in span_data[SPANDATA.GEN_AI_RESPONSE_TEXT] @@ -6264,8 +4330,6 @@ def test_streaming_responses_api_data_collection_outputs( assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span_data -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize( "conversation, expected_id", [ @@ -6278,62 +4342,35 @@ def test_streaming_responses_api_data_collection_outputs( @pytest.mark.skipif(SKIP_RESPONSES_TESTS, reason="Responses API not available") def test_responses_api_conversation_id( sentry_init, - capture_events, capture_items, conversation, expected_id, - stream_gen_ai_spans, - span_streaming, ): sentry_init( integrations=[OpenAIIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = OpenAI(api_key="z") client.responses._post = mock.Mock(return_value=EXAMPLE_RESPONSE) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with start_transaction(name="openai tx"): - client.responses.create( - model="gpt-4o", - input="hello", - conversation=conversation, - ) + client.responses.create( + model="gpt-4o", + input="hello", + conversation=conversation, + ) - sentry_sdk.flush() - (span,) = (item.payload for item in items) + sentry_sdk.flush() + (span,) = (item.payload for item in items) - if expected_id is None: - assert "gen_ai.conversation.id" not in span["attributes"] - else: - assert span["attributes"]["gen_ai.conversation.id"] == expected_id + if expected_id is None: + assert "gen_ai.conversation.id" not in span["attributes"] else: - events = capture_events() - - with start_transaction(name="openai tx"): - client.responses.create( - model="gpt-4o", - input="hello", - conversation=conversation, - ) - - (transaction,) = events - (span,) = transaction["spans"] + assert span["attributes"]["gen_ai.conversation.id"] == expected_id - if expected_id is None: - assert "gen_ai.conversation.id" not in span["data"] - else: - assert span["data"]["gen_ai.conversation.id"] == expected_id - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize( "reasoning, expected_level", [ @@ -6346,164 +4383,76 @@ def test_responses_api_conversation_id( @pytest.mark.skipif(SKIP_RESPONSES_TESTS, reason="Responses API not available") def test_responses_api_reasoning_level( sentry_init, - capture_events, capture_items, reasoning, expected_level, - stream_gen_ai_spans, - span_streaming, ): sentry_init( integrations=[OpenAIIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = OpenAI(api_key="z") client.responses._post = mock.Mock(return_value=EXAMPLE_RESPONSE) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with start_transaction(name="openai tx"): - client.responses.create( - model="gpt-4o", - input="hello", - reasoning=reasoning, - ) - - sentry_sdk.flush() - span = next(item.payload for item in items if item.type == "span") + client.responses.create( + model="gpt-4o", + input="hello", + reasoning=reasoning, + ) - if expected_level is None: - assert SPANDATA.GEN_AI_REQUEST_REASONING_LEVEL not in span["attributes"] - else: - assert ( - span["attributes"][SPANDATA.GEN_AI_REQUEST_REASONING_LEVEL] - == expected_level - ) + sentry_sdk.flush() + span = next(item.payload for item in items if item.type == "span") + if expected_level is None: + assert SPANDATA.GEN_AI_REQUEST_REASONING_LEVEL not in span["attributes"] else: - events = capture_events() - - with start_transaction(name="openai tx"): - client.responses.create( - model="gpt-4o", - input="hello", - reasoning=reasoning, - ) - - (transaction,) = events - span = transaction["spans"][0] - - if expected_level is None: - assert SPANDATA.GEN_AI_REQUEST_REASONING_LEVEL not in span["data"] - else: - assert ( - span["data"][SPANDATA.GEN_AI_REQUEST_REASONING_LEVEL] == expected_level - ) + assert ( + span["attributes"][SPANDATA.GEN_AI_REQUEST_REASONING_LEVEL] + == expected_level + ) -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.skipif(SKIP_RESPONSES_TESTS, reason="Responses API not available") def test_error_in_responses_api( sentry_init, - capture_events, capture_items, - stream_gen_ai_spans, - span_streaming, ): sentry_init( - integrations=[OpenAIIntegration(include_prompts=True)], + integrations=[OpenAIIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = OpenAI(api_key="z") client.responses._post = mock.Mock( side_effect=OpenAIError("API rate limit reached") ) + items = capture_items("event", "span") - if span_streaming: - items = capture_items("event", "span") - - with sentry_sdk.traces.start_span(name="openai tx"), pytest.raises(OpenAIError): - client.responses.create( - model="gpt-4o", - instructions="You are a coding assistant that talks like a pirate.", - input="How do I check if a Python object is an instance of a class?", - ) - - # make sure the span where the error occurred is captured - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert spans[0]["attributes"]["sentry.op"] == "gen_ai.responses" - - (error_event,) = (item.payload for item in items if item.type == "event") - - assert error_event["level"] == "error" - assert error_event["exception"]["values"][0]["type"] == "OpenAIError" - - assert spans[1]["is_segment"] is True - assert error_event["contexts"]["trace"]["trace_id"] == spans[1]["trace_id"] - elif stream_gen_ai_spans: - items = capture_items("event", "transaction", "span") - - with start_transaction(name="openai tx"), pytest.raises(OpenAIError): - client.responses.create( - model="gpt-4o", - instructions="You are a coding assistant that talks like a pirate.", - input="How do I check if a Python object is an instance of a class?", - ) - - # make sure the span where the error occurred is captured - spans = [item.payload for item in items if item.type == "span"] - assert spans[0]["attributes"]["sentry.op"] == "gen_ai.responses" - - (error_event,) = (item.payload for item in items if item.type == "event") - - assert error_event["level"] == "error" - assert error_event["exception"]["values"][0]["type"] == "OpenAIError" - - (transaction_event,) = ( - item.payload for item in items if item.type == "transaction" - ) - assert ( - error_event["contexts"]["trace"]["trace_id"] - == transaction_event["contexts"]["trace"]["trace_id"] + with pytest.raises(OpenAIError): + client.responses.create( + model="gpt-4o", + instructions="You are a coding assistant that talks like a pirate.", + input="How do I check if a Python object is an instance of a class?", ) - else: - events = capture_events() - with start_transaction(name="openai tx"), pytest.raises(OpenAIError): - client.responses.create( - model="gpt-4o", - instructions="You are a coding assistant that talks like a pirate.", - input="How do I check if a Python object is an instance of a class?", - ) + # make sure the span where the error occurred is captured + sentry_sdk.flush() + spans = [item.payload for item in items if item.type == "span"] + assert spans[0]["attributes"]["sentry.op"] == "gen_ai.responses" - (error_event, transaction_event) = events + (error_event,) = (item.payload for item in items if item.type == "event") - assert transaction_event["type"] == "transaction" - # make sure the span where the error occurred is captured - assert transaction_event["spans"][0]["op"] == "gen_ai.responses" + assert error_event["level"] == "error" + assert error_event["exception"]["values"][0]["type"] == "OpenAIError" - assert error_event["level"] == "error" - assert error_event["exception"]["values"][0]["type"] == "OpenAIError" - assert ( - error_event["contexts"]["trace"]["trace_id"] - == transaction_event["contexts"]["trace"]["trace_id"] - ) + assert error_event["contexts"]["trace"]["trace_id"] == spans[0]["trace_id"] -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio @pytest.mark.skipif(SKIP_RESPONSES_TESTS, reason="Responses API not available") @pytest.mark.parametrize( @@ -6651,175 +4600,68 @@ def test_error_in_responses_api( ) async def test_ai_client_span_responses_async_api( sentry_init, - capture_events, capture_items, instructions, input, expected_system_instructions, expected_request_messages, - stream_gen_ai_spans, - span_streaming, ): sentry_init( - integrations=[OpenAIIntegration(include_prompts=True)], + integrations=[OpenAIIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = AsyncOpenAI(api_key="z") client.responses._post = AsyncMock(return_value=EXAMPLE_RESPONSE) + items = capture_items("span") + + await client.responses.create( + model="gpt-4o", + instructions=instructions, + input=input, + max_output_tokens=100, + temperature=0.7, + top_p=0.9, + reasoning={"effort": "high"}, + ) - if span_streaming: - items = capture_items("span") - - with sentry_sdk.traces.start_span(name="openai tx"): - await client.responses.create( - model="gpt-4o", - instructions=instructions, - input=input, - max_output_tokens=100, - temperature=0.7, - top_p=0.9, - reasoning={"effort": "high"}, - ) - - sentry_sdk.flush() - spans = [item.payload for item in items] - - assert len(spans) == 2 - - expected_data = { - "gen_ai.operation.name": "responses", - "gen_ai.request.max_tokens": 100, - "gen_ai.request.temperature": 0.7, - "gen_ai.request.top_p": 0.9, - "gen_ai.request.reasoning.level": "high", - "gen_ai.request.messages": safe_serialize(expected_request_messages), - "gen_ai.request.model": "gpt-4o", - "gen_ai.response.model": "response-model-id", - "gen_ai.response.streaming": False, - "gen_ai.system": "openai", - "gen_ai.usage.input_tokens": 20, - "gen_ai.usage.input_tokens.cached": 5, - "gen_ai.usage.output_tokens": 10, - "gen_ai.usage.output_tokens.reasoning": 8, - "gen_ai.usage.total_tokens": 30, - "gen_ai.response.text": "the model response", - "sentry.op": "gen_ai.responses", - "sentry.origin": "auto.ai.openai", - "sentry.segment.name": "openai tx", - } - - if expected_system_instructions is not None: - expected_data["gen_ai.system_instructions"] = safe_serialize( - expected_system_instructions - ) - - for attr, value in expected_data.items(): - assert spans[0]["attributes"][attr] == value - - elif stream_gen_ai_spans: - items = capture_items("span") - - with start_transaction(name="openai tx"): - await client.responses.create( - model="gpt-4o", - instructions=instructions, - input=input, - max_output_tokens=100, - temperature=0.7, - top_p=0.9, - reasoning={"effort": "high"}, - ) - - spans = [item.payload for item in items] - - assert len(spans) == 1 - - expected_data = { - "gen_ai.operation.name": "responses", - "gen_ai.request.max_tokens": 100, - "gen_ai.request.temperature": 0.7, - "gen_ai.request.top_p": 0.9, - "gen_ai.request.reasoning.level": "high", - "gen_ai.request.messages": safe_serialize(expected_request_messages), - "gen_ai.request.model": "gpt-4o", - "gen_ai.response.model": "response-model-id", - "gen_ai.response.streaming": False, - "gen_ai.system": "openai", - "gen_ai.usage.input_tokens": 20, - "gen_ai.usage.input_tokens.cached": 5, - "gen_ai.usage.output_tokens": 10, - "gen_ai.usage.output_tokens.reasoning": 8, - "gen_ai.usage.total_tokens": 30, - "gen_ai.response.text": "the model response", - "sentry.op": "gen_ai.responses", - "sentry.origin": "auto.ai.openai", - "sentry.segment.name": "openai tx", - } - - if expected_system_instructions is not None: - expected_data["gen_ai.system_instructions"] = safe_serialize( - expected_system_instructions - ) - - for attr, value in expected_data.items(): - assert spans[0]["attributes"][attr] == value - - else: - events = capture_events() - - with start_transaction(name="openai tx"): - await client.responses.create( - model="gpt-4o", - instructions=instructions, - input=input, - max_output_tokens=100, - temperature=0.7, - top_p=0.9, - reasoning={"effort": "high"}, - ) + sentry_sdk.flush() + spans = [item.payload for item in items] + + assert len(spans) == 1 + + expected_data = { + "gen_ai.operation.name": "responses", + "gen_ai.request.max_tokens": 100, + "gen_ai.request.temperature": 0.7, + "gen_ai.request.top_p": 0.9, + "gen_ai.request.reasoning.level": "high", + "gen_ai.request.messages": safe_serialize(expected_request_messages), + "gen_ai.request.model": "gpt-4o", + "gen_ai.response.model": "response-model-id", + "gen_ai.response.streaming": False, + SPANDATA.GEN_AI_PROVIDER_NAME: "openai", + "gen_ai.usage.input_tokens": 20, + SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS: 5, + "gen_ai.usage.output_tokens": 10, + SPANDATA.GEN_AI_USAGE_REASONING_OUTPUT_TOKENS: 8, + "gen_ai.usage.total_tokens": 30, + "gen_ai.response.text": "the model response", + "sentry.op": "gen_ai.responses", + "sentry.origin": "auto.ai.openai", + } - (transaction,) = events - spans = transaction["spans"] - - assert len(spans) == 1 - assert spans[0]["op"] == "gen_ai.responses" - assert spans[0]["origin"] == "auto.ai.openai" - - expected_data = { - "gen_ai.operation.name": "responses", - "gen_ai.request.max_tokens": 100, - "gen_ai.request.temperature": 0.7, - "gen_ai.request.top_p": 0.9, - "gen_ai.request.reasoning.level": "high", - "gen_ai.request.messages": safe_serialize(expected_request_messages[-1:]), - "gen_ai.request.model": "gpt-4o", - "gen_ai.response.model": "response-model-id", - "gen_ai.response.streaming": False, - "gen_ai.system": "openai", - "gen_ai.usage.input_tokens": 20, - "gen_ai.usage.input_tokens.cached": 5, - "gen_ai.usage.output_tokens": 10, - "gen_ai.usage.output_tokens.reasoning": 8, - "gen_ai.usage.total_tokens": 30, - "gen_ai.response.text": "the model response", - } - - if expected_system_instructions is not None: - expected_data["gen_ai.system_instructions"] = safe_serialize( - expected_system_instructions - ) + if expected_system_instructions is not None: + expected_data["gen_ai.system_instructions"] = safe_serialize( + expected_system_instructions + ) - for attr, value in expected_data.items(): - assert spans[0]["data"][attr] == value + for attr, value in expected_data.items(): + assert spans[0]["attributes"][attr] == value -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio @pytest.mark.parametrize( "instructions,input,expected_system_instructions,expected_request_messages", @@ -6967,7 +4809,6 @@ async def test_ai_client_span_responses_async_api( @pytest.mark.skipif(SKIP_RESPONSES_TESTS, reason="Responses API not available") async def test_ai_client_span_streaming_responses_async_api( sentry_init, - capture_events, capture_items, instructions, input, @@ -6976,244 +4817,117 @@ async def test_ai_client_span_streaming_responses_async_api( get_model_response, async_iterator, server_side_event_chunks, - stream_gen_ai_spans, - span_streaming, ): sentry_init( - integrations=[OpenAIIntegration(include_prompts=True)], + integrations=[OpenAIIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = AsyncOpenAI(api_key="z") returned_stream = get_model_response( async_iterator(server_side_event_chunks(EXAMPLE_RESPONSES_STREAM)) ) - - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - ctx = ( - sentry_sdk.traces.start_span(name="openai tx") - if span_streaming - else start_transaction(name="openai tx") + items = capture_items("span") + + with mock.patch.object( + client.responses._client._client, + "send", + return_value=returned_stream, + ): + result = await client.responses.create( + model="gpt-4o", + instructions=instructions, + input=input, + stream=True, + max_output_tokens=100, + temperature=0.7, + top_p=0.9, + reasoning={"effort": "high"}, ) - with mock.patch.object( - client.responses._client._client, - "send", - return_value=returned_stream, - ), ctx: - result = await client.responses.create( - model="gpt-4o", - instructions=instructions, - input=input, - stream=True, - max_output_tokens=100, - temperature=0.7, - top_p=0.9, - reasoning={"effort": "high"}, - ) - async for _ in result: - pass - - sentry_sdk.flush() - spans = [item.payload for item in items] - spans = [ - span - for span in spans - if span["attributes"].get("sentry.op") == OP.GEN_AI_RESPONSES - ] - - assert len(spans) == 1 - - expected_data = { - "gen_ai.operation.name": "responses", - "gen_ai.request.max_tokens": 100, - "gen_ai.request.messages": safe_serialize(expected_request_messages), - "gen_ai.request.temperature": 0.7, - "gen_ai.request.top_p": 0.9, - "gen_ai.request.reasoning.level": "high", - "gen_ai.response.model": "response-model-id", - "gen_ai.response.streaming": True, - "gen_ai.system": "openai", - "gen_ai.response.time_to_first_token": mock.ANY, - "gen_ai.usage.input_tokens": 20, - "gen_ai.usage.input_tokens.cached": 5, - "gen_ai.usage.output_tokens": 10, - "gen_ai.usage.output_tokens.reasoning": 8, - "gen_ai.usage.total_tokens": 30, - "gen_ai.request.model": "gpt-4o", - "gen_ai.response.text": "hello world", - "sentry.environment": "production", - "sentry.op": "gen_ai.responses", - "sentry.origin": "auto.ai.openai", - "sentry.segment.name": "openai tx", - } - - if expected_system_instructions is not None: - expected_data["gen_ai.system_instructions"] = safe_serialize( - expected_system_instructions - ) - - for attr, value in expected_data.items(): - assert spans[0]["attributes"][attr] == value - - else: - events = capture_events() - - with mock.patch.object( - client.responses._client._client, - "send", - return_value=returned_stream, - ), start_transaction(name="openai tx"): - result = await client.responses.create( - model="gpt-4o", - instructions=instructions, - input=input, - stream=True, - max_output_tokens=100, - temperature=0.7, - top_p=0.9, - reasoning={"effort": "high"}, - ) - async for _ in result: - pass + async for _ in result: + pass + + sentry_sdk.flush() + spans = [item.payload for item in items] + spans = [ + span + for span in spans + if span["attributes"].get("sentry.op") == OP.GEN_AI_RESPONSES + ] - (transaction,) = events - spans = [ - span for span in transaction["spans"] if span["op"] == OP.GEN_AI_RESPONSES - ] + assert len(spans) == 1 + + expected_data = { + "gen_ai.operation.name": "responses", + "gen_ai.request.max_tokens": 100, + "gen_ai.request.messages": safe_serialize(expected_request_messages), + "gen_ai.request.temperature": 0.7, + "gen_ai.request.top_p": 0.9, + "gen_ai.request.reasoning.level": "high", + "gen_ai.response.model": "response-model-id", + "gen_ai.response.streaming": True, + SPANDATA.GEN_AI_PROVIDER_NAME: "openai", + SPANDATA.GEN_AI_RESPONSE_TIME_TO_FIRST_CHUNK: mock.ANY, + "gen_ai.usage.input_tokens": 20, + SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS: 5, + "gen_ai.usage.output_tokens": 10, + SPANDATA.GEN_AI_USAGE_REASONING_OUTPUT_TOKENS: 8, + "gen_ai.usage.total_tokens": 30, + "gen_ai.request.model": "gpt-4o", + "gen_ai.response.text": "hello world", + "sentry.environment": "production", + "sentry.op": "gen_ai.responses", + "sentry.origin": "auto.ai.openai", + } - assert len(spans) == 1 - assert spans[0]["origin"] == "auto.ai.openai" - - expected_data = { - "gen_ai.operation.name": "responses", - "gen_ai.request.max_tokens": 100, - "gen_ai.request.messages": safe_serialize(expected_request_messages[-1:]), - "gen_ai.request.temperature": 0.7, - "gen_ai.request.top_p": 0.9, - "gen_ai.request.reasoning.level": "high", - "gen_ai.response.model": "response-model-id", - "gen_ai.response.streaming": True, - "gen_ai.system": "openai", - "gen_ai.response.time_to_first_token": mock.ANY, - "gen_ai.usage.input_tokens": 20, - "gen_ai.usage.input_tokens.cached": 5, - "gen_ai.usage.output_tokens": 10, - "gen_ai.usage.output_tokens.reasoning": 8, - "gen_ai.usage.total_tokens": 30, - "gen_ai.request.model": "gpt-4o", - "gen_ai.response.text": "hello world", - } - - if expected_system_instructions is not None: - expected_data["gen_ai.system_instructions"] = safe_serialize( - expected_system_instructions - ) + if expected_system_instructions is not None: + expected_data["gen_ai.system_instructions"] = safe_serialize( + expected_system_instructions + ) - for attr, value in expected_data.items(): - assert spans[0]["data"][attr] == value + for attr, value in expected_data.items(): + assert spans[0]["attributes"][attr] == value -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio @pytest.mark.skipif(SKIP_RESPONSES_TESTS, reason="Responses API not available") async def test_error_in_responses_async_api( sentry_init, - capture_events, capture_items, - stream_gen_ai_spans, - span_streaming, ): sentry_init( - integrations=[OpenAIIntegration(include_prompts=True)], + integrations=[OpenAIIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = AsyncOpenAI(api_key="z") client.responses._post = AsyncMock( side_effect=OpenAIError("API rate limit reached") ) + items = capture_items("event", "span") - if span_streaming: - items = capture_items("event", "span") - - with sentry_sdk.traces.start_span(name="openai tx"), pytest.raises(OpenAIError): - await client.responses.create( - model="gpt-4o", - instructions="You are a coding assistant that talks like a pirate.", - input="How do I check if a Python object is an instance of a class?", - ) - - # make sure the span where the error occurred is captured - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert spans[0]["attributes"]["sentry.op"] == "gen_ai.responses" - - (error_event,) = (item.payload for item in items if item.type == "event") - - assert error_event["level"] == "error" - assert error_event["exception"]["values"][0]["type"] == "OpenAIError" - - assert spans[1]["is_segment"] is True - assert error_event["contexts"]["trace"]["trace_id"] == spans[1]["trace_id"] - elif stream_gen_ai_spans: - items = capture_items("event", "transaction", "span") - - with start_transaction(name="openai tx"), pytest.raises(OpenAIError): - await client.responses.create( - model="gpt-4o", - instructions="You are a coding assistant that talks like a pirate.", - input="How do I check if a Python object is an instance of a class?", - ) - - # make sure the span where the error occurred is captured - spans = [item.payload for item in items if item.type == "span"] - assert spans[0]["attributes"]["sentry.op"] == "gen_ai.responses" - - (error_event,) = (item.payload for item in items if item.type == "event") - - assert error_event["level"] == "error" - assert error_event["exception"]["values"][0]["type"] == "OpenAIError" - - (transaction_event,) = ( - item.payload for item in items if item.type == "transaction" - ) - assert ( - error_event["contexts"]["trace"]["trace_id"] - == transaction_event["contexts"]["trace"]["trace_id"] + with pytest.raises(OpenAIError): + await client.responses.create( + model="gpt-4o", + instructions="You are a coding assistant that talks like a pirate.", + input="How do I check if a Python object is an instance of a class?", ) - else: - events = capture_events() - with start_transaction(name="openai tx"), pytest.raises(OpenAIError): - await client.responses.create( - model="gpt-4o", - instructions="You are a coding assistant that talks like a pirate.", - input="How do I check if a Python object is an instance of a class?", - ) + # make sure the span where the error occurred is captured + sentry_sdk.flush() + spans = [item.payload for item in items if item.type == "span"] + assert spans[0]["attributes"]["sentry.op"] == "gen_ai.responses" - (error_event, transaction_event) = events + (error_event,) = (item.payload for item in items if item.type == "event") - assert transaction_event["type"] == "transaction" - # make sure the span where the error occurred is captured - assert transaction_event["spans"][0]["op"] == "gen_ai.responses" + assert error_event["level"] == "error" + assert error_event["exception"]["values"][0]["type"] == "OpenAIError" - assert error_event["level"] == "error" - assert error_event["exception"]["values"][0]["type"] == "OpenAIError" - assert ( - error_event["contexts"]["trace"]["trace_id"] - == transaction_event["contexts"]["trace"]["trace_id"] - ) + assert error_event["contexts"]["trace"]["trace_id"] == spans[0]["trace_id"] if SKIP_RESPONSES_TESTS: @@ -7290,35 +5004,23 @@ async def test_error_in_responses_async_api( ] -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize( - "send_default_pii, include_prompts", - [(True, True), (True, False), (False, True), (False, False)], + "send_default_pii", + [True, False], ) @pytest.mark.skipif(SKIP_RESPONSES_TESTS, reason="Responses API not available") def test_streaming_responses_api( sentry_init, - capture_events, capture_items, send_default_pii, - include_prompts, get_model_response, server_side_event_chunks, - stream_gen_ai_spans, - span_streaming, ): sentry_init( - integrations=[ - OpenAIIntegration( - include_prompts=include_prompts, - ) - ], + integrations=[OpenAIIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = OpenAI(api_key="z") @@ -7327,235 +5029,125 @@ def test_streaming_responses_api( EXAMPLE_RESPONSES_STREAM, ) ) + items = capture_items("span") + + with mock.patch.object( + client.responses._client._client, + "send", + return_value=returned_stream, + ): + response_stream = client.responses.create( + model="some-model", + input="hello", + stream=True, + max_output_tokens=100, + temperature=0.7, + top_p=0.9, + reasoning={"effort": "high"}, + ) - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with mock.patch.object( - client.responses._client._client, - "send", - return_value=returned_stream, - ), start_transaction(name="openai tx"): - response_stream = client.responses.create( - model="some-model", - input="hello", - stream=True, - max_output_tokens=100, - temperature=0.7, - top_p=0.9, - reasoning={"effort": "high"}, - ) - - response_string = "" - for item in response_stream: - if hasattr(item, "delta"): - response_string += item.delta - - assert response_string == "hello world" - - sentry_sdk.flush() - (span,) = (item.payload for item in items) - assert span["attributes"]["sentry.op"] == "gen_ai.responses" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "openai" - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 100 - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TEMPERATURE] == 0.7 - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TOP_P] == 0.9 - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_REASONING_LEVEL] == "high" - - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_MODEL] == "response-model-id" - - if send_default_pii and include_prompts: - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] == '["hello"]' - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "hello world" - else: - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] - - assert span["attributes"]["gen_ai.usage.input_tokens"] == 20 - assert span["attributes"]["gen_ai.usage.output_tokens"] == 10 - assert span["attributes"]["gen_ai.usage.total_tokens"] == 30 - else: - events = capture_events() - - with mock.patch.object( - client.responses._client._client, - "send", - return_value=returned_stream, - ), start_transaction(name="openai tx"): - response_stream = client.responses.create( - model="some-model", - input="hello", - stream=True, - max_output_tokens=100, - temperature=0.7, - top_p=0.9, - reasoning={"effort": "high"}, - ) - - response_string = "" - for item in response_stream: - if hasattr(item, "delta"): - response_string += item.delta + response_string = "" + for item in response_stream: + if hasattr(item, "delta"): + response_string += item.delta - assert response_string == "hello world" + assert response_string == "hello world" - (transaction,) = events - (span,) = transaction["spans"] - assert span["op"] == "gen_ai.responses" - assert span["data"][SPANDATA.GEN_AI_SYSTEM] == "openai" - assert span["data"][SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 100 - assert span["data"][SPANDATA.GEN_AI_REQUEST_TEMPERATURE] == 0.7 - assert span["data"][SPANDATA.GEN_AI_REQUEST_TOP_P] == 0.9 - assert span["data"][SPANDATA.GEN_AI_REQUEST_REASONING_LEVEL] == "high" + sentry_sdk.flush() + (span,) = (item.payload for item in items) + assert span["attributes"]["sentry.op"] == "gen_ai.responses" + assert span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "openai" + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 100 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TEMPERATURE] == 0.7 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TOP_P] == 0.9 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_REASONING_LEVEL] == "high" - assert span["data"][SPANDATA.GEN_AI_RESPONSE_MODEL] == "response-model-id" + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_MODEL] == "response-model-id" - if send_default_pii and include_prompts: - assert span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES] == '["hello"]' - assert span["data"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "hello world" - else: - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["data"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["data"] + if send_default_pii: + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] == '["hello"]' + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "hello world" + else: + assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] + assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] - assert span["data"]["gen_ai.usage.input_tokens"] == 20 - assert span["data"]["gen_ai.usage.output_tokens"] == 10 - assert span["data"]["gen_ai.usage.total_tokens"] == 30 + assert span["attributes"]["gen_ai.usage.input_tokens"] == 20 + assert span["attributes"]["gen_ai.usage.output_tokens"] == 10 + assert span["attributes"]["gen_ai.usage.total_tokens"] == 30 -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio @pytest.mark.parametrize( - "send_default_pii, include_prompts", - [(True, True), (True, False), (False, True), (False, False)], + "send_default_pii", + [True, False], ) @pytest.mark.skipif(SKIP_RESPONSES_TESTS, reason="Responses API not available") async def test_streaming_responses_api_async( sentry_init, - capture_events, capture_items, send_default_pii, - include_prompts, get_model_response, async_iterator, server_side_event_chunks, - stream_gen_ai_spans, - span_streaming, ): sentry_init( - integrations=[ - OpenAIIntegration( - include_prompts=include_prompts, - ) - ], + integrations=[OpenAIIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = AsyncOpenAI(api_key="z") returned_stream = get_model_response( async_iterator(server_side_event_chunks(EXAMPLE_RESPONSES_STREAM)) ) + items = capture_items("span") + + with mock.patch.object( + client.responses._client._client, + "send", + return_value=returned_stream, + ): + response_stream = await client.responses.create( + model="some-model", + input="hello", + stream=True, + max_output_tokens=100, + temperature=0.7, + top_p=0.9, + reasoning={"effort": "high"}, + ) - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with mock.patch.object( - client.responses._client._client, - "send", - return_value=returned_stream, - ), start_transaction(name="openai tx"): - response_stream = await client.responses.create( - model="some-model", - input="hello", - stream=True, - max_output_tokens=100, - temperature=0.7, - top_p=0.9, - reasoning={"effort": "high"}, - ) - - response_string = "" - async for item in response_stream: - if hasattr(item, "delta"): - response_string += item.delta - - assert response_string == "hello world" - - sentry_sdk.flush() - (span,) = (item.payload for item in items) - assert span["attributes"]["sentry.op"] == "gen_ai.responses" - assert span["attributes"][SPANDATA.GEN_AI_SYSTEM] == "openai" - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 100 - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TEMPERATURE] == 0.7 - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TOP_P] == 0.9 - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_REASONING_LEVEL] == "high" - - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_MODEL] == "response-model-id" - - if send_default_pii and include_prompts: - assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] == '["hello"]' - assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "hello world" - else: - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] - - assert span["attributes"]["gen_ai.usage.input_tokens"] == 20 - assert span["attributes"]["gen_ai.usage.output_tokens"] == 10 - assert span["attributes"]["gen_ai.usage.total_tokens"] == 30 - else: - events = capture_events() - - with mock.patch.object( - client.responses._client._client, - "send", - return_value=returned_stream, - ), start_transaction(name="openai tx"): - response_stream = await client.responses.create( - model="some-model", - input="hello", - stream=True, - max_output_tokens=100, - temperature=0.7, - top_p=0.9, - reasoning={"effort": "high"}, - ) - - response_string = "" - async for item in response_stream: - if hasattr(item, "delta"): - response_string += item.delta + response_string = "" + async for item in response_stream: + if hasattr(item, "delta"): + response_string += item.delta - assert response_string == "hello world" + assert response_string == "hello world" - (transaction,) = events - (span,) = transaction["spans"] - assert span["op"] == "gen_ai.responses" - assert span["data"][SPANDATA.GEN_AI_SYSTEM] == "openai" - assert span["data"][SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 100 - assert span["data"][SPANDATA.GEN_AI_REQUEST_TEMPERATURE] == 0.7 - assert span["data"][SPANDATA.GEN_AI_REQUEST_TOP_P] == 0.9 - assert span["data"][SPANDATA.GEN_AI_REQUEST_REASONING_LEVEL] == "high" + sentry_sdk.flush() + (span,) = (item.payload for item in items) + assert span["attributes"]["sentry.op"] == "gen_ai.responses" + assert span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "openai" + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 100 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TEMPERATURE] == 0.7 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_TOP_P] == 0.9 + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_REASONING_LEVEL] == "high" - assert span["data"][SPANDATA.GEN_AI_RESPONSE_MODEL] == "response-model-id" + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_MODEL] == "response-model-id" - if send_default_pii and include_prompts: - assert span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES] == '["hello"]' - assert span["data"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "hello world" - else: - assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["data"] - assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["data"] + if send_default_pii: + assert span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] == '["hello"]' + assert span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == "hello world" + else: + assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span["attributes"] + assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span["attributes"] - assert span["data"]["gen_ai.usage.input_tokens"] == 20 - assert span["data"]["gen_ai.usage.output_tokens"] == 10 - assert span["data"]["gen_ai.usage.total_tokens"] == 30 + assert span["attributes"]["gen_ai.usage.input_tokens"] == 20 + assert span["attributes"]["gen_ai.usage.output_tokens"] == 10 + assert span["attributes"]["gen_ai.usage.total_tokens"] == 30 -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) # Feature added in https://github.com/openai/openai-python/pull/1952 @pytest.mark.skipif( OPENAI_VERSION is None or OPENAI_VERSION < (1, 58, 0), @@ -7572,20 +5164,15 @@ async def test_streaming_responses_api_async( ) def test_chat_completion_reasoning_level( sentry_init, - capture_events, capture_items, reasoning_effort, expected_level, nonstreaming_chat_completions_model_response, - stream_gen_ai_spans, - span_streaming, ): sentry_init( integrations=[OpenAIIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = OpenAI(api_key="z") @@ -7602,51 +5189,27 @@ def test_chat_completion_reasoning_level( ), ) ) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with start_transaction(name="openai tx"): - client.chat.completions.create( - model="some-model", - messages=[{"role": "system", "content": "hello"}], - reasoning_effort=reasoning_effort, - ) + client.chat.completions.create( + model="some-model", + messages=[{"role": "system", "content": "hello"}], + reasoning_effort=reasoning_effort, + ) - sentry_sdk.flush() - span = next(item.payload for item in items if item.type == "span") + sentry_sdk.flush() + span = next(item.payload for item in items if item.type == "span") - if expected_level is None: - assert SPANDATA.GEN_AI_REQUEST_REASONING_LEVEL not in span["attributes"] - else: - assert ( - span["attributes"][SPANDATA.GEN_AI_REQUEST_REASONING_LEVEL] - == expected_level - ) + if expected_level is None: + assert SPANDATA.GEN_AI_REQUEST_REASONING_LEVEL not in span["attributes"] else: - events = capture_events() - - with start_transaction(name="openai tx"): - client.chat.completions.create( - model="some-model", - messages=[{"role": "system", "content": "hello"}], - reasoning_effort=reasoning_effort, - ) - - (event,) = events - span = event["spans"][0] - - if expected_level is None: - assert SPANDATA.GEN_AI_REQUEST_REASONING_LEVEL not in span["data"] - else: - assert ( - span["data"][SPANDATA.GEN_AI_REQUEST_REASONING_LEVEL] == expected_level - ) + assert ( + span["attributes"][SPANDATA.GEN_AI_REQUEST_REASONING_LEVEL] + == expected_level + ) # Test messages with mixed roles including "ai" that should be mapped to "assistant" -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize( "test_message,expected_role", [ @@ -7663,23 +5226,18 @@ def test_chat_completion_reasoning_level( ) def test_openai_message_role_mapping( sentry_init, - capture_events, capture_items, test_message, expected_role, nonstreaming_chat_completions_model_response, - stream_gen_ai_spans, - span_streaming, ): """Test that OpenAI integration properly maps message roles like 'ai' to 'assistant'""" sentry_init( - integrations=[OpenAIIntegration(include_prompts=True)], + integrations=[OpenAIIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = OpenAI(api_key="z") @@ -7698,114 +5256,28 @@ def test_openai_message_role_mapping( ) test_messages = [test_message] + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with start_transaction(name="openai tx"): - client.chat.completions.create(model="test-model", messages=test_messages) - - # Verify that the span was created correctly - sentry_sdk.flush() - span = next(item.payload for item in items) - assert span["attributes"]["sentry.op"] == "gen_ai.chat" - assert SPANDATA.GEN_AI_REQUEST_MESSAGES in span["attributes"] - - stored_messages = json.loads( - span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - ) - else: - events = capture_events() - - with start_transaction(name="openai tx"): - client.chat.completions.create(model="test-model", messages=test_messages) + client.chat.completions.create(model="test-model", messages=test_messages) - # Verify that the span was created correctly - (event,) = events - span = event["spans"][0] - assert span["op"] == "gen_ai.chat" - assert SPANDATA.GEN_AI_REQUEST_MESSAGES in span["data"] + # Verify that the span was created correctly + sentry_sdk.flush() + span = next(item.payload for item in items) + assert span["attributes"]["sentry.op"] == "gen_ai.chat" + assert SPANDATA.GEN_AI_REQUEST_MESSAGES in span["attributes"] - stored_messages = json.loads(span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) + stored_messages = json.loads(span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) assert len(stored_messages) == 1 assert stored_messages[0]["role"] == expected_role -def test_openai_message_truncation( - sentry_init, - capture_events, - nonstreaming_chat_completions_model_response, -): - """Test that large messages are truncated properly in OpenAI integration.""" - sentry_init( - integrations=[OpenAIIntegration(include_prompts=True)], - traces_sample_rate=1.0, - send_default_pii=True, - stream_gen_ai_spans=False, - ) - - client = OpenAI(api_key="z") - client.chat.completions._post = mock.Mock( - return_value=nonstreaming_chat_completions_model_response( - response_id="chat-id", - response_model="gpt-3.5-turbo", - message_content="the model response", - created=10000000, - usage=CompletionUsage( - prompt_tokens=20, - completion_tokens=10, - total_tokens=30, - ), - ) - ) - - large_content = ( - "This is a very long message that will exceed our size limits. " * 1000 - ) - large_messages = [ - {"role": "system", "content": "You are a helpful assistant."}, - {"role": "user", "content": large_content}, - {"role": "assistant", "content": large_content}, - {"role": "user", "content": large_content}, - ] - - events = capture_events() - - with start_transaction(name="openai tx"): - client.chat.completions.create( - model="some-model", - messages=large_messages, - ) - - (event,) = events - span = event["spans"][0] - assert SPANDATA.GEN_AI_REQUEST_MESSAGES in span["data"] - - messages_data = span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - assert isinstance(messages_data, str) - - parsed_messages = json.loads(messages_data) - assert isinstance(parsed_messages, list) - assert len(parsed_messages) <= len(large_messages) - - meta_path = event["_meta"] - span_meta = meta_path["spans"]["0"]["data"] - messages_meta = span_meta[SPANDATA.GEN_AI_REQUEST_MESSAGES] - assert "len" in messages_meta.get("", {}) - - # noinspection PyTypeChecker -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_streaming_chat_completion_ttft( sentry_init, - capture_events, capture_items, get_model_response, server_side_event_chunks, - stream_gen_ai_spans, - span_streaming, ): """ Test that streaming chat completions capture time-to-first-token (TTFT). @@ -7814,8 +5286,6 @@ def test_streaming_chat_completion_ttft( integrations=[OpenAIIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = OpenAI(api_key="z") @@ -7852,73 +5322,42 @@ def test_streaming_chat_completion_ttft( include_event_type=False, ), ) + items = capture_items("span") + + with mock.patch.object( + client.chat._client._client, + "send", + return_value=returned_stream, + ): + response_stream = client.chat.completions.create( + model="some-model", + messages=[{"role": "user", "content": "Say hello"}], + stream=True, + ) + # Consume the stream + for _ in response_stream: + pass - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with mock.patch.object( - client.chat._client._client, - "send", - return_value=returned_stream, - ), start_transaction(name="openai tx"): - response_stream = client.chat.completions.create( - model="some-model", - messages=[{"role": "user", "content": "Say hello"}], - stream=True, - ) - # Consume the stream - for _ in response_stream: - pass - - sentry_sdk.flush() - span = next(item.payload for item in items) - assert span["attributes"]["sentry.op"] == "gen_ai.chat" - - # Verify TTFT is captured - assert SPANDATA.GEN_AI_RESPONSE_TIME_TO_FIRST_TOKEN in span["attributes"] - ttft = span["attributes"][SPANDATA.GEN_AI_RESPONSE_TIME_TO_FIRST_TOKEN] - else: - events = capture_events() - - with mock.patch.object( - client.chat._client._client, - "send", - return_value=returned_stream, - ), start_transaction(name="openai tx"): - response_stream = client.chat.completions.create( - model="some-model", - messages=[{"role": "user", "content": "Say hello"}], - stream=True, - ) - # Consume the stream - for _ in response_stream: - pass - - (tx,) = events - span = tx["spans"][0] - assert span["op"] == "gen_ai.chat" + sentry_sdk.flush() + span = next(item.payload for item in items) + assert span["attributes"]["sentry.op"] == "gen_ai.chat" - # Verify TTFT is captured - assert SPANDATA.GEN_AI_RESPONSE_TIME_TO_FIRST_TOKEN in span["data"] - ttft = span["data"][SPANDATA.GEN_AI_RESPONSE_TIME_TO_FIRST_TOKEN] + # Verify TTFT is captured + assert SPANDATA.GEN_AI_RESPONSE_TIME_TO_FIRST_CHUNK in span["attributes"] + ttft = span["attributes"][SPANDATA.GEN_AI_RESPONSE_TIME_TO_FIRST_CHUNK] assert isinstance(ttft, float) assert ttft > 0 # noinspection PyTypeChecker -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio async def test_streaming_chat_completion_ttft_async( sentry_init, - capture_events, capture_items, get_model_response, async_iterator, server_side_event_chunks, - stream_gen_ai_spans, - span_streaming, ): """ Test that async streaming chat completions capture time-to-first-token (TTFT). @@ -7927,8 +5366,6 @@ async def test_streaming_chat_completion_ttft_async( integrations=[OpenAIIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = AsyncOpenAI(api_key="z") @@ -7967,72 +5404,41 @@ async def test_streaming_chat_completion_ttft_async( ), ) ) + items = capture_items("span") + + with mock.patch.object( + client.chat._client._client, + "send", + return_value=returned_stream, + ): + response_stream = await client.chat.completions.create( + model="some-model", + messages=[{"role": "user", "content": "Say hello"}], + stream=True, + ) + # Consume the stream + async for _ in response_stream: + pass - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with mock.patch.object( - client.chat._client._client, - "send", - return_value=returned_stream, - ), start_transaction(name="openai tx"): - response_stream = await client.chat.completions.create( - model="some-model", - messages=[{"role": "user", "content": "Say hello"}], - stream=True, - ) - # Consume the stream - async for _ in response_stream: - pass - - sentry_sdk.flush() - span = next(item.payload for item in items) - assert span["attributes"]["sentry.op"] == "gen_ai.chat" - - # Verify TTFT is captured - assert SPANDATA.GEN_AI_RESPONSE_TIME_TO_FIRST_TOKEN in span["attributes"] - ttft = span["attributes"][SPANDATA.GEN_AI_RESPONSE_TIME_TO_FIRST_TOKEN] - else: - events = capture_events() - - with mock.patch.object( - client.chat._client._client, - "send", - return_value=returned_stream, - ), start_transaction(name="openai tx"): - response_stream = await client.chat.completions.create( - model="some-model", - messages=[{"role": "user", "content": "Say hello"}], - stream=True, - ) - # Consume the stream - async for _ in response_stream: - pass - - (tx,) = events - span = tx["spans"][0] - assert span["op"] == "gen_ai.chat" + sentry_sdk.flush() + span = next(item.payload for item in items) + assert span["attributes"]["sentry.op"] == "gen_ai.chat" - # Verify TTFT is captured - assert SPANDATA.GEN_AI_RESPONSE_TIME_TO_FIRST_TOKEN in span["data"] - ttft = span["data"][SPANDATA.GEN_AI_RESPONSE_TIME_TO_FIRST_TOKEN] + # Verify TTFT is captured + assert SPANDATA.GEN_AI_RESPONSE_TIME_TO_FIRST_CHUNK in span["attributes"] + ttft = span["attributes"][SPANDATA.GEN_AI_RESPONSE_TIME_TO_FIRST_CHUNK] assert isinstance(ttft, float) assert ttft > 0 # noinspection PyTypeChecker -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.skipif(SKIP_RESPONSES_TESTS, reason="Responses API not available") def test_streaming_responses_api_ttft( sentry_init, - capture_events, capture_items, get_model_response, server_side_event_chunks, - stream_gen_ai_spans, - span_streaming, ): """ Test that streaming responses API captures time-to-first-token (TTFT). @@ -8041,82 +5447,49 @@ def test_streaming_responses_api_ttft( integrations=[OpenAIIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = OpenAI(api_key="z") returned_stream = get_model_response( server_side_event_chunks(EXAMPLE_RESPONSES_STREAM) ) + items = capture_items("span") + + with mock.patch.object( + client.responses._client._client, + "send", + return_value=returned_stream, + ): + response_stream = client.responses.create( + model="some-model", + input="hello", + stream=True, + ) + # Consume the stream + for _ in response_stream: + pass - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with mock.patch.object( - client.responses._client._client, - "send", - return_value=returned_stream, - ), start_transaction(name="openai tx"): - response_stream = client.responses.create( - model="some-model", - input="hello", - stream=True, - ) - # Consume the stream - for _ in response_stream: - pass - - sentry_sdk.flush() - span = next(item.payload for item in items) - assert span["attributes"]["sentry.op"] == "gen_ai.responses" - - # Verify TTFT is captured - assert SPANDATA.GEN_AI_RESPONSE_TIME_TO_FIRST_TOKEN in span["attributes"] - ttft = span["attributes"][SPANDATA.GEN_AI_RESPONSE_TIME_TO_FIRST_TOKEN] - else: - events = capture_events() - - with mock.patch.object( - client.responses._client._client, - "send", - return_value=returned_stream, - ), start_transaction(name="openai tx"): - response_stream = client.responses.create( - model="some-model", - input="hello", - stream=True, - ) - # Consume the stream - for _ in response_stream: - pass - - (tx,) = events - span = tx["spans"][0] - assert span["op"] == "gen_ai.responses" + sentry_sdk.flush() + span = next(item.payload for item in items) + assert span["attributes"]["sentry.op"] == "gen_ai.responses" - # Verify TTFT is captured - assert SPANDATA.GEN_AI_RESPONSE_TIME_TO_FIRST_TOKEN in span["data"] - ttft = span["data"][SPANDATA.GEN_AI_RESPONSE_TIME_TO_FIRST_TOKEN] + # Verify TTFT is captured + assert SPANDATA.GEN_AI_RESPONSE_TIME_TO_FIRST_CHUNK in span["attributes"] + ttft = span["attributes"][SPANDATA.GEN_AI_RESPONSE_TIME_TO_FIRST_CHUNK] assert isinstance(ttft, float) assert ttft > 0 # noinspection PyTypeChecker -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio @pytest.mark.skipif(SKIP_RESPONSES_TESTS, reason="Responses API not available") async def test_streaming_responses_api_ttft_async( sentry_init, - capture_events, capture_items, get_model_response, async_iterator, server_side_event_chunks, - stream_gen_ai_spans, - span_streaming, ): """ Test that async streaming responses API captures time-to-first-token (TTFT). @@ -8125,63 +5498,35 @@ async def test_streaming_responses_api_ttft_async( integrations=[OpenAIIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) client = AsyncOpenAI(api_key="z") returned_stream = get_model_response( async_iterator(server_side_event_chunks(EXAMPLE_RESPONSES_STREAM)) ) + items = capture_items("span") + + with mock.patch.object( + client.responses._client._client, + "send", + return_value=returned_stream, + ): + response_stream = await client.responses.create( + model="some-model", + input="hello", + stream=True, + ) + # Consume the stream + async for _ in response_stream: + pass - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with mock.patch.object( - client.responses._client._client, - "send", - return_value=returned_stream, - ), start_transaction(name="openai tx"): - response_stream = await client.responses.create( - model="some-model", - input="hello", - stream=True, - ) - # Consume the stream - async for _ in response_stream: - pass - - sentry_sdk.flush() - span = next(item.payload for item in items) - assert span["attributes"]["sentry.op"] == "gen_ai.responses" - - # Verify TTFT is captured - assert SPANDATA.GEN_AI_RESPONSE_TIME_TO_FIRST_TOKEN in span["attributes"] - ttft = span["attributes"][SPANDATA.GEN_AI_RESPONSE_TIME_TO_FIRST_TOKEN] - else: - events = capture_events() - - with mock.patch.object( - client.responses._client._client, - "send", - return_value=returned_stream, - ), start_transaction(name="openai tx"): - response_stream = await client.responses.create( - model="some-model", - input="hello", - stream=True, - ) - # Consume the stream - async for _ in response_stream: - pass - - (tx,) = events - span = tx["spans"][0] - assert span["op"] == "gen_ai.responses" + sentry_sdk.flush() + span = next(item.payload for item in items) + assert span["attributes"]["sentry.op"] == "gen_ai.responses" - # Verify TTFT is captured - assert SPANDATA.GEN_AI_RESPONSE_TIME_TO_FIRST_TOKEN in span["data"] - ttft = span["data"][SPANDATA.GEN_AI_RESPONSE_TIME_TO_FIRST_TOKEN] + # Verify TTFT is captured + assert SPANDATA.GEN_AI_RESPONSE_TIME_TO_FIRST_CHUNK in span["attributes"] + ttft = span["attributes"][SPANDATA.GEN_AI_RESPONSE_TIME_TO_FIRST_CHUNK] assert isinstance(ttft, float) assert ttft > 0 diff --git a/tests/integrations/openai_agents/test_openai_agents.py b/tests/integrations/openai_agents/test_openai_agents.py index 8bc49a2c9f..227001b3ec 100644 --- a/tests/integrations/openai_agents/test_openai_agents.py +++ b/tests/integrations/openai_agents/test_openai_agents.py @@ -16,7 +16,7 @@ Usage, ) from agents.computer import Computer -from agents.exceptions import MaxTurnsExceeded, ModelBehaviorError +from agents.exceptions import ModelBehaviorError from agents.items import ( ResponseFunctionToolCall, ResponseOutputMessage, @@ -24,7 +24,6 @@ ) from agents.models.openai_responses import OpenAIResponsesModel from agents.tool import HostedMCPTool -from agents.version import __version__ as OPENAI_AGENTS_VERSION from openai import AsyncOpenAI, InternalServerError from openai.types.responses.tool_param import CodeInterpreter, ImageGeneration @@ -68,13 +67,12 @@ from typing import Any, cast import sentry_sdk -from sentry_sdk import start_span from sentry_sdk.consts import OP, SPANDATA from sentry_sdk.integrations.logging import LoggingIntegration from sentry_sdk.integrations.openai_agents import OpenAIAgentsIntegration from sentry_sdk.integrations.openai_agents.utils import _set_input_data, safe_serialize from sentry_sdk.integrations.stdlib import StdlibIntegration -from sentry_sdk.utils import package_version, parse_version +from sentry_sdk.utils import package_version OPENAI_VERSION = package_version("openai") @@ -267,18 +265,13 @@ def drag(self, _path): self.calls.append("drag") -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio async def test_tool_definitions( sentry_init, - capture_events, capture_items, test_agent, nonstreaming_responses_model_response, get_model_response, - stream_gen_ai_spans, - span_streaming, ): """ Verifies that the `gen_ai.tool.definitions` attribute is set. @@ -318,9 +311,7 @@ def some_function(a: str, b: list[int]) -> str: ] expected_available_tools = [ - {"type": "web_search", "name": "web_search_preview"} - if parse_version(OPENAI_AGENTS_VERSION) < (0, 3, 0) - else {"type": "web_search", "name": "web_search"}, + {"type": "web_search", "name": "web_search"}, {"type": "file_search", "name": "file_search"}, {"type": "computer", "name": "computer_use_preview"}, {"type": "mcp", "name": "hosted_mcp"}, @@ -392,121 +383,48 @@ def some_function(a: str, b: list[int]) -> str: response = get_model_response( nonstreaming_responses_model_response, serialize_pydantic=True ) - - if span_streaming: - with patch.object( - agent.model._client._client, - "send", - return_value=response, - ) as _: - sentry_init( - integrations=[OpenAIAgentsIntegration()], - disabled_integrations=[StdlibIntegration], - traces_sample_rate=1.0, - send_default_pii=False, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream", - ) - - items = capture_items("span") - - result = await agents.Runner.run( - agent, - "Test input", - run_config=test_run_config, - ) - - assert result is not None - assert result.final_output == "Hello, how can I help you?" - - sentry_sdk.flush() - spans = [item.payload for item in items] - ai_client_span = next( - span for span in spans if span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - ) - - assert ( - json.loads(ai_client_span["attributes"][SPANDATA.GEN_AI_TOOL_DEFINITIONS]) - == expected_available_tools + with patch.object( + agent.model._client._client, + "send", + return_value=response, + ) as _: + sentry_init( + integrations=[OpenAIAgentsIntegration()], + disabled_integrations=[StdlibIntegration], + traces_sample_rate=1.0, + send_default_pii=False, ) - elif stream_gen_ai_spans: - with patch.object( - agent.model._client._client, - "send", - return_value=response, - ) as _: - sentry_init( - integrations=[OpenAIAgentsIntegration()], - traces_sample_rate=1.0, - send_default_pii=False, - stream_gen_ai_spans=stream_gen_ai_spans, - ) - - items = capture_items("span", "transaction") - - result = await agents.Runner.run( - agent, - "Test input", - run_config=test_run_config, - ) - - assert result is not None - assert result.final_output == "Hello, how can I help you?" - spans = [item.payload for item in items if item.type == "span"] - ai_client_span = next( - span for span in spans if span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - ) + items = capture_items("span") - assert ( - json.loads(ai_client_span["attributes"][SPANDATA.GEN_AI_TOOL_DEFINITIONS]) - == expected_available_tools + result = await agents.Runner.run( + agent, + "Test input", + run_config=test_run_config, ) - else: - with patch.object( - agent.model._client._client, - "send", - return_value=response, - ) as _: - sentry_init( - integrations=[OpenAIAgentsIntegration()], - traces_sample_rate=1.0, - send_default_pii=False, - stream_gen_ai_spans=stream_gen_ai_spans, - ) - events = capture_events() - result = await agents.Runner.run( - agent, - "Test input", - run_config=test_run_config, - ) - - assert result is not None - assert result.final_output == "Hello, how can I help you?" + assert result is not None + assert result.final_output == "Hello, how can I help you?" - (transaction,) = events - spans = transaction["spans"] - ai_client_span = next(span for span in spans if span["op"] == OP.GEN_AI_CHAT) + sentry_sdk.flush() + spans = [item.payload for item in items] + ai_client_span = next( + span for span in spans if span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT + ) - assert ( - json.loads(ai_client_span["data"][SPANDATA.GEN_AI_TOOL_DEFINITIONS]) - == expected_available_tools - ) + assert ( + json.loads(ai_client_span["attributes"][SPANDATA.GEN_AI_TOOL_DEFINITIONS]) + == expected_available_tools + ) -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio async def test_agent_invocation_span_no_pii( sentry_init, - capture_events, capture_items, test_agent, nonstreaming_responses_model_response, get_model_response, - stream_gen_ai_spans, - span_streaming, ): client = AsyncOpenAI(api_key="test-key") model = OpenAIResponsesModel(model="gpt-4", openai_client=client) @@ -515,191 +433,62 @@ async def test_agent_invocation_span_no_pii( response = get_model_response( nonstreaming_responses_model_response, serialize_pydantic=True ) - - if span_streaming: - with patch.object( - agent.model._client._client, - "send", - return_value=response, - ) as _: - sentry_init( - integrations=[OpenAIAgentsIntegration()], - disabled_integrations=[StdlibIntegration], - traces_sample_rate=1.0, - send_default_pii=False, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream", - ) - - items = capture_items("span") - - result = await agents.Runner.run( - agent, "Test input", run_config=test_run_config - ) - - assert result is not None - assert result.final_output == "Hello, how can I help you?" - - sentry_sdk.flush() - spans = [item.payload for item in items] - invoke_agent_span = next( - span - for span in spans - if span["attributes"]["sentry.op"] == OP.GEN_AI_INVOKE_AGENT - ) - ai_client_span = next( - span for span in spans if span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - ) - - assert spans[2]["name"] == "test_agent workflow" - assert spans[2]["attributes"]["sentry.origin"] == "auto.ai.openai_agents" - - assert invoke_agent_span["name"] == "invoke_agent test_agent" - - assert ( - SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in invoke_agent_span["attributes"] - ) - assert "gen_ai.request.messages" not in invoke_agent_span["attributes"] - assert "gen_ai.response.text" not in invoke_agent_span["attributes"] - - assert ( - invoke_agent_span["attributes"]["gen_ai.operation.name"] == "invoke_agent" - ) - assert invoke_agent_span["attributes"]["gen_ai.system"] == "openai" - assert invoke_agent_span["attributes"]["gen_ai.agent.name"] == "test_agent" - assert invoke_agent_span["attributes"]["gen_ai.request.max_tokens"] == 100 - assert invoke_agent_span["attributes"]["gen_ai.request.model"] == "gpt-4" - assert invoke_agent_span["attributes"]["gen_ai.request.temperature"] == 0.7 - assert invoke_agent_span["attributes"]["gen_ai.request.top_p"] == 1.0 - - assert ai_client_span["name"] == "chat gpt-4" - assert ai_client_span["attributes"]["gen_ai.operation.name"] == "chat" - assert ai_client_span["attributes"]["gen_ai.system"] == "openai" - assert ai_client_span["attributes"]["gen_ai.agent.name"] == "test_agent" - assert ai_client_span["attributes"]["gen_ai.request.max_tokens"] == 100 - assert ai_client_span["attributes"]["gen_ai.request.model"] == "gpt-4" - assert ai_client_span["attributes"]["gen_ai.request.temperature"] == 0.7 - assert ai_client_span["attributes"]["gen_ai.request.top_p"] == 1.0 - elif stream_gen_ai_spans: - with patch.object( - agent.model._client._client, - "send", - return_value=response, - ) as _: - sentry_init( - integrations=[OpenAIAgentsIntegration()], - traces_sample_rate=1.0, - send_default_pii=False, - stream_gen_ai_spans=stream_gen_ai_spans, - ) - - items = capture_items("span", "transaction") - - result = await agents.Runner.run( - agent, "Test input", run_config=test_run_config - ) - - assert result is not None - assert result.final_output == "Hello, how can I help you?" - - spans = [item.payload for item in items if item.type == "span"] - invoke_agent_span = next( - span - for span in spans - if span["attributes"]["sentry.op"] == OP.GEN_AI_INVOKE_AGENT - ) - ai_client_span = next( - span for span in spans if span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT + with patch.object( + agent.model._client._client, + "send", + return_value=response, + ) as _: + sentry_init( + integrations=[OpenAIAgentsIntegration()], + disabled_integrations=[StdlibIntegration], + traces_sample_rate=1.0, + send_default_pii=False, ) - (transaction,) = (item.payload for item in items if item.type == "transaction") - - assert transaction["transaction"] == "test_agent workflow" - assert transaction["contexts"]["trace"]["origin"] == "auto.ai.openai_agents" - - assert invoke_agent_span["name"] == "invoke_agent test_agent" - - assert ( - SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in invoke_agent_span["attributes"] - ) - assert "gen_ai.request.messages" not in invoke_agent_span["attributes"] - assert "gen_ai.response.text" not in invoke_agent_span["attributes"] + items = capture_items("span") - assert ( - invoke_agent_span["attributes"]["gen_ai.operation.name"] == "invoke_agent" + result = await agents.Runner.run( + agent, "Test input", run_config=test_run_config ) - assert invoke_agent_span["attributes"]["gen_ai.system"] == "openai" - assert invoke_agent_span["attributes"]["gen_ai.agent.name"] == "test_agent" - assert invoke_agent_span["attributes"]["gen_ai.request.max_tokens"] == 100 - assert invoke_agent_span["attributes"]["gen_ai.request.model"] == "gpt-4" - assert invoke_agent_span["attributes"]["gen_ai.request.temperature"] == 0.7 - assert invoke_agent_span["attributes"]["gen_ai.request.top_p"] == 1.0 - - assert ai_client_span["name"] == "chat gpt-4" - assert ai_client_span["attributes"]["gen_ai.operation.name"] == "chat" - assert ai_client_span["attributes"]["gen_ai.system"] == "openai" - assert ai_client_span["attributes"]["gen_ai.agent.name"] == "test_agent" - assert ai_client_span["attributes"]["gen_ai.request.max_tokens"] == 100 - assert ai_client_span["attributes"]["gen_ai.request.model"] == "gpt-4" - assert ai_client_span["attributes"]["gen_ai.request.temperature"] == 0.7 - assert ai_client_span["attributes"]["gen_ai.request.top_p"] == 1.0 - else: - with patch.object( - agent.model._client._client, - "send", - return_value=response, - ) as _: - sentry_init( - integrations=[OpenAIAgentsIntegration()], - traces_sample_rate=1.0, - send_default_pii=False, - stream_gen_ai_spans=stream_gen_ai_spans, - ) - events = capture_events() - - result = await agents.Runner.run( - agent, "Test input", run_config=test_run_config - ) - - assert result is not None - assert result.final_output == "Hello, how can I help you?" - (transaction,) = events - spans = transaction["spans"] - invoke_agent_span = next( - span for span in spans if span["op"] == OP.GEN_AI_INVOKE_AGENT - ) - ai_client_span = next(span for span in spans if span["op"] == OP.GEN_AI_CHAT) + assert result is not None + assert result.final_output == "Hello, how can I help you?" - assert transaction["transaction"] == "test_agent workflow" - assert transaction["contexts"]["trace"]["origin"] == "auto.ai.openai_agents" + sentry_sdk.flush() + spans = [item.payload for item in items] + invoke_agent_span = next( + span + for span in spans + if span["attributes"]["sentry.op"] == OP.GEN_AI_INVOKE_AGENT + ) + ai_client_span = next( + span for span in spans if span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT + ) - assert invoke_agent_span["description"] == "invoke_agent test_agent" + assert invoke_agent_span["name"] == "invoke_agent test_agent" - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in invoke_agent_span["data"] - assert "gen_ai.request.messages" not in invoke_agent_span["data"] - assert "gen_ai.response.text" not in invoke_agent_span["data"] + assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in invoke_agent_span["attributes"] + assert "gen_ai.request.messages" not in invoke_agent_span["attributes"] + assert "gen_ai.response.text" not in invoke_agent_span["attributes"] - assert invoke_agent_span["data"]["gen_ai.operation.name"] == "invoke_agent" - assert invoke_agent_span["data"]["gen_ai.system"] == "openai" - assert invoke_agent_span["data"]["gen_ai.agent.name"] == "test_agent" - assert invoke_agent_span["data"]["gen_ai.request.max_tokens"] == 100 - assert invoke_agent_span["data"]["gen_ai.request.model"] == "gpt-4" - assert invoke_agent_span["data"]["gen_ai.request.temperature"] == 0.7 - assert invoke_agent_span["data"]["gen_ai.request.top_p"] == 1.0 + assert invoke_agent_span["attributes"]["gen_ai.operation.name"] == "invoke_agent" + assert invoke_agent_span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "openai" + assert invoke_agent_span["attributes"]["gen_ai.agent.name"] == "test_agent" + assert invoke_agent_span["attributes"]["gen_ai.request.max_tokens"] == 100 + assert invoke_agent_span["attributes"]["gen_ai.request.model"] == "gpt-4" + assert invoke_agent_span["attributes"]["gen_ai.request.temperature"] == 0.7 + assert invoke_agent_span["attributes"]["gen_ai.request.top_p"] == 1.0 - assert ai_client_span["description"] == "chat gpt-4" - assert ai_client_span["data"]["gen_ai.operation.name"] == "chat" - assert ai_client_span["data"]["gen_ai.system"] == "openai" - assert ai_client_span["data"]["gen_ai.agent.name"] == "test_agent" - assert ai_client_span["data"]["gen_ai.request.max_tokens"] == 100 - assert ai_client_span["data"]["gen_ai.request.model"] == "gpt-4" - assert ai_client_span["data"]["gen_ai.request.temperature"] == 0.7 - assert ai_client_span["data"]["gen_ai.request.top_p"] == 1.0 + assert ai_client_span["name"] == "chat gpt-4" + assert ai_client_span["attributes"]["gen_ai.operation.name"] == "chat" + assert ai_client_span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "openai" + assert ai_client_span["attributes"]["gen_ai.agent.name"] == "test_agent" + assert ai_client_span["attributes"]["gen_ai.request.max_tokens"] == 100 + assert ai_client_span["attributes"]["gen_ai.request.model"] == "gpt-4" + assert ai_client_span["attributes"]["gen_ai.request.temperature"] == 0.7 + assert ai_client_span["attributes"]["gen_ai.request.top_p"] == 1.0 -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize( "init_kwargs,expect_messages", [ @@ -749,15 +538,12 @@ async def test_agent_invocation_span_no_pii( @pytest.mark.asyncio async def test_invoke_agent_span_data_collection_inputs( sentry_init, - capture_events, capture_items, test_agent, nonstreaming_responses_model_response, get_model_response, init_kwargs, expect_messages, - stream_gen_ai_spans, - span_streaming, ): client = AsyncOpenAI(api_key="test-key") model = OpenAIResponsesModel(model="gpt-4", openai_client=client) @@ -775,98 +561,35 @@ async def test_invoke_agent_span_data_collection_inputs( "role": "user", "content": [{"text": "Test input", "type": "text"}], } - expected_messages = ( - [user_message] - if not stream_gen_ai_spans and not span_streaming - else [system_message, user_message] - ) - - if span_streaming: - with patch.object( - agent.model._client._client, - "send", - return_value=response, - ) as _: - sentry_init( - integrations=[OpenAIAgentsIntegration()], - disabled_integrations=[StdlibIntegration], - traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream", - **init_kwargs, - ) - - items = capture_items("span") - - result = await agents.Runner.run( - agent, "Test input", run_config=test_run_config - ) - - assert result is not None - - sentry_sdk.flush() - spans = [item.payload for item in items] - invoke_agent_span = next( - span - for span in spans - if span["attributes"]["sentry.op"] == OP.GEN_AI_INVOKE_AGENT + expected_messages = [system_message, user_message] + with patch.object( + agent.model._client._client, + "send", + return_value=response, + ) as _: + sentry_init( + integrations=[OpenAIAgentsIntegration()], + disabled_integrations=[StdlibIntegration], + traces_sample_rate=1.0, + **init_kwargs, ) - span_data = invoke_agent_span["attributes"] - elif stream_gen_ai_spans: - with patch.object( - agent.model._client._client, - "send", - return_value=response, - ) as _: - sentry_init( - integrations=[OpenAIAgentsIntegration()], - traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - **init_kwargs, - ) - - items = capture_items("span", "transaction") - result = await agents.Runner.run( - agent, "Test input", run_config=test_run_config - ) - - assert result is not None + items = capture_items("span") - spans = [item.payload for item in items if item.type == "span"] - invoke_agent_span = next( - span - for span in spans - if span["attributes"]["sentry.op"] == OP.GEN_AI_INVOKE_AGENT + result = await agents.Runner.run( + agent, "Test input", run_config=test_run_config ) - span_data = invoke_agent_span["attributes"] - else: - with patch.object( - agent.model._client._client, - "send", - return_value=response, - ) as _: - sentry_init( - integrations=[OpenAIAgentsIntegration()], - traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - **init_kwargs, - ) - events = capture_events() - result = await agents.Runner.run( - agent, "Test input", run_config=test_run_config - ) - - assert result is not None + assert result is not None - (transaction,) = events - invoke_agent_span = next( - span - for span in transaction["spans"] - if span["op"] == OP.GEN_AI_INVOKE_AGENT - ) - span_data = invoke_agent_span["data"] + sentry_sdk.flush() + spans = [item.payload for item in items] + invoke_agent_span = next( + span + for span in spans + if span["attributes"]["sentry.op"] == OP.GEN_AI_INVOKE_AGENT + ) + span_data = invoke_agent_span["attributes"] if expect_messages: assert ( @@ -876,8 +599,6 @@ async def test_invoke_agent_span_data_collection_inputs( assert SPANDATA.GEN_AI_REQUEST_MESSAGES not in span_data -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize( "init_kwargs,expect_response_text", [ @@ -927,15 +648,12 @@ async def test_invoke_agent_span_data_collection_inputs( @pytest.mark.asyncio async def test_invoke_agent_span_data_collection_outputs( sentry_init, - capture_events, capture_items, test_agent, nonstreaming_responses_model_response, get_model_response, init_kwargs, expect_response_text, - stream_gen_ai_spans, - span_streaming, ): client = AsyncOpenAI(api_key="test-key") model = OpenAIResponsesModel(model="gpt-4", openai_client=client) @@ -944,102 +662,41 @@ async def test_invoke_agent_span_data_collection_outputs( response = get_model_response( nonstreaming_responses_model_response, serialize_pydantic=True ) + with patch.object( + agent.model._client._client, + "send", + return_value=response, + ) as _: + sentry_init( + integrations=[OpenAIAgentsIntegration()], + disabled_integrations=[StdlibIntegration], + traces_sample_rate=1.0, + **init_kwargs, + ) - if span_streaming: - with patch.object( - agent.model._client._client, - "send", - return_value=response, - ) as _: - sentry_init( - integrations=[OpenAIAgentsIntegration()], - disabled_integrations=[StdlibIntegration], - traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream", - **init_kwargs, - ) - - items = capture_items("span") - - result = await agents.Runner.run( - agent, "Test input", run_config=test_run_config - ) - - assert result is not None + items = capture_items("span") - sentry_sdk.flush() - spans = [item.payload for item in items] - invoke_agent_span = next( - span - for span in spans - if span["attributes"]["sentry.op"] == OP.GEN_AI_INVOKE_AGENT + result = await agents.Runner.run( + agent, "Test input", run_config=test_run_config ) - span_data = invoke_agent_span["attributes"] - elif stream_gen_ai_spans: - with patch.object( - agent.model._client._client, - "send", - return_value=response, - ) as _: - sentry_init( - integrations=[OpenAIAgentsIntegration()], - traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - **init_kwargs, - ) - items = capture_items("span", "transaction") - - result = await agents.Runner.run( - agent, "Test input", run_config=test_run_config - ) + assert result is not None - assert result is not None + sentry_sdk.flush() + spans = [item.payload for item in items] + invoke_agent_span = next( + span + for span in spans + if span["attributes"]["sentry.op"] == OP.GEN_AI_INVOKE_AGENT + ) + span_data = invoke_agent_span["attributes"] - spans = [item.payload for item in items if item.type == "span"] - invoke_agent_span = next( - span - for span in spans - if span["attributes"]["sentry.op"] == OP.GEN_AI_INVOKE_AGENT - ) - span_data = invoke_agent_span["attributes"] - else: - with patch.object( - agent.model._client._client, - "send", - return_value=response, - ) as _: - sentry_init( - integrations=[OpenAIAgentsIntegration()], - traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - **init_kwargs, - ) - events = capture_events() - - result = await agents.Runner.run( - agent, "Test input", run_config=test_run_config - ) - - assert result is not None - - (transaction,) = events - invoke_agent_span = next( - span - for span in transaction["spans"] - if span["op"] == OP.GEN_AI_INVOKE_AGENT - ) - span_data = invoke_agent_span["data"] - - if expect_response_text: - assert span_data[SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hello, how can I help you?" + if expect_response_text: + assert span_data[SPANDATA.GEN_AI_RESPONSE_TEXT] == "Hello, how can I help you?" else: assert SPANDATA.GEN_AI_RESPONSE_TEXT not in span_data -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize( "data_collection,send_default_pii,expect_input", [ @@ -1090,7 +747,6 @@ async def test_invoke_agent_span_data_collection_outputs( @pytest.mark.asyncio async def test_data_collection_inputs( sentry_init, - capture_events, capture_items, test_agent, simple_test_tool, @@ -1099,8 +755,6 @@ async def test_data_collection_inputs( data_collection, send_default_pii, expect_input, - stream_gen_ai_spans, - span_streaming, ): client = AsyncOpenAI(api_key="test-key") model = OpenAIResponsesModel(model="gpt-4", openai_client=client) @@ -1114,11 +768,8 @@ async def test_data_collection_inputs( "integrations": [OpenAIAgentsIntegration()], "traces_sample_rate": 1.0, "send_default_pii": send_default_pii, - "stream_gen_ai_spans": stream_gen_ai_spans, } - if span_streaming: - init_kwargs["disabled_integrations"] = [StdlibIntegration] - init_kwargs["trace_lifecycle"] = "stream" + init_kwargs["disabled_integrations"] = [StdlibIntegration] if data_collection is not None: init_kwargs["data_collection"] = data_collection @@ -1128,33 +779,19 @@ async def test_data_collection_inputs( return_value=response, ) as _: sentry_init(**init_kwargs) - - if span_streaming: - items = capture_items("span") - elif stream_gen_ai_spans: - items = capture_items("span", "transaction") - else: - events = capture_events() + items = capture_items("span") result = await agents.Runner.run( agent, "Test input", run_config=test_run_config ) assert result is not None - - if span_streaming or stream_gen_ai_spans: - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - ai_client_span = next( - span for span in spans if span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - ) - span_data = ai_client_span["attributes"] - else: - (transaction,) = events - ai_client_span = next( - span for span in transaction["spans"] if span["op"] == OP.GEN_AI_CHAT - ) - span_data = ai_client_span["data"] + sentry_sdk.flush() + spans = [item.payload for item in items] + ai_client_span = next( + span for span in spans if span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT + ) + span_data = ai_client_span["attributes"] if expect_input: assert "Test input" in span_data[SPANDATA.GEN_AI_REQUEST_MESSAGES] @@ -1177,8 +814,6 @@ async def test_data_collection_inputs( assert span_data[SPANDATA.GEN_AI_USAGE_INPUT_TOKENS] == 10 -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize( "data_collection,send_default_pii,expect_output", [ @@ -1229,7 +864,6 @@ async def test_data_collection_inputs( @pytest.mark.asyncio async def test_data_collection_outputs( sentry_init, - capture_events, capture_items, test_agent, simple_test_tool, @@ -1238,8 +872,6 @@ async def test_data_collection_outputs( data_collection, send_default_pii, expect_output, - stream_gen_ai_spans, - span_streaming, ): client = AsyncOpenAI(api_key="test-key") model = OpenAIResponsesModel(model="gpt-4", openai_client=client) @@ -1272,11 +904,8 @@ async def test_data_collection_outputs( "integrations": [OpenAIAgentsIntegration()], "traces_sample_rate": 1.0, "send_default_pii": send_default_pii, - "stream_gen_ai_spans": stream_gen_ai_spans, } - if span_streaming: - init_kwargs["disabled_integrations"] = [StdlibIntegration] - init_kwargs["trace_lifecycle"] = "stream" + init_kwargs["disabled_integrations"] = [StdlibIntegration] if data_collection is not None: init_kwargs["data_collection"] = data_collection @@ -1286,35 +915,20 @@ async def test_data_collection_outputs( side_effect=[tool_response, final_response], ) as _: sentry_init(**init_kwargs) - - if span_streaming: - items = capture_items("span") - elif stream_gen_ai_spans: - items = capture_items("span", "transaction") - else: - events = capture_events() + items = capture_items("span") await agents.Runner.run( agent_with_tool, "Please use the simple test tool", run_config=test_run_config, ) - - if span_streaming or stream_gen_ai_spans: - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - chat_span_data = [ - span["attributes"] - for span in spans - if span["attributes"].get("sentry.op") == OP.GEN_AI_CHAT - ] - else: - (transaction,) = events - chat_span_data = [ - span["data"] - for span in transaction["spans"] - if span["op"] == OP.GEN_AI_CHAT - ] + sentry_sdk.flush() + spans = [item.payload for item in items] + chat_span_data = [ + span["attributes"] + for span in spans + if span["attributes"].get("sentry.op") == OP.GEN_AI_CHAT + ] assert len(chat_span_data) == 2 @@ -1339,8 +953,6 @@ async def test_data_collection_outputs( assert data[SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS] == 5 -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio @pytest.mark.parametrize( "instructions,input,expected_system_instructions,expected_request_messages", @@ -1534,7 +1146,6 @@ async def test_data_collection_outputs( ) async def test_agent_invocation_span( sentry_init, - capture_events, capture_items, test_agent_with_instructions, nonstreaming_responses_model_response, @@ -1543,8 +1154,6 @@ async def test_agent_invocation_span( expected_system_instructions, expected_request_messages, get_model_response, - stream_gen_ai_spans, - span_streaming, ): """ Test that the integration creates spans for agent invocations. @@ -1556,227 +1165,77 @@ async def test_agent_invocation_span( response = get_model_response( nonstreaming_responses_model_response, serialize_pydantic=True ) - - if span_streaming: - with patch.object( - agent.model._client._client, - "send", - return_value=response, - ) as _: - sentry_init( - integrations=[OpenAIAgentsIntegration()], - disabled_integrations=[StdlibIntegration], - traces_sample_rate=1.0, - send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream", - ) - - items = capture_items("span") - - result = await agents.Runner.run( - agent, - input, - run_config=test_run_config, - ) - - assert result is not None - assert result.final_output == "Hello, how can I help you?" - - sentry_sdk.flush() - spans = [item.payload for item in items] - ai_client_span, invoke_agent_span, workflow_span = spans - - assert workflow_span["name"] == "test_agent workflow" - assert workflow_span["attributes"]["sentry.origin"] == "auto.ai.openai_agents" - - assert invoke_agent_span["name"] == "invoke_agent test_agent" - - if expected_system_instructions is None: - assert "gen_ai.system_instructions" not in ai_client_span["attributes"] - else: - assert ai_client_span["attributes"][ - "gen_ai.system_instructions" - ] == safe_serialize(expected_system_instructions) - - assert ( - json.loads(ai_client_span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) - == expected_request_messages + with patch.object( + agent.model._client._client, + "send", + return_value=response, + ) as _: + sentry_init( + integrations=[OpenAIAgentsIntegration()], + disabled_integrations=[StdlibIntegration], + traces_sample_rate=1.0, + send_default_pii=True, ) - assert ( - invoke_agent_span["attributes"]["gen_ai.response.text"] - == "Hello, how can I help you?" - ) + items = capture_items("span") - assert ( - invoke_agent_span["attributes"]["gen_ai.operation.name"] == "invoke_agent" + result = await agents.Runner.run( + agent, + input, + run_config=test_run_config, ) - assert invoke_agent_span["attributes"]["gen_ai.system"] == "openai" - assert invoke_agent_span["attributes"]["gen_ai.agent.name"] == "test_agent" - assert invoke_agent_span["attributes"]["gen_ai.request.max_tokens"] == 100 - assert invoke_agent_span["attributes"]["gen_ai.request.model"] == "gpt-4" - assert invoke_agent_span["attributes"]["gen_ai.request.temperature"] == 0.7 - assert invoke_agent_span["attributes"]["gen_ai.request.top_p"] == 1.0 - - assert ai_client_span["name"] == "chat gpt-4" - assert ai_client_span["attributes"]["gen_ai.operation.name"] == "chat" - assert ai_client_span["attributes"]["gen_ai.system"] == "openai" - assert ai_client_span["attributes"]["gen_ai.agent.name"] == "test_agent" - assert ai_client_span["attributes"]["gen_ai.request.max_tokens"] == 100 - assert ai_client_span["attributes"]["gen_ai.request.model"] == "gpt-4" - assert ai_client_span["attributes"]["gen_ai.request.temperature"] == 0.7 - assert ai_client_span["attributes"]["gen_ai.request.top_p"] == 1.0 - - elif stream_gen_ai_spans: - with patch.object( - agent.model._client._client, - "send", - return_value=response, - ) as _: - sentry_init( - integrations=[OpenAIAgentsIntegration()], - traces_sample_rate=1.0, - send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - ) - - items = capture_items("span", "transaction") - - result = await agents.Runner.run( - agent, - input, - run_config=test_run_config, - ) - - assert result is not None - assert result.final_output == "Hello, how can I help you?" - - (transaction,) = (item.payload for item in items if item.type == "transaction") - - assert transaction["transaction"] == "test_agent workflow" - assert transaction["contexts"]["trace"]["origin"] == "auto.ai.openai_agents" - - spans = [item.payload for item in items if item.type == "span"] - invoke_agent_span, ai_client_span = spans - assert invoke_agent_span["name"] == "invoke_agent test_agent" - - if expected_system_instructions is None: - assert "gen_ai.system_instructions" not in ai_client_span["attributes"] - else: - assert ai_client_span["attributes"][ - "gen_ai.system_instructions" - ] == safe_serialize(expected_system_instructions) - - assert ( - json.loads(ai_client_span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) - == expected_request_messages - ) + assert result is not None + assert result.final_output == "Hello, how can I help you?" - assert ( - invoke_agent_span["attributes"]["gen_ai.response.text"] - == "Hello, how can I help you?" - ) + sentry_sdk.flush() + spans = [item.payload for item in items] + ai_client_span, invoke_agent_span = spans - assert ( - invoke_agent_span["attributes"]["gen_ai.operation.name"] == "invoke_agent" - ) - assert invoke_agent_span["attributes"]["gen_ai.system"] == "openai" - assert invoke_agent_span["attributes"]["gen_ai.agent.name"] == "test_agent" - assert invoke_agent_span["attributes"]["gen_ai.request.max_tokens"] == 100 - assert invoke_agent_span["attributes"]["gen_ai.request.model"] == "gpt-4" - assert invoke_agent_span["attributes"]["gen_ai.request.temperature"] == 0.7 - assert invoke_agent_span["attributes"]["gen_ai.request.top_p"] == 1.0 - - assert ai_client_span["name"] == "chat gpt-4" - assert ai_client_span["attributes"]["gen_ai.operation.name"] == "chat" - assert ai_client_span["attributes"]["gen_ai.system"] == "openai" - assert ai_client_span["attributes"]["gen_ai.agent.name"] == "test_agent" - assert ai_client_span["attributes"]["gen_ai.request.max_tokens"] == 100 - assert ai_client_span["attributes"]["gen_ai.request.model"] == "gpt-4" - assert ai_client_span["attributes"]["gen_ai.request.temperature"] == 0.7 - assert ai_client_span["attributes"]["gen_ai.request.top_p"] == 1.0 + assert invoke_agent_span["name"] == "invoke_agent test_agent" + if expected_system_instructions is None: + assert "gen_ai.system_instructions" not in ai_client_span["attributes"] else: - with patch.object( - agent.model._client._client, - "send", - return_value=response, - ) as _: - sentry_init( - integrations=[OpenAIAgentsIntegration()], - traces_sample_rate=1.0, - send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - ) - events = capture_events() - - result = await agents.Runner.run( - agent, - input, - run_config=test_run_config, - ) + assert ai_client_span["attributes"][ + "gen_ai.system_instructions" + ] == safe_serialize(expected_system_instructions) - assert result is not None - assert result.final_output == "Hello, how can I help you?" - - (transaction,) = events - spans = transaction["spans"] - invoke_agent_span, ai_client_span = spans - - assert transaction["transaction"] == "test_agent workflow" - assert transaction["contexts"]["trace"]["origin"] == "auto.ai.openai_agents" + assert ( + json.loads(ai_client_span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) + == expected_request_messages + ) - assert invoke_agent_span["description"] == "invoke_agent test_agent" + assert ( + invoke_agent_span["attributes"]["gen_ai.response.text"] + == "Hello, how can I help you?" + ) - if expected_system_instructions is None: - assert "gen_ai.system_instructions" not in ai_client_span["data"] - else: - assert ai_client_span["data"][ - "gen_ai.system_instructions" - ] == safe_serialize(expected_system_instructions) + assert invoke_agent_span["attributes"]["gen_ai.operation.name"] == "invoke_agent" + assert invoke_agent_span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "openai" + assert invoke_agent_span["attributes"]["gen_ai.agent.name"] == "test_agent" + assert invoke_agent_span["attributes"]["gen_ai.request.max_tokens"] == 100 + assert invoke_agent_span["attributes"]["gen_ai.request.model"] == "gpt-4" + assert invoke_agent_span["attributes"]["gen_ai.request.temperature"] == 0.7 + assert invoke_agent_span["attributes"]["gen_ai.request.top_p"] == 1.0 - assert ( - json.loads(ai_client_span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) - == expected_request_messages[-1:] - ) + assert ai_client_span["name"] == "chat gpt-4" + assert ai_client_span["attributes"]["gen_ai.operation.name"] == "chat" + assert ai_client_span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "openai" + assert ai_client_span["attributes"]["gen_ai.agent.name"] == "test_agent" + assert ai_client_span["attributes"]["gen_ai.request.max_tokens"] == 100 + assert ai_client_span["attributes"]["gen_ai.request.model"] == "gpt-4" + assert ai_client_span["attributes"]["gen_ai.request.temperature"] == 0.7 + assert ai_client_span["attributes"]["gen_ai.request.top_p"] == 1.0 - assert ( - invoke_agent_span["data"]["gen_ai.response.text"] - == "Hello, how can I help you?" - ) - assert invoke_agent_span["data"]["gen_ai.operation.name"] == "invoke_agent" - assert invoke_agent_span["data"]["gen_ai.system"] == "openai" - assert invoke_agent_span["data"]["gen_ai.agent.name"] == "test_agent" - assert invoke_agent_span["data"]["gen_ai.request.max_tokens"] == 100 - assert invoke_agent_span["data"]["gen_ai.request.model"] == "gpt-4" - assert invoke_agent_span["data"]["gen_ai.request.temperature"] == 0.7 - assert invoke_agent_span["data"]["gen_ai.request.top_p"] == 1.0 - - assert ai_client_span["description"] == "chat gpt-4" - assert ai_client_span["data"]["gen_ai.operation.name"] == "chat" - assert ai_client_span["data"]["gen_ai.system"] == "openai" - assert ai_client_span["data"]["gen_ai.agent.name"] == "test_agent" - assert ai_client_span["data"]["gen_ai.request.max_tokens"] == 100 - assert ai_client_span["data"]["gen_ai.request.model"] == "gpt-4" - assert ai_client_span["data"]["gen_ai.request.temperature"] == 0.7 - assert ai_client_span["data"]["gen_ai.request.top_p"] == 1.0 - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio async def test_client_span_custom_model( sentry_init, - capture_events, capture_items, test_agent_custom_model, nonstreaming_responses_model_response, get_model_response, - stream_gen_ai_spans, - span_streaming, ): """ Test that the integration uses the correct model name if a custom model is used. @@ -1789,77 +1248,42 @@ async def test_client_span_custom_model( response = get_model_response( nonstreaming_responses_model_response, serialize_pydantic=True ) - - if span_streaming or stream_gen_ai_spans: - with patch.object( - agent.model._client._client, - "send", - return_value=response, - ) as _: - sentry_init( - integrations=[OpenAIAgentsIntegration()], - disabled_integrations=[StdlibIntegration], - traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", - ) - - items = capture_items("span") - - result = await agents.Runner.run( - agent, "Test input", run_config=test_run_config - ) - - assert result is not None - assert result.final_output == "Hello, how can I help you?" - - sentry_sdk.flush() - spans = [item.payload for item in items] - ai_client_span = next( - span for span in spans if span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT + with patch.object( + agent.model._client._client, + "send", + return_value=response, + ) as _: + sentry_init( + integrations=[OpenAIAgentsIntegration()], + disabled_integrations=[StdlibIntegration], + traces_sample_rate=1.0, ) - assert ai_client_span["name"] == "chat my-custom-model" - assert ai_client_span["attributes"]["gen_ai.request.model"] == "my-custom-model" - else: - with patch.object( - agent.model._client._client, - "send", - return_value=response, - ) as _: - sentry_init( - integrations=[OpenAIAgentsIntegration()], - traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - ) - events = capture_events() + items = capture_items("span") - result = await agents.Runner.run( - agent, "Test input", run_config=test_run_config - ) + result = await agents.Runner.run( + agent, "Test input", run_config=test_run_config + ) - assert result is not None - assert result.final_output == "Hello, how can I help you?" + assert result is not None + assert result.final_output == "Hello, how can I help you?" - (transaction,) = events - spans = transaction["spans"] - ai_client_span = next(span for span in spans if span["op"] == OP.GEN_AI_CHAT) + sentry_sdk.flush() + spans = [item.payload for item in items] + ai_client_span = next( + span for span in spans if span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT + ) - assert ai_client_span["description"] == "chat my-custom-model" - assert ai_client_span["data"]["gen_ai.request.model"] == "my-custom-model" + assert ai_client_span["name"] == "chat my-custom-model" + assert ai_client_span["attributes"]["gen_ai.request.model"] == "my-custom-model" -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_agent_invocation_span_sync_no_pii( sentry_init, - capture_events, capture_items, test_agent, nonstreaming_responses_model_response, get_model_response, - stream_gen_ai_spans, - span_streaming, sync_event_loop, ): """ @@ -1872,183 +1296,58 @@ def test_agent_invocation_span_sync_no_pii( response = get_model_response( nonstreaming_responses_model_response, serialize_pydantic=True ) - - if span_streaming: - with patch.object( - agent.model._client._client, - "send", - return_value=response, - ) as _: - sentry_init( - integrations=[OpenAIAgentsIntegration()], - disabled_integrations=[StdlibIntegration], - traces_sample_rate=1.0, - send_default_pii=False, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream", - ) - - items = capture_items("span") - - result = agents.Runner.run_sync( - agent, "Test input", run_config=test_run_config - ) - - assert result is not None - assert result.final_output == "Hello, how can I help you?" - - sentry_sdk.flush() - spans = [item.payload for item in items] - - assert spans[2]["name"] == "test_agent workflow" - assert spans[2]["attributes"]["sentry.origin"] == "auto.ai.openai_agents" - - invoke_agent_span = next( - span - for span in spans - if span["attributes"]["sentry.op"] == OP.GEN_AI_INVOKE_AGENT - ) - ai_client_span = next( - span for span in spans if span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - ) - - assert invoke_agent_span["name"] == "invoke_agent test_agent" - assert ( - invoke_agent_span["attributes"]["gen_ai.operation.name"] == "invoke_agent" - ) - assert invoke_agent_span["attributes"]["gen_ai.system"] == "openai" - assert invoke_agent_span["attributes"]["gen_ai.agent.name"] == "test_agent" - assert invoke_agent_span["attributes"]["gen_ai.request.max_tokens"] == 100 - assert invoke_agent_span["attributes"]["gen_ai.request.model"] == "gpt-4" - assert invoke_agent_span["attributes"]["gen_ai.request.temperature"] == 0.7 - assert invoke_agent_span["attributes"]["gen_ai.request.top_p"] == 1.0 - - assert ai_client_span["name"] == "chat gpt-4" - assert ai_client_span["attributes"]["gen_ai.operation.name"] == "chat" - assert ai_client_span["attributes"]["gen_ai.system"] == "openai" - assert ai_client_span["attributes"]["gen_ai.agent.name"] == "test_agent" - assert ai_client_span["attributes"]["gen_ai.request.max_tokens"] == 100 - assert ai_client_span["attributes"]["gen_ai.request.model"] == "gpt-4" - assert ai_client_span["attributes"]["gen_ai.request.temperature"] == 0.7 - assert ai_client_span["attributes"]["gen_ai.request.top_p"] == 1.0 - - assert ( - SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in invoke_agent_span["attributes"] + with patch.object( + agent.model._client._client, + "send", + return_value=response, + ) as _: + sentry_init( + integrations=[OpenAIAgentsIntegration()], + disabled_integrations=[StdlibIntegration], + traces_sample_rate=1.0, + send_default_pii=False, ) - elif stream_gen_ai_spans: - with patch.object( - agent.model._client._client, - "send", - return_value=response, - ) as _: - sentry_init( - integrations=[OpenAIAgentsIntegration()], - traces_sample_rate=1.0, - send_default_pii=False, - stream_gen_ai_spans=stream_gen_ai_spans, - ) - items = capture_items("span", "transaction") - - result = agents.Runner.run_sync( - agent, "Test input", run_config=test_run_config - ) + items = capture_items("span") - assert result is not None - assert result.final_output == "Hello, how can I help you?" + result = agents.Runner.run_sync(agent, "Test input", run_config=test_run_config) - (transaction,) = (item.payload for item in items if item.type == "transaction") + assert result is not None + assert result.final_output == "Hello, how can I help you?" - assert transaction["transaction"] == "test_agent workflow" - assert transaction["contexts"]["trace"]["origin"] == "auto.ai.openai_agents" + sentry_sdk.flush() + spans = [item.payload for item in items] - spans = [item.payload for item in items if item.type == "span"] - invoke_agent_span = next( - span - for span in spans - if span["attributes"]["sentry.op"] == OP.GEN_AI_INVOKE_AGENT - ) - ai_client_span = next( - span for span in spans if span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - ) + invoke_agent_span = next( + span + for span in spans + if span["attributes"]["sentry.op"] == OP.GEN_AI_INVOKE_AGENT + ) + ai_client_span = next( + span for span in spans if span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT + ) - assert invoke_agent_span["name"] == "invoke_agent test_agent" - assert ( - invoke_agent_span["attributes"]["gen_ai.operation.name"] == "invoke_agent" - ) - assert invoke_agent_span["attributes"]["gen_ai.system"] == "openai" - assert invoke_agent_span["attributes"]["gen_ai.agent.name"] == "test_agent" - assert invoke_agent_span["attributes"]["gen_ai.request.max_tokens"] == 100 - assert invoke_agent_span["attributes"]["gen_ai.request.model"] == "gpt-4" - assert invoke_agent_span["attributes"]["gen_ai.request.temperature"] == 0.7 - assert invoke_agent_span["attributes"]["gen_ai.request.top_p"] == 1.0 - - assert ai_client_span["name"] == "chat gpt-4" - assert ai_client_span["attributes"]["gen_ai.operation.name"] == "chat" - assert ai_client_span["attributes"]["gen_ai.system"] == "openai" - assert ai_client_span["attributes"]["gen_ai.agent.name"] == "test_agent" - assert ai_client_span["attributes"]["gen_ai.request.max_tokens"] == 100 - assert ai_client_span["attributes"]["gen_ai.request.model"] == "gpt-4" - assert ai_client_span["attributes"]["gen_ai.request.temperature"] == 0.7 - assert ai_client_span["attributes"]["gen_ai.request.top_p"] == 1.0 + assert invoke_agent_span["name"] == "invoke_agent test_agent" + assert invoke_agent_span["attributes"]["gen_ai.operation.name"] == "invoke_agent" + assert invoke_agent_span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "openai" + assert invoke_agent_span["attributes"]["gen_ai.agent.name"] == "test_agent" + assert invoke_agent_span["attributes"]["gen_ai.request.max_tokens"] == 100 + assert invoke_agent_span["attributes"]["gen_ai.request.model"] == "gpt-4" + assert invoke_agent_span["attributes"]["gen_ai.request.temperature"] == 0.7 + assert invoke_agent_span["attributes"]["gen_ai.request.top_p"] == 1.0 - assert ( - SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in invoke_agent_span["attributes"] - ) - else: - with patch.object( - agent.model._client._client, - "send", - return_value=response, - ) as _: - sentry_init( - integrations=[OpenAIAgentsIntegration()], - traces_sample_rate=1.0, - send_default_pii=False, - stream_gen_ai_spans=stream_gen_ai_spans, - ) - events = capture_events() + assert ai_client_span["name"] == "chat gpt-4" + assert ai_client_span["attributes"]["gen_ai.operation.name"] == "chat" + assert ai_client_span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "openai" + assert ai_client_span["attributes"]["gen_ai.agent.name"] == "test_agent" + assert ai_client_span["attributes"]["gen_ai.request.max_tokens"] == 100 + assert ai_client_span["attributes"]["gen_ai.request.model"] == "gpt-4" + assert ai_client_span["attributes"]["gen_ai.request.temperature"] == 0.7 + assert ai_client_span["attributes"]["gen_ai.request.top_p"] == 1.0 - result = agents.Runner.run_sync( - agent, "Test input", run_config=test_run_config - ) + assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in invoke_agent_span["attributes"] - assert result is not None - assert result.final_output == "Hello, how can I help you?" - (transaction,) = events - spans = transaction["spans"] - invoke_agent_span = next( - span for span in spans if span["op"] == OP.GEN_AI_INVOKE_AGENT - ) - ai_client_span = next(span for span in spans if span["op"] == OP.GEN_AI_CHAT) - - assert transaction["transaction"] == "test_agent workflow" - assert transaction["contexts"]["trace"]["origin"] == "auto.ai.openai_agents" - - assert invoke_agent_span["description"] == "invoke_agent test_agent" - assert invoke_agent_span["data"]["gen_ai.operation.name"] == "invoke_agent" - assert invoke_agent_span["data"]["gen_ai.system"] == "openai" - assert invoke_agent_span["data"]["gen_ai.agent.name"] == "test_agent" - assert invoke_agent_span["data"]["gen_ai.request.max_tokens"] == 100 - assert invoke_agent_span["data"]["gen_ai.request.model"] == "gpt-4" - assert invoke_agent_span["data"]["gen_ai.request.temperature"] == 0.7 - assert invoke_agent_span["data"]["gen_ai.request.top_p"] == 1.0 - - assert ai_client_span["description"] == "chat gpt-4" - assert ai_client_span["data"]["gen_ai.operation.name"] == "chat" - assert ai_client_span["data"]["gen_ai.system"] == "openai" - assert ai_client_span["data"]["gen_ai.agent.name"] == "test_agent" - assert ai_client_span["data"]["gen_ai.request.max_tokens"] == 100 - assert ai_client_span["data"]["gen_ai.request.model"] == "gpt-4" - assert ai_client_span["data"]["gen_ai.request.temperature"] == 0.7 - assert ai_client_span["data"]["gen_ai.request.top_p"] == 1.0 - - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in invoke_agent_span["data"] - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize( "instructions,input,expected_system_instructions,expected_request_messages", [ @@ -2241,7 +1540,6 @@ def test_agent_invocation_span_sync_no_pii( ) def test_agent_invocation_span_sync( sentry_init, - capture_events, capture_items, test_agent_with_instructions, nonstreaming_responses_model_response, @@ -2250,8 +1548,6 @@ def test_agent_invocation_span_sync( expected_system_instructions, expected_request_messages, get_model_response, - stream_gen_ai_spans, - span_streaming, sync_event_loop, ): """ @@ -2264,570 +1560,347 @@ def test_agent_invocation_span_sync( response = get_model_response( nonstreaming_responses_model_response, serialize_pydantic=True ) + with patch.object( + agent.model._client._client, + "send", + return_value=response, + ) as _: + sentry_init( + integrations=[OpenAIAgentsIntegration()], + disabled_integrations=[StdlibIntegration], + traces_sample_rate=1.0, + send_default_pii=True, + ) - if span_streaming: - with patch.object( - agent.model._client._client, - "send", - return_value=response, - ) as _: - sentry_init( - integrations=[OpenAIAgentsIntegration()], - disabled_integrations=[StdlibIntegration], - traces_sample_rate=1.0, - send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream", - ) - - items = capture_items("span") - - result = agents.Runner.run_sync( - agent, - input, - run_config=test_run_config, - ) - - assert result is not None - assert result.final_output == "Hello, how can I help you?" - - sentry_sdk.flush() - spans = [item.payload for item in items] - ai_client_span, invoke_agent_span, workflow_span = spans - - assert workflow_span["name"] == "test_agent workflow" - assert workflow_span["attributes"]["sentry.origin"] == "auto.ai.openai_agents" - - assert invoke_agent_span["name"] == "invoke_agent test_agent" - assert ( - invoke_agent_span["attributes"]["gen_ai.operation.name"] == "invoke_agent" - ) - assert invoke_agent_span["attributes"]["gen_ai.system"] == "openai" - assert invoke_agent_span["attributes"]["gen_ai.agent.name"] == "test_agent" - assert invoke_agent_span["attributes"]["gen_ai.request.max_tokens"] == 100 - assert invoke_agent_span["attributes"]["gen_ai.request.model"] == "gpt-4" - assert invoke_agent_span["attributes"]["gen_ai.request.temperature"] == 0.7 - assert invoke_agent_span["attributes"]["gen_ai.request.top_p"] == 1.0 - - assert ai_client_span["name"] == "chat gpt-4" - assert ai_client_span["attributes"]["gen_ai.operation.name"] == "chat" - assert ai_client_span["attributes"]["gen_ai.system"] == "openai" - assert ai_client_span["attributes"]["gen_ai.agent.name"] == "test_agent" - assert ai_client_span["attributes"]["gen_ai.request.max_tokens"] == 100 - assert ai_client_span["attributes"]["gen_ai.request.model"] == "gpt-4" - assert ai_client_span["attributes"]["gen_ai.request.temperature"] == 0.7 - assert ai_client_span["attributes"]["gen_ai.request.top_p"] == 1.0 - - if expected_system_instructions is None: - assert "gen_ai.system_instructions" not in ai_client_span["attributes"] - else: - assert ai_client_span["attributes"][ - "gen_ai.system_instructions" - ] == safe_serialize(expected_system_instructions) + items = capture_items("span") - assert ( - json.loads(ai_client_span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) - == expected_request_messages + result = agents.Runner.run_sync( + agent, + input, + run_config=test_run_config, ) - elif stream_gen_ai_spans: - with patch.object( - agent.model._client._client, - "send", - return_value=response, - ) as _: - sentry_init( - integrations=[OpenAIAgentsIntegration()], - traces_sample_rate=1.0, - send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - ) - - items = capture_items("span", "transaction") - result = agents.Runner.run_sync( - agent, - input, - run_config=test_run_config, - ) - - assert result is not None - assert result.final_output == "Hello, how can I help you?" - - (transaction,) = (item.payload for item in items if item.type == "transaction") - assert transaction["transaction"] == "test_agent workflow" - assert transaction["contexts"]["trace"]["origin"] == "auto.ai.openai_agents" - - spans = [item.payload for item in items if item.type == "span"] - invoke_agent_span, ai_client_span = spans - - assert invoke_agent_span["name"] == "invoke_agent test_agent" - assert ( - invoke_agent_span["attributes"]["gen_ai.operation.name"] == "invoke_agent" - ) - assert invoke_agent_span["attributes"]["gen_ai.system"] == "openai" - assert invoke_agent_span["attributes"]["gen_ai.agent.name"] == "test_agent" - assert invoke_agent_span["attributes"]["gen_ai.request.max_tokens"] == 100 - assert invoke_agent_span["attributes"]["gen_ai.request.model"] == "gpt-4" - assert invoke_agent_span["attributes"]["gen_ai.request.temperature"] == 0.7 - assert invoke_agent_span["attributes"]["gen_ai.request.top_p"] == 1.0 - - assert ai_client_span["name"] == "chat gpt-4" - assert ai_client_span["attributes"]["gen_ai.operation.name"] == "chat" - assert ai_client_span["attributes"]["gen_ai.system"] == "openai" - assert ai_client_span["attributes"]["gen_ai.agent.name"] == "test_agent" - assert ai_client_span["attributes"]["gen_ai.request.max_tokens"] == 100 - assert ai_client_span["attributes"]["gen_ai.request.model"] == "gpt-4" - assert ai_client_span["attributes"]["gen_ai.request.temperature"] == 0.7 - assert ai_client_span["attributes"]["gen_ai.request.top_p"] == 1.0 - - if expected_system_instructions is None: - assert "gen_ai.system_instructions" not in ai_client_span["attributes"] - else: - assert ai_client_span["attributes"][ - "gen_ai.system_instructions" - ] == safe_serialize(expected_system_instructions) + assert result is not None + assert result.final_output == "Hello, how can I help you?" - assert ( - json.loads(ai_client_span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) - == expected_request_messages - ) + sentry_sdk.flush() + spans = [item.payload for item in items] + ai_client_span, invoke_agent_span = spans + + assert invoke_agent_span["name"] == "invoke_agent test_agent" + assert invoke_agent_span["attributes"]["gen_ai.operation.name"] == "invoke_agent" + assert invoke_agent_span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "openai" + assert invoke_agent_span["attributes"]["gen_ai.agent.name"] == "test_agent" + assert invoke_agent_span["attributes"]["gen_ai.request.max_tokens"] == 100 + assert invoke_agent_span["attributes"]["gen_ai.request.model"] == "gpt-4" + assert invoke_agent_span["attributes"]["gen_ai.request.temperature"] == 0.7 + assert invoke_agent_span["attributes"]["gen_ai.request.top_p"] == 1.0 + + assert ai_client_span["name"] == "chat gpt-4" + assert ai_client_span["attributes"]["gen_ai.operation.name"] == "chat" + assert ai_client_span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "openai" + assert ai_client_span["attributes"]["gen_ai.agent.name"] == "test_agent" + assert ai_client_span["attributes"]["gen_ai.request.max_tokens"] == 100 + assert ai_client_span["attributes"]["gen_ai.request.model"] == "gpt-4" + assert ai_client_span["attributes"]["gen_ai.request.temperature"] == 0.7 + assert ai_client_span["attributes"]["gen_ai.request.top_p"] == 1.0 + + if expected_system_instructions is None: + assert "gen_ai.system_instructions" not in ai_client_span["attributes"] else: - with patch.object( - agent.model._client._client, - "send", - return_value=response, - ) as _: - sentry_init( - integrations=[OpenAIAgentsIntegration()], - traces_sample_rate=1.0, - send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - ) - - events = capture_events() + assert ai_client_span["attributes"][ + "gen_ai.system_instructions" + ] == safe_serialize(expected_system_instructions) - result = agents.Runner.run_sync( - agent, - input, - run_config=test_run_config, - ) + assert ( + json.loads(ai_client_span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) + == expected_request_messages + ) - assert result is not None - assert result.final_output == "Hello, how can I help you?" - (transaction,) = events - spans = transaction["spans"] - invoke_agent_span, ai_client_span = spans - - assert transaction["transaction"] == "test_agent workflow" - assert transaction["contexts"]["trace"]["origin"] == "auto.ai.openai_agents" - - assert invoke_agent_span["description"] == "invoke_agent test_agent" - assert invoke_agent_span["data"]["gen_ai.operation.name"] == "invoke_agent" - assert invoke_agent_span["data"]["gen_ai.system"] == "openai" - assert invoke_agent_span["data"]["gen_ai.agent.name"] == "test_agent" - assert invoke_agent_span["data"]["gen_ai.request.max_tokens"] == 100 - assert invoke_agent_span["data"]["gen_ai.request.model"] == "gpt-4" - assert invoke_agent_span["data"]["gen_ai.request.temperature"] == 0.7 - assert invoke_agent_span["data"]["gen_ai.request.top_p"] == 1.0 - - assert ai_client_span["description"] == "chat gpt-4" - assert ai_client_span["data"]["gen_ai.operation.name"] == "chat" - assert ai_client_span["data"]["gen_ai.system"] == "openai" - assert ai_client_span["data"]["gen_ai.agent.name"] == "test_agent" - assert ai_client_span["data"]["gen_ai.request.max_tokens"] == 100 - assert ai_client_span["data"]["gen_ai.request.model"] == "gpt-4" - assert ai_client_span["data"]["gen_ai.request.temperature"] == 0.7 - assert ai_client_span["data"]["gen_ai.request.top_p"] == 1.0 - - if expected_system_instructions is None: - assert "gen_ai.system_instructions" not in ai_client_span["data"] - else: - assert ai_client_span["data"][ - "gen_ai.system_instructions" - ] == safe_serialize(expected_system_instructions) - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) +@pytest.mark.parametrize("user_hooks", [True, False]) @pytest.mark.asyncio -async def test_handoff_span( +async def test_tool_execution_span( sentry_init, - capture_events, capture_items, + test_agent, + simple_test_tool, get_model_response, - stream_gen_ai_spans, - span_streaming, + nonstreaming_responses_tool_call_model_responses, + user_hooks, ): """ - Test that handoff spans are created when agents hand off to other agents. + Test tool execution span creation with `AgentRunner.run()`. """ - client = AsyncOpenAI(api_key="test-key") - model = OpenAIResponsesModel(model="gpt-4-mini", openai_client=client) - # Create two simple agents with a handoff relationship - secondary_agent = agents.Agent( - name="secondary_agent", - instructions="You are a secondary agent.", - model=model, - ) - - primary_agent = agents.Agent( - name="primary_agent", - instructions="You are a primary agent that hands off to secondary agent.", - model=model, - handoffs=[secondary_agent], - ) + # Create agent with the tool + client = AsyncOpenAI(api_key="test-key") + model = OpenAIResponsesModel(model="gpt-4", openai_client=client) + agent_with_tool = test_agent.clone(tools=[simple_test_tool], model=model) - handoff_response = get_model_response( - Response( - id="resp_tool_123", - output=[ - ResponseFunctionToolCall( - id="call_handoff_123", - call_id="call_handoff_123", - name="transfer_to_secondary_agent", - type="function_call", - arguments="{}", - ) - ], - parallel_tool_calls=False, - tool_choice="none", - tools=[], - created_at=10000000, - model="gpt-4", - object="response", - usage=ResponseUsage( - input_tokens=10, - input_tokens_details=InputTokensDetails( - cached_tokens=0, - cache_write_tokens=0, + responses = nonstreaming_responses_tool_call_model_responses( + tool_name="simple_test_tool", + arguments='{"message": "hello"}', + response_model="gpt-4", + response_text="Task completed using the tool", + response_ids=iter(["resp_tool_123", "resp_final_123"]), + usages=iter( + [ + ResponseUsage( + input_tokens=10, + input_tokens_details=InputTokensDetails( + cached_tokens=0, + cache_write_tokens=0, + ), + output_tokens=5, + output_tokens_details=OutputTokensDetails( + reasoning_tokens=0, + ), + total_tokens=15, ), - output_tokens=20, - output_tokens_details=OutputTokensDetails( - reasoning_tokens=5, + ResponseUsage( + input_tokens=15, + input_tokens_details=InputTokensDetails( + cached_tokens=0, + cache_write_tokens=0, + ), + output_tokens=10, + output_tokens_details=OutputTokensDetails( + reasoning_tokens=0, + ), + total_tokens=25, ), - total_tokens=30, - ), + ] ), + ) + tool_response = get_model_response( + next(responses), serialize_pydantic=True, ) - final_response = get_model_response( - Response( - id="resp_final_123", - output=[ - ResponseOutputMessage( - id="msg_final", - type="message", - status="completed", - content=[ - ResponseOutputText( - text="I'm the specialist and I can help with that!", - type="output_text", - annotations=[], - ) - ], - role="assistant", - ) - ], - parallel_tool_calls=False, - tool_choice="none", - tools=[], - created_at=10000000, - model="gpt-4", - object="response", - usage=ResponseUsage( - input_tokens=10, - input_tokens_details=InputTokensDetails( - cached_tokens=0, - cache_write_tokens=0, - ), - output_tokens=20, - output_tokens_details=OutputTokensDetails( - reasoning_tokens=5, - ), - total_tokens=30, - ), - ), + next(responses), serialize_pydantic=True, ) + with patch.object( + agent_with_tool.model._client._client, + "send", + side_effect=[tool_response, final_response], + ) as _: + sentry_init( + integrations=[OpenAIAgentsIntegration()], + disabled_integrations=[StdlibIntegration], + traces_sample_rate=1.0, + send_default_pii=True, + ) - if span_streaming or stream_gen_ai_spans: - with patch.object( - primary_agent.model._client._client, - "send", - side_effect=[handoff_response, final_response], - ) as _: - sentry_init( - integrations=[OpenAIAgentsIntegration()], - disabled_integrations=[StdlibIntegration], - traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", - ) + items = capture_items("span") - items = capture_items("transaction", "span") + await agents.Runner.run( + agent_with_tool, + "Please use the simple test tool", + run_config=test_run_config, + hooks=RunHooks() if user_hooks else None, + ) - result = await agents.Runner.run( - primary_agent, - "Please hand off to secondary agent", - run_config=test_run_config, - ) + sentry_sdk.flush() + spans = [item.payload for item in items] - assert result is not None + agent_span = next( + span + for span in spans + if span["attributes"]["sentry.op"] == OP.GEN_AI_INVOKE_AGENT + ) + ai_client_span1, ai_client_span2 = ( + span for span in spans if span["attributes"].get("sentry.op") == OP.GEN_AI_CHAT + ) + tool_span = next( + span + for span in spans + if span["attributes"]["sentry.op"] == OP.GEN_AI_EXECUTE_TOOL + ) - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - handoff_span = next( - span - for span in spans - if span["attributes"].get("sentry.op") == OP.GEN_AI_HANDOFF - ) + available_tool = { + "name": "simple_test_tool", + "description": "A simple tool", + "parameters": { + "properties": {"message": {"title": "Message", "type": "string"}}, + "required": ["message"], + "title": "simple_test_tool_args", + "type": "object", + "additionalProperties": False, + }, + } - # Verify handoff span was created - assert handoff_span is not None - assert handoff_span["name"] == "handoff from primary_agent to secondary_agent" - assert handoff_span["attributes"]["gen_ai.operation.name"] == "handoff" - else: - with patch.object( - primary_agent.model._client._client, - "send", - side_effect=[handoff_response, final_response], - ) as _: - sentry_init( - integrations=[OpenAIAgentsIntegration()], - traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - ) - events = capture_events() + assert agent_span["name"] == "invoke_agent test_agent" + assert agent_span["attributes"]["sentry.origin"] == "auto.ai.openai_agents" + assert agent_span["attributes"]["gen_ai.agent.name"] == "test_agent" + assert agent_span["attributes"]["gen_ai.operation.name"] == "invoke_agent" - result = await agents.Runner.run( - primary_agent, - "Please hand off to secondary agent", - run_config=test_run_config, - ) + assert agent_span["attributes"]["gen_ai.request.max_tokens"] == 100 + assert agent_span["attributes"]["gen_ai.request.model"] == "gpt-4" + assert agent_span["attributes"]["gen_ai.request.temperature"] == 0.7 + assert agent_span["attributes"]["gen_ai.request.top_p"] == 1.0 + assert agent_span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "openai" - assert result is not None + assert ai_client_span1["name"] == "chat gpt-4" + assert ai_client_span1["attributes"]["gen_ai.operation.name"] == "chat" + assert ai_client_span1["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "openai" + assert ai_client_span1["attributes"]["gen_ai.agent.name"] == "test_agent" - (transaction,) = events - spans = transaction["spans"] - handoff_span = next( - span for span in spans if span.get("op") == OP.GEN_AI_HANDOFF - ) + ai_client_span1_available_tool = json.loads( + ai_client_span1["attributes"][SPANDATA.GEN_AI_TOOL_DEFINITIONS] + )[0] - # Verify handoff span was created - assert handoff_span is not None - assert ( - handoff_span["description"] - == "handoff from primary_agent to secondary_agent" - ) - assert handoff_span["data"]["gen_ai.operation.name"] == "handoff" + assert all( + ai_client_span1_available_tool[k] == v for k, v in available_tool.items() + ) + + assert ai_client_span1["attributes"]["gen_ai.request.max_tokens"] == 100 + assert ai_client_span1["attributes"]["gen_ai.request.messages"] == safe_serialize( + [ + { + "role": "user", + "content": [ + {"type": "text", "text": "Please use the simple test tool"} + ], + }, + ] + ) + assert ai_client_span1["attributes"]["gen_ai.request.model"] == "gpt-4" + assert ai_client_span1["attributes"]["gen_ai.request.temperature"] == 0.7 + assert ai_client_span1["attributes"]["gen_ai.request.top_p"] == 1.0 + assert ai_client_span1["attributes"]["gen_ai.usage.input_tokens"] == 10 + assert ( + ai_client_span1["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] + == 0 + ) + assert ai_client_span1["attributes"]["gen_ai.usage.output_tokens"] == 5 + assert ( + ai_client_span1["attributes"][SPANDATA.GEN_AI_USAGE_REASONING_OUTPUT_TOKENS] + == 0 + ) + assert ai_client_span1["attributes"]["gen_ai.usage.total_tokens"] == 15 + + tool_call = { + "arguments": '{"message": "hello"}', + "call_id": "call_123", + "name": "simple_test_tool", + "type": "function_call", + "id": "call_123", + "status": None, + } + + if OPENAI_VERSION >= (2, 25, 0): + tool_call["namespace"] = None + + parsed_tool_calls = json.loads( + ai_client_span1["attributes"]["gen_ai.response.tool_calls"] + ) + assert len(parsed_tool_calls) == 1 + assert tool_call.items() <= parsed_tool_calls[0].items() + + assert tool_span["name"] == "execute_tool simple_test_tool" + assert tool_span["attributes"]["gen_ai.agent.name"] == "test_agent" + assert tool_span["attributes"]["gen_ai.operation.name"] == "execute_tool" + + assert tool_span["attributes"]["gen_ai.request.max_tokens"] == 100 + assert tool_span["attributes"]["gen_ai.request.model"] == "gpt-4" + assert tool_span["attributes"]["gen_ai.request.temperature"] == 0.7 + assert tool_span["attributes"]["gen_ai.request.top_p"] == 1.0 + assert tool_span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "openai" + assert tool_span["attributes"]["gen_ai.tool.description"] == "A simple tool" + assert tool_span["attributes"]["gen_ai.tool.input"] == '{"message": "hello"}' + assert tool_span["attributes"]["gen_ai.tool.name"] == "simple_test_tool" + assert tool_span["attributes"]["gen_ai.tool.output"] == "Tool executed with: hello" + assert ai_client_span2["name"] == "chat gpt-4" + assert ai_client_span2["attributes"]["gen_ai.agent.name"] == "test_agent" + assert ai_client_span2["attributes"]["gen_ai.operation.name"] == "chat" + + ai_client_span2_available_tool = json.loads( + ai_client_span2["attributes"][SPANDATA.GEN_AI_TOOL_DEFINITIONS] + )[0] + + assert all( + ai_client_span2_available_tool[k] == v for k, v in available_tool.items() + ) + + assert ai_client_span2["attributes"]["gen_ai.request.max_tokens"] == 100 + assert ai_client_span2["attributes"]["gen_ai.request.messages"] == safe_serialize( + [ + { + "role": "user", + "content": [ + {"type": "text", "text": "Please use the simple test tool"} + ], + }, + { + "role": "assistant", + "content": [ + { + "arguments": '{"message": "hello"}', + "call_id": "call_123", + "name": "simple_test_tool", + "type": "function_call", + "id": "call_123", + } + ], + }, + { + "role": "tool", + "content": [ + { + "call_id": "call_123", + "output": "Tool executed with: hello", + "type": "function_call_output", + } + ], + }, + ] + ) + assert ai_client_span2["attributes"]["gen_ai.request.model"] == "gpt-4" + assert ai_client_span2["attributes"]["gen_ai.request.temperature"] == 0.7 + assert ai_client_span2["attributes"]["gen_ai.request.top_p"] == 1.0 + assert ( + ai_client_span2["attributes"]["gen_ai.response.text"] + == "Task completed using the tool" + ) + assert ai_client_span2["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "openai" + assert ( + ai_client_span2["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] + == 0 + ) + assert ai_client_span2["attributes"]["gen_ai.usage.input_tokens"] == 15 + assert ( + ai_client_span2["attributes"][SPANDATA.GEN_AI_USAGE_REASONING_OUTPUT_TOKENS] + == 0 + ) + assert ai_client_span2["attributes"]["gen_ai.usage.output_tokens"] == 10 + assert ai_client_span2["attributes"]["gen_ai.usage.total_tokens"] == 25 -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) +@pytest.mark.parametrize("user_hooks", [True, False]) @pytest.mark.asyncio -async def test_max_turns_before_handoff_span( +async def test_run_streamed_tool_execution_span( sentry_init, - capture_events, capture_items, + test_agent, + simple_test_tool, get_model_response, - stream_gen_ai_spans, - span_streaming, + async_iterator, + server_side_event_chunks, + streaming_responses_tool_call_model_responses, + user_hooks, ): """ - Example raising agents.exceptions.AgentsException after the agent invocation span is complete. + Test tool execution span creation with `AgentRunner.run_streamed()`. """ - client = AsyncOpenAI(api_key="test-key") - model = OpenAIResponsesModel(model="gpt-4-mini", openai_client=client) - - # Create two simple agents with a handoff relationship - secondary_agent = agents.Agent( - name="secondary_agent", - instructions="You are a secondary agent.", - model=model, - ) - primary_agent = agents.Agent( - name="primary_agent", - instructions="You are a primary agent that hands off to secondary agent.", - model=model, - handoffs=[secondary_agent], - ) + # Create agent with the tool + client = AsyncOpenAI(api_key="test-key") + model = OpenAIResponsesModel(model="gpt-4", openai_client=client) + agent_with_tool = test_agent.clone(tools=[simple_test_tool], model=model) - handoff_response = get_model_response( - Response( - id="resp_tool_123", - output=[ - ResponseFunctionToolCall( - id="call_handoff_123", - call_id="call_handoff_123", - name="transfer_to_secondary_agent", - type="function_call", - arguments="{}", - ) - ], - parallel_tool_calls=False, - tool_choice="none", - tools=[], - created_at=10000000, - model="gpt-4", - object="response", - usage=ResponseUsage( - input_tokens=10, - input_tokens_details=InputTokensDetails( - cached_tokens=0, - cache_write_tokens=0, - ), - output_tokens=20, - output_tokens_details=OutputTokensDetails( - reasoning_tokens=5, - ), - total_tokens=30, - ), - ), - serialize_pydantic=True, - ) - - final_response = get_model_response( - Response( - id="resp_final_123", - output=[ - ResponseOutputMessage( - id="msg_final", - type="message", - status="completed", - content=[ - ResponseOutputText( - text="I'm the specialist and I can help with that!", - type="output_text", - annotations=[], - ) - ], - role="assistant", - ) - ], - parallel_tool_calls=False, - tool_choice="none", - tools=[], - created_at=10000000, - model="gpt-4", - object="response", - usage=ResponseUsage( - input_tokens=10, - input_tokens_details=InputTokensDetails( - cached_tokens=0, - cache_write_tokens=0, - ), - output_tokens=20, - output_tokens_details=OutputTokensDetails( - reasoning_tokens=5, - ), - total_tokens=30, - ), - ), - serialize_pydantic=True, - ) - - if span_streaming or stream_gen_ai_spans: - with patch.object( - primary_agent.model._client._client, - "send", - side_effect=[handoff_response, final_response], - ) as _: - sentry_init( - integrations=[OpenAIAgentsIntegration()], - disabled_integrations=[StdlibIntegration], - traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", - ) - - items = capture_items("transaction", "span") - - with pytest.raises(MaxTurnsExceeded): - await agents.Runner.run( - primary_agent, - "Please hand off to secondary agent", - run_config=test_run_config, - max_turns=1, - ) - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - handoff_span = next( - span - for span in spans - if span["attributes"].get("sentry.op") == OP.GEN_AI_HANDOFF - ) - - # Verify handoff span was created - assert handoff_span is not None - assert handoff_span["name"] == "handoff from primary_agent to secondary_agent" - assert handoff_span["attributes"]["gen_ai.operation.name"] == "handoff" - else: - with patch.object( - primary_agent.model._client._client, - "send", - side_effect=[handoff_response, final_response], - ) as _: - sentry_init( - integrations=[OpenAIAgentsIntegration()], - traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - ) - events = capture_events() - - with pytest.raises(MaxTurnsExceeded): - await agents.Runner.run( - primary_agent, - "Please hand off to secondary agent", - run_config=test_run_config, - max_turns=1, - ) - - (error, transaction) = events - spans = transaction["spans"] - handoff_span = next( - span for span in spans if span.get("op") == OP.GEN_AI_HANDOFF - ) - - # Verify handoff span was created - assert handoff_span is not None - assert ( - handoff_span["description"] - == "handoff from primary_agent to secondary_agent" - ) - assert handoff_span["data"]["gen_ai.operation.name"] == "handoff" - - -@pytest.mark.parametrize("user_hooks", [True, False]) -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) -@pytest.mark.asyncio -async def test_tool_execution_span( - sentry_init, - capture_events, - capture_items, - test_agent, - simple_test_tool, - get_model_response, - nonstreaming_responses_tool_call_model_responses, - stream_gen_ai_spans, - span_streaming, - user_hooks, -): - """ - Test tool execution span creation with `AgentRunner.run()`. - """ - - # Create agent with the tool - client = AsyncOpenAI(api_key="test-key") - model = OpenAIResponsesModel(model="gpt-4", openai_client=client) - agent_with_tool = test_agent.clone(tools=[simple_test_tool], model=model) - - responses = nonstreaming_responses_tool_call_model_responses( + responses = streaming_responses_tool_call_model_responses( tool_name="simple_test_tool", arguments='{"message": "hello"}', response_model="gpt-4", @@ -2862,16 +1935,140 @@ async def test_tool_execution_span( ] ), ) + + request_headers = { + "X-Stainless-Raw-Response": "stream", + } + tool_response = get_model_response( - next(responses), - serialize_pydantic=True, + async_iterator(server_side_event_chunks(next(responses))), + request_headers=request_headers, ) final_response = get_model_response( - next(responses), - serialize_pydantic=True, + async_iterator(server_side_event_chunks(next(responses))), + request_headers=request_headers, + ) + with patch.object( + agent_with_tool.model._client._client, + "send", + side_effect=[tool_response, final_response], + ) as _: + sentry_init( + integrations=[OpenAIAgentsIntegration()], + disabled_integrations=[StdlibIntegration], + traces_sample_rate=1.0, + send_default_pii=True, + ) + + items = capture_items("span") + + result = agents.Runner.run_streamed( + agent_with_tool, + "Please use the simple test tool", + run_config=test_run_config, + hooks=RunHooks() if user_hooks else None, + ) + + async for event in result.stream_events(): + pass + + sentry_sdk.flush() + spans = [item.payload for item in items] + + agent_span = next( + span + for span in spans + if span["attributes"]["sentry.op"] == OP.GEN_AI_INVOKE_AGENT ) + tool_span = next( + span + for span in spans + if span["attributes"].get("sentry.op") == OP.GEN_AI_EXECUTE_TOOL + ) + + assert agent_span["name"] == "invoke_agent test_agent" + assert agent_span["attributes"]["sentry.origin"] == "auto.ai.openai_agents" + assert agent_span["attributes"]["gen_ai.agent.name"] == "test_agent" + assert agent_span["attributes"]["gen_ai.operation.name"] == "invoke_agent" + + assert agent_span["attributes"]["gen_ai.request.max_tokens"] == 100 + assert agent_span["attributes"]["gen_ai.request.model"] == "gpt-4" + assert agent_span["attributes"]["gen_ai.request.temperature"] == 0.7 + assert agent_span["attributes"]["gen_ai.request.top_p"] == 1.0 + assert agent_span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "openai" + + assert tool_span["name"] == "execute_tool simple_test_tool" + assert tool_span["attributes"]["gen_ai.agent.name"] == "test_agent" + assert tool_span["attributes"]["gen_ai.operation.name"] == "execute_tool" + + assert tool_span["attributes"]["gen_ai.request.max_tokens"] == 100 + assert tool_span["attributes"]["gen_ai.request.model"] == "gpt-4" + assert tool_span["attributes"]["gen_ai.request.temperature"] == 0.7 + assert tool_span["attributes"]["gen_ai.request.top_p"] == 1.0 + assert tool_span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "openai" + assert tool_span["attributes"]["gen_ai.tool.description"] == "A simple tool" + assert tool_span["attributes"]["gen_ai.tool.input"] == '{"message": "hello"}' + assert tool_span["attributes"]["gen_ai.tool.name"] == "simple_test_tool" + assert tool_span["attributes"]["gen_ai.tool.output"] == "Tool executed with: hello" + + +@pytest.fixture +def run_tool_agent( + sentry_init, + capture_items, + test_agent, + get_model_response, + nonstreaming_responses_tool_call_model_responses, +): + async def inner(tool, run_kwargs=None, **init_kwargs): + client = AsyncOpenAI(api_key="test-key") + model = OpenAIResponsesModel(model="gpt-4", openai_client=client) + agent_with_tool = test_agent.clone(tools=[tool], model=model) + + responses = nonstreaming_responses_tool_call_model_responses( + tool_name=tool.name, + arguments='{"message": "hello"}', + response_model="gpt-4", + response_text="Task completed using the tool", + response_ids=iter(["resp_tool_123", "resp_final_123"]), + usages=iter( + [ + ResponseUsage( + input_tokens=10, + input_tokens_details=InputTokensDetails( + cached_tokens=0, + cache_write_tokens=0, + ), + output_tokens=5, + output_tokens_details=OutputTokensDetails( + reasoning_tokens=0, + ), + total_tokens=15, + ), + ResponseUsage( + input_tokens=15, + input_tokens_details=InputTokensDetails( + cached_tokens=0, + cache_write_tokens=0, + ), + output_tokens=10, + output_tokens_details=OutputTokensDetails( + reasoning_tokens=0, + ), + total_tokens=25, + ), + ] + ), + ) + tool_response = get_model_response( + next(responses), + serialize_pydantic=True, + ) + final_response = get_model_response( + next(responses), + serialize_pydantic=True, + ) - if span_streaming: with patch.object( agent_with_tool.model._client._client, "send", @@ -2881,4115 +2078,1162 @@ async def test_tool_execution_span( integrations=[OpenAIAgentsIntegration()], disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, - send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream", + **init_kwargs, ) items = capture_items("span") + events = None await agents.Runner.run( agent_with_tool, - "Please use the simple test tool", + "Please use the tool", run_config=test_run_config, - hooks=RunHooks() if user_hooks else None, + **(run_kwargs or {}), ) - sentry_sdk.flush() - spans = [item.payload for item in items] - - assert spans[4]["name"] == "test_agent workflow" - assert spans[4]["attributes"]["sentry.origin"] == "auto.ai.openai_agents" - - agent_span = next( - span - for span in spans - if span["attributes"]["sentry.op"] == OP.GEN_AI_INVOKE_AGENT - ) - ai_client_span1, ai_client_span2 = ( - span - for span in spans - if span["attributes"].get("sentry.op") == OP.GEN_AI_CHAT - ) tool_span = next( - span - for span in spans - if span["attributes"]["sentry.op"] == OP.GEN_AI_EXECUTE_TOOL - ) - - available_tool = { - "name": "simple_test_tool", - "description": "A simple tool", - "parameters": { - "properties": {"message": {"title": "Message", "type": "string"}}, - "required": ["message"], - "title": "simple_test_tool_args", - "type": "object", - "additionalProperties": False, - }, - } - - assert agent_span["name"] == "invoke_agent test_agent" - assert agent_span["attributes"]["sentry.origin"] == "auto.ai.openai_agents" - assert agent_span["attributes"]["gen_ai.agent.name"] == "test_agent" - assert agent_span["attributes"]["gen_ai.operation.name"] == "invoke_agent" - - assert agent_span["attributes"]["gen_ai.request.max_tokens"] == 100 - assert agent_span["attributes"]["gen_ai.request.model"] == "gpt-4" - assert agent_span["attributes"]["gen_ai.request.temperature"] == 0.7 - assert agent_span["attributes"]["gen_ai.request.top_p"] == 1.0 - assert agent_span["attributes"]["gen_ai.system"] == "openai" - - assert ai_client_span1["name"] == "chat gpt-4" - assert ai_client_span1["attributes"]["gen_ai.operation.name"] == "chat" - assert ai_client_span1["attributes"]["gen_ai.system"] == "openai" - assert ai_client_span1["attributes"]["gen_ai.agent.name"] == "test_agent" - - ai_client_span1_available_tool = json.loads( - ai_client_span1["attributes"][SPANDATA.GEN_AI_TOOL_DEFINITIONS] - )[0] - - assert all( - ai_client_span1_available_tool[k] == v for k, v in available_tool.items() + item.payload + for item in items + if item.payload["attributes"].get("sentry.op") == OP.GEN_AI_EXECUTE_TOOL ) + return tool_span, tool_span["attributes"] - assert ai_client_span1["attributes"]["gen_ai.request.max_tokens"] == 100 - assert ai_client_span1["attributes"][ - "gen_ai.request.messages" - ] == safe_serialize( - [ - { - "role": "user", - "content": [ - {"type": "text", "text": "Please use the simple test tool"} - ], - }, - ] - ) - assert ai_client_span1["attributes"]["gen_ai.request.model"] == "gpt-4" - assert ai_client_span1["attributes"]["gen_ai.request.temperature"] == 0.7 - assert ai_client_span1["attributes"]["gen_ai.request.top_p"] == 1.0 - assert ai_client_span1["attributes"]["gen_ai.usage.input_tokens"] == 10 - assert ai_client_span1["attributes"]["gen_ai.usage.input_tokens.cached"] == 0 - assert ai_client_span1["attributes"]["gen_ai.usage.output_tokens"] == 5 - assert ( - ai_client_span1["attributes"]["gen_ai.usage.output_tokens.reasoning"] == 0 - ) - assert ai_client_span1["attributes"]["gen_ai.usage.total_tokens"] == 15 - - tool_call = { - "arguments": '{"message": "hello"}', - "call_id": "call_123", - "name": "simple_test_tool", - "type": "function_call", - "id": "call_123", - "status": None, - } - - if OPENAI_VERSION >= (2, 25, 0): - tool_call["namespace"] = None - - parsed_tool_calls = json.loads( - ai_client_span1["attributes"]["gen_ai.response.tool_calls"] - ) - assert len(parsed_tool_calls) == 1 - assert tool_call.items() <= parsed_tool_calls[0].items() - - assert tool_span["name"] == "execute_tool simple_test_tool" - assert tool_span["attributes"]["gen_ai.agent.name"] == "test_agent" - assert tool_span["attributes"]["gen_ai.operation.name"] == "execute_tool" - - assert tool_span["attributes"]["gen_ai.request.max_tokens"] == 100 - assert tool_span["attributes"]["gen_ai.request.model"] == "gpt-4" - assert tool_span["attributes"]["gen_ai.request.temperature"] == 0.7 - assert tool_span["attributes"]["gen_ai.request.top_p"] == 1.0 - assert tool_span["attributes"]["gen_ai.system"] == "openai" - assert tool_span["attributes"]["gen_ai.tool.description"] == "A simple tool" - assert tool_span["attributes"]["gen_ai.tool.input"] == '{"message": "hello"}' - assert tool_span["attributes"]["gen_ai.tool.name"] == "simple_test_tool" - assert ( - tool_span["attributes"]["gen_ai.tool.output"] == "Tool executed with: hello" + (transaction,) = events + tool_span = next( + span + for span in transaction["spans"] + if span["op"] == OP.GEN_AI_EXECUTE_TOOL ) - assert ai_client_span2["name"] == "chat gpt-4" - assert ai_client_span2["attributes"]["gen_ai.agent.name"] == "test_agent" - assert ai_client_span2["attributes"]["gen_ai.operation.name"] == "chat" + return tool_span, tool_span["data"] - ai_client_span2_available_tool = json.loads( - ai_client_span2["attributes"][SPANDATA.GEN_AI_TOOL_DEFINITIONS] - )[0] + return inner - assert all( - ai_client_span2_available_tool[k] == v for k, v in available_tool.items() - ) - assert ai_client_span2["attributes"]["gen_ai.request.max_tokens"] == 100 - assert ai_client_span2["attributes"][ - "gen_ai.request.messages" - ] == safe_serialize( - [ - { - "role": "user", - "content": [ - {"type": "text", "text": "Please use the simple test tool"} - ], - }, - { - "role": "assistant", - "content": [ - { - "arguments": '{"message": "hello"}', - "call_id": "call_123", - "name": "simple_test_tool", - "type": "function_call", - "id": "call_123", - } - ], - }, - { - "role": "tool", - "content": [ - { - "call_id": "call_123", - "output": "Tool executed with: hello", - "type": "function_call_output", - } - ], - }, - ] - ) - assert ai_client_span2["attributes"]["gen_ai.request.model"] == "gpt-4" - assert ai_client_span2["attributes"]["gen_ai.request.temperature"] == 0.7 - assert ai_client_span2["attributes"]["gen_ai.request.top_p"] == 1.0 - assert ( - ai_client_span2["attributes"]["gen_ai.response.text"] - == "Task completed using the tool" - ) - assert ai_client_span2["attributes"]["gen_ai.system"] == "openai" - assert ai_client_span2["attributes"]["gen_ai.usage.input_tokens.cached"] == 0 - assert ai_client_span2["attributes"]["gen_ai.usage.input_tokens"] == 15 - assert ( - ai_client_span2["attributes"]["gen_ai.usage.output_tokens.reasoning"] == 0 - ) - assert ai_client_span2["attributes"]["gen_ai.usage.output_tokens"] == 10 - assert ai_client_span2["attributes"]["gen_ai.usage.total_tokens"] == 25 - - elif stream_gen_ai_spans: - with patch.object( - agent_with_tool.model._client._client, - "send", - side_effect=[tool_response, final_response], - ) as _: - sentry_init( - integrations=[OpenAIAgentsIntegration()], - traces_sample_rate=1.0, - send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - ) - - items = capture_items("transaction", "span") - - await agents.Runner.run( - agent_with_tool, - "Please use the simple test tool", - run_config=test_run_config, - hooks=RunHooks() if user_hooks else None, - ) - - (transaction,) = (item.payload for item in items if item.type == "transaction") - assert transaction["transaction"] == "test_agent workflow" - assert transaction["contexts"]["trace"]["origin"] == "auto.ai.openai_agents" - - spans = [item.payload for item in items if item.type == "span"] - agent_span = next( - span - for span in spans - if span["attributes"]["sentry.op"] == OP.GEN_AI_INVOKE_AGENT - ) - ai_client_span1, ai_client_span2 = ( - span for span in spans if span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - ) - tool_span = next( - span - for span in spans - if span["attributes"]["sentry.op"] == OP.GEN_AI_EXECUTE_TOOL - ) - - available_tool = { - "name": "simple_test_tool", - "description": "A simple tool", - "parameters": { - "properties": {"message": {"title": "Message", "type": "string"}}, - "required": ["message"], - "title": "simple_test_tool_args", - "type": "object", - "additionalProperties": False, - }, - } - - assert agent_span["name"] == "invoke_agent test_agent" - assert agent_span["attributes"]["sentry.origin"] == "auto.ai.openai_agents" - assert agent_span["attributes"]["gen_ai.agent.name"] == "test_agent" - assert agent_span["attributes"]["gen_ai.operation.name"] == "invoke_agent" - - assert agent_span["attributes"]["gen_ai.request.max_tokens"] == 100 - assert agent_span["attributes"]["gen_ai.request.model"] == "gpt-4" - assert agent_span["attributes"]["gen_ai.request.temperature"] == 0.7 - assert agent_span["attributes"]["gen_ai.request.top_p"] == 1.0 - assert agent_span["attributes"]["gen_ai.system"] == "openai" - - assert ai_client_span1["name"] == "chat gpt-4" - assert ai_client_span1["attributes"]["gen_ai.operation.name"] == "chat" - assert ai_client_span1["attributes"]["gen_ai.system"] == "openai" - assert ai_client_span1["attributes"]["gen_ai.agent.name"] == "test_agent" - - ai_client_span1_available_tool = json.loads( - ai_client_span1["attributes"][SPANDATA.GEN_AI_TOOL_DEFINITIONS] - )[0] - - assert all( - ai_client_span1_available_tool[k] == v for k, v in available_tool.items() - ) - - assert ai_client_span1["attributes"]["gen_ai.request.max_tokens"] == 100 - assert ai_client_span1["attributes"][ - "gen_ai.request.messages" - ] == safe_serialize( - [ - { - "role": "user", - "content": [ - {"type": "text", "text": "Please use the simple test tool"} - ], - }, - ] - ) - assert ai_client_span1["attributes"]["gen_ai.request.model"] == "gpt-4" - assert ai_client_span1["attributes"]["gen_ai.request.temperature"] == 0.7 - assert ai_client_span1["attributes"]["gen_ai.request.top_p"] == 1.0 - assert ai_client_span1["attributes"]["gen_ai.usage.input_tokens"] == 10 - assert ai_client_span1["attributes"]["gen_ai.usage.input_tokens.cached"] == 0 - assert ai_client_span1["attributes"]["gen_ai.usage.output_tokens"] == 5 - assert ( - ai_client_span1["attributes"]["gen_ai.usage.output_tokens.reasoning"] == 0 - ) - assert ai_client_span1["attributes"]["gen_ai.usage.total_tokens"] == 15 - - tool_call = { - "arguments": '{"message": "hello"}', - "call_id": "call_123", - "name": "simple_test_tool", - "type": "function_call", - "id": "call_123", - "status": None, - } - - parsed_tool_calls = json.loads( - ai_client_span1["attributes"]["gen_ai.response.tool_calls"] - ) - assert len(parsed_tool_calls) == 1 - assert tool_call.items() <= parsed_tool_calls[0].items() - - assert tool_span["name"] == "execute_tool simple_test_tool" - assert tool_span["attributes"]["gen_ai.agent.name"] == "test_agent" - assert tool_span["attributes"]["gen_ai.operation.name"] == "execute_tool" - - assert tool_span["attributes"]["gen_ai.request.max_tokens"] == 100 - assert tool_span["attributes"]["gen_ai.request.model"] == "gpt-4" - assert tool_span["attributes"]["gen_ai.request.temperature"] == 0.7 - assert tool_span["attributes"]["gen_ai.request.top_p"] == 1.0 - assert tool_span["attributes"]["gen_ai.system"] == "openai" - assert tool_span["attributes"]["gen_ai.tool.description"] == "A simple tool" - assert tool_span["attributes"]["gen_ai.tool.input"] == '{"message": "hello"}' - assert tool_span["attributes"]["gen_ai.tool.name"] == "simple_test_tool" - assert ( - tool_span["attributes"]["gen_ai.tool.output"] == "Tool executed with: hello" - ) - assert ai_client_span2["name"] == "chat gpt-4" - assert ai_client_span2["attributes"]["gen_ai.agent.name"] == "test_agent" - assert ai_client_span2["attributes"]["gen_ai.operation.name"] == "chat" - - ai_client_span2_available_tool = json.loads( - ai_client_span2["attributes"][SPANDATA.GEN_AI_TOOL_DEFINITIONS] - )[0] - - assert all( - ai_client_span2_available_tool[k] == v for k, v in available_tool.items() - ) - - assert ai_client_span2["attributes"]["gen_ai.request.max_tokens"] == 100 - assert ai_client_span2["attributes"][ - "gen_ai.request.messages" - ] == safe_serialize( - [ - { - "role": "user", - "content": [ - {"type": "text", "text": "Please use the simple test tool"} - ], - }, - { - "role": "assistant", - "content": [ - { - "arguments": '{"message": "hello"}', - "call_id": "call_123", - "name": "simple_test_tool", - "type": "function_call", - "id": "call_123", - } - ], - }, - { - "role": "tool", - "content": [ - { - "call_id": "call_123", - "output": "Tool executed with: hello", - "type": "function_call_output", - } - ], - }, - ] - ) - assert ai_client_span2["attributes"]["gen_ai.request.model"] == "gpt-4" - assert ai_client_span2["attributes"]["gen_ai.request.temperature"] == 0.7 - assert ai_client_span2["attributes"]["gen_ai.request.top_p"] == 1.0 - assert ( - ai_client_span2["attributes"]["gen_ai.response.text"] - == "Task completed using the tool" - ) - assert ai_client_span2["attributes"]["gen_ai.system"] == "openai" - assert ai_client_span2["attributes"]["gen_ai.usage.input_tokens.cached"] == 0 - assert ai_client_span2["attributes"]["gen_ai.usage.input_tokens"] == 15 - assert ( - ai_client_span2["attributes"]["gen_ai.usage.output_tokens.reasoning"] == 0 - ) - assert ai_client_span2["attributes"]["gen_ai.usage.output_tokens"] == 10 - assert ai_client_span2["attributes"]["gen_ai.usage.total_tokens"] == 25 - - else: - with patch.object( - agent_with_tool.model._client._client, - "send", - side_effect=[tool_response, final_response], - ) as _: - sentry_init( - integrations=[OpenAIAgentsIntegration()], - traces_sample_rate=1.0, - send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - ) - - events = capture_events() - - await agents.Runner.run( - agent_with_tool, - "Please use the simple test tool", - run_config=test_run_config, - hooks=RunHooks() if user_hooks else None, - ) - - (transaction,) = events - spans = transaction["spans"] - agent_span = next( - span for span in spans if span["op"] == OP.GEN_AI_INVOKE_AGENT - ) - ai_client_span1, ai_client_span2 = ( - span for span in spans if span["op"] == OP.GEN_AI_CHAT - ) - tool_span = next(span for span in spans if span["op"] == OP.GEN_AI_EXECUTE_TOOL) - - available_tool = { - "name": "simple_test_tool", - "description": "A simple tool", - "parameters": { - "properties": {"message": {"title": "Message", "type": "string"}}, - "required": ["message"], - "title": "simple_test_tool_args", - "type": "object", - "additionalProperties": False, - }, - } - - assert transaction["transaction"] == "test_agent workflow" - assert transaction["contexts"]["trace"]["origin"] == "auto.ai.openai_agents" - - assert agent_span["description"] == "invoke_agent test_agent" - assert agent_span["origin"] == "auto.ai.openai_agents" - assert agent_span["data"]["gen_ai.agent.name"] == "test_agent" - assert agent_span["data"]["gen_ai.operation.name"] == "invoke_agent" - - assert agent_span["data"]["gen_ai.request.max_tokens"] == 100 - assert agent_span["data"]["gen_ai.request.model"] == "gpt-4" - assert agent_span["data"]["gen_ai.request.temperature"] == 0.7 - assert agent_span["data"]["gen_ai.request.top_p"] == 1.0 - assert agent_span["data"]["gen_ai.system"] == "openai" - - assert ai_client_span1["description"] == "chat gpt-4" - assert ai_client_span1["data"]["gen_ai.operation.name"] == "chat" - assert ai_client_span1["data"]["gen_ai.system"] == "openai" - assert ai_client_span1["data"]["gen_ai.agent.name"] == "test_agent" - - ai_client_span1_available_tool = json.loads( - ai_client_span1["data"][SPANDATA.GEN_AI_TOOL_DEFINITIONS] - )[0] - assert all( - ai_client_span1_available_tool[k] == v for k, v in available_tool.items() - ) - - assert ai_client_span1["data"]["gen_ai.request.max_tokens"] == 100 - assert ai_client_span1["data"]["gen_ai.request.messages"] == safe_serialize( - [ - { - "role": "user", - "content": [ - {"type": "text", "text": "Please use the simple test tool"} - ], - }, - ] - ) - assert ai_client_span1["data"]["gen_ai.request.model"] == "gpt-4" - assert ai_client_span1["data"]["gen_ai.request.temperature"] == 0.7 - assert ai_client_span1["data"]["gen_ai.request.top_p"] == 1.0 - assert ai_client_span1["data"]["gen_ai.usage.input_tokens"] == 10 - assert ai_client_span1["data"]["gen_ai.usage.input_tokens.cached"] == 0 - assert ai_client_span1["data"]["gen_ai.usage.output_tokens"] == 5 - assert ai_client_span1["data"]["gen_ai.usage.output_tokens.reasoning"] == 0 - assert ai_client_span1["data"]["gen_ai.usage.total_tokens"] == 15 - - tool_call = { - "arguments": '{"message": "hello"}', - "call_id": "call_123", - "name": "simple_test_tool", - "type": "function_call", - "id": "call_123", - "status": None, - } - - parsed_tool_calls = json.loads( - ai_client_span1["data"]["gen_ai.response.tool_calls"] - ) - assert len(parsed_tool_calls) == 1 - assert tool_call.items() <= parsed_tool_calls[0].items() - - assert tool_span["description"] == "execute_tool simple_test_tool" - assert tool_span["data"]["gen_ai.agent.name"] == "test_agent" - assert tool_span["data"]["gen_ai.operation.name"] == "execute_tool" - - assert tool_span["data"]["gen_ai.request.max_tokens"] == 100 - assert tool_span["data"]["gen_ai.request.model"] == "gpt-4" - assert tool_span["data"]["gen_ai.request.temperature"] == 0.7 - assert tool_span["data"]["gen_ai.request.top_p"] == 1.0 - assert tool_span["data"]["gen_ai.system"] == "openai" - assert tool_span["data"]["gen_ai.tool.description"] == "A simple tool" - assert tool_span["data"]["gen_ai.tool.input"] == '{"message": "hello"}' - assert tool_span["data"]["gen_ai.tool.name"] == "simple_test_tool" - assert tool_span["data"]["gen_ai.tool.output"] == "Tool executed with: hello" - assert ai_client_span2["description"] == "chat gpt-4" - assert ai_client_span2["data"]["gen_ai.agent.name"] == "test_agent" - assert ai_client_span2["data"]["gen_ai.operation.name"] == "chat" - - ai_client_span2_available_tool = json.loads( - ai_client_span2["data"][SPANDATA.GEN_AI_TOOL_DEFINITIONS] - )[0] - assert all( - ai_client_span2_available_tool[k] == v for k, v in available_tool.items() - ) - - assert ai_client_span2["data"]["gen_ai.request.max_tokens"] == 100 - assert ai_client_span2["data"]["gen_ai.request.messages"] == safe_serialize( - [ - { - "role": "tool", - "content": [ - { - "call_id": "call_123", - "output": "Tool executed with: hello", - "type": "function_call_output", - } - ], - }, - ] - ) - assert ai_client_span2["data"]["gen_ai.request.model"] == "gpt-4" - assert ai_client_span2["data"]["gen_ai.request.temperature"] == 0.7 - assert ai_client_span2["data"]["gen_ai.request.top_p"] == 1.0 - assert ( - ai_client_span2["data"]["gen_ai.response.text"] - == "Task completed using the tool" - ) - assert ai_client_span2["data"]["gen_ai.system"] == "openai" - assert ai_client_span2["data"]["gen_ai.usage.input_tokens.cached"] == 0 - assert ai_client_span2["data"]["gen_ai.usage.input_tokens"] == 15 - assert ai_client_span2["data"]["gen_ai.usage.output_tokens.reasoning"] == 0 - assert ai_client_span2["data"]["gen_ai.usage.output_tokens"] == 10 - assert ai_client_span2["data"]["gen_ai.usage.total_tokens"] == 25 - - -@pytest.mark.parametrize("user_hooks", [True, False]) -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) -@pytest.mark.asyncio -async def test_run_streamed_tool_execution_span( - sentry_init, - capture_events, - capture_items, - test_agent, - simple_test_tool, - get_model_response, - async_iterator, - server_side_event_chunks, - streaming_responses_tool_call_model_responses, - stream_gen_ai_spans, - span_streaming, - user_hooks, -): - """ - Test tool execution span creation with `AgentRunner.run_streamed()`. - """ - - # Create agent with the tool - client = AsyncOpenAI(api_key="test-key") - model = OpenAIResponsesModel(model="gpt-4", openai_client=client) - agent_with_tool = test_agent.clone(tools=[simple_test_tool], model=model) - - responses = streaming_responses_tool_call_model_responses( - tool_name="simple_test_tool", - arguments='{"message": "hello"}', - response_model="gpt-4", - response_text="Task completed using the tool", - response_ids=iter(["resp_tool_123", "resp_final_123"]), - usages=iter( - [ - ResponseUsage( - input_tokens=10, - input_tokens_details=InputTokensDetails( - cached_tokens=0, - cache_write_tokens=0, - ), - output_tokens=5, - output_tokens_details=OutputTokensDetails( - reasoning_tokens=0, - ), - total_tokens=15, - ), - ResponseUsage( - input_tokens=15, - input_tokens_details=InputTokensDetails( - cached_tokens=0, - cache_write_tokens=0, - ), - output_tokens=10, - output_tokens_details=OutputTokensDetails( - reasoning_tokens=0, - ), - total_tokens=25, - ), - ] - ), - ) - - request_headers = {} - # openai-agents calls with_streaming_response() if available starting with - # https://github.com/openai/openai-agents-python/commit/159beb56130f7d85192acfd593c9168757984dc0. - # When using with_streaming_response() the header set below changes the response type: - # https://github.com/openai/openai-python/blob/656e3cab4a18262a49b961d41293367e45ee71b9/src/openai/_response.py#L67. - if parse_version(OPENAI_AGENTS_VERSION) >= (0, 10, 3) and hasattr( - agent_with_tool.model._client.responses, "with_streaming_response" - ): - request_headers["X-Stainless-Raw-Response"] = "stream" - - tool_response = get_model_response( - async_iterator(server_side_event_chunks(next(responses))), - request_headers=request_headers, - ) - final_response = get_model_response( - async_iterator(server_side_event_chunks(next(responses))), - request_headers=request_headers, - ) - - if span_streaming: - with patch.object( - agent_with_tool.model._client._client, - "send", - side_effect=[tool_response, final_response], - ) as _: - sentry_init( - integrations=[OpenAIAgentsIntegration()], - disabled_integrations=[StdlibIntegration], - traces_sample_rate=1.0, - send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream", - ) - - items = capture_items("span") - - result = agents.Runner.run_streamed( - agent_with_tool, - "Please use the simple test tool", - run_config=test_run_config, - hooks=RunHooks() if user_hooks else None, - ) - - async for event in result.stream_events(): - pass - - sentry_sdk.flush() - spans = [item.payload for item in items] - - agent_span = next( - span - for span in spans - if span["attributes"]["sentry.op"] == OP.GEN_AI_INVOKE_AGENT - ) - tool_span = next( - span - for span in spans - if span["attributes"].get("sentry.op") == OP.GEN_AI_EXECUTE_TOOL - ) - - assert agent_span["name"] == "invoke_agent test_agent" - assert agent_span["attributes"]["sentry.origin"] == "auto.ai.openai_agents" - assert agent_span["attributes"]["gen_ai.agent.name"] == "test_agent" - assert agent_span["attributes"]["gen_ai.operation.name"] == "invoke_agent" - - assert agent_span["attributes"]["gen_ai.request.max_tokens"] == 100 - assert agent_span["attributes"]["gen_ai.request.model"] == "gpt-4" - assert agent_span["attributes"]["gen_ai.request.temperature"] == 0.7 - assert agent_span["attributes"]["gen_ai.request.top_p"] == 1.0 - assert agent_span["attributes"]["gen_ai.system"] == "openai" - - assert tool_span["name"] == "execute_tool simple_test_tool" - assert tool_span["attributes"]["gen_ai.agent.name"] == "test_agent" - assert tool_span["attributes"]["gen_ai.operation.name"] == "execute_tool" - - assert tool_span["attributes"]["gen_ai.request.max_tokens"] == 100 - assert tool_span["attributes"]["gen_ai.request.model"] == "gpt-4" - assert tool_span["attributes"]["gen_ai.request.temperature"] == 0.7 - assert tool_span["attributes"]["gen_ai.request.top_p"] == 1.0 - assert tool_span["attributes"]["gen_ai.system"] == "openai" - assert tool_span["attributes"]["gen_ai.tool.description"] == "A simple tool" - assert tool_span["attributes"]["gen_ai.tool.input"] == '{"message": "hello"}' - assert tool_span["attributes"]["gen_ai.tool.name"] == "simple_test_tool" - assert ( - tool_span["attributes"]["gen_ai.tool.output"] == "Tool executed with: hello" - ) - - elif stream_gen_ai_spans: - with patch.object( - agent_with_tool.model._client._client, - "send", - side_effect=[tool_response, final_response], - ) as _: - sentry_init( - integrations=[OpenAIAgentsIntegration()], - traces_sample_rate=1.0, - send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - ) - - items = capture_items("transaction", "span") - - result = agents.Runner.run_streamed( - agent_with_tool, - "Please use the simple test tool", - run_config=test_run_config, - hooks=RunHooks() if user_hooks else None, - ) - - async for event in result.stream_events(): - pass - - (transaction,) = (item.payload for item in items if item.type == "transaction") - assert transaction["transaction"] == "test_agent workflow" - assert transaction["contexts"]["trace"]["origin"] == "auto.ai.openai_agents" - - spans = [item.payload for item in items if item.type == "span"] - agent_span = next( - span - for span in spans - if span["attributes"]["sentry.op"] == OP.GEN_AI_INVOKE_AGENT - ) - tool_span = next( - span - for span in spans - if span["attributes"]["sentry.op"] == OP.GEN_AI_EXECUTE_TOOL - ) - - assert agent_span["name"] == "invoke_agent test_agent" - assert agent_span["attributes"]["sentry.origin"] == "auto.ai.openai_agents" - assert agent_span["attributes"]["gen_ai.agent.name"] == "test_agent" - assert agent_span["attributes"]["gen_ai.operation.name"] == "invoke_agent" - - assert agent_span["attributes"]["gen_ai.request.max_tokens"] == 100 - assert agent_span["attributes"]["gen_ai.request.model"] == "gpt-4" - assert agent_span["attributes"]["gen_ai.request.temperature"] == 0.7 - assert agent_span["attributes"]["gen_ai.request.top_p"] == 1.0 - assert agent_span["attributes"]["gen_ai.system"] == "openai" - - assert tool_span["name"] == "execute_tool simple_test_tool" - assert tool_span["attributes"]["gen_ai.agent.name"] == "test_agent" - assert tool_span["attributes"]["gen_ai.operation.name"] == "execute_tool" - - assert tool_span["attributes"]["gen_ai.request.max_tokens"] == 100 - assert tool_span["attributes"]["gen_ai.request.model"] == "gpt-4" - assert tool_span["attributes"]["gen_ai.request.temperature"] == 0.7 - assert tool_span["attributes"]["gen_ai.request.top_p"] == 1.0 - assert tool_span["attributes"]["gen_ai.system"] == "openai" - assert tool_span["attributes"]["gen_ai.tool.description"] == "A simple tool" - assert tool_span["attributes"]["gen_ai.tool.input"] == '{"message": "hello"}' - assert tool_span["attributes"]["gen_ai.tool.name"] == "simple_test_tool" - assert ( - tool_span["attributes"]["gen_ai.tool.output"] == "Tool executed with: hello" - ) - else: - with patch.object( - agent_with_tool.model._client._client, - "send", - side_effect=[tool_response, final_response], - ) as _: - sentry_init( - integrations=[OpenAIAgentsIntegration()], - traces_sample_rate=1.0, - send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - ) - - events = capture_events() - - result = agents.Runner.run_streamed( - agent_with_tool, - "Please use the simple test tool", - run_config=test_run_config, - hooks=RunHooks() if user_hooks else None, - ) - - async for event in result.stream_events(): - pass - - (transaction,) = events - spans = transaction["spans"] - agent_span = next( - span for span in spans if span["op"] == OP.GEN_AI_INVOKE_AGENT - ) - tool_span = next(span for span in spans if span["op"] == OP.GEN_AI_EXECUTE_TOOL) - - assert transaction["transaction"] == "test_agent workflow" - assert transaction["contexts"]["trace"]["origin"] == "auto.ai.openai_agents" - - assert agent_span["description"] == "invoke_agent test_agent" - assert agent_span["origin"] == "auto.ai.openai_agents" - assert agent_span["data"]["gen_ai.agent.name"] == "test_agent" - assert agent_span["data"]["gen_ai.operation.name"] == "invoke_agent" - - assert agent_span["data"]["gen_ai.request.max_tokens"] == 100 - assert agent_span["data"]["gen_ai.request.model"] == "gpt-4" - assert agent_span["data"]["gen_ai.request.temperature"] == 0.7 - assert agent_span["data"]["gen_ai.request.top_p"] == 1.0 - assert agent_span["data"]["gen_ai.system"] == "openai" - - assert tool_span["description"] == "execute_tool simple_test_tool" - assert tool_span["data"]["gen_ai.agent.name"] == "test_agent" - assert tool_span["data"]["gen_ai.operation.name"] == "execute_tool" - - assert tool_span["data"]["gen_ai.request.max_tokens"] == 100 - assert tool_span["data"]["gen_ai.request.model"] == "gpt-4" - assert tool_span["data"]["gen_ai.request.temperature"] == 0.7 - assert tool_span["data"]["gen_ai.request.top_p"] == 1.0 - assert tool_span["data"]["gen_ai.system"] == "openai" - assert tool_span["data"]["gen_ai.tool.description"] == "A simple tool" - assert tool_span["data"]["gen_ai.tool.input"] == '{"message": "hello"}' - assert tool_span["data"]["gen_ai.tool.name"] == "simple_test_tool" - assert tool_span["data"]["gen_ai.tool.output"] == "Tool executed with: hello" - - -@pytest.fixture -def run_tool_agent( - sentry_init, - capture_events, - capture_items, - test_agent, - get_model_response, - nonstreaming_responses_tool_call_model_responses, -): - async def inner(tool, span_streaming, run_kwargs=None, **init_kwargs): - client = AsyncOpenAI(api_key="test-key") - model = OpenAIResponsesModel(model="gpt-4", openai_client=client) - agent_with_tool = test_agent.clone(tools=[tool], model=model) - - responses = nonstreaming_responses_tool_call_model_responses( - tool_name=tool.name, - arguments='{"message": "hello"}', - response_model="gpt-4", - response_text="Task completed using the tool", - response_ids=iter(["resp_tool_123", "resp_final_123"]), - usages=iter( - [ - ResponseUsage( - input_tokens=10, - input_tokens_details=InputTokensDetails( - cached_tokens=0, - cache_write_tokens=0, - ), - output_tokens=5, - output_tokens_details=OutputTokensDetails( - reasoning_tokens=0, - ), - total_tokens=15, - ), - ResponseUsage( - input_tokens=15, - input_tokens_details=InputTokensDetails( - cached_tokens=0, - cache_write_tokens=0, - ), - output_tokens=10, - output_tokens_details=OutputTokensDetails( - reasoning_tokens=0, - ), - total_tokens=25, - ), - ] - ), - ) - tool_response = get_model_response( - next(responses), - serialize_pydantic=True, - ) - final_response = get_model_response( - next(responses), - serialize_pydantic=True, - ) - - with patch.object( - agent_with_tool.model._client._client, - "send", - side_effect=[tool_response, final_response], - ) as _: - sentry_init( - integrations=[OpenAIAgentsIntegration()], - disabled_integrations=[StdlibIntegration], - traces_sample_rate=1.0, - stream_gen_ai_spans=span_streaming, - trace_lifecycle="stream" if span_streaming else "static", - **init_kwargs, - ) - - items = capture_items("span") if span_streaming else None - events = None if span_streaming else capture_events() - - await agents.Runner.run( - agent_with_tool, - "Please use the tool", - run_config=test_run_config, - **(run_kwargs or {}), - ) - - if span_streaming: - sentry_sdk.flush() - tool_span = next( - item.payload - for item in items - if item.payload["attributes"].get("sentry.op") == OP.GEN_AI_EXECUTE_TOOL - ) - return tool_span, tool_span["attributes"] - - (transaction,) = events - tool_span = next( - span - for span in transaction["spans"] - if span["op"] == OP.GEN_AI_EXECUTE_TOOL - ) - return tool_span, tool_span["data"] - - return inner - - -@pytest.fixture -def simple_test_tool(): - @agents.function_tool - def simple_test_tool(message: str) -> str: - """A simple tool""" - return f"Tool executed with: {message}" - - return simple_test_tool - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize( - "data_collection,send_default_pii,expect_input,expect_output", - [ - pytest.param( - {"gen_ai": {"inputs": True, "outputs": True}}, - False, - True, - True, - id="gen-ai-inputs-and-outputs-enabled-overrides-pii-disabled", - ), - pytest.param( - {"gen_ai": {"inputs": False, "outputs": False}}, - True, - False, - False, - id="gen-ai-inputs-and-outputs-disabled-overrides-pii-enabled", - ), - pytest.param( - {"gen_ai": {"inputs": True, "outputs": False}}, - False, - True, - False, - id="gen-ai-only-inputs-enabled", - ), - pytest.param( - {"gen_ai": {"inputs": False, "outputs": True}}, - False, - False, - True, - id="gen-ai-only-outputs-enabled", - ), - pytest.param( - {}, - False, - True, - True, - id="gen-ai-omitted-defaults-to-enabled", - ), - pytest.param( - {"gen_ai": {"inputs": False, "outputs": False}}, - False, - False, - False, - id="gen-ai-inputs-and-outputs-disabled-and-pii-disabled", - ), - pytest.param( - None, - False, - False, - False, - id="no-gen-ai-data-collection-falls-back-to-send-default-pii", - ), - pytest.param( - None, - True, - True, - True, - id="no-gen-ai-data-collection-pii-enabled-collects", - ), - ], -) -@pytest.mark.asyncio -async def test_tool_execution_span_data_collection( - run_tool_agent, - simple_test_tool, - data_collection, - send_default_pii, - expect_input, - expect_output, - span_streaming, -): - init_kwargs = {"send_default_pii": send_default_pii} - if data_collection is not None: - init_kwargs["data_collection"] = data_collection - - _, tool_span_data = await run_tool_agent( - simple_test_tool, - span_streaming, - **init_kwargs, - ) - - if expect_input: - assert tool_span_data[SPANDATA.GEN_AI_TOOL_INPUT] == '{"message": "hello"}' - else: - assert SPANDATA.GEN_AI_TOOL_INPUT not in tool_span_data - - if expect_output: - assert ( - tool_span_data[SPANDATA.GEN_AI_TOOL_OUTPUT] == "Tool executed with: hello" - ) - else: - assert SPANDATA.GEN_AI_TOOL_OUTPUT not in tool_span_data - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.asyncio -async def test_tool_execution_error_data_collection( - run_tool_agent, - span_streaming, -): - @agents.function_tool - def failing_tool(message: str) -> str: - """A tool that fails""" - raise ValueError("Tool execution failed") - - tool_span, tool_span_data = await run_tool_agent( - failing_tool, - span_streaming, - data_collection={"gen_ai": {"outputs": False}}, - ) - - assert tool_span_data[SPANDATA.GEN_AI_TOOL_NAME] == "failing_tool" - assert tool_span["status"] == ("error" if span_streaming else "internal_error") - assert SPANDATA.GEN_AI_TOOL_OUTPUT not in tool_span_data - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.skipif( - parse_version(OPENAI_AGENTS_VERSION) < (0, 4, 0), - reason="conversation_id support requires openai-agents >= 0.4.0", -) -@pytest.mark.asyncio -async def test_tool_execution_span_non_pii_data_always_set( - run_tool_agent, - simple_test_tool, - span_streaming, -): - _, tool_span_data = await run_tool_agent( - simple_test_tool, - span_streaming, - run_kwargs={"conversation_id": "conv_tool_test_456"}, - data_collection={"gen_ai": {"inputs": False, "outputs": False}}, - ) - - assert tool_span_data[SPANDATA.GEN_AI_TOOL_NAME] == "simple_test_tool" - assert tool_span_data[SPANDATA.GEN_AI_TOOL_DESCRIPTION] == "A simple tool" - assert tool_span_data[SPANDATA.GEN_AI_CONVERSATION_ID] == "conv_tool_test_456" - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) -@pytest.mark.asyncio -async def test_hosted_mcp_tool_propagation_header_streamed( - sentry_init, - capture_events, - capture_items, - test_agent, - get_model_response, - async_iterator, - server_side_event_chunks, - stream_gen_ai_spans, - span_streaming, -): - """ - Test responses API is given trace propagation headers with HostedMCPTool. - """ - - hosted_tool = HostedMCPTool( - tool_config={ - "type": "mcp", - "server_label": "test_server", - "server_url": "http://example.com/", - "headers": { - "baggage": "custom=data", - }, - }, - ) - - client = AsyncOpenAI(api_key="z") - - model = OpenAIResponsesModel(model="gpt-4", openai_client=client) - - agent_with_tool = test_agent.clone( - tools=[hosted_tool], - model=model, - ) - - sentry_init( - integrations=[OpenAIAgentsIntegration()], - traces_sample_rate=1.0, - release="d08ebdb9309e1b004c6f52202de58a09c2268e42", - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", - ) - - request_headers = {} - # openai-agents calls with_streaming_response() if available starting with - # https://github.com/openai/openai-agents-python/commit/159beb56130f7d85192acfd593c9168757984dc0. - # When using with_streaming_response() the header set below changes the response type: - # https://github.com/openai/openai-python/blob/656e3cab4a18262a49b961d41293367e45ee71b9/src/openai/_response.py#L67. - if parse_version(OPENAI_AGENTS_VERSION) >= (0, 10, 3) and hasattr( - agent_with_tool.model._client.responses, "with_streaming_response" - ): - request_headers["X-Stainless-Raw-Response"] = "stream" - - response = get_model_response( - async_iterator( - server_side_event_chunks( - [ - ResponseCreatedEvent( - response=Response( - id="chat-id", - output=[], - parallel_tool_calls=False, - tool_choice="none", - tools=[], - created_at=10000000, - model="response-model-id", - object="response", - ), - type="response.created", - sequence_number=0, - ), - ResponseCompletedEvent( - response=Response( - id="chat-id", - output=[ - ResponseOutputMessage( - id="message-id", - content=[ - ResponseOutputText( - annotations=[], - text="the model response", - type="output_text", - ), - ], - role="assistant", - status="completed", - type="message", - ), - ], - parallel_tool_calls=False, - tool_choice="none", - tools=[], - created_at=10000000, - model="response-model-id", - object="response", - usage=ResponseUsage( - input_tokens=20, - input_tokens_details=InputTokensDetails( - cached_tokens=5, - cache_write_tokens=0, - ), - output_tokens=10, - output_tokens_details=OutputTokensDetails( - reasoning_tokens=8, - ), - total_tokens=30, - ), - ), - type="response.completed", - sequence_number=1, - ), - ] - ) - ), - request_headers=request_headers, - ) - - if span_streaming: - items = capture_items("span") - - # Patching https://github.com/openai/openai-python/blob/656e3cab4a18262a49b961d41293367e45ee71b9/src/openai/_base_client.py#L1604 - with patch.object( - agent_with_tool.model._client._client, - "send", - return_value=response, - ) as create, mock.patch( - "sentry_sdk.tracing_utils.Random.randrange", return_value=500000 - ): - sentry_sdk.traces.continue_trace( - {"sentry-trace": "01234567890123456789012345678901-0000000000000000"} - ) - - with sentry_sdk.traces.start_span( - name="/interactions/other-dogs/new-dog", - attributes={ - "sentry.op": "greeting.sniff", - }, - ) as span: - result = agents.Runner.run_streamed( - agent_with_tool, - "Please use the simple test tool", - run_config=test_run_config, - ) - - async for event in result.stream_events(): - pass - - sentry_sdk.flush() - spans = [item.payload for item in items] - - ai_client_span = next( - span - for span in spans - if span["attributes"].get("sentry.op") == OP.GEN_AI_CHAT - ) - - args, kwargs = create.call_args - - request = args[0] - body = json.loads(request.content.decode("utf-8")) - hosted_mcp_tool = body["tools"][0] - - assert hosted_mcp_tool["headers"][ - "sentry-trace" - ] == "{trace_id}-{parent_span_id}-{sampled}".format( - trace_id=span.trace_id, - parent_span_id=ai_client_span["span_id"], - sampled=1, - ) - - expected_outgoing_baggage = ( - "custom=data," - "sentry-trace_id=01234567890123456789012345678901," - "sentry-sample_rand=0.500000," - "sentry-environment=production," - "sentry-release=d08ebdb9309e1b004c6f52202de58a09c2268e42," - "sentry-transaction=/interactions/other-dogs/new-dog," - "sentry-sample_rate=1.0," - "sentry-sampled=true" - ) - - assert hosted_mcp_tool["headers"]["baggage"] == expected_outgoing_baggage - elif stream_gen_ai_spans: - items = capture_items("span") - - # Patching https://github.com/openai/openai-python/blob/656e3cab4a18262a49b961d41293367e45ee71b9/src/openai/_base_client.py#L1604 - with patch.object( - agent_with_tool.model._client._client, - "send", - return_value=response, - ) as create, mock.patch( - "sentry_sdk.tracing_utils.Random.randrange", return_value=500000 - ): - with sentry_sdk.start_transaction( - name="/interactions/other-dogs/new-dog", - op="greeting.sniff", - trace_id="01234567890123456789012345678901", - ) as transaction: - result = agents.Runner.run_streamed( - agent_with_tool, - "Please use the simple test tool", - run_config=test_run_config, - ) - - async for event in result.stream_events(): - pass - - sentry_sdk.flush() - spans = [item.payload for item in items] - - ai_client_span = next( - span - for span in spans - if span["attributes"].get("sentry.op") == OP.GEN_AI_CHAT - ) - - args, kwargs = create.call_args - - request = args[0] - body = json.loads(request.content.decode("utf-8")) - hosted_mcp_tool = body["tools"][0] - - assert hosted_mcp_tool["headers"][ - "sentry-trace" - ] == "{trace_id}-{parent_span_id}-{sampled}".format( - trace_id=transaction.trace_id, - parent_span_id=ai_client_span["span_id"], - sampled=1, - ) - - expected_outgoing_baggage = ( - "custom=data," - "sentry-trace_id=01234567890123456789012345678901," - "sentry-sample_rand=0.500000," - "sentry-environment=production," - "sentry-release=d08ebdb9309e1b004c6f52202de58a09c2268e42," - "sentry-transaction=/interactions/other-dogs/new-dog," - "sentry-sample_rate=1.0," - "sentry-sampled=true" - ) - - assert hosted_mcp_tool["headers"]["baggage"] == expected_outgoing_baggage - else: - events = capture_events() - - # Patching https://github.com/openai/openai-python/blob/656e3cab4a18262a49b961d41293367e45ee71b9/src/openai/_base_client.py#L1604 - with patch.object( - agent_with_tool.model._client._client, - "send", - return_value=response, - ) as create, mock.patch( - "sentry_sdk.tracing_utils.Random.randrange", return_value=500000 - ): - with sentry_sdk.start_transaction( - name="/interactions/other-dogs/new-dog", - op="greeting.sniff", - trace_id="01234567890123456789012345678901", - ) as transaction: - result = agents.Runner.run_streamed( - agent_with_tool, - "Please use the simple test tool", - run_config=test_run_config, - ) - - async for event in result.stream_events(): - pass - - (transaction_event,) = events - - ai_client_span = next( - span - for span in transaction_event["spans"] - if span["op"] == OP.GEN_AI_CHAT - ) - - args, kwargs = create.call_args - - request = args[0] - body = json.loads(request.content.decode("utf-8")) - hosted_mcp_tool = body["tools"][0] - - assert hosted_mcp_tool["headers"][ - "sentry-trace" - ] == "{trace_id}-{parent_span_id}-{sampled}".format( - trace_id=transaction.trace_id, - parent_span_id=ai_client_span["span_id"], - sampled=1, - ) - - expected_outgoing_baggage = ( - "custom=data," - "sentry-trace_id=01234567890123456789012345678901," - "sentry-sample_rand=0.500000," - "sentry-environment=production," - "sentry-release=d08ebdb9309e1b004c6f52202de58a09c2268e42," - "sentry-transaction=/interactions/other-dogs/new-dog," - "sentry-sample_rate=1.0," - "sentry-sampled=true" - ) - - assert hosted_mcp_tool["headers"]["baggage"] == expected_outgoing_baggage - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) -@pytest.mark.asyncio -async def test_hosted_mcp_tool_propagation_headers( - sentry_init, - capture_events, - capture_items, - test_agent, - get_model_response, - stream_gen_ai_spans, - span_streaming, -): - """ - Test responses API is given trace propagation headers with HostedMCPTool. - """ - - hosted_tool = HostedMCPTool( - tool_config={ - "type": "mcp", - "server_label": "test_server", - "server_url": "http://example.com/", - "headers": { - "baggage": "custom=data", - }, - }, - ) - - client = AsyncOpenAI(api_key="test-key") - model = OpenAIResponsesModel(model="gpt-4", openai_client=client) - - agent_with_tool = test_agent.clone( - tools=[hosted_tool], - model=model, - ) - - sentry_init( - integrations=[OpenAIAgentsIntegration()], - traces_sample_rate=1.0, - release="d08ebdb9309e1b004c6f52202de58a09c2268e42", - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", - ) - - response = get_model_response(EXAMPLE_RESPONSE, serialize_pydantic=True) - - if span_streaming: - items = capture_items("span") - - with patch.object( - agent_with_tool.model._client._client, - "send", - return_value=response, - ) as send, mock.patch( - "sentry_sdk.tracing_utils.Random.randrange", return_value=500000 - ): - sentry_sdk.traces.continue_trace( - {"sentry-trace": "01234567890123456789012345678901-0000000000000000"} - ) - - with sentry_sdk.traces.start_span( - name="/interactions/other-dogs/new-dog", - attributes={ - "sentry.op": "greeting.sniff", - }, - ) as span: - await agents.Runner.run( - agent_with_tool, - "Please use the simple test tool", - run_config=test_run_config, - ) - - sentry_sdk.flush() - spans = [item.payload for item in items] - - ai_client_span = next( - span - for span in spans - if span["attributes"].get("sentry.op") == OP.GEN_AI_CHAT - ) - - args, kwargs = send.call_args - - request = args[0] - body = json.loads(request.content.decode("utf-8")) - hosted_mcp_tool = body["tools"][0] - - assert hosted_mcp_tool["headers"][ - "sentry-trace" - ] == "{trace_id}-{parent_span_id}-{sampled}".format( - trace_id=span.trace_id, - parent_span_id=ai_client_span["span_id"], - sampled=1, - ) - - expected_outgoing_baggage = ( - "custom=data," - "sentry-trace_id=01234567890123456789012345678901," - "sentry-sample_rand=0.500000," - "sentry-environment=production," - "sentry-release=d08ebdb9309e1b004c6f52202de58a09c2268e42," - "sentry-transaction=/interactions/other-dogs/new-dog," - "sentry-sample_rate=1.0," - "sentry-sampled=true" - ) - - assert hosted_mcp_tool["headers"]["baggage"] == expected_outgoing_baggage - elif stream_gen_ai_spans: - items = capture_items("span") - - with patch.object( - agent_with_tool.model._client._client, - "send", - return_value=response, - ) as send, mock.patch( - "sentry_sdk.tracing_utils.Random.randrange", return_value=500000 - ): - with sentry_sdk.start_transaction( - name="/interactions/other-dogs/new-dog", - op="greeting.sniff", - trace_id="01234567890123456789012345678901", - ) as transaction: - await agents.Runner.run( - agent_with_tool, - "Please use the simple test tool", - run_config=test_run_config, - ) - - spans = [item.payload for item in items] - - ai_client_span = next( - span - for span in spans - if span["attributes"].get("sentry.op") == OP.GEN_AI_CHAT - ) - - args, kwargs = send.call_args - - request = args[0] - body = json.loads(request.content.decode("utf-8")) - hosted_mcp_tool = body["tools"][0] - - assert hosted_mcp_tool["headers"][ - "sentry-trace" - ] == "{trace_id}-{parent_span_id}-{sampled}".format( - trace_id=transaction.trace_id, - parent_span_id=ai_client_span["span_id"], - sampled=1, - ) - - expected_outgoing_baggage = ( - "custom=data," - "sentry-trace_id=01234567890123456789012345678901," - "sentry-sample_rand=0.500000," - "sentry-environment=production," - "sentry-release=d08ebdb9309e1b004c6f52202de58a09c2268e42," - "sentry-transaction=/interactions/other-dogs/new-dog," - "sentry-sample_rate=1.0," - "sentry-sampled=true" - ) - - assert hosted_mcp_tool["headers"]["baggage"] == expected_outgoing_baggage - else: - events = capture_events() - - with patch.object( - agent_with_tool.model._client._client, - "send", - return_value=response, - ) as send, mock.patch( - "sentry_sdk.tracing_utils.Random.randrange", return_value=500000 - ): - with sentry_sdk.start_transaction( - name="/interactions/other-dogs/new-dog", - op="greeting.sniff", - trace_id="01234567890123456789012345678901", - ) as transaction: - await agents.Runner.run( - agent_with_tool, - "Please use the simple test tool", - run_config=test_run_config, - ) - - (transaction_event,) = events - - ai_client_span = next( - span - for span in transaction_event["spans"] - if span["op"] == OP.GEN_AI_CHAT - ) - - args, kwargs = send.call_args - - request = args[0] - body = json.loads(request.content.decode("utf-8")) - hosted_mcp_tool = body["tools"][0] - - assert hosted_mcp_tool["headers"][ - "sentry-trace" - ] == "{trace_id}-{parent_span_id}-{sampled}".format( - trace_id=transaction.trace_id, - parent_span_id=ai_client_span["span_id"], - sampled=1, - ) - - expected_outgoing_baggage = ( - "custom=data," - "sentry-trace_id=01234567890123456789012345678901," - "sentry-sample_rand=0.500000," - "sentry-environment=production," - "sentry-release=d08ebdb9309e1b004c6f52202de58a09c2268e42," - "sentry-transaction=/interactions/other-dogs/new-dog," - "sentry-sample_rate=1.0," - "sentry-sampled=true" - ) - - assert hosted_mcp_tool["headers"]["baggage"] == expected_outgoing_baggage - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) -@pytest.mark.asyncio -async def test_model_behavior_error( - sentry_init, - capture_events, - capture_items, - test_agent, - simple_test_tool, - stream_gen_ai_spans, - span_streaming, -): - """ - Example raising agents.exceptions.AgentsException before the agent invocation span is complete. - The mocked API response indicates that "wrong_tool" was called. - """ - - # Create agent with the tool - agent_with_tool = test_agent.clone(tools=[simple_test_tool]) - - if span_streaming: - with patch.dict(os.environ, {"OPENAI_API_KEY": "test-key"}), patch( - "agents.models.openai_responses.OpenAIResponsesModel.get_response" - ) as mock_get_response: - # Create a mock response that includes tool calls - tool_call = ResponseFunctionToolCall( - id="call_123", - call_id="call_123", - name="wrong_tool", - type="function_call", - arguments='{"message": "hello"}', - ) - - tool_response = ModelResponse( - output=[tool_call], - usage=Usage( - requests=1, input_tokens=10, output_tokens=5, total_tokens=15 - ), - response_id="resp_tool_123", - ) - - mock_get_response.side_effect = [tool_response] - - sentry_init( - integrations=[OpenAIAgentsIntegration()], - disabled_integrations=[StdlibIntegration], - traces_sample_rate=1.0, - send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream", - ) - - items = capture_items("span") - - with pytest.raises(ModelBehaviorError): - await agents.Runner.run( - agent_with_tool, - "Please use the simple test tool", - run_config=test_run_config, - ) - - sentry_sdk.flush() - spans = [item.payload for item in items] - - ( - ai_client_span1, - agent_span, - workflow_span, - ) = spans - assert workflow_span["name"] == "test_agent workflow" - assert workflow_span["attributes"]["sentry.origin"] == "auto.ai.openai_agents" - - assert agent_span["name"] == "invoke_agent test_agent" - assert agent_span["attributes"]["sentry.origin"] == "auto.ai.openai_agents" - - # Error due to unrecognized tool in model response. - assert agent_span["status"] == "error" - elif stream_gen_ai_spans: - with patch.dict(os.environ, {"OPENAI_API_KEY": "test-key"}), patch( - "agents.models.openai_responses.OpenAIResponsesModel.get_response" - ) as mock_get_response: - # Create a mock response that includes tool calls - tool_call = ResponseFunctionToolCall( - id="call_123", - call_id="call_123", - name="wrong_tool", - type="function_call", - arguments='{"message": "hello"}', - ) - - tool_response = ModelResponse( - output=[tool_call], - usage=Usage( - requests=1, input_tokens=10, output_tokens=5, total_tokens=15 - ), - response_id="resp_tool_123", - ) - - mock_get_response.side_effect = [tool_response] - - sentry_init( - integrations=[OpenAIAgentsIntegration()], - traces_sample_rate=1.0, - send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - ) - - items = capture_items("span", "transaction") - - with pytest.raises(ModelBehaviorError): - await agents.Runner.run( - agent_with_tool, - "Please use the simple test tool", - run_config=test_run_config, - ) - - (transaction,) = (item.payload for item in items if item.type == "transaction") - assert transaction["transaction"] == "test_agent workflow" - assert transaction["contexts"]["trace"]["origin"] == "auto.ai.openai_agents" - - spans = [item.payload for item in items if item.type == "span"] - - ( - agent_span, - ai_client_span1, - ) = spans - assert agent_span["name"] == "invoke_agent test_agent" - assert agent_span["attributes"]["sentry.origin"] == "auto.ai.openai_agents" - - # Error due to unrecognized tool in model response. - assert agent_span["status"] == "error" - else: - with patch.dict(os.environ, {"OPENAI_API_KEY": "test-key"}), patch( - "agents.models.openai_responses.OpenAIResponsesModel.get_response" - ) as mock_get_response: - # Create a mock response that includes tool calls - tool_call = ResponseFunctionToolCall( - id="call_123", - call_id="call_123", - name="wrong_tool", - type="function_call", - arguments='{"message": "hello"}', - ) - - tool_response = ModelResponse( - output=[tool_call], - usage=Usage( - requests=1, input_tokens=10, output_tokens=5, total_tokens=15 - ), - response_id="resp_tool_123", - ) - - mock_get_response.side_effect = [tool_response] - - sentry_init( - integrations=[OpenAIAgentsIntegration()], - traces_sample_rate=1.0, - send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - ) - events = capture_events() - - with pytest.raises(ModelBehaviorError): - await agents.Runner.run( - agent_with_tool, - "Please use the simple test tool", - run_config=test_run_config, - ) - - (error, transaction) = events - spans = transaction["spans"] - ( - agent_span, - ai_client_span1, - ) = spans - - assert transaction["transaction"] == "test_agent workflow" - assert transaction["contexts"]["trace"]["origin"] == "auto.ai.openai_agents" - - assert agent_span["description"] == "invoke_agent test_agent" - assert agent_span["origin"] == "auto.ai.openai_agents" - - # Error due to unrecognized tool in model response. - assert agent_span["status"] == "internal_error" - assert agent_span["tags"]["status"] == "internal_error" - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) -@pytest.mark.asyncio -async def test_run_error_handling( - sentry_init, - capture_events, - capture_items, - test_agent, - stream_gen_ai_spans, - span_streaming, -): - """ - Test error handling in agent execution. - """ - - if span_streaming: - with patch.dict(os.environ, {"OPENAI_API_KEY": "test-key"}), patch( - "agents.models.openai_responses.OpenAIResponsesModel.get_response" - ) as mock_get_response: - mock_get_response.side_effect = Exception("Model Error") - - sentry_init( - integrations=[ - OpenAIAgentsIntegration(), - LoggingIntegration(event_level=logging.CRITICAL), - ], - disabled_integrations=[StdlibIntegration], - traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream", - ) - - items = capture_items("event", "span") - - with pytest.raises(Exception, match="Model Error"): - await agents.Runner.run( - test_agent, "Test input", run_config=test_run_config - ) - - (error_event,) = (item.payload for item in items if item.type == "event") - - assert error_event["exception"]["values"][0]["type"] == "Exception" - assert error_event["exception"]["values"][0]["value"] == "Model Error" - assert ( - error_event["exception"]["values"][0]["mechanism"]["type"] - == "openai_agents" - ) - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - (ai_client_span, invoke_agent_span, workflow_span) = spans - - assert workflow_span["name"] == "test_agent workflow" - assert workflow_span["attributes"]["sentry.origin"] == "auto.ai.openai_agents" - - assert invoke_agent_span["name"] == "invoke_agent test_agent" - assert ( - invoke_agent_span["attributes"]["sentry.origin"] == "auto.ai.openai_agents" - ) - - assert ai_client_span["name"] == "chat gpt-4" - assert ai_client_span["attributes"]["sentry.origin"] == "auto.ai.openai_agents" - assert ai_client_span["status"] == "error" - elif stream_gen_ai_spans: - with patch.dict(os.environ, {"OPENAI_API_KEY": "test-key"}), patch( - "agents.models.openai_responses.OpenAIResponsesModel.get_response" - ) as mock_get_response: - mock_get_response.side_effect = Exception("Model Error") - - sentry_init( - integrations=[ - OpenAIAgentsIntegration(), - LoggingIntegration(event_level=logging.CRITICAL), - ], - traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - ) - - items = capture_items("event", "span", "transaction") - - with pytest.raises(Exception, match="Model Error"): - await agents.Runner.run( - test_agent, "Test input", run_config=test_run_config - ) - - (error_event,) = (item.payload for item in items if item.type == "event") - - assert error_event["exception"]["values"][0]["type"] == "Exception" - assert error_event["exception"]["values"][0]["value"] == "Model Error" - assert ( - error_event["exception"]["values"][0]["mechanism"]["type"] - == "openai_agents" - ) - - (transaction,) = (item.payload for item in items if item.type == "transaction") - - assert transaction["transaction"] == "test_agent workflow" - assert transaction["contexts"]["trace"]["origin"] == "auto.ai.openai_agents" - - spans = [item.payload for item in items if item.type == "span"] - (invoke_agent_span, ai_client_span) = spans - - assert invoke_agent_span["name"] == "invoke_agent test_agent" - assert ( - invoke_agent_span["attributes"]["sentry.origin"] == "auto.ai.openai_agents" - ) - - assert ai_client_span["name"] == "chat gpt-4" - assert ai_client_span["attributes"]["sentry.origin"] == "auto.ai.openai_agents" - assert ai_client_span["status"] == "error" - else: - with patch.dict(os.environ, {"OPENAI_API_KEY": "test-key"}), patch( - "agents.models.openai_responses.OpenAIResponsesModel.get_response" - ) as mock_get_response: - mock_get_response.side_effect = Exception("Model Error") - - sentry_init( - integrations=[ - OpenAIAgentsIntegration(), - LoggingIntegration(event_level=logging.CRITICAL), - ], - traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - ) - events = capture_events() - - with pytest.raises(Exception, match="Model Error"): - await agents.Runner.run( - test_agent, "Test input", run_config=test_run_config - ) - - ( - error_event, - transaction, - ) = events - - assert error_event["exception"]["values"][0]["type"] == "Exception" - assert error_event["exception"]["values"][0]["value"] == "Model Error" - assert ( - error_event["exception"]["values"][0]["mechanism"]["type"] - == "openai_agents" - ) - - spans = transaction["spans"] - (invoke_agent_span, ai_client_span) = spans - - assert transaction["transaction"] == "test_agent workflow" - assert transaction["contexts"]["trace"]["origin"] == "auto.ai.openai_agents" - - assert invoke_agent_span["description"] == "invoke_agent test_agent" - assert invoke_agent_span["origin"] == "auto.ai.openai_agents" - - assert ai_client_span["description"] == "chat gpt-4" - assert ai_client_span["origin"] == "auto.ai.openai_agents" - assert ai_client_span["status"] == "internal_error" - assert ai_client_span["tags"]["status"] == "internal_error" - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) -@pytest.mark.asyncio -async def test_run_streamed_error_handling( - sentry_init, - capture_events, - capture_items, - test_agent, - stream_gen_ai_spans, - span_streaming, -): - """ - Test error handling in agent execution. - """ - - if span_streaming: - with patch.dict(os.environ, {"OPENAI_API_KEY": "test-key"}), patch( - "agents.models.openai_responses.OpenAIResponsesModel.stream_response" - ) as mock_get_response: - mock_get_response.side_effect = Exception("Model Error") - - sentry_init( - integrations=[ - OpenAIAgentsIntegration(), - LoggingIntegration(event_level=logging.CRITICAL), - ], - disabled_integrations=[StdlibIntegration], - traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream", - ) - - items = capture_items("event", "span") - - with pytest.raises(Exception, match="Model Error"): - result = agents.Runner.run_streamed( - test_agent, "Test input", run_config=test_run_config - ) - - async for event in result.stream_events(): - pass - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - (ai_client_span, invoke_agent_span, workflow_span) = spans - - assert workflow_span["name"] == "test_agent workflow" - assert workflow_span["attributes"]["sentry.origin"] == "auto.ai.openai_agents" - - assert invoke_agent_span["name"] == "invoke_agent test_agent" - assert ( - invoke_agent_span["attributes"]["sentry.origin"] == "auto.ai.openai_agents" - ) - - assert ai_client_span["name"] == "chat gpt-4" - assert ai_client_span["attributes"]["sentry.origin"] == "auto.ai.openai_agents" - assert ai_client_span["status"] == "error" - elif stream_gen_ai_spans: - with patch.dict(os.environ, {"OPENAI_API_KEY": "test-key"}), patch( - "agents.models.openai_responses.OpenAIResponsesModel.stream_response" - ) as mock_get_response: - mock_get_response.side_effect = Exception("Model Error") - - sentry_init( - integrations=[ - OpenAIAgentsIntegration(), - LoggingIntegration(event_level=logging.CRITICAL), - ], - traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - ) - - items = capture_items("event", "span", "transaction") - - with pytest.raises(Exception, match="Model Error"): - result = agents.Runner.run_streamed( - test_agent, "Test input", run_config=test_run_config - ) - - async for event in result.stream_events(): - pass - - (transaction,) = (item.payload for item in items if item.type == "transaction") - - assert transaction["transaction"] == "test_agent workflow" - assert transaction["contexts"]["trace"]["origin"] == "auto.ai.openai_agents" - - spans = [item.payload for item in items if item.type == "span"] - (invoke_agent_span, ai_client_span) = spans - - assert invoke_agent_span["name"] == "invoke_agent test_agent" - assert ( - invoke_agent_span["attributes"]["sentry.origin"] == "auto.ai.openai_agents" - ) - - assert ai_client_span["name"] == "chat gpt-4" - assert ai_client_span["attributes"]["sentry.origin"] == "auto.ai.openai_agents" - assert ai_client_span["status"] == "error" - else: - with patch.dict(os.environ, {"OPENAI_API_KEY": "test-key"}), patch( - "agents.models.openai_responses.OpenAIResponsesModel.stream_response" - ) as mock_get_response: - mock_get_response.side_effect = Exception("Model Error") - - sentry_init( - integrations=[ - OpenAIAgentsIntegration(), - LoggingIntegration(event_level=logging.CRITICAL), - ], - traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - ) - events = capture_events() - - with pytest.raises(Exception, match="Model Error"): - result = agents.Runner.run_streamed( - test_agent, "Test input", run_config=test_run_config - ) - - async for event in result.stream_events(): - pass - - (transaction,) = events - - spans = transaction["spans"] - (invoke_agent_span, ai_client_span) = spans - - assert transaction["transaction"] == "test_agent workflow" - assert transaction["contexts"]["trace"]["origin"] == "auto.ai.openai_agents" - - assert invoke_agent_span["description"] == "invoke_agent test_agent" - assert invoke_agent_span["origin"] == "auto.ai.openai_agents" - - assert ai_client_span["description"] == "chat gpt-4" - assert ai_client_span["origin"] == "auto.ai.openai_agents" - assert ai_client_span["status"] == "internal_error" - assert ai_client_span["tags"]["status"] == "internal_error" - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) -@pytest.mark.asyncio -async def test_error_captures_input_data( - sentry_init, - capture_events, - capture_items, - test_agent, - stream_gen_ai_spans, - span_streaming, -): - """ - Test that input data is captured even when the API call raises an exception. - This verifies that _set_input_data is called before the API call. - """ - client = AsyncOpenAI(api_key="test-key") - model = OpenAIResponsesModel(model="gpt-4", openai_client=client) - agent = test_agent.clone(model=model) - - model_request = httpx.Request( - "POST", - "/responses", - ) - - response = httpx.Response( - 500, - request=model_request, - ) - - if span_streaming or stream_gen_ai_spans: - with patch.object( - agent.model._client._client, - "send", - return_value=response, - ) as _: - sentry_init( - integrations=[ - OpenAIAgentsIntegration(), - LoggingIntegration(event_level=logging.CRITICAL), - ], - disabled_integrations=[StdlibIntegration], - traces_sample_rate=1.0, - send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", - ) - - items = capture_items("event", "span") - - with pytest.raises(InternalServerError, match="Error code: 500"): - await agents.Runner.run(agent, "Test input", run_config=test_run_config) - - (error_event,) = (item.payload for item in items if item.type == "event") - - assert error_event["exception"]["values"][0]["type"] == "InternalServerError" - assert error_event["exception"]["values"][0]["value"] == "Error code: 500" - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - ai_client_span = [ - s for s in spans if s["attributes"].get("sentry.op", "") == "gen_ai.chat" - ][0] - - assert ai_client_span["name"] == "chat gpt-4" - assert ai_client_span["status"] == "error" - - assert "gen_ai.request.messages" in ai_client_span["attributes"] - request_messages = safe_serialize( - [ - {"role": "user", "content": [{"type": "text", "text": "Test input"}]}, - ] - ) - assert ( - ai_client_span["attributes"]["gen_ai.request.messages"] == request_messages - ) - else: - with patch.object( - agent.model._client._client, - "send", - return_value=response, - ) as _: - sentry_init( - integrations=[ - OpenAIAgentsIntegration(), - LoggingIntegration(event_level=logging.CRITICAL), - ], - traces_sample_rate=1.0, - send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - ) - - events = capture_events() - - with pytest.raises(InternalServerError, match="Error code: 500"): - await agents.Runner.run(agent, "Test input", run_config=test_run_config) - - ( - error_event, - transaction, - ) = events - - assert error_event["exception"]["values"][0]["type"] == "InternalServerError" - assert error_event["exception"]["values"][0]["value"] == "Error code: 500" - - spans = transaction["spans"] - ai_client_span = [s for s in spans if s["op"] == "gen_ai.chat"][0] - - assert ai_client_span["description"] == "chat gpt-4" - assert ai_client_span["status"] == "internal_error" - assert ai_client_span["tags"]["status"] == "internal_error" - - assert "gen_ai.request.messages" in ai_client_span["data"] - request_messages = safe_serialize( - [ - {"role": "user", "content": [{"type": "text", "text": "Test input"}]}, - ] - ) - assert ai_client_span["data"]["gen_ai.request.messages"] == request_messages - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) -@pytest.mark.asyncio -async def test_span_status_error( - sentry_init, - capture_events, - capture_items, - test_agent, - stream_gen_ai_spans, - span_streaming, -): - if span_streaming: - with patch.dict(os.environ, {"OPENAI_API_KEY": "test-key"}), patch( - "agents.models.openai_responses.OpenAIResponsesModel.get_response" - ) as mock_get_response: - mock_get_response.side_effect = ValueError("Model Error") - - sentry_init( - integrations=[ - OpenAIAgentsIntegration(), - LoggingIntegration(event_level=logging.CRITICAL), - ], - disabled_integrations=[StdlibIntegration], - traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream", - ) - - items = capture_items("event", "span") - - with pytest.raises(ValueError, match="Model Error"): - await agents.Runner.run( - test_agent, "Test input", run_config=test_run_config - ) - - (error,) = (item.payload for item in items if item.type == "event") - assert error["level"] == "error" - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert spans[0]["status"] == "error" - - assert spans[2]["is_segment"] is True - assert spans[2]["status"] == "error" - elif stream_gen_ai_spans: - with patch.dict(os.environ, {"OPENAI_API_KEY": "test-key"}), patch( - "agents.models.openai_responses.OpenAIResponsesModel.get_response" - ) as mock_get_response: - mock_get_response.side_effect = ValueError("Model Error") - - sentry_init( - integrations=[ - OpenAIAgentsIntegration(), - LoggingIntegration(event_level=logging.CRITICAL), - ], - disabled_integrations=[StdlibIntegration], - traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - ) - - items = capture_items("event", "transaction", "span") - - with pytest.raises(ValueError, match="Model Error"): - await agents.Runner.run( - test_agent, "Test input", run_config=test_run_config - ) - - (error,) = (item.payload for item in items if item.type == "event") - assert error["level"] == "error" - - spans = [item.payload for item in items if item.type == "span"] - assert spans[0]["status"] == "error" - - (transaction,) = (item.payload for item in items if item.type == "transaction") - assert transaction["contexts"]["trace"]["status"] == "internal_error" - else: - with patch.dict(os.environ, {"OPENAI_API_KEY": "test-key"}), patch( - "agents.models.openai_responses.OpenAIResponsesModel.get_response" - ) as mock_get_response: - mock_get_response.side_effect = ValueError("Model Error") - - sentry_init( - integrations=[ - OpenAIAgentsIntegration(), - LoggingIntegration(event_level=logging.CRITICAL), - ], - traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - ) - - events = capture_events() - - with pytest.raises(ValueError, match="Model Error"): - await agents.Runner.run( - test_agent, "Test input", run_config=test_run_config - ) - - (error, transaction) = events - assert error["level"] == "error" - assert transaction["spans"][0]["status"] == "internal_error" - assert transaction["spans"][0]["tags"]["status"] == "internal_error" - assert transaction["contexts"]["trace"]["status"] == "internal_error" - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) -@pytest.mark.asyncio -async def test_multiple_agents_asyncio( - sentry_init, - capture_events, - capture_items, - test_agent, - nonstreaming_responses_model_response, - get_model_response, - stream_gen_ai_spans, - span_streaming, -): - """ - Test that multiple agents can be run at the same time in asyncio tasks - without interfering with each other. - """ - client = AsyncOpenAI(api_key="test-key") - model = OpenAIResponsesModel(model="gpt-4", openai_client=client) - agent = test_agent.clone(model=model) - - response = get_model_response( - nonstreaming_responses_model_response, serialize_pydantic=True - ) - - if span_streaming: - with patch.object( - agent.model._client._client, - "send", - return_value=response, - ) as _: - sentry_init( - integrations=[OpenAIAgentsIntegration()], - disabled_integrations=[StdlibIntegration], - traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream", - ) - - items = capture_items("span") - - async def run(): - await agents.Runner.run( - starting_agent=agent, - input="Test input", - run_config=test_run_config, - ) - - await asyncio.gather(*[run() for _ in range(3)]) - - sentry_sdk.flush() - spans = [item.payload for item in items] - - assert spans[2]["name"] == "test_agent workflow" - assert spans[5]["name"] == "test_agent workflow" - assert spans[8]["name"] == "test_agent workflow" - elif stream_gen_ai_spans: - with patch.object( - agent.model._client._client, - "send", - return_value=response, - ) as _: - sentry_init( - integrations=[OpenAIAgentsIntegration()], - disabled_integrations=[StdlibIntegration], - traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - ) - - items = capture_items("span", "transaction") - - async def run(): - await agents.Runner.run( - starting_agent=agent, - input="Test input", - run_config=test_run_config, - ) - - await asyncio.gather(*[run() for _ in range(3)]) - - txn1, txn2, txn3 = ( - item.payload for item in items if item.type == "transaction" - ) - - assert txn1["transaction"] == "test_agent workflow" - assert txn2["transaction"] == "test_agent workflow" - assert txn3["transaction"] == "test_agent workflow" - else: - with patch.object( - agent.model._client._client, - "send", - return_value=response, - ) as _: - sentry_init( - integrations=[OpenAIAgentsIntegration()], - traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - ) - events = capture_events() - - async def run(): - await agents.Runner.run( - starting_agent=agent, - input="Test input", - run_config=test_run_config, - ) - - await asyncio.gather(*[run() for _ in range(3)]) - - assert len(events) == 3 - txn1, txn2, txn3 = events +@pytest.fixture +def simple_test_tool(): + @agents.function_tool + def simple_test_tool(message: str) -> str: + """A simple tool""" + return f"Tool executed with: {message}" - assert txn1["type"] == "transaction" - assert txn1["transaction"] == "test_agent workflow" - assert txn2["type"] == "transaction" - assert txn2["transaction"] == "test_agent workflow" - assert txn3["type"] == "transaction" - assert txn3["transaction"] == "test_agent workflow" + return simple_test_tool -# Test input messages with mixed roles including "ai" @pytest.mark.parametrize( - "test_message,expected_role", + "data_collection,send_default_pii,expect_input,expect_output", [ - ({"role": "user", "content": "Hello"}, "user"), - ( - {"role": "ai", "content": "Hi there!"}, - "assistant", - ), # Should be mapped to "assistant" - ( - {"role": "assistant", "content": "How can I help?"}, - "assistant", - ), # Should stay "assistant" - ], -) -def test_openai_agents_message_role_mapping( - sentry_init, capture_items, test_message, expected_role -): - """Test that OpenAI Agents integration properly maps message roles like 'ai' to 'assistant'""" - sentry_init( - integrations=[OpenAIAgentsIntegration()], - traces_sample_rate=1.0, - send_default_pii=True, - ) - - get_response_kwargs = {"input": [test_message]} - - from sentry_sdk import start_span - from sentry_sdk.integrations.openai_agents.utils import _set_input_data - - with start_span(op="test") as span: - _set_input_data(span, get_response_kwargs) - - # Verify that messages were processed and roles were mapped - from sentry_sdk.consts import SPANDATA - - stored_messages = json.loads(span._data[SPANDATA.GEN_AI_REQUEST_MESSAGES]) - - # Verify roles were properly mapped - assert stored_messages[0]["role"] == expected_role - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) -@pytest.mark.asyncio -async def test_tool_execution_error_tracing( - sentry_init, - capture_events, - capture_items, - test_agent, - get_model_response, - nonstreaming_responses_tool_call_model_responses, - stream_gen_ai_spans, - span_streaming, -): - """ - Test that tool execution errors are properly tracked via error tracing patch. - - This tests the patch of agents error tracing function to ensure execute_tool - spans are set to error status when tool execution fails. - - The function location varies by version: - - Newer versions: agents.util._error_tracing.attach_error_to_current_span - - Older versions: agents._utils.attach_error_to_current_span - """ - - @agents.function_tool - def failing_tool(message: str) -> str: - """A tool that fails""" - raise ValueError("Tool execution failed") - - # Create agent with the failing tool - client = AsyncOpenAI(api_key="test-key") - model = OpenAIResponsesModel(model="gpt-4", openai_client=client) - agent_with_tool = test_agent.clone(tools=[failing_tool], model=model) - - responses = nonstreaming_responses_tool_call_model_responses( - tool_name="failing_tool", - arguments='{"message": "test"}', - response_model="gpt-4-0613", - response_text="An error occurred while running the tool", - response_ids=iter(["resp_1", "resp_2"]), - usages=iter( - [ - ResponseUsage( - input_tokens=10, - input_tokens_details=InputTokensDetails( - cached_tokens=0, - cache_write_tokens=0, - ), - output_tokens=5, - output_tokens_details=OutputTokensDetails( - reasoning_tokens=0, - ), - total_tokens=15, - ), - ResponseUsage( - input_tokens=15, - input_tokens_details=InputTokensDetails( - cached_tokens=0, - cache_write_tokens=0, - ), - output_tokens=10, - output_tokens_details=OutputTokensDetails( - reasoning_tokens=0, - ), - total_tokens=25, - ), - ] + pytest.param( + {"gen_ai": {"inputs": True, "outputs": True}}, + False, + True, + True, + id="gen-ai-inputs-and-outputs-enabled-overrides-pii-disabled", ), - ) - tool_response = get_model_response( - next(responses), - serialize_pydantic=True, - ) - final_response = get_model_response( - next(responses), - serialize_pydantic=True, - ) - - if span_streaming or stream_gen_ai_spans: - with patch.object( - agent_with_tool.model._client._client, - "send", - side_effect=[tool_response, final_response], - ) as _: - sentry_init( - integrations=[OpenAIAgentsIntegration()], - disabled_integrations=[StdlibIntegration], - traces_sample_rate=1.0, - send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", - ) - items = capture_items("span", "transaction") - - # Note: The agents library catches tool exceptions internally, - # so we don't expect this to raise - await agents.Runner.run( - agent_with_tool, - "Please use the failing tool", - run_config=test_run_config, - ) - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - - # Find the execute_tool span - execute_tool_span = None - for span in spans: - description = span.get("name", "") - if description is not None and description.startswith( - "execute_tool failing_tool" - ): - execute_tool_span = span - break - - # Verify the execute_tool span was created - assert execute_tool_span is not None, "execute_tool span was not created" - assert execute_tool_span["name"] == "execute_tool failing_tool" - assert execute_tool_span["attributes"]["gen_ai.tool.name"] == "failing_tool" - - # Verify error status was set (this is the key test for our patch) - # The span should be marked as error because the tool execution failed - assert execute_tool_span["status"] == "error" - else: - with patch.object( - agent_with_tool.model._client._client, - "send", - side_effect=[tool_response, final_response], - ) as _: - sentry_init( - integrations=[OpenAIAgentsIntegration()], - traces_sample_rate=1.0, - send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - ) - events = capture_events() - - # Note: The agents library catches tool exceptions internally, - # so we don't expect this to raise - await agents.Runner.run( - agent_with_tool, - "Please use the failing tool", - run_config=test_run_config, - ) - - (transaction,) = events - spans = transaction["spans"] - - # Find the execute_tool span - execute_tool_span = None - for span in spans: - description = span.get("description", "") - if description is not None and description.startswith( - "execute_tool failing_tool" - ): - execute_tool_span = span - break - - # Verify the execute_tool span was created - assert execute_tool_span is not None, "execute_tool span was not created" - assert execute_tool_span["description"] == "execute_tool failing_tool" - assert execute_tool_span["data"]["gen_ai.tool.name"] == "failing_tool" - - # Verify error status was set (this is the key test for our patch) - # The span should be marked as error because the tool execution failed - assert execute_tool_span["status"] == "internal_error" - assert execute_tool_span["tags"]["status"] == "internal_error" - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) -@pytest.mark.asyncio -async def test_invoke_agent_span_includes_usage_data( - sentry_init, - capture_events, - capture_items, - test_agent, - get_model_response, - stream_gen_ai_spans, - span_streaming, -): - """ - Test that invoke_agent spans include aggregated usage data from context_wrapper. - This verifies the new functionality added to track token usage in invoke_agent spans. - """ - client = AsyncOpenAI(api_key="z") - model = OpenAIResponsesModel(model="gpt-4", openai_client=client) - agent = test_agent.clone(model=model) - - response = get_model_response( - Response( - id="resp_123", - output=[ - ResponseOutputMessage( - id="msg_123", - type="message", - status="completed", - content=[ - ResponseOutputText( - text="Response with usage", - type="output_text", - annotations=[], - ) - ], - role="assistant", - ) - ], - parallel_tool_calls=False, - tool_choice="none", - tools=[], - created_at=10000000, - model="gpt-4.1-2025-04-14", - object="response", - usage=ResponseUsage( - input_tokens=10, - input_tokens_details=InputTokensDetails( - cached_tokens=0, - cache_write_tokens=0, - ), - output_tokens=20, - output_tokens_details=OutputTokensDetails( - reasoning_tokens=5, - ), - total_tokens=30, - ), + pytest.param( + {"gen_ai": {"inputs": False, "outputs": False}}, + True, + False, + False, + id="gen-ai-inputs-and-outputs-disabled-overrides-pii-enabled", + ), + pytest.param( + {"gen_ai": {"inputs": True, "outputs": False}}, + False, + True, + False, + id="gen-ai-only-inputs-enabled", + ), + pytest.param( + {"gen_ai": {"inputs": False, "outputs": True}}, + False, + False, + True, + id="gen-ai-only-outputs-enabled", + ), + pytest.param( + {}, + False, + True, + True, + id="gen-ai-omitted-defaults-to-enabled", ), - serialize_pydantic=True, - ) - - if span_streaming or stream_gen_ai_spans: - with patch.object( - agent.model._client._client, - "send", - return_value=response, - ) as _: - sentry_init( - integrations=[OpenAIAgentsIntegration()], - disabled_integrations=[StdlibIntegration], - traces_sample_rate=1.0, - send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", - ) - items = capture_items("span", "transaction") - - result = await agents.Runner.run( - agent, "Test input", run_config=test_run_config - ) - - assert result is not None + pytest.param( + {"gen_ai": {"inputs": False, "outputs": False}}, + False, + False, + False, + id="gen-ai-inputs-and-outputs-disabled-and-pii-disabled", + ), + pytest.param( + None, + False, + False, + False, + id="no-gen-ai-data-collection-falls-back-to-send-default-pii", + ), + pytest.param( + None, + True, + True, + True, + id="no-gen-ai-data-collection-pii-enabled-collects", + ), + ], +) +@pytest.mark.asyncio +async def test_tool_execution_span_data_collection( + run_tool_agent, + simple_test_tool, + data_collection, + send_default_pii, + expect_input, + expect_output, +): + init_kwargs = { + "send_default_pii": send_default_pii, + } + if data_collection is not None: + init_kwargs["data_collection"] = data_collection - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - invoke_agent_span = next( - span - for span in spans - if span["attributes"]["sentry.op"] == OP.GEN_AI_INVOKE_AGENT - ) + _, tool_span_data = await run_tool_agent( + simple_test_tool, + **init_kwargs, + ) - # Verify invoke_agent span has usage data from context_wrapper - assert invoke_agent_span["name"] == "invoke_agent test_agent" - assert "gen_ai.usage.input_tokens" in invoke_agent_span["attributes"] - assert "gen_ai.usage.output_tokens" in invoke_agent_span["attributes"] - assert "gen_ai.usage.total_tokens" in invoke_agent_span["attributes"] + if expect_input: + assert tool_span_data[SPANDATA.GEN_AI_TOOL_INPUT] == '{"message": "hello"}' + else: + assert SPANDATA.GEN_AI_TOOL_INPUT not in tool_span_data - assert invoke_agent_span["attributes"]["gen_ai.usage.input_tokens"] == 10 - assert invoke_agent_span["attributes"]["gen_ai.usage.output_tokens"] == 20 - assert invoke_agent_span["attributes"]["gen_ai.usage.total_tokens"] == 30 - assert invoke_agent_span["attributes"]["gen_ai.usage.input_tokens.cached"] == 0 + if expect_output: assert ( - invoke_agent_span["attributes"]["gen_ai.usage.output_tokens.reasoning"] == 5 + tool_span_data[SPANDATA.GEN_AI_TOOL_OUTPUT] == "Tool executed with: hello" ) else: - with patch.object( - agent.model._client._client, - "send", - return_value=response, - ) as _: - sentry_init( - integrations=[OpenAIAgentsIntegration()], - traces_sample_rate=1.0, - send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - ) - events = capture_events() - - result = await agents.Runner.run( - agent, "Test input", run_config=test_run_config - ) - - assert result is not None - - (transaction,) = events - spans = transaction["spans"] - invoke_agent_span = next( - span for span in spans if span["op"] == OP.GEN_AI_INVOKE_AGENT - ) - - # Verify invoke_agent span has usage data from context_wrapper - assert invoke_agent_span["description"] == "invoke_agent test_agent" - assert "gen_ai.usage.input_tokens" in invoke_agent_span["data"] - assert "gen_ai.usage.output_tokens" in invoke_agent_span["data"] - assert "gen_ai.usage.total_tokens" in invoke_agent_span["data"] - - assert invoke_agent_span["data"]["gen_ai.usage.input_tokens"] == 10 - assert invoke_agent_span["data"]["gen_ai.usage.output_tokens"] == 20 - assert invoke_agent_span["data"]["gen_ai.usage.total_tokens"] == 30 - assert invoke_agent_span["data"]["gen_ai.usage.input_tokens.cached"] == 0 - assert invoke_agent_span["data"]["gen_ai.usage.output_tokens.reasoning"] == 5 + assert SPANDATA.GEN_AI_TOOL_OUTPUT not in tool_span_data -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio -async def test_ai_client_span_includes_response_model( - sentry_init, - capture_events, - capture_items, - test_agent, - get_model_response, - stream_gen_ai_spans, - span_streaming, +async def test_tool_execution_error_data_collection( + run_tool_agent, ): - """ - Test that ai_client spans (gen_ai.chat) include the response model from the actual API response. - This verifies we capture the actual model used (which may differ from the requested model). - """ - client = AsyncOpenAI(api_key="z") - model = OpenAIResponsesModel(model="gpt-4", openai_client=client) - agent = test_agent.clone(model=model) + @agents.function_tool + def failing_tool(message: str) -> str: + """A tool that fails""" + raise ValueError("Tool execution failed") - response = get_model_response( - Response( - id="resp_123", - output=[ - ResponseOutputMessage( - id="msg_123", - type="message", - status="completed", - content=[ - ResponseOutputText( - text="Hello from GPT-4.1", - type="output_text", - annotations=[], - ) - ], - role="assistant", - ) - ], - parallel_tool_calls=False, - tool_choice="none", - tools=[], - created_at=10000000, - model="gpt-4.1-2025-04-14", - object="response", - usage=ResponseUsage( - input_tokens=10, - input_tokens_details=InputTokensDetails( - cached_tokens=0, - cache_write_tokens=0, - ), - output_tokens=20, - output_tokens_details=OutputTokensDetails( - reasoning_tokens=5, - ), - total_tokens=30, - ), - ), - serialize_pydantic=True, + tool_span, tool_span_data = await run_tool_agent( + failing_tool, + data_collection={"gen_ai": {"outputs": False}}, ) - if span_streaming or stream_gen_ai_spans: - with patch.object( - agent.model._client._client, - "send", - return_value=response, - ) as _: - sentry_init( - integrations=[OpenAIAgentsIntegration()], - disabled_integrations=[StdlibIntegration], - traces_sample_rate=1.0, - send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", - ) - items = capture_items("span", "transaction") - - result = await agents.Runner.run( - agent, "Test input", run_config=test_run_config - ) - - assert result is not None - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - ai_client_span = next( - span for span in spans if span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - ) - - # Verify ai_client span has response model from API response - assert ai_client_span["name"] == "chat gpt-4" - assert "gen_ai.response.model" in ai_client_span["attributes"] - assert ( - ai_client_span["attributes"]["gen_ai.response.model"] - == "gpt-4.1-2025-04-14" - ) - else: - with patch.object( - agent.model._client._client, - "send", - return_value=response, - ) as _: - sentry_init( - integrations=[OpenAIAgentsIntegration()], - traces_sample_rate=1.0, - send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - ) - events = capture_events() - - result = await agents.Runner.run( - agent, "Test input", run_config=test_run_config - ) + assert tool_span_data[SPANDATA.GEN_AI_TOOL_NAME] == "failing_tool" + assert tool_span["status"] == "error" + assert SPANDATA.GEN_AI_TOOL_OUTPUT not in tool_span_data - assert result is not None - (transaction,) = events - spans = transaction["spans"] - ai_client_span = next(span for span in spans if span["op"] == OP.GEN_AI_CHAT) +@pytest.mark.asyncio +async def test_tool_execution_span_non_pii_data_always_set( + run_tool_agent, + simple_test_tool, +): + _, tool_span_data = await run_tool_agent( + simple_test_tool, + run_kwargs={"conversation_id": "conv_tool_test_456"}, + data_collection={"gen_ai": {"inputs": False, "outputs": False}}, + ) - # Verify ai_client span has response model from API response - assert ai_client_span["description"] == "chat gpt-4" - assert "gen_ai.response.model" in ai_client_span["data"] - assert ai_client_span["data"]["gen_ai.response.model"] == "gpt-4.1-2025-04-14" + assert tool_span_data[SPANDATA.GEN_AI_TOOL_NAME] == "simple_test_tool" + assert tool_span_data[SPANDATA.GEN_AI_TOOL_DESCRIPTION] == "A simple tool" + assert tool_span_data[SPANDATA.GEN_AI_CONVERSATION_ID] == "conv_tool_test_456" -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio -async def test_ai_client_span_response_model_with_chat_completions( +async def test_hosted_mcp_tool_propagation_header_streamed( sentry_init, - capture_events, capture_items, + test_agent, get_model_response, - stream_gen_ai_spans, - span_streaming, + async_iterator, + server_side_event_chunks, ): """ - Test that response model is captured when using ChatCompletions API (not Responses API). - This ensures our implementation works with different OpenAI model types. + Test responses API is given trace propagation headers with HostedMCPTool. """ - # Create agent that uses ChatCompletions model + + hosted_tool = HostedMCPTool( + tool_config={ + "type": "mcp", + "server_label": "test_server", + "server_url": "http://example.com/", + "headers": { + "baggage": "custom=data", + }, + }, + ) + client = AsyncOpenAI(api_key="z") - model = OpenAIResponsesModel(model="gpt-4o-mini", openai_client=client) - agent = Agent( - name="chat_completions_agent", - instructions="Test agent using ChatCompletions", + model = OpenAIResponsesModel(model="gpt-4", openai_client=client) + + agent_with_tool = test_agent.clone( + tools=[hosted_tool], model=model, ) - response = get_model_response( - Response( - id="resp_123", - output=[ - ResponseOutputMessage( - id="msg_123", - type="message", - status="completed", - content=[ - ResponseOutputText( - text="Response from model", - type="output_text", - annotations=[], - ) - ], - role="assistant", - ) - ], - parallel_tool_calls=False, - tool_choice="none", - tools=[], - created_at=10000000, - model="gpt-4o-mini-2024-07-18", - object="response", - usage=ResponseUsage( - input_tokens=15, - input_tokens_details=InputTokensDetails( - cached_tokens=0, - cache_write_tokens=0, - ), - output_tokens=25, - output_tokens_details=OutputTokensDetails( - reasoning_tokens=5, - ), - total_tokens=40, - ), - ), - serialize_pydantic=True, + sentry_init( + integrations=[OpenAIAgentsIntegration()], + traces_sample_rate=1.0, + release="d08ebdb9309e1b004c6f52202de58a09c2268e42", ) - if span_streaming or stream_gen_ai_spans: - with patch.object( - agent.model._client._client, - "send", - return_value=response, - ) as _: - sentry_init( - integrations=[OpenAIAgentsIntegration()], - disabled_integrations=[StdlibIntegration], - traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", + request_headers = {"X-Stainless-Raw-Response": "stream"} + + response = get_model_response( + async_iterator( + server_side_event_chunks( + [ + ResponseCreatedEvent( + response=Response( + id="chat-id", + output=[], + parallel_tool_calls=False, + tool_choice="none", + tools=[], + created_at=10000000, + model="response-model-id", + object="response", + ), + type="response.created", + sequence_number=0, + ), + ResponseCompletedEvent( + response=Response( + id="chat-id", + output=[ + ResponseOutputMessage( + id="message-id", + content=[ + ResponseOutputText( + annotations=[], + text="the model response", + type="output_text", + ), + ], + role="assistant", + status="completed", + type="message", + ), + ], + parallel_tool_calls=False, + tool_choice="none", + tools=[], + created_at=10000000, + model="response-model-id", + object="response", + usage=ResponseUsage( + input_tokens=20, + input_tokens_details=InputTokensDetails( + cached_tokens=5, + cache_write_tokens=0, + ), + output_tokens=10, + output_tokens_details=OutputTokensDetails( + reasoning_tokens=8, + ), + total_tokens=30, + ), + ), + type="response.completed", + sequence_number=1, + ), + ] ) + ), + request_headers=request_headers, + ) + items = capture_items("span") - items = capture_items("span", "transaction") + # Patching https://github.com/openai/openai-python/blob/656e3cab4a18262a49b961d41293367e45ee71b9/src/openai/_base_client.py#L1604 + with patch.object( + agent_with_tool.model._client._client, + "send", + return_value=response, + ) as create, mock.patch( + "sentry_sdk.tracing_utils.Random.randrange", return_value=500000 + ): + sentry_sdk.continue_trace( + {"sentry-trace": "01234567890123456789012345678901-0000000000000000"} + ) - result = await agents.Runner.run( - agent, "Test input", run_config=test_run_config + with sentry_sdk.start_span( + name="/interactions/other-dogs/new-dog", + attributes={ + "sentry.op": "greeting.sniff", + }, + ) as span: + result = agents.Runner.run_streamed( + agent_with_tool, + "Please use the simple test tool", + run_config=test_run_config, ) - assert result is not None + async for event in result.stream_events(): + pass sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - ai_client_span = next( - span for span in spans if span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - ) + spans = [item.payload for item in items] - # Verify response model from API response is captured - assert "gen_ai.response.model" in ai_client_span["attributes"] - assert ( - ai_client_span["attributes"]["gen_ai.response.model"] - == "gpt-4o-mini-2024-07-18" + ai_client_span = next( + span + for span in spans + if span["attributes"].get("sentry.op") == OP.GEN_AI_CHAT ) - else: - with patch.object( - agent.model._client._client, - "send", - return_value=response, - ) as _: - sentry_init( - integrations=[OpenAIAgentsIntegration()], - traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - ) - events = capture_events() - result = await agents.Runner.run( - agent, "Test input", run_config=test_run_config - ) + args, kwargs = create.call_args - assert result is not None + request = args[0] + body = json.loads(request.content.decode("utf-8")) + hosted_mcp_tool = body["tools"][0] - (transaction,) = events - spans = transaction["spans"] - ai_client_span = next(span for span in spans if span["op"] == OP.GEN_AI_CHAT) + assert hosted_mcp_tool["headers"][ + "sentry-trace" + ] == "{trace_id}-{parent_span_id}-{sampled}".format( + trace_id=span.trace_id, + parent_span_id=ai_client_span["span_id"], + sampled=1, + ) - # Verify response model from API response is captured - assert "gen_ai.response.model" in ai_client_span["data"] - assert ( - ai_client_span["data"]["gen_ai.response.model"] == "gpt-4o-mini-2024-07-18" + expected_outgoing_baggage = ( + "custom=data," + "sentry-trace_id=01234567890123456789012345678901," + "sentry-sample_rand=0.500000," + "sentry-environment=production," + "sentry-release=d08ebdb9309e1b004c6f52202de58a09c2268e42," + "sentry-transaction=/interactions/other-dogs/new-dog," + "sentry-sample_rate=1.0," + "sentry-sampled=true" ) + assert hosted_mcp_tool["headers"]["baggage"] == expected_outgoing_baggage + -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio -async def test_multiple_llm_calls_aggregate_usage( +async def test_hosted_mcp_tool_propagation_headers( sentry_init, - capture_events, capture_items, test_agent, get_model_response, - stream_gen_ai_spans, - span_streaming, ): """ - Test that invoke_agent spans show aggregated usage across multiple LLM calls - (e.g., when tools are used and multiple API calls are made). + Test responses API is given trace propagation headers with HostedMCPTool. """ - @agents.function_tool - def calculator(a: int, b: int) -> int: - """Add two numbers""" - return a + b + hosted_tool = HostedMCPTool( + tool_config={ + "type": "mcp", + "server_label": "test_server", + "server_url": "http://example.com/", + "headers": { + "baggage": "custom=data", + }, + }, + ) client = AsyncOpenAI(api_key="test-key") model = OpenAIResponsesModel(model="gpt-4", openai_client=client) - agent_with_tool = test_agent.clone(tools=[calculator], model=model) - tool_call_response = get_model_response( - Response( - id="resp_1", - output=[ - ResponseFunctionToolCall( - id="call_123", - call_id="call_123", - name="calculator", - type="function_call", - arguments='{"a": 5, "b": 3}', - ) - ], - parallel_tool_calls=False, - tool_choice="none", - tools=[], - created_at=10000000, - model="gpt-4.1-2025-04-14", - object="response", - usage=ResponseUsage( - input_tokens=10, - input_tokens_details=InputTokensDetails( - cached_tokens=0, - cache_write_tokens=0, - ), - output_tokens=5, - output_tokens_details=OutputTokensDetails( - reasoning_tokens=0, - ), - total_tokens=15, - ), - ), - serialize_pydantic=True, + agent_with_tool = test_agent.clone( + tools=[hosted_tool], + model=model, ) - final_response = get_model_response( - Response( - id="resp_2", - output=[ - ResponseOutputMessage( - id="msg_final", - type="message", - status="completed", - content=[ - ResponseOutputText( - text="The result is 8", - type="output_text", - annotations=[], - ) - ], - role="assistant", - ) - ], - parallel_tool_calls=False, - tool_choice="none", - tools=[], - created_at=10000000, - model="gpt-4-0613", - object="response", - usage=ResponseUsage( - input_tokens=20, - input_tokens_details=InputTokensDetails( - cached_tokens=5, - cache_write_tokens=0, - ), - output_tokens=15, - output_tokens_details=OutputTokensDetails( - reasoning_tokens=3, - ), - total_tokens=35, - ), - ), - serialize_pydantic=True, + sentry_init( + integrations=[OpenAIAgentsIntegration()], + traces_sample_rate=1.0, + release="d08ebdb9309e1b004c6f52202de58a09c2268e42", ) - if span_streaming: - with patch.object( - agent_with_tool.model._client._client, - "send", - side_effect=[tool_call_response, final_response], - ) as _: - sentry_init( - integrations=[OpenAIAgentsIntegration()], - disabled_integrations=[StdlibIntegration], - traces_sample_rate=1.0, - send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream", - ) + response = get_model_response(EXAMPLE_RESPONSE, serialize_pydantic=True) + items = capture_items("span") - items = capture_items("span") + with patch.object( + agent_with_tool.model._client._client, + "send", + return_value=response, + ) as send, mock.patch( + "sentry_sdk.tracing_utils.Random.randrange", return_value=500000 + ): + sentry_sdk.continue_trace( + {"sentry-trace": "01234567890123456789012345678901-0000000000000000"} + ) - result = await agents.Runner.run( + with sentry_sdk.start_span( + name="/interactions/other-dogs/new-dog", + attributes={ + "sentry.op": "greeting.sniff", + }, + ) as span: + await agents.Runner.run( agent_with_tool, - "What is 5 + 3?", + "Please use the simple test tool", run_config=test_run_config, ) - assert result is not None - sentry_sdk.flush() spans = [item.payload for item in items] - invoke_agent_span = spans[3] + ai_client_span = next( + span + for span in spans + if span["attributes"].get("sentry.op") == OP.GEN_AI_CHAT + ) + + args, kwargs = send.call_args - # Verify invoke_agent span has aggregated usage from both API calls - # Total: 10 + 20 = 30 input tokens, 5 + 15 = 20 output tokens, 15 + 35 = 50 total - assert invoke_agent_span["attributes"]["gen_ai.usage.input_tokens"] == 30 - assert invoke_agent_span["attributes"]["gen_ai.usage.output_tokens"] == 20 - assert invoke_agent_span["attributes"]["gen_ai.usage.total_tokens"] == 50 - # Cached tokens should be aggregated: 0 + 5 = 5 - assert invoke_agent_span["attributes"]["gen_ai.usage.input_tokens.cached"] == 5 - # Reasoning tokens should be aggregated: 0 + 3 = 3 - assert ( - invoke_agent_span["attributes"]["gen_ai.usage.output_tokens.reasoning"] == 3 + request = args[0] + body = json.loads(request.content.decode("utf-8")) + hosted_mcp_tool = body["tools"][0] + + assert hosted_mcp_tool["headers"][ + "sentry-trace" + ] == "{trace_id}-{parent_span_id}-{sampled}".format( + trace_id=span.trace_id, + parent_span_id=ai_client_span["span_id"], + sampled=1, + ) + + expected_outgoing_baggage = ( + "custom=data," + "sentry-trace_id=01234567890123456789012345678901," + "sentry-sample_rand=0.500000," + "sentry-environment=production," + "sentry-release=d08ebdb9309e1b004c6f52202de58a09c2268e42," + "sentry-transaction=/interactions/other-dogs/new-dog," + "sentry-sample_rate=1.0," + "sentry-sampled=true" ) - elif stream_gen_ai_spans: - with patch.object( - agent_with_tool.model._client._client, - "send", - side_effect=[tool_call_response, final_response], - ) as _: - sentry_init( - integrations=[OpenAIAgentsIntegration()], - traces_sample_rate=1.0, - send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - ) - items = capture_items("span", "transaction") + assert hosted_mcp_tool["headers"]["baggage"] == expected_outgoing_baggage - result = await agents.Runner.run( - agent_with_tool, - "What is 5 + 3?", - run_config=test_run_config, - ) - assert result is not None +@pytest.mark.asyncio +async def test_model_behavior_error( + sentry_init, + capture_items, + test_agent, + simple_test_tool, +): + """ + Example raising agents.exceptions.AgentsException before the agent invocation span is complete. + The mocked API response indicates that "wrong_tool" was called. + """ + + # Create agent with the tool + agent_with_tool = test_agent.clone(tools=[simple_test_tool]) + with patch.dict(os.environ, {"OPENAI_API_KEY": "test-key"}), patch( + "agents.models.openai_responses.OpenAIResponsesModel.get_response" + ) as mock_get_response: + # Create a mock response that includes tool calls + tool_call = ResponseFunctionToolCall( + id="call_123", + call_id="call_123", + name="wrong_tool", + type="function_call", + arguments='{"message": "hello"}', + ) - spans = [item.payload for item in items if item.type == "span"] + tool_response = ModelResponse( + output=[tool_call], + usage=Usage(requests=1, input_tokens=10, output_tokens=5, total_tokens=15), + response_id="resp_tool_123", + ) - invoke_agent_span = spans[0] + mock_get_response.side_effect = [tool_response] - # Verify invoke_agent span has aggregated usage from both API calls - # Total: 10 + 20 = 30 input tokens, 5 + 15 = 20 output tokens, 15 + 35 = 50 total - assert invoke_agent_span["attributes"]["gen_ai.usage.input_tokens"] == 30 - assert invoke_agent_span["attributes"]["gen_ai.usage.output_tokens"] == 20 - assert invoke_agent_span["attributes"]["gen_ai.usage.total_tokens"] == 50 - # Cached tokens should be aggregated: 0 + 5 = 5 - assert invoke_agent_span["attributes"]["gen_ai.usage.input_tokens.cached"] == 5 - # Reasoning tokens should be aggregated: 0 + 3 = 3 - assert ( - invoke_agent_span["attributes"]["gen_ai.usage.output_tokens.reasoning"] == 3 + sentry_init( + integrations=[OpenAIAgentsIntegration()], + disabled_integrations=[StdlibIntegration], + traces_sample_rate=1.0, + send_default_pii=True, ) - else: - with patch.object( - agent_with_tool.model._client._client, - "send", - side_effect=[tool_call_response, final_response], - ) as _: - sentry_init( - integrations=[OpenAIAgentsIntegration()], - traces_sample_rate=1.0, - send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - ) - events = capture_events() - result = await agents.Runner.run( + items = capture_items("span") + + with pytest.raises(ModelBehaviorError): + await agents.Runner.run( agent_with_tool, - "What is 5 + 3?", + "Please use the simple test tool", run_config=test_run_config, ) - assert result is not None + sentry_sdk.flush() + spans = [item.payload for item in items] - (transaction,) = events - spans = transaction["spans"] + ( + ai_client_span1, + agent_span, + ) = spans - invoke_agent_span = spans[0] + assert agent_span["name"] == "invoke_agent test_agent" + assert agent_span["attributes"]["sentry.origin"] == "auto.ai.openai_agents" - # Verify invoke_agent span has aggregated usage from both API calls - # Total: 10 + 20 = 30 input tokens, 5 + 15 = 20 output tokens, 15 + 35 = 50 total - assert invoke_agent_span["data"]["gen_ai.usage.input_tokens"] == 30 - assert invoke_agent_span["data"]["gen_ai.usage.output_tokens"] == 20 - assert invoke_agent_span["data"]["gen_ai.usage.total_tokens"] == 50 - # Cached tokens should be aggregated: 0 + 5 = 5 - assert invoke_agent_span["data"]["gen_ai.usage.input_tokens.cached"] == 5 - # Reasoning tokens should be aggregated: 0 + 3 = 3 - assert invoke_agent_span["data"]["gen_ai.usage.output_tokens.reasoning"] == 3 + # Error due to unrecognized tool in model response. + assert agent_span["status"] == "error" -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio -async def test_invoke_agent_span_includes_response_model( +async def test_run_error_handling( sentry_init, - capture_events, capture_items, test_agent, - get_model_response, - stream_gen_ai_spans, - span_streaming, ): """ - Test that invoke_agent spans include the response model from the API response. + Test error handling in agent execution. """ - client = AsyncOpenAI(api_key="z") - model = OpenAIResponsesModel(model="gpt-4", openai_client=client) - agent = test_agent.clone(model=model) + with patch.dict(os.environ, {"OPENAI_API_KEY": "test-key"}), patch( + "agents.models.openai_responses.OpenAIResponsesModel.get_response" + ) as mock_get_response: + mock_get_response.side_effect = Exception("Model Error") - response = get_model_response( - Response( - id="resp_123", - output=[ - ResponseOutputMessage( - id="msg_123", - type="message", - status="completed", - content=[ - ResponseOutputText( - text="Response from model", - type="output_text", - annotations=[], - ) - ], - role="assistant", - ) + sentry_init( + integrations=[ + OpenAIAgentsIntegration(), + LoggingIntegration(event_level=logging.CRITICAL), ], - parallel_tool_calls=False, - tool_choice="none", - tools=[], - created_at=10000000, - model="gpt-4.1-2025-04-14", - object="response", - usage=ResponseUsage( - input_tokens=10, - input_tokens_details=InputTokensDetails( - cached_tokens=0, - cache_write_tokens=0, - ), - output_tokens=20, - output_tokens_details=OutputTokensDetails( - reasoning_tokens=5, - ), - total_tokens=30, - ), - ), - serialize_pydantic=True, - ) - - if span_streaming or stream_gen_ai_spans: - with patch.object( - agent.model._client._client, - "send", - return_value=response, - ) as _: - sentry_init( - integrations=[OpenAIAgentsIntegration()], - disabled_integrations=[StdlibIntegration], - traces_sample_rate=1.0, - send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", - ) + disabled_integrations=[StdlibIntegration], + traces_sample_rate=1.0, + ) - items = capture_items("span", "transaction") + items = capture_items("event", "span") - result = await agents.Runner.run( - agent, "Test input", run_config=test_run_config + with pytest.raises(Exception, match="Model Error"): + await agents.Runner.run( + test_agent, "Test input", run_config=test_run_config ) - assert result is not None - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - ai_client_span = next( - span for span in spans if span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - ) - - # Also verify ai_client span has it - assert "gen_ai.response.model" in ai_client_span["attributes"] - assert ( - ai_client_span["attributes"]["gen_ai.response.model"] - == "gpt-4.1-2025-04-14" - ) - else: - with patch.object( - agent.model._client._client, - "send", - return_value=response, - ) as _: - sentry_init( - integrations=[OpenAIAgentsIntegration()], - traces_sample_rate=1.0, - send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - ) - events = capture_events() + (error_event,) = (item.payload for item in items if item.type == "event") - result = await agents.Runner.run( - agent, "Test input", run_config=test_run_config - ) + assert error_event["exception"]["values"][0]["type"] == "Exception" + assert error_event["exception"]["values"][0]["value"] == "Model Error" + assert error_event["exception"]["values"][0]["mechanism"]["type"] == "openai_agents" - assert result is not None + sentry_sdk.flush() + spans = [item.payload for item in items if item.type == "span"] + ( + ai_client_span, + invoke_agent_span, + ) = spans - (transaction,) = events - spans = transaction["spans"] - ai_client_span = next(span for span in spans if span["op"] == OP.GEN_AI_CHAT) + assert invoke_agent_span["name"] == "invoke_agent test_agent" + assert invoke_agent_span["attributes"]["sentry.origin"] == "auto.ai.openai_agents" - # Also verify ai_client span has it - assert "gen_ai.response.model" in ai_client_span["data"] - assert ai_client_span["data"]["gen_ai.response.model"] == "gpt-4.1-2025-04-14" + assert ai_client_span["name"] == "chat gpt-4" + assert ai_client_span["attributes"]["sentry.origin"] == "auto.ai.openai_agents" + assert ai_client_span["status"] == "error" -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio -async def test_invoke_agent_span_uses_last_response_model( +async def test_run_streamed_error_handling( sentry_init, - capture_events, capture_items, test_agent, - get_model_response, - stream_gen_ai_spans, - span_streaming, ): """ - Test that when an agent makes multiple LLM calls (e.g., with tools), - the invoke_agent span reports the last response model used. + Test error handling in agent execution. """ + with patch.dict(os.environ, {"OPENAI_API_KEY": "test-key"}), patch( + "agents.models.openai_responses.OpenAIResponsesModel.stream_response" + ) as mock_get_response: + mock_get_response.side_effect = Exception("Model Error") - @agents.function_tool - def calculator(a: int, b: int) -> int: - """Add two numbers""" - return a + b - - client = AsyncOpenAI(api_key="test-key") - model = OpenAIResponsesModel(model="gpt-4", openai_client=client) - agent_with_tool = test_agent.clone(tools=[calculator], model=model) - - first_response = get_model_response( - Response( - id="resp_1", - output=[ - ResponseFunctionToolCall( - id="call_123", - call_id="call_123", - name="calculator", - type="function_call", - arguments='{"a": 5, "b": 3}', - ) - ], - parallel_tool_calls=False, - tool_choice="none", - tools=[], - created_at=10000000, - model="gpt-4-0613", - object="response", - usage=ResponseUsage( - input_tokens=10, - input_tokens_details=InputTokensDetails( - cached_tokens=0, - cache_write_tokens=0, - ), - output_tokens=5, - output_tokens_details=OutputTokensDetails( - reasoning_tokens=0, - ), - total_tokens=15, - ), - ), - serialize_pydantic=True, - ) - - second_response = get_model_response( - Response( - id="resp_2", - output=[ - ResponseOutputMessage( - id="msg_final", - type="message", - status="completed", - content=[ - ResponseOutputText( - text="I'm the specialist and I can help with that!", - type="output_text", - annotations=[], - ) - ], - role="assistant", - ) + sentry_init( + integrations=[ + OpenAIAgentsIntegration(), + LoggingIntegration(event_level=logging.CRITICAL), ], - parallel_tool_calls=False, - tool_choice="none", - tools=[], - created_at=10000000, - model="gpt-4.1-2025-04-14", - object="response", - usage=ResponseUsage( - input_tokens=20, - input_tokens_details=InputTokensDetails( - cached_tokens=0, - cache_write_tokens=0, - ), - output_tokens=15, - output_tokens_details=OutputTokensDetails( - reasoning_tokens=5, - ), - total_tokens=35, - ), - ), - serialize_pydantic=True, - ) - - if span_streaming: - with patch.object( - agent_with_tool.model._client._client, - "send", - side_effect=[first_response, second_response], - ) as _: - sentry_init( - integrations=[OpenAIAgentsIntegration()], - disabled_integrations=[StdlibIntegration], - traces_sample_rate=1.0, - send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream", - ) + disabled_integrations=[StdlibIntegration], + traces_sample_rate=1.0, + ) - items = capture_items("span") + items = capture_items("event", "span") - result = await agents.Runner.run( - agent_with_tool, - "What is 5 + 3?", - run_config=test_run_config, + with pytest.raises(Exception, match="Model Error"): + result = agents.Runner.run_streamed( + test_agent, "Test input", run_config=test_run_config ) - assert result is not None - - sentry_sdk.flush() - spans = [item.payload for item in items] - - first_ai_client_span = spans[0] - second_ai_client_span = spans[2] # After tool span - - # Each ai_client span has its own response model from the API - assert ( - first_ai_client_span["attributes"]["gen_ai.response.model"] == "gpt-4-0613" - ) - assert ( - second_ai_client_span["attributes"]["gen_ai.response.model"] - == "gpt-4.1-2025-04-14" - ) - elif stream_gen_ai_spans: - with patch.object( - agent_with_tool.model._client._client, - "send", - side_effect=[first_response, second_response], - ) as _: - sentry_init( - integrations=[OpenAIAgentsIntegration()], - traces_sample_rate=1.0, - send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - ) + async for event in result.stream_events(): + pass - items = capture_items("span", "transaction") + sentry_sdk.flush() + spans = [item.payload for item in items if item.type == "span"] + ( + ai_client_span, + invoke_agent_span, + ) = spans - result = await agents.Runner.run( - agent_with_tool, - "What is 5 + 3?", - run_config=test_run_config, - ) + assert invoke_agent_span["name"] == "invoke_agent test_agent" + assert invoke_agent_span["attributes"]["sentry.origin"] == "auto.ai.openai_agents" - assert result is not None + assert ai_client_span["name"] == "chat gpt-4" + assert ai_client_span["attributes"]["sentry.origin"] == "auto.ai.openai_agents" + assert ai_client_span["status"] == "error" - spans = [item.payload for item in items if item.type == "span"] - first_ai_client_span = spans[1] - second_ai_client_span = spans[3] # After tool span +@pytest.mark.asyncio +async def test_error_captures_input_data( + sentry_init, + capture_items, + test_agent, +): + """ + Test that input data is captured even when the API call raises an exception. + This verifies that _set_input_data is called before the API call. + """ + client = AsyncOpenAI(api_key="test-key") + model = OpenAIResponsesModel(model="gpt-4", openai_client=client) + agent = test_agent.clone(model=model) - # Each ai_client span has its own response model from the API - assert ( - first_ai_client_span["attributes"]["gen_ai.response.model"] == "gpt-4-0613" - ) - assert ( - second_ai_client_span["attributes"]["gen_ai.response.model"] - == "gpt-4.1-2025-04-14" - ) - else: - with patch.object( - agent_with_tool.model._client._client, - "send", - side_effect=[first_response, second_response], - ) as _: - sentry_init( - integrations=[OpenAIAgentsIntegration()], - traces_sample_rate=1.0, - send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - ) - events = capture_events() + model_request = httpx.Request( + "POST", + "/responses", + ) - result = await agents.Runner.run( - agent_with_tool, - "What is 5 + 3?", - run_config=test_run_config, - ) + response = httpx.Response( + 500, + request=model_request, + ) + with patch.object( + agent.model._client._client, + "send", + return_value=response, + ) as _: + sentry_init( + integrations=[ + OpenAIAgentsIntegration(), + LoggingIntegration(event_level=logging.CRITICAL), + ], + disabled_integrations=[StdlibIntegration], + traces_sample_rate=1.0, + send_default_pii=True, + ) - assert result is not None + items = capture_items("event", "span") - (transaction,) = events - spans = transaction["spans"] + with pytest.raises(InternalServerError, match="Error code: 500"): + await agents.Runner.run(agent, "Test input", run_config=test_run_config) - first_ai_client_span = spans[1] - second_ai_client_span = spans[3] # After tool span + (error_event,) = (item.payload for item in items if item.type == "event") - # Each ai_client span has its own response model from the API - assert first_ai_client_span["data"]["gen_ai.response.model"] == "gpt-4-0613" - assert ( - second_ai_client_span["data"]["gen_ai.response.model"] - == "gpt-4.1-2025-04-14" - ) + assert error_event["exception"]["values"][0]["type"] == "InternalServerError" + assert error_event["exception"]["values"][0]["value"] == "Error code: 500" + sentry_sdk.flush() + spans = [item.payload for item in items if item.type == "span"] + ai_client_span = [ + s for s in spans if s["attributes"].get("sentry.op", "") == "gen_ai.chat" + ][0] -def test_openai_agents_message_truncation(sentry_init, capture_items): - """Test that large messages are truncated properly in OpenAI Agents integration.""" + assert ai_client_span["name"] == "chat gpt-4" + assert ai_client_span["status"] == "error" - large_content = ( - "This is a very long message that will exceed our size limits. " * 1000 + assert "gen_ai.request.messages" in ai_client_span["attributes"] + request_messages = safe_serialize( + [ + {"role": "user", "content": [{"type": "text", "text": "Test input"}]}, + ] ) + assert ai_client_span["attributes"]["gen_ai.request.messages"] == request_messages - sentry_init( - integrations=[OpenAIAgentsIntegration()], - traces_sample_rate=1.0, - send_default_pii=True, - stream_gen_ai_spans=False, - ) - test_messages = [ - {"role": "user", "content": large_content}, - {"role": "assistant", "content": large_content}, - {"role": "user", "content": "small message 4"}, - {"role": "assistant", "content": "small message 5"}, - ] +@pytest.mark.asyncio +async def test_span_status_error( + sentry_init, + capture_items, + test_agent, +): + with patch.dict(os.environ, {"OPENAI_API_KEY": "test-key"}), patch( + "agents.models.openai_responses.OpenAIResponsesModel.get_response" + ) as mock_get_response: + mock_get_response.side_effect = ValueError("Model Error") - get_response_kwargs = {"input": test_messages} + sentry_init( + integrations=[ + OpenAIAgentsIntegration(), + LoggingIntegration(event_level=logging.CRITICAL), + ], + disabled_integrations=[StdlibIntegration], + traces_sample_rate=1.0, + ) - with start_span(op="gen_ai.chat") as span: - scope = sentry_sdk.get_current_scope() - _set_input_data(span, get_response_kwargs) - if hasattr(scope, "_gen_ai_original_message_count"): - truncated_count = scope._gen_ai_original_message_count.get(span.span_id) - assert truncated_count == 4, ( - f"Expected 4 original messages, got {truncated_count}" - ) + items = capture_items("event", "span") - assert SPANDATA.GEN_AI_REQUEST_MESSAGES in span._data - messages_data = span._data[SPANDATA.GEN_AI_REQUEST_MESSAGES] - assert isinstance(messages_data, str) + with pytest.raises(ValueError, match="Model Error"): + await agents.Runner.run( + test_agent, "Test input", run_config=test_run_config + ) - parsed_messages = json.loads(messages_data) - assert isinstance(parsed_messages, list) - assert len(parsed_messages) == 1 - assert "small message 5" in str(parsed_messages[0]) + (error,) = (item.payload for item in items if item.type == "event") + assert error["level"] == "error" + sentry_sdk.flush() + spans = [item.payload for item in items if item.type == "span"] + assert spans[0]["status"] == "error" -@pytest.mark.asyncio -async def test_streaming_span_update_captures_response_data( - sentry_init, test_agent, mock_usage -): - """ - Test that update_ai_client_span correctly captures response text, - usage data, and response model from a streaming response. - """ - from sentry_sdk.integrations.openai_agents.spans.ai_client import ( - update_ai_client_span, - ) +# Test input messages with mixed roles including "ai" +@pytest.mark.parametrize( + "test_message,expected_role", + [ + ({"role": "user", "content": "Hello"}, "user"), + ( + {"role": "ai", "content": "Hi there!"}, + "assistant", + ), # Should be mapped to "assistant" + ( + {"role": "assistant", "content": "How can I help?"}, + "assistant", + ), # Should stay "assistant" + ], +) +def test_openai_agents_message_role_mapping(sentry_init, test_message, expected_role): + """Test that OpenAI Agents integration properly maps message roles like 'ai' to 'assistant'""" sentry_init( integrations=[OpenAIAgentsIntegration()], traces_sample_rate=1.0, send_default_pii=True, ) - # Create a mock streaming response object (similar to what we'd get from ResponseCompletedEvent) - mock_streaming_response = MagicMock() - mock_streaming_response.model = "gpt-4-streaming" - mock_streaming_response.usage = mock_usage - mock_streaming_response.output = [ - ResponseOutputMessage( - id="msg_streaming_123", - type="message", - status="completed", - content=[ - ResponseOutputText( - text="Hello from streaming!", - type="output_text", - annotations=[], - ) - ], - role="assistant", - ) - ] + get_response_kwargs = {"input": [test_message]} - # Test the unified update function (works for both streaming and non-streaming) - with start_span(op="gen_ai.chat", description="test chat") as span: - update_ai_client_span(span, mock_streaming_response) + with sentry_sdk.start_span(name="test") as span: + _set_input_data(span, get_response_kwargs) - # Verify the span data was set correctly - assert span._data["gen_ai.response.text"] == "Hello from streaming!" - assert span._data["gen_ai.usage.input_tokens"] == 10 - assert span._data["gen_ai.usage.output_tokens"] == 20 - assert span._data["gen_ai.response.model"] == "gpt-4-streaming" + # Verify that messages were processed and roles were mapped + from sentry_sdk.consts import SPANDATA + + stored_messages = json.loads(span._attributes[SPANDATA.GEN_AI_REQUEST_MESSAGES]) + + # Verify roles were properly mapped + assert stored_messages[0]["role"] == expected_role -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio -async def test_streaming_ttft_on_chat_span( +async def test_tool_execution_error_tracing( sentry_init, - capture_events, capture_items, test_agent, get_model_response, - async_iterator, - server_side_event_chunks, - stream_gen_ai_spans, - span_streaming, + nonstreaming_responses_tool_call_model_responses, ): """ - Test that time-to-first-token (TTFT) is recorded on chat spans during streaming. + Test that tool execution errors are properly tracked via error tracing patch. - TTFT is triggered by events with a `delta` attribute, which includes: - - ResponseTextDeltaEvent (text output) - - ResponseAudioDeltaEvent (audio output) - - ResponseReasoningTextDeltaEvent (reasoning/thinking) - - ResponseFunctionCallArgumentsDeltaEvent (function call args) - - and other delta events... + This tests the patch of agents error tracing function to ensure execute_tool + spans are set to error status when tool execution fails. - Events WITHOUT delta (like ResponseCompletedEvent, ResponseCreatedEvent, etc.) - should NOT trigger TTFT. + The function location varies by version: + - Newer versions: agents.util._error_tracing.attach_error_to_current_span + - Older versions: agents._utils.attach_error_to_current_span """ - client = AsyncOpenAI(api_key="z") - - model = OpenAIResponsesModel(model="gpt-4", openai_client=client) - agent_with_tool = test_agent.clone( - model=model, - ) - - sentry_init( - integrations=[OpenAIAgentsIntegration()], - traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", - ) + @agents.function_tool + def failing_tool(message: str) -> str: + """A tool that fails""" + raise ValueError("Tool execution failed") - request_headers = {} - # openai-agents calls with_streaming_response() if available starting with - # https://github.com/openai/openai-agents-python/commit/159beb56130f7d85192acfd593c9168757984dc0. - # When using with_streaming_response() the header set below changes the response type: - # https://github.com/openai/openai-python/blob/656e3cab4a18262a49b961d41293367e45ee71b9/src/openai/_response.py#L67. - if parse_version(OPENAI_AGENTS_VERSION) >= (0, 10, 3) and hasattr( - agent_with_tool.model._client.responses, "with_streaming_response" - ): - request_headers["X-Stainless-Raw-Response"] = "stream" + # Create agent with the failing tool + client = AsyncOpenAI(api_key="test-key") + model = OpenAIResponsesModel(model="gpt-4", openai_client=client) + agent_with_tool = test_agent.clone(tools=[failing_tool], model=model) - response = get_model_response( - async_iterator( - server_side_event_chunks( - [ - ResponseCreatedEvent( - response=Response( - id="chat-id", - output=[], - parallel_tool_calls=False, - tool_choice="none", - tools=[], - created_at=10000000, - model="response-model-id", - object="response", - ), - type="response.created", - sequence_number=0, + responses = nonstreaming_responses_tool_call_model_responses( + tool_name="failing_tool", + arguments='{"message": "test"}', + response_model="gpt-4-0613", + response_text="An error occurred while running the tool", + response_ids=iter(["resp_1", "resp_2"]), + usages=iter( + [ + ResponseUsage( + input_tokens=10, + input_tokens_details=InputTokensDetails( + cached_tokens=0, + cache_write_tokens=0, ), - ResponseTextDeltaEvent( - type="response.output_text.delta", - item_id="message-id", - output_index=0, - content_index=0, - delta="Hello", - logprobs=[], - sequence_number=1, + output_tokens=5, + output_tokens_details=OutputTokensDetails( + reasoning_tokens=0, ), - ResponseTextDeltaEvent( - type="response.output_text.delta", - item_id="message-id", - output_index=0, - content_index=0, - delta=" world!", - logprobs=[], - sequence_number=2, + total_tokens=15, + ), + ResponseUsage( + input_tokens=15, + input_tokens_details=InputTokensDetails( + cached_tokens=0, + cache_write_tokens=0, ), - ResponseCompletedEvent( - response=Response( - id="chat-id", - output=[ - ResponseOutputMessage( - id="message-id", - content=[ - ResponseOutputText( - annotations=[], - text="Hello world!", - type="output_text", - ), - ], - role="assistant", - status="completed", - type="message", - ), - ], - parallel_tool_calls=False, - tool_choice="none", - tools=[], - created_at=10000000, - model="response-model-id", - object="response", - usage=ResponseUsage( - input_tokens=20, - input_tokens_details=InputTokensDetails( - cached_tokens=5, - cache_write_tokens=0, - ), - output_tokens=10, - output_tokens_details=OutputTokensDetails( - reasoning_tokens=8, - ), - total_tokens=30, - ), - ), - type="response.completed", - sequence_number=3, + output_tokens=10, + output_tokens_details=OutputTokensDetails( + reasoning_tokens=0, ), - ] - ) + total_tokens=25, + ), + ] ), - request_headers=request_headers, ) - - if span_streaming: - items = capture_items("span") - - # Patching https://github.com/openai/openai-python/blob/656e3cab4a18262a49b961d41293367e45ee71b9/src/openai/_base_client.py#L1604 - with patch.object( - agent_with_tool.model._client._client, - "send", - return_value=response, - ) as _, sentry_sdk.traces.start_span(name="test_ttft"): - result = agents.Runner.run_streamed( - agent_with_tool, - "Please use the simple test tool", - run_config=test_run_config, - ) - - async for event in result.stream_events(): - pass - - sentry_sdk.flush() - spans = [item.payload for item in items] - - # Verify TTFT is recorded on the chat span - chat_spans = [ - s for s in spans if s["attributes"].get("sentry.op") == "gen_ai.chat" - ] - assert len(chat_spans) >= 1 - chat_span = chat_spans[0] - - assert SPANDATA.GEN_AI_RESPONSE_TIME_TO_FIRST_TOKEN in chat_span["attributes"] - assert chat_span["attributes"].get(SPANDATA.GEN_AI_RESPONSE_STREAMING) is True - elif stream_gen_ai_spans: + tool_response = get_model_response( + next(responses), + serialize_pydantic=True, + ) + final_response = get_model_response( + next(responses), + serialize_pydantic=True, + ) + with patch.object( + agent_with_tool.model._client._client, + "send", + side_effect=[tool_response, final_response], + ) as _: + sentry_init( + integrations=[OpenAIAgentsIntegration()], + disabled_integrations=[StdlibIntegration], + traces_sample_rate=1.0, + send_default_pii=True, + ) items = capture_items("span") - # Patching https://github.com/openai/openai-python/blob/656e3cab4a18262a49b961d41293367e45ee71b9/src/openai/_base_client.py#L1604 - with patch.object( - agent_with_tool.model._client._client, - "send", - return_value=response, - ) as _, sentry_sdk.start_transaction(name="test_ttft", sampled=True): - result = agents.Runner.run_streamed( - agent_with_tool, - "Please use the simple test tool", - run_config=test_run_config, - ) - - async for event in result.stream_events(): - pass - - spans = [item.payload for item in items] - - # Verify TTFT is recorded on the chat span - chat_spans = [ - s for s in spans if s["attributes"].get("sentry.op") == "gen_ai.chat" - ] - assert len(chat_spans) >= 1 - chat_span = chat_spans[0] - - assert SPANDATA.GEN_AI_RESPONSE_TIME_TO_FIRST_TOKEN in chat_span["attributes"] - assert chat_span["attributes"].get(SPANDATA.GEN_AI_RESPONSE_STREAMING) is True - else: - events = capture_events() - - # Patching https://github.com/openai/openai-python/blob/656e3cab4a18262a49b961d41293367e45ee71b9/src/openai/_base_client.py#L1604 - with patch.object( - agent_with_tool.model._client._client, - "send", - return_value=response, - ) as _, sentry_sdk.start_transaction(name="test_ttft", sampled=True): - result = agents.Runner.run_streamed( - agent_with_tool, - "Please use the simple test tool", - run_config=test_run_config, - ) + # Note: The agents library catches tool exceptions internally, + # so we don't expect this to raise + await agents.Runner.run( + agent_with_tool, + "Please use the failing tool", + run_config=test_run_config, + ) - async for event in result.stream_events(): - pass + sentry_sdk.flush() + spans = [item.payload for item in items] - (transaction_event,) = events + # Find the execute_tool span + execute_tool_span = None + for span in spans: + description = span.get("name", "") + if description is not None and description.startswith( + "execute_tool failing_tool" + ): + execute_tool_span = span + break - # Verify TTFT is recorded on the chat span - chat_spans = [s for s in transaction_event["spans"] if s["op"] == "gen_ai.chat"] - assert len(chat_spans) >= 1 - chat_span = chat_spans[0] + # Verify the execute_tool span was created + assert execute_tool_span is not None, "execute_tool span was not created" + assert execute_tool_span["name"] == "execute_tool failing_tool" + assert execute_tool_span["attributes"]["gen_ai.tool.name"] == "failing_tool" - assert SPANDATA.GEN_AI_RESPONSE_TIME_TO_FIRST_TOKEN in chat_span["data"] - assert chat_span["data"].get(SPANDATA.GEN_AI_RESPONSE_STREAMING) is True + # Verify error status was set (this is the key test for our patch) + # The span should be marked as error because the tool execution failed + assert execute_tool_span["status"] == "error" -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) -@pytest.mark.skipif( - parse_version(OPENAI_AGENTS_VERSION) < (0, 4, 0), - reason="conversation_id support requires openai-agents >= 0.4.0", -) @pytest.mark.asyncio -async def test_conversation_id_on_all_spans( +async def test_ai_client_span_includes_response_model( sentry_init, - capture_events, capture_items, test_agent, - nonstreaming_responses_model_response, get_model_response, - stream_gen_ai_spans, - span_streaming, ): """ - Test that gen_ai.conversation.id is set on all AI-related spans when passed to Runner.run(). + Test that ai_client spans (gen_ai.chat) include the response model from the actual API response. + This verifies we capture the actual model used (which may differ from the requested model). """ - - client = AsyncOpenAI(api_key="test-key") + client = AsyncOpenAI(api_key="z") model = OpenAIResponsesModel(model="gpt-4", openai_client=client) agent = test_agent.clone(model=model) response = get_model_response( - nonstreaming_responses_model_response, serialize_pydantic=True + Response( + id="resp_123", + output=[ + ResponseOutputMessage( + id="msg_123", + type="message", + status="completed", + content=[ + ResponseOutputText( + text="Hello from GPT-4.1", + type="output_text", + annotations=[], + ) + ], + role="assistant", + ) + ], + parallel_tool_calls=False, + tool_choice="none", + tools=[], + created_at=10000000, + model="gpt-4.1-2025-04-14", + object="response", + usage=ResponseUsage( + input_tokens=10, + input_tokens_details=InputTokensDetails( + cached_tokens=0, + cache_write_tokens=0, + ), + output_tokens=20, + output_tokens_details=OutputTokensDetails( + reasoning_tokens=5, + ), + total_tokens=30, + ), + ), + serialize_pydantic=True, ) + with patch.object( + agent.model._client._client, + "send", + return_value=response, + ) as _: + sentry_init( + integrations=[OpenAIAgentsIntegration()], + disabled_integrations=[StdlibIntegration], + traces_sample_rate=1.0, + send_default_pii=True, + ) + items = capture_items("span") - if span_streaming: - with patch.object( - agent.model._client._client, - "send", - return_value=response, - ) as _: - sentry_init( - integrations=[OpenAIAgentsIntegration()], - disabled_integrations=[StdlibIntegration], - traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream", - ) + result = await agents.Runner.run( + agent, "Test input", run_config=test_run_config + ) - items = capture_items("span") + assert result is not None - result = await agents.Runner.run( - agent, - "Test input", - run_config=test_run_config, - conversation_id="conv_test_123", - ) + sentry_sdk.flush() + spans = [item.payload for item in items] + ai_client_span = next( + span for span in spans if span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT + ) - assert result is not None + # Verify ai_client span has response model from API response + assert ai_client_span["name"] == "chat gpt-4" + assert "gen_ai.response.model" in ai_client_span["attributes"] + assert ai_client_span["attributes"]["gen_ai.response.model"] == "gpt-4.1-2025-04-14" - sentry_sdk.flush() - spans = [item.payload for item in items] - invoke_agent_span = next( - span - for span in spans - if span["attributes"]["sentry.op"] == OP.GEN_AI_INVOKE_AGENT - ) - ai_client_span = next( - span for span in spans if span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - ) - assert spans[2]["attributes"]["gen_ai.conversation.id"] == "conv_test_123" +@pytest.mark.asyncio +async def test_ai_client_span_response_model_with_chat_completions( + sentry_init, + capture_items, + get_model_response, +): + """ + Test that response model is captured when using ChatCompletions API (not Responses API). + This ensures our implementation works with different OpenAI model types. + """ + # Create agent that uses ChatCompletions model + client = AsyncOpenAI(api_key="z") + model = OpenAIResponsesModel(model="gpt-4o-mini", openai_client=client) - # Verify invoke_agent span has conversation_id - assert ( - invoke_agent_span["attributes"]["gen_ai.conversation.id"] == "conv_test_123" + agent = Agent( + name="chat_completions_agent", + instructions="Test agent using ChatCompletions", + model=model, + ) + + response = get_model_response( + Response( + id="resp_123", + output=[ + ResponseOutputMessage( + id="msg_123", + type="message", + status="completed", + content=[ + ResponseOutputText( + text="Response from model", + type="output_text", + annotations=[], + ) + ], + role="assistant", + ) + ], + parallel_tool_calls=False, + tool_choice="none", + tools=[], + created_at=10000000, + model="gpt-4o-mini-2024-07-18", + object="response", + usage=ResponseUsage( + input_tokens=15, + input_tokens_details=InputTokensDetails( + cached_tokens=0, + cache_write_tokens=0, + ), + output_tokens=25, + output_tokens_details=OutputTokensDetails( + reasoning_tokens=5, + ), + total_tokens=40, + ), + ), + serialize_pydantic=True, + ) + with patch.object( + agent.model._client._client, + "send", + return_value=response, + ) as _: + sentry_init( + integrations=[OpenAIAgentsIntegration()], + disabled_integrations=[StdlibIntegration], + traces_sample_rate=1.0, ) - # Verify ai_client span has conversation_id - assert ai_client_span["attributes"]["gen_ai.conversation.id"] == "conv_test_123" - elif stream_gen_ai_spans: - with patch.object( - agent.model._client._client, - "send", - return_value=response, - ) as _: - sentry_init( - integrations=[OpenAIAgentsIntegration()], - traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", - ) + items = capture_items("span") - items = capture_items("span", "transaction") + result = await agents.Runner.run( + agent, "Test input", run_config=test_run_config + ) - result = await agents.Runner.run( - agent, - "Test input", - run_config=test_run_config, - conversation_id="conv_test_123", - ) + assert result is not None - assert result is not None + sentry_sdk.flush() + spans = [item.payload for item in items] + ai_client_span = next( + span for span in spans if span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT + ) - spans = [item.payload for item in items if item.type == "span"] - invoke_agent_span = next( - span - for span in spans - if span["attributes"]["sentry.op"] == OP.GEN_AI_INVOKE_AGENT - ) - ai_client_span = next( - span for span in spans if span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - ) + # Verify response model from API response is captured + assert "gen_ai.response.model" in ai_client_span["attributes"] + assert ( + ai_client_span["attributes"]["gen_ai.response.model"] + == "gpt-4o-mini-2024-07-18" + ) - # Verify workflow span (transaction) has conversation_id - (transaction,) = (item.payload for item in items if item.type == "transaction") - assert ( - transaction["contexts"]["trace"]["data"]["gen_ai.conversation.id"] - == "conv_test_123" - ) +@pytest.mark.asyncio +async def test_invoke_agent_span_includes_response_model( + sentry_init, + capture_items, + test_agent, + get_model_response, +): + """ + Test that invoke_agent spans include the response model from the API response. + """ + client = AsyncOpenAI(api_key="z") + model = OpenAIResponsesModel(model="gpt-4", openai_client=client) + agent = test_agent.clone(model=model) - # Verify invoke_agent span has conversation_id - assert ( - invoke_agent_span["attributes"]["gen_ai.conversation.id"] == "conv_test_123" + response = get_model_response( + Response( + id="resp_123", + output=[ + ResponseOutputMessage( + id="msg_123", + type="message", + status="completed", + content=[ + ResponseOutputText( + text="Response from model", + type="output_text", + annotations=[], + ) + ], + role="assistant", + ) + ], + parallel_tool_calls=False, + tool_choice="none", + tools=[], + created_at=10000000, + model="gpt-4.1-2025-04-14", + object="response", + usage=ResponseUsage( + input_tokens=10, + input_tokens_details=InputTokensDetails( + cached_tokens=0, + cache_write_tokens=0, + ), + output_tokens=20, + output_tokens_details=OutputTokensDetails( + reasoning_tokens=5, + ), + total_tokens=30, + ), + ), + serialize_pydantic=True, + ) + with patch.object( + agent.model._client._client, + "send", + return_value=response, + ) as _: + sentry_init( + integrations=[OpenAIAgentsIntegration()], + disabled_integrations=[StdlibIntegration], + traces_sample_rate=1.0, + send_default_pii=True, ) - # Verify ai_client span has conversation_id - assert ai_client_span["attributes"]["gen_ai.conversation.id"] == "conv_test_123" - else: - with patch.object( - agent.model._client._client, - "send", - return_value=response, - ) as _: - sentry_init( - integrations=[OpenAIAgentsIntegration()], - traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - ) - events = capture_events() - - result = await agents.Runner.run( - agent, - "Test input", - run_config=test_run_config, - conversation_id="conv_test_123", - ) - - assert result is not None + items = capture_items("span") - (transaction,) = events - spans = transaction["spans"] - invoke_agent_span = next( - span for span in spans if span["op"] == OP.GEN_AI_INVOKE_AGENT + result = await agents.Runner.run( + agent, "Test input", run_config=test_run_config ) - ai_client_span = next(span for span in spans if span["op"] == OP.GEN_AI_CHAT) - # Verify workflow span (transaction) has conversation_id - assert ( - transaction["contexts"]["trace"]["data"]["gen_ai.conversation.id"] - == "conv_test_123" - ) + assert result is not None - # Verify invoke_agent span has conversation_id - assert invoke_agent_span["data"]["gen_ai.conversation.id"] == "conv_test_123" + sentry_sdk.flush() + spans = [item.payload for item in items] + ai_client_span = next( + span for span in spans if span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT + ) - # Verify ai_client span has conversation_id - assert ai_client_span["data"]["gen_ai.conversation.id"] == "conv_test_123" + # Also verify ai_client span has it + assert "gen_ai.response.model" in ai_client_span["attributes"] + assert ai_client_span["attributes"]["gen_ai.response.model"] == "gpt-4.1-2025-04-14" -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) -@pytest.mark.skipif( - parse_version(OPENAI_AGENTS_VERSION) < (0, 4, 0), - reason="conversation_id support requires openai-agents >= 0.4.0", -) @pytest.mark.asyncio -async def test_conversation_id_on_tool_span( +async def test_invoke_agent_span_uses_last_response_model( sentry_init, - capture_events, capture_items, test_agent, get_model_response, - stream_gen_ai_spans, - span_streaming, ): """ - Test that gen_ai.conversation.id is set on tool execution spans when passed to Runner.run(). + Test that when an agent makes multiple LLM calls (e.g., with tools), + the invoke_agent span reports the last response model used. """ @agents.function_tool - def simple_tool(message: str) -> str: - """A simple tool""" - return f"Result: {message}" + def calculator(a: int, b: int) -> int: + """Add two numbers""" + return a + b client = AsyncOpenAI(api_key="test-key") model = OpenAIResponsesModel(model="gpt-4", openai_client=client) - agent_with_tool = test_agent.clone(tools=[simple_tool], model=model) + agent_with_tool = test_agent.clone(tools=[calculator], model=model) - tool_response = get_model_response( + first_response = get_model_response( Response( - id="call_123", + id="resp_1", output=[ ResponseFunctionToolCall( id="call_123", call_id="call_123", - name="simple_tool", + name="calculator", type="function_call", - arguments='{"message": "hello"}', + arguments='{"a": 5, "b": 3}', ) ], parallel_tool_calls=False, tool_choice="none", tools=[], created_at=10000000, - model="gpt-4", + model="gpt-4-0613", object="response", usage=ResponseUsage( input_tokens=10, @@ -7007,9 +3251,9 @@ def simple_tool(message: str) -> str: serialize_pydantic=True, ) - final_response = get_model_response( + second_response = get_model_response( Response( - id="resp_final_789", + id="resp_2", output=[ ResponseOutputMessage( id="msg_final", @@ -7017,7 +3261,7 @@ def simple_tool(message: str) -> str: status="completed", content=[ ResponseOutputText( - text="Done", + text="I'm the specialist and I can help with that!", type="output_text", annotations=[], ) @@ -7029,371 +3273,146 @@ def simple_tool(message: str) -> str: tool_choice="none", tools=[], created_at=10000000, - model="gpt-4", + model="gpt-4.1-2025-04-14", object="response", usage=ResponseUsage( input_tokens=20, input_tokens_details=InputTokensDetails( - cached_tokens=5, + cached_tokens=0, cache_write_tokens=0, ), - output_tokens=10, + output_tokens=15, output_tokens_details=OutputTokensDetails( - reasoning_tokens=8, + reasoning_tokens=5, ), - total_tokens=30, + total_tokens=35, ), ), serialize_pydantic=True, ) - - if span_streaming: - with patch.object( - agent_with_tool.model._client._client, - "send", - side_effect=[tool_response, final_response], - ) as _: - sentry_init( - integrations=[OpenAIAgentsIntegration()], - disabled_integrations=[StdlibIntegration], - traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream", - ) - - items = capture_items("span") - - await agents.Runner.run( - agent_with_tool, - "Use the tool", - run_config=test_run_config, - conversation_id="conv_tool_test_456", - ) - - sentry_sdk.flush() - spans = [item.payload for item in items] - - # Find the tool span - tool_span = None - for span in spans: - if span.get("name", "").startswith("execute_tool"): - tool_span = span - break - - assert tool_span is not None - # Tool span should have the conversation_id passed to Runner.run() - assert tool_span["attributes"]["gen_ai.conversation.id"] == "conv_tool_test_456" - - # Workflow span should have the same conversation_id - workflow_span = spans[4] - assert workflow_span["is_segment"] is True - - assert ( - workflow_span["attributes"]["gen_ai.conversation.id"] - == "conv_tool_test_456" - ) - elif stream_gen_ai_spans: - with patch.object( - agent_with_tool.model._client._client, - "send", - side_effect=[tool_response, final_response], - ) as _: - sentry_init( - integrations=[OpenAIAgentsIntegration()], - traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - ) - - items = capture_items("span", "transaction") - - await agents.Runner.run( - agent_with_tool, - "Use the tool", - run_config=test_run_config, - conversation_id="conv_tool_test_456", - ) - - spans = [item.payload for item in items if item.type == "span"] - - # Find the tool span - tool_span = None - for span in spans: - if span.get("name", "").startswith("execute_tool"): - tool_span = span - break - - assert tool_span is not None - # Tool span should have the conversation_id passed to Runner.run() - assert tool_span["attributes"]["gen_ai.conversation.id"] == "conv_tool_test_456" - - # Workflow span (transaction) should have the same conversation_id - (transaction,) = (item.payload for item in items if item.type == "transaction") - - # Workflow span (transaction) should have the same conversation_id - assert ( - transaction["contexts"]["trace"]["data"]["gen_ai.conversation.id"] - == "conv_tool_test_456" + with patch.object( + agent_with_tool.model._client._client, + "send", + side_effect=[first_response, second_response], + ) as _: + sentry_init( + integrations=[OpenAIAgentsIntegration()], + disabled_integrations=[StdlibIntegration], + traces_sample_rate=1.0, + send_default_pii=True, ) - else: - with patch.object( - agent_with_tool.model._client._client, - "send", - side_effect=[tool_response, final_response], - ) as _: - sentry_init( - integrations=[OpenAIAgentsIntegration()], - traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - ) - - events = capture_events() - - await agents.Runner.run( - agent_with_tool, - "Use the tool", - run_config=test_run_config, - conversation_id="conv_tool_test_456", - ) - - (transaction,) = events - spans = transaction["spans"] - # Find the tool span - tool_span = None - for span in spans: - if span.get("description", "").startswith("execute_tool"): - tool_span = span - break - - assert tool_span is not None - # Tool span should have the conversation_id passed to Runner.run() - assert tool_span["data"]["gen_ai.conversation.id"] == "conv_tool_test_456" + items = capture_items("span") - # Workflow span (transaction) should have the same conversation_id - assert ( - transaction["contexts"]["trace"]["data"]["gen_ai.conversation.id"] - == "conv_tool_test_456" + result = await agents.Runner.run( + agent_with_tool, + "What is 5 + 3?", + run_config=test_run_config, ) + assert result is not None -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) -@pytest.mark.skipif( - parse_version(OPENAI_AGENTS_VERSION) < (0, 4, 0), - reason="conversation_id support requires openai-agents >= 0.4.0", -) -@pytest.mark.asyncio -async def test_no_conversation_id_when_not_provided( - sentry_init, - capture_events, - capture_items, - test_agent, - nonstreaming_responses_model_response, - get_model_response, - stream_gen_ai_spans, - span_streaming, -): - """ - Test that gen_ai.conversation.id is not set when not passed to Runner.run(). - """ + sentry_sdk.flush() + spans = [item.payload for item in items] - client = AsyncOpenAI(api_key="test-key") - model = OpenAIResponsesModel(model="gpt-4", openai_client=client) - agent = test_agent.clone(model=model) + first_ai_client_span = spans[0] + second_ai_client_span = spans[2] # After tool span - response = get_model_response( - nonstreaming_responses_model_response, serialize_pydantic=True + # Each ai_client span has its own response model from the API + assert first_ai_client_span["attributes"]["gen_ai.response.model"] == "gpt-4-0613" + assert ( + second_ai_client_span["attributes"]["gen_ai.response.model"] + == "gpt-4.1-2025-04-14" ) - if span_streaming: - with patch.object( - agent.model._client._client, - "send", - return_value=response, - ) as _: - sentry_init( - integrations=[OpenAIAgentsIntegration()], - disabled_integrations=[StdlibIntegration], - traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream", - ) - - items = capture_items("span") - - # Don't pass conversation_id - result = await agents.Runner.run( - agent, "Test input", run_config=test_run_config - ) - - assert result is not None - - sentry_sdk.flush() - spans = [item.payload for item in items] - - workflow_span = spans[2] - assert workflow_span["is_segment"] is True - - invoke_agent_span = next( - span - for span in spans - if span["attributes"]["sentry.op"] == OP.GEN_AI_INVOKE_AGENT - ) - ai_client_span = next( - span for span in spans if span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - ) - - # Verify conversation_id is NOT set on any spans - assert "gen_ai.conversation.id" not in workflow_span.get("attributes", {}) - assert "gen_ai.conversation.id" not in invoke_agent_span.get("attributes", {}) - assert "gen_ai.conversation.id" not in ai_client_span.get("attributes", {}) - elif stream_gen_ai_spans: - with patch.object( - agent.model._client._client, - "send", - return_value=response, - ) as _: - sentry_init( - integrations=[OpenAIAgentsIntegration()], - traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - ) - - items = capture_items("span", "transaction") - - # Don't pass conversation_id - result = await agents.Runner.run( - agent, "Test input", run_config=test_run_config - ) - - assert result is not None - - (transaction,) = (item.payload for item in items if item.type == "transaction") - - spans = [item.payload for item in items if item.type == "span"] - invoke_agent_span = next( - span - for span in spans - if span["attributes"]["sentry.op"] == OP.GEN_AI_INVOKE_AGENT - ) - ai_client_span = next( - span for span in spans if span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT - ) - - # Verify conversation_id is NOT set on any spans - assert "gen_ai.conversation.id" not in transaction["contexts"]["trace"].get( - "attributes", {} - ) - assert "gen_ai.conversation.id" not in invoke_agent_span.get("attributes", {}) - assert "gen_ai.conversation.id" not in ai_client_span.get("attributes", {}) - else: - with patch.object( - agent.model._client._client, - "send", - return_value=response, - ) as _: - sentry_init( - integrations=[OpenAIAgentsIntegration()], - traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - ) - - events = capture_events() - - # Don't pass conversation_id - result = await agents.Runner.run( - agent, "Test input", run_config=test_run_config - ) - - assert result is not None - - (transaction,) = events - spans = transaction["spans"] - invoke_agent_span = next( - span for span in spans if span["op"] == OP.GEN_AI_INVOKE_AGENT - ) - ai_client_span = next(span for span in spans if span["op"] == OP.GEN_AI_CHAT) - - # Verify conversation_id is NOT set on any spans - assert "gen_ai.conversation.id" not in transaction["contexts"]["trace"].get( - "data", {} - ) - assert "gen_ai.conversation.id" not in invoke_agent_span.get("data", {}) - assert "gen_ai.conversation.id" not in ai_client_span.get("data", {}) - -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio -async def test_runner_run_with_starting_agent_kwarg( - sentry_init, - capture_events, - test_agent, - nonstreaming_responses_model_response, - get_model_response, - stream_gen_ai_spans, +async def test_streaming_span_update_captures_response_data( + sentry_init, test_agent, mock_usage ): - """Runner.run(starting_agent=agent, input=...) must not crash. - - Regression test for https://github.com/getsentry/sentry-python/issues/6418 """ - client = AsyncOpenAI(api_key="test-key") - model = OpenAIResponsesModel(model="gpt-4", openai_client=client) - agent = test_agent.clone(model=model) - - response = get_model_response( - nonstreaming_responses_model_response, serialize_pydantic=True + Test that update_ai_client_span correctly captures response text, + usage data, and response model from a streaming response. + """ + from sentry_sdk.integrations.openai_agents.spans.ai_client import ( + update_ai_client_span, ) - with patch.object( - agent.model._client._client, - "send", - return_value=response, - ): - sentry_init( - integrations=[OpenAIAgentsIntegration()], - traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - ) - - events = capture_events() + sentry_init( + integrations=[OpenAIAgentsIntegration()], + traces_sample_rate=1.0, + send_default_pii=True, + ) - result = await agents.run.DEFAULT_AGENT_RUNNER.run( - starting_agent=agent, - input="Test input", - run_config=test_run_config, + # Create a mock streaming response object (similar to what we'd get from ResponseCompletedEvent) + mock_streaming_response = MagicMock() + mock_streaming_response.model = "gpt-4-streaming" + mock_streaming_response.usage = mock_usage + mock_streaming_response.output = [ + ResponseOutputMessage( + id="msg_streaming_123", + type="message", + status="completed", + content=[ + ResponseOutputText( + text="Hello from streaming!", + type="output_text", + annotations=[], + ) + ], + role="assistant", ) + ] - assert result is not None - assert result.final_output == "Hello, how can I help you?" + # Test the unified update function (works for both streaming and non-streaming) + with sentry_sdk.start_span( + attributes={"sentry.op": "gen_ai.chat"}, name="test chat" + ) as span: + update_ai_client_span(span, mock_streaming_response) - (transaction,) = events - assert transaction["transaction"] == "test_agent workflow" + # Verify the span data was set correctly + assert span._attributes["gen_ai.response.text"] == "Hello from streaming!" + assert span._attributes["gen_ai.usage.input_tokens"] == 10 + assert span._attributes["gen_ai.usage.output_tokens"] == 20 + assert span._attributes["gen_ai.response.model"] == "gpt-4-streaming" -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio -async def test_runner_run_streamed_with_starting_agent_kwarg( +async def test_streaming_ttft_on_chat_span( sentry_init, - capture_events, + capture_items, test_agent, + get_model_response, async_iterator, server_side_event_chunks, - get_model_response, - stream_gen_ai_spans, ): - """Runner.run_streamed(starting_agent=agent, input=...) must not crash. + """ + Test that time-to-first-token (TTFT) is recorded on chat spans during streaming. + + TTFT is triggered by events with a `delta` attribute, which includes: + - ResponseTextDeltaEvent (text output) + - ResponseAudioDeltaEvent (audio output) + - ResponseReasoningTextDeltaEvent (reasoning/thinking) + - ResponseFunctionCallArgumentsDeltaEvent (function call args) + - and other delta events... - Regression test for https://github.com/getsentry/sentry-python/issues/6418 + Events WITHOUT delta (like ResponseCompletedEvent, ResponseCreatedEvent, etc.) + should NOT trigger TTFT. """ - client = AsyncOpenAI(api_key="test-key") + client = AsyncOpenAI(api_key="z") + model = OpenAIResponsesModel(model="gpt-4", openai_client=client) - agent = test_agent.clone(model=model) - request_headers = {} - if parse_version(OPENAI_AGENTS_VERSION) >= (0, 10, 3) and hasattr( - agent.model._client.responses, "with_streaming_response" - ): - request_headers["X-Stainless-Raw-Response"] = "stream" + agent_with_tool = test_agent.clone( + model=model, + ) + + sentry_init( + integrations=[OpenAIAgentsIntegration()], + traces_sample_rate=1.0, + ) + + request_headers = {"X-Stainless-Raw-Response": "stream"} response = get_model_response( async_iterator( @@ -7407,12 +3426,30 @@ async def test_runner_run_streamed_with_starting_agent_kwarg( tool_choice="none", tools=[], created_at=10000000, - model="gpt-4", + model="response-model-id", object="response", ), type="response.created", sequence_number=0, ), + ResponseTextDeltaEvent( + type="response.output_text.delta", + item_id="message-id", + output_index=0, + content_index=0, + delta="Hello", + logprobs=[], + sequence_number=1, + ), + ResponseTextDeltaEvent( + type="response.output_text.delta", + item_id="message-id", + output_index=0, + content_index=0, + delta=" world!", + logprobs=[], + sequence_number=2, + ), ResponseCompletedEvent( response=Response( id="chat-id", @@ -7422,7 +3459,7 @@ async def test_runner_run_streamed_with_starting_agent_kwarg( content=[ ResponseOutputText( annotations=[], - text="Hello, how can I help you?", + text="Hello world!", type="output_text", ), ], @@ -7435,51 +3472,240 @@ async def test_runner_run_streamed_with_starting_agent_kwarg( tool_choice="none", tools=[], created_at=10000000, - model="gpt-4", + model="response-model-id", object="response", usage=ResponseUsage( - input_tokens=10, + input_tokens=20, input_tokens_details=InputTokensDetails( - cached_tokens=0, + cached_tokens=5, cache_write_tokens=0, ), - output_tokens=20, + output_tokens=10, output_tokens_details=OutputTokensDetails( - reasoning_tokens=5, + reasoning_tokens=8, ), total_tokens=30, ), ), type="response.completed", - sequence_number=1, + sequence_number=3, ), ] ) ), request_headers=request_headers, ) + items = capture_items("span") + + # Patching https://github.com/openai/openai-python/blob/656e3cab4a18262a49b961d41293367e45ee71b9/src/openai/_base_client.py#L1604 + with patch.object( + agent_with_tool.model._client._client, + "send", + return_value=response, + ) as _: + result = agents.Runner.run_streamed( + agent_with_tool, + "Please use the simple test tool", + run_config=test_run_config, + ) + + async for event in result.stream_events(): + pass + + sentry_sdk.flush() + spans = [item.payload for item in items] + + # Verify TTFT is recorded on the chat span + chat_spans = [s for s in spans if s["attributes"].get("sentry.op") == "gen_ai.chat"] + assert len(chat_spans) >= 1 + chat_span = chat_spans[0] + + assert SPANDATA.GEN_AI_RESPONSE_TIME_TO_FIRST_CHUNK in chat_span["attributes"] + assert chat_span["attributes"].get(SPANDATA.GEN_AI_RESPONSE_STREAMING) is True + + +@pytest.mark.asyncio +async def test_conversation_id_on_all_spans( + sentry_init, + capture_items, + test_agent, + nonstreaming_responses_model_response, + get_model_response, +): + """ + Test that gen_ai.conversation.id is set on all AI-related spans when passed to Runner.run(). + """ + + client = AsyncOpenAI(api_key="test-key") + model = OpenAIResponsesModel(model="gpt-4", openai_client=client) + agent = test_agent.clone(model=model) + response = get_model_response( + nonstreaming_responses_model_response, serialize_pydantic=True + ) with patch.object( agent.model._client._client, "send", return_value=response, - ): + ) as _: sentry_init( integrations=[OpenAIAgentsIntegration()], + disabled_integrations=[StdlibIntegration], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, ) - events = capture_events() + items = capture_items("span") - result = agents.run.DEFAULT_AGENT_RUNNER.run_streamed( - starting_agent=agent, - input="Test input", + result = await agents.Runner.run( + agent, + "Test input", run_config=test_run_config, + conversation_id="conv_test_123", ) - async for _event in result.stream_events(): - pass + assert result is not None + + sentry_sdk.flush() + spans = [item.payload for item in items] + invoke_agent_span = next( + span + for span in spans + if span["attributes"]["sentry.op"] == OP.GEN_AI_INVOKE_AGENT + ) + ai_client_span = next( + span for span in spans if span["attributes"]["sentry.op"] == OP.GEN_AI_CHAT + ) + + # Verify invoke_agent span has conversation_id + assert invoke_agent_span["attributes"]["gen_ai.conversation.id"] == "conv_test_123" + + # Verify ai_client span has conversation_id + assert ai_client_span["attributes"]["gen_ai.conversation.id"] == "conv_test_123" + + +@pytest.mark.asyncio +async def test_conversation_id_on_tool_span( + sentry_init, + capture_items, + test_agent, + get_model_response, +): + """ + Test that gen_ai.conversation.id is set on tool execution spans when passed to Runner.run(). + """ + + @agents.function_tool + def simple_tool(message: str) -> str: + """A simple tool""" + return f"Result: {message}" + + client = AsyncOpenAI(api_key="test-key") + model = OpenAIResponsesModel(model="gpt-4", openai_client=client) + agent_with_tool = test_agent.clone(tools=[simple_tool], model=model) + + tool_response = get_model_response( + Response( + id="call_123", + output=[ + ResponseFunctionToolCall( + id="call_123", + call_id="call_123", + name="simple_tool", + type="function_call", + arguments='{"message": "hello"}', + ) + ], + parallel_tool_calls=False, + tool_choice="none", + tools=[], + created_at=10000000, + model="gpt-4", + object="response", + usage=ResponseUsage( + input_tokens=10, + input_tokens_details=InputTokensDetails( + cached_tokens=0, + cache_write_tokens=0, + ), + output_tokens=5, + output_tokens_details=OutputTokensDetails( + reasoning_tokens=0, + ), + total_tokens=15, + ), + ), + serialize_pydantic=True, + ) + + final_response = get_model_response( + Response( + id="resp_final_789", + output=[ + ResponseOutputMessage( + id="msg_final", + type="message", + status="completed", + content=[ + ResponseOutputText( + text="Done", + type="output_text", + annotations=[], + ) + ], + role="assistant", + ) + ], + parallel_tool_calls=False, + tool_choice="none", + tools=[], + created_at=10000000, + model="gpt-4", + object="response", + usage=ResponseUsage( + input_tokens=20, + input_tokens_details=InputTokensDetails( + cached_tokens=5, + cache_write_tokens=0, + ), + output_tokens=10, + output_tokens_details=OutputTokensDetails( + reasoning_tokens=8, + ), + total_tokens=30, + ), + ), + serialize_pydantic=True, + ) + with patch.object( + agent_with_tool.model._client._client, + "send", + side_effect=[tool_response, final_response], + ) as _: + sentry_init( + integrations=[OpenAIAgentsIntegration()], + disabled_integrations=[StdlibIntegration], + traces_sample_rate=1.0, + ) + + items = capture_items("span") + + await agents.Runner.run( + agent_with_tool, + "Use the tool", + run_config=test_run_config, + conversation_id="conv_tool_test_456", + ) + + sentry_sdk.flush() + spans = [item.payload for item in items] + + # Find the tool span + tool_span = None + for span in spans: + if span.get("name", "").startswith("execute_tool"): + tool_span = span + break - (transaction,) = events - assert transaction["transaction"] == "test_agent workflow" + assert tool_span is not None + # Tool span should have the conversation_id passed to Runner.run() + assert tool_span["attributes"]["gen_ai.conversation.id"] == "conv_tool_test_456" diff --git a/tests/integrations/openfeature/test_openfeature.py b/tests/integrations/openfeature/test_openfeature.py index d1c58926a8..fd5b2a8c85 100644 --- a/tests/integrations/openfeature/test_openfeature.py +++ b/tests/integrations/openfeature/test_openfeature.py @@ -6,9 +6,7 @@ from openfeature.provider.in_memory_provider import InMemoryFlag, InMemoryProvider import sentry_sdk -from sentry_sdk import start_span, start_transaction from sentry_sdk.integrations.openfeature import OpenFeatureIntegration -from tests.conftest import ApproxDict def test_openfeature_integration(sentry_init, capture_events, uninstall_integration): @@ -154,22 +152,16 @@ async def runner(): } -@pytest.mark.parametrize( - "span_streaming", - [True, False], -) def test_openfeature_span_integration( sentry_init, capture_events, capture_items, uninstall_integration, - span_streaming, ): uninstall_integration(OpenFeatureIntegration.identifier) sentry_init( traces_sample_rate=1.0, integrations=[OpenFeatureIntegration()], - trace_lifecycle="stream" if span_streaming else "static", ) api.set_provider( @@ -177,28 +169,14 @@ def test_openfeature_span_integration( ) client = api.get_client() - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="bar"): - client.get_boolean_value("hello", default_value=False) - client.get_boolean_value("world", default_value=False) + items = capture_items("span") + with sentry_sdk.start_span(name="bar"): + client.get_boolean_value("hello", default_value=False) + client.get_boolean_value("world", default_value=False) - sentry_sdk.flush() + sentry_sdk.flush() - assert len(items) == 1 - span = items[0].payload - assert span["attributes"]["flag.evaluation.hello"] is True - assert span["attributes"]["flag.evaluation.world"] is False - - else: - events = capture_events() - - with start_transaction(name="hi"): - with start_span(op="foo", name="bar"): - client.get_boolean_value("hello", default_value=False) - client.get_boolean_value("world", default_value=False) - - (event,) = events - assert event["spans"][0]["data"] == ApproxDict( - {"flag.evaluation.hello": True, "flag.evaluation.world": False} - ) + assert len(items) == 1 + span = items[0].payload + assert span["attributes"]["flag.evaluation.hello"] is True + assert span["attributes"]["flag.evaluation.world"] is False diff --git a/tests/integrations/opentelemetry/__init__.py b/tests/integrations/opentelemetry/__init__.py deleted file mode 100644 index 75763c2fee..0000000000 --- a/tests/integrations/opentelemetry/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -import pytest - -pytest.importorskip("opentelemetry") diff --git a/tests/integrations/opentelemetry/test_entry_points.py b/tests/integrations/opentelemetry/test_entry_points.py deleted file mode 100644 index 77d9898278..0000000000 --- a/tests/integrations/opentelemetry/test_entry_points.py +++ /dev/null @@ -1,26 +0,0 @@ -try: - from importlib.metadata import entry_points -except ImportError: - from importlib_metadata import entry_points - -from sentry_sdk.integrations.opentelemetry import SentryPropagator - - -def test_propagator_registered_as_entry_point(): - all_eps = entry_points() - - if isinstance(all_eps, dict): - # Python 3.7-3.8 stdlib returns a dict keyed by group - matches = [ - ep - for ep in all_eps.get("opentelemetry_propagator", []) - if ep.name == "sentry" - ] - else: - matches = list(all_eps.select(group="opentelemetry_propagator", name="sentry")) - - assert len(matches) >= 1 - assert matches[0].value == "sentry_sdk.integrations.opentelemetry:SentryPropagator" - - loaded = matches[0].load() - assert loaded is SentryPropagator diff --git a/tests/integrations/opentelemetry/test_experimental.py b/tests/integrations/opentelemetry/test_experimental.py deleted file mode 100644 index 905ab0d5b4..0000000000 --- a/tests/integrations/opentelemetry/test_experimental.py +++ /dev/null @@ -1,57 +0,0 @@ -from unittest.mock import MagicMock, patch - -import pytest - -from sentry_sdk.integrations.opentelemetry.integration import OpenTelemetryIntegration - - -@pytest.mark.forked -def test_integration_enabled_if_option_is_on(sentry_init, reset_integrations): - mocked_setup_sentry_tracing = MagicMock() - - with patch( - "sentry_sdk.integrations.opentelemetry.integration._setup_sentry_tracing", - mocked_setup_sentry_tracing, - ): - with pytest.warns(DeprecationWarning): - sentry_init(_experiments={"otel_powered_performance": True}) - mocked_setup_sentry_tracing.assert_called_once() - - -@pytest.mark.forked -def test_integration_not_enabled_if_option_is_off(sentry_init, reset_integrations): - mocked_setup_sentry_tracing = MagicMock() - - with patch( - "sentry_sdk.integrations.opentelemetry.integration._setup_sentry_tracing", - mocked_setup_sentry_tracing, - ): - sentry_init(_experiments={"otel_powered_performance": False}) - mocked_setup_sentry_tracing.assert_not_called() - - -@pytest.mark.forked -def test_integration_not_enabled_if_option_is_missing(sentry_init, reset_integrations): - mocked_setup_sentry_tracing = MagicMock() - - with patch( - "sentry_sdk.integrations.opentelemetry.integration._setup_sentry_tracing", - mocked_setup_sentry_tracing, - ): - sentry_init() - mocked_setup_sentry_tracing.assert_not_called() - - -@pytest.mark.forked -def test_integration_disabled_with_span_streaming(sentry_init, reset_integrations): - mocked_setup_sentry_tracing = MagicMock() - - with patch( - "sentry_sdk.integrations.opentelemetry.integration._setup_sentry_tracing", - mocked_setup_sentry_tracing, - ): - sentry_init( - integrations=[OpenTelemetryIntegration()], - trace_lifecycle="stream", - ) - mocked_setup_sentry_tracing.assert_not_called() diff --git a/tests/integrations/opentelemetry/test_propagator.py b/tests/integrations/opentelemetry/test_propagator.py deleted file mode 100644 index 1c3e301c3d..0000000000 --- a/tests/integrations/opentelemetry/test_propagator.py +++ /dev/null @@ -1,322 +0,0 @@ -from unittest import mock -from unittest.mock import MagicMock - -import pytest -from opentelemetry import trace -from opentelemetry.context import get_current -from opentelemetry.trace import ( - SpanContext, - TraceFlags, - set_span_in_context, -) -from opentelemetry.trace.propagation import get_current_span - -from sentry_sdk.integrations.opentelemetry.consts import ( - SENTRY_BAGGAGE_KEY, - SENTRY_TRACE_KEY, -) -from sentry_sdk.integrations.opentelemetry.integration import ( - OpenTelemetryIntegration, -) -from sentry_sdk.integrations.opentelemetry.propagator import SentryPropagator -from sentry_sdk.integrations.opentelemetry.span_processor import SentrySpanProcessor -from sentry_sdk.scope import global_event_processors -from sentry_sdk.tracing_utils import Baggage - - -@pytest.mark.forked -def test_extract_no_context_no_sentry_trace_header(): - """ - No context and NO Sentry trace data in getter. - Extract should return empty context. - """ - carrier = None - context = None - getter = MagicMock() - getter.get.return_value = None - - modified_context = SentryPropagator().extract(carrier, context, getter) - - assert modified_context == {} - - -@pytest.mark.forked -def test_extract_context_no_sentry_trace_header(): - """ - Context but NO Sentry trace data in getter. - Extract should return context as is. - """ - carrier = None - context = {"some": "value"} - getter = MagicMock() - getter.get.return_value = None - - modified_context = SentryPropagator().extract(carrier, context, getter) - - assert modified_context == context - - -@pytest.mark.forked -def test_extract_empty_context_sentry_trace_header_no_baggage(): - """ - Empty context but Sentry trace data but NO Baggage in getter. - Extract should return context that has empty baggage in it and also a NoopSpan with span_id and trace_id. - """ - carrier = None - context = {} - getter = MagicMock() - getter.get.side_effect = [ - ["1234567890abcdef1234567890abcdef-1234567890abcdef-1"], - None, - ] - - modified_context = SentryPropagator().extract(carrier, context, getter) - - assert len(modified_context.keys()) == 3 - - assert modified_context[SENTRY_TRACE_KEY] == { - "trace_id": "1234567890abcdef1234567890abcdef", - "parent_span_id": "1234567890abcdef", - "parent_sampled": True, - } - assert modified_context[SENTRY_BAGGAGE_KEY].serialize() == "" - - span_context = get_current_span(modified_context).get_span_context() - assert span_context.span_id == int("1234567890abcdef", 16) - assert span_context.trace_id == int("1234567890abcdef1234567890abcdef", 16) - - -@pytest.mark.forked -def test_extract_context_sentry_trace_header_baggage(): - """ - Empty context but Sentry trace data and Baggage in getter. - Extract should return context that has baggage in it and also a NoopSpan with span_id and trace_id. - """ - baggage_header = ( - "other-vendor-value-1=foo;bar;baz, sentry-trace_id=771a43a4192642f0b136d5159a501700, " - "sentry-public_key=49d0f7386ad645858ae85020e393bef3, sentry-sample_rate=0.01337, " - "sentry-user_id=Am%C3%A9lie, other-vendor-value-2=foo;bar;" - ) - - carrier = None - context = {"some": "value"} - getter = MagicMock() - getter.get.side_effect = [ - ["1234567890abcdef1234567890abcdef-1234567890abcdef-1"], - [baggage_header], - ] - - modified_context = SentryPropagator().extract(carrier, context, getter) - - assert len(modified_context.keys()) == 4 - - assert modified_context[SENTRY_TRACE_KEY] == { - "trace_id": "1234567890abcdef1234567890abcdef", - "parent_span_id": "1234567890abcdef", - "parent_sampled": True, - } - - assert modified_context[SENTRY_BAGGAGE_KEY].serialize() == ( - "sentry-trace_id=771a43a4192642f0b136d5159a501700," - "sentry-public_key=49d0f7386ad645858ae85020e393bef3," - "sentry-sample_rate=0.01337,sentry-user_id=Am%C3%A9lie" - ) - - span_context = get_current_span(modified_context).get_span_context() - assert span_context.span_id == int("1234567890abcdef", 16) - assert span_context.trace_id == int("1234567890abcdef1234567890abcdef", 16) - - -@pytest.mark.forked -def test_inject_empty_otel_span_map(): - """ - Empty otel_span_map. - So there is no sentry_span to be found in inject() - and the function is returned early and no setters are called. - """ - carrier = None - context = get_current() - setter = MagicMock() - setter.set = MagicMock() - - span_context = SpanContext( - trace_id=int("1234567890abcdef1234567890abcdef", 16), - span_id=int("1234567890abcdef", 16), - trace_flags=TraceFlags(TraceFlags.SAMPLED), - is_remote=True, - ) - span = MagicMock() - span.get_span_context.return_value = span_context - - with mock.patch( - "sentry_sdk.integrations.opentelemetry.propagator.trace.get_current_span", - return_value=span, - ): - full_context = set_span_in_context(span, context) - SentryPropagator().inject(carrier, full_context, setter) - - setter.set.assert_not_called() - - -@pytest.mark.forked -def test_inject_sentry_span_no_baggage(): - """ - Inject a sentry span with no baggage. - """ - carrier = None - context = get_current() - setter = MagicMock() - setter.set = MagicMock() - - trace_id = "1234567890abcdef1234567890abcdef" - span_id = "1234567890abcdef" - - span_context = SpanContext( - trace_id=int(trace_id, 16), - span_id=int(span_id, 16), - trace_flags=TraceFlags(TraceFlags.SAMPLED), - is_remote=True, - ) - span = MagicMock() - span.get_span_context.return_value = span_context - - sentry_span = MagicMock() - sentry_span.to_traceparent = mock.Mock( - return_value="1234567890abcdef1234567890abcdef-1234567890abcdef-1" - ) - sentry_span.containing_transaction.get_baggage = mock.Mock(return_value=None) - - span_processor = SentrySpanProcessor() - span_processor.otel_span_map[span_id] = sentry_span - - with mock.patch( - "sentry_sdk.integrations.opentelemetry.propagator.trace.get_current_span", - return_value=span, - ): - full_context = set_span_in_context(span, context) - SentryPropagator().inject(carrier, full_context, setter) - - setter.set.assert_called_once_with( - carrier, - "sentry-trace", - "1234567890abcdef1234567890abcdef-1234567890abcdef-1", - ) - - -def test_inject_sentry_span_empty_baggage(): - """ - Inject a sentry span with no baggage. - """ - carrier = None - context = get_current() - setter = MagicMock() - setter.set = MagicMock() - - trace_id = "1234567890abcdef1234567890abcdef" - span_id = "1234567890abcdef" - - span_context = SpanContext( - trace_id=int(trace_id, 16), - span_id=int(span_id, 16), - trace_flags=TraceFlags(TraceFlags.SAMPLED), - is_remote=True, - ) - span = MagicMock() - span.get_span_context.return_value = span_context - - sentry_span = MagicMock() - sentry_span.to_traceparent = mock.Mock( - return_value="1234567890abcdef1234567890abcdef-1234567890abcdef-1" - ) - sentry_span.containing_transaction.get_baggage = mock.Mock(return_value=Baggage({})) - - span_processor = SentrySpanProcessor() - span_processor.otel_span_map[span_id] = sentry_span - - with mock.patch( - "sentry_sdk.integrations.opentelemetry.propagator.trace.get_current_span", - return_value=span, - ): - full_context = set_span_in_context(span, context) - SentryPropagator().inject(carrier, full_context, setter) - - setter.set.assert_called_once_with( - carrier, - "sentry-trace", - "1234567890abcdef1234567890abcdef-1234567890abcdef-1", - ) - - -def test_inject_sentry_span_baggage(): - """ - Inject a sentry span with baggage. - """ - carrier = None - context = get_current() - setter = MagicMock() - setter.set = MagicMock() - - trace_id = "1234567890abcdef1234567890abcdef" - span_id = "1234567890abcdef" - - span_context = SpanContext( - trace_id=int(trace_id, 16), - span_id=int(span_id, 16), - trace_flags=TraceFlags(TraceFlags.SAMPLED), - is_remote=True, - ) - span = MagicMock() - span.get_span_context.return_value = span_context - - sentry_span = MagicMock() - sentry_span.to_traceparent = mock.Mock( - return_value="1234567890abcdef1234567890abcdef-1234567890abcdef-1" - ) - sentry_items = { - "sentry-trace_id": "771a43a4192642f0b136d5159a501700", - "sentry-public_key": "49d0f7386ad645858ae85020e393bef3", - "sentry-sample_rate": 0.01337, - "sentry-user_id": "Amélie", - } - baggage = Baggage(sentry_items=sentry_items) - sentry_span.containing_transaction.get_baggage = MagicMock(return_value=baggage) - - span_processor = SentrySpanProcessor() - span_processor.otel_span_map[span_id] = sentry_span - - with mock.patch( - "sentry_sdk.integrations.opentelemetry.propagator.trace.get_current_span", - return_value=span, - ): - full_context = set_span_in_context(span, context) - SentryPropagator().inject(carrier, full_context, setter) - - setter.set.assert_any_call( - carrier, - "sentry-trace", - "1234567890abcdef1234567890abcdef-1234567890abcdef-1", - ) - - setter.set.assert_any_call( - carrier, - "baggage", - baggage.serialize(), - ) - - -def test_inject_no_memory_leak(): - - OpenTelemetryIntegration.setup_once() - - tracer = trace.get_tracer(__name__) - propagator = SentryPropagator() - - cnt_before = len(global_event_processors) - - with tracer.start_as_current_span("bar") as new_span: - context = set_span_in_context(new_span) - carrier = "any_carrier" - propagator.inject(carrier, context) - - cnt_after = len(global_event_processors) - assert cnt_after == cnt_before diff --git a/tests/integrations/opentelemetry/test_span_processor.py b/tests/integrations/opentelemetry/test_span_processor.py deleted file mode 100644 index abecee7301..0000000000 --- a/tests/integrations/opentelemetry/test_span_processor.py +++ /dev/null @@ -1,635 +0,0 @@ -import time -from datetime import datetime, timezone -from unittest import mock -from unittest.mock import MagicMock - -import pytest -from opentelemetry.trace import SpanContext, SpanKind, Status, StatusCode - -import sentry_sdk -from sentry_sdk.integrations.opentelemetry.span_processor import ( - SentrySpanProcessor, - link_trace_context_to_error_event, -) -from sentry_sdk.scope import global_event_processors -from sentry_sdk.tracing import Span, Transaction -from sentry_sdk.tracing_utils import extract_sentrytrace_data -from sentry_sdk.utils import Dsn - - -def test_is_sentry_span(): - otel_span = MagicMock() - - span_processor = SentrySpanProcessor() - assert not span_processor._is_sentry_span(otel_span) - - client = MagicMock() - client.options = {"instrumenter": "otel"} - client.parsed_dsn = Dsn("https://1234567890abcdef@o123456.ingest.sentry.io/123456") - sentry_sdk.get_global_scope().set_client(client) - - assert not span_processor._is_sentry_span(otel_span) - - otel_span.attributes = { - "http.url": "https://example.com", - } - assert not span_processor._is_sentry_span(otel_span) - - otel_span.attributes = { - "http.url": "https://o123456.ingest.sentry.io/api/123/envelope", - } - assert span_processor._is_sentry_span(otel_span) - - -def test_get_otel_context(): - otel_span = MagicMock() - otel_span.attributes = {"foo": "bar"} - otel_span.resource = MagicMock() - otel_span.resource.attributes = {"baz": "qux"} - - span_processor = SentrySpanProcessor() - otel_context = span_processor._get_otel_context(otel_span) - - assert otel_context == { - "attributes": {"foo": "bar"}, - "resource": {"baz": "qux"}, - } - - -def test_get_trace_data_with_span_and_trace(): - otel_span = MagicMock() - span_context = SpanContext( - trace_id=int("1234567890abcdef1234567890abcdef", 16), - span_id=int("1234567890abcdef", 16), - is_remote=True, - ) - otel_span.get_span_context.return_value = span_context - otel_span.parent = None - - parent_context = {} - - span_processor = SentrySpanProcessor() - sentry_trace_data = span_processor._get_trace_data( - otel_span.get_span_context(), otel_span.parent, parent_context - ) - assert sentry_trace_data["trace_id"] == "1234567890abcdef1234567890abcdef" - assert sentry_trace_data["span_id"] == "1234567890abcdef" - assert sentry_trace_data["parent_span_id"] is None - assert sentry_trace_data["parent_sampled"] is None - assert sentry_trace_data["baggage"] is None - - -def test_get_trace_data_with_span_and_trace_and_parent(): - otel_span = MagicMock() - span_context = SpanContext( - trace_id=int("1234567890abcdef1234567890abcdef", 16), - span_id=int("1234567890abcdef", 16), - is_remote=True, - ) - otel_span.get_span_context.return_value = span_context - otel_span.parent = MagicMock() - otel_span.parent.span_id = int("abcdef1234567890", 16) - - parent_context = {} - - span_processor = SentrySpanProcessor() - sentry_trace_data = span_processor._get_trace_data( - otel_span.get_span_context(), otel_span.parent, parent_context - ) - assert sentry_trace_data["trace_id"] == "1234567890abcdef1234567890abcdef" - assert sentry_trace_data["span_id"] == "1234567890abcdef" - assert sentry_trace_data["parent_span_id"] == "abcdef1234567890" - assert sentry_trace_data["parent_sampled"] is None - assert sentry_trace_data["baggage"] is None - - -def test_get_trace_data_with_sentry_trace(): - otel_span = MagicMock() - span_context = SpanContext( - trace_id=int("1234567890abcdef1234567890abcdef", 16), - span_id=int("1234567890abcdef", 16), - is_remote=True, - ) - otel_span.get_span_context.return_value = span_context - otel_span.parent = MagicMock() - otel_span.parent.span_id = int("abcdef1234567890", 16) - - parent_context = {} - - with mock.patch( - "sentry_sdk.integrations.opentelemetry.span_processor.get_value", - side_effect=[ - extract_sentrytrace_data( - "1234567890abcdef1234567890abcdef-1234567890abcdef-1" - ), - None, - ], - ): - span_processor = SentrySpanProcessor() - sentry_trace_data = span_processor._get_trace_data( - otel_span.get_span_context(), otel_span.parent, parent_context - ) - assert sentry_trace_data["trace_id"] == "1234567890abcdef1234567890abcdef" - assert sentry_trace_data["span_id"] == "1234567890abcdef" - assert sentry_trace_data["parent_span_id"] == "abcdef1234567890" - assert sentry_trace_data["parent_sampled"] is True - assert sentry_trace_data["baggage"] is None - - with mock.patch( - "sentry_sdk.integrations.opentelemetry.span_processor.get_value", - side_effect=[ - extract_sentrytrace_data( - "1234567890abcdef1234567890abcdef-1234567890abcdef-0" - ), - None, - ], - ): - span_processor = SentrySpanProcessor() - sentry_trace_data = span_processor._get_trace_data( - otel_span.get_span_context(), otel_span.parent, parent_context - ) - assert sentry_trace_data["trace_id"] == "1234567890abcdef1234567890abcdef" - assert sentry_trace_data["span_id"] == "1234567890abcdef" - assert sentry_trace_data["parent_span_id"] == "abcdef1234567890" - assert sentry_trace_data["parent_sampled"] is False - assert sentry_trace_data["baggage"] is None - - -def test_get_trace_data_with_sentry_trace_and_baggage(): - otel_span = MagicMock() - span_context = SpanContext( - trace_id=int("1234567890abcdef1234567890abcdef", 16), - span_id=int("1234567890abcdef", 16), - is_remote=True, - ) - otel_span.get_span_context.return_value = span_context - otel_span.parent = MagicMock() - otel_span.parent.span_id = int("abcdef1234567890", 16) - - parent_context = {} - - baggage = ( - "sentry-trace_id=771a43a4192642f0b136d5159a501700," - "sentry-public_key=49d0f7386ad645858ae85020e393bef3," - "sentry-sample_rate=0.01337,sentry-user_id=Am%C3%A9lie" - ) - - with mock.patch( - "sentry_sdk.integrations.opentelemetry.span_processor.get_value", - side_effect=[ - extract_sentrytrace_data( - "1234567890abcdef1234567890abcdef-1234567890abcdef-1" - ), - baggage, - ], - ): - span_processor = SentrySpanProcessor() - sentry_trace_data = span_processor._get_trace_data( - otel_span.get_span_context(), otel_span.parent, parent_context - ) - assert sentry_trace_data["trace_id"] == "1234567890abcdef1234567890abcdef" - assert sentry_trace_data["span_id"] == "1234567890abcdef" - assert sentry_trace_data["parent_span_id"] == "abcdef1234567890" - assert sentry_trace_data["parent_sampled"] - assert sentry_trace_data["baggage"] == baggage - - -def test_update_span_with_otel_data_http_method(): - sentry_span = Span() - - otel_span = MagicMock() - otel_span.name = "Test OTel Span" - otel_span.kind = SpanKind.CLIENT - otel_span.attributes = { - "http.method": "GET", - "http.status_code": 429, - "http.status_text": "xxx", - "http.user_agent": "curl/7.64.1", - "net.peer.name": "example.com", - "http.target": "/", - } - - span_processor = SentrySpanProcessor() - span_processor._update_span_with_otel_data(sentry_span, otel_span) - - assert sentry_span.op == "http.client" - assert sentry_span.description == "GET example.com /" - assert sentry_span.status == "resource_exhausted" - - assert sentry_span._data["http.method"] == "GET" - assert sentry_span._data["http.response.status_code"] == 429 - assert sentry_span._data["http.status_text"] == "xxx" - assert sentry_span._data["http.user_agent"] == "curl/7.64.1" - assert sentry_span._data["net.peer.name"] == "example.com" - assert sentry_span._data["http.target"] == "/" - - -@pytest.mark.parametrize( - "otel_status, expected_status", - [ - pytest.param(Status(StatusCode.UNSET), None, id="unset"), - pytest.param(Status(StatusCode.OK), "ok", id="ok"), - pytest.param(Status(StatusCode.ERROR), "internal_error", id="error"), - ], -) -def test_update_span_with_otel_status(otel_status, expected_status): - sentry_span = Span() - - otel_span = MagicMock() - otel_span.name = "Test OTel Span" - otel_span.kind = SpanKind.INTERNAL - otel_span.status = otel_status - - span_processor = SentrySpanProcessor() - span_processor._update_span_with_otel_status(sentry_span, otel_span) - - assert sentry_span.get_trace_context().get("status") == expected_status - - -def test_update_span_with_otel_data_http_method2(): - sentry_span = Span() - - otel_span = MagicMock() - otel_span.name = "Test OTel Span" - otel_span.kind = SpanKind.SERVER - otel_span.attributes = { - "http.method": "GET", - "http.status_code": 429, - "http.status_text": "xxx", - "http.user_agent": "curl/7.64.1", - "http.url": "https://example.com/status/403?password=123&username=test@example.com&author=User123&auth=1234567890abcdef", - } - - span_processor = SentrySpanProcessor() - span_processor._update_span_with_otel_data(sentry_span, otel_span) - - assert sentry_span.op == "http.server" - assert sentry_span.description == "GET https://example.com/status/403" - assert sentry_span.status == "resource_exhausted" - - assert sentry_span._data["http.method"] == "GET" - assert sentry_span._data["http.response.status_code"] == 429 - assert sentry_span._data["http.status_text"] == "xxx" - assert sentry_span._data["http.user_agent"] == "curl/7.64.1" - assert ( - sentry_span._data["http.url"] - == "https://example.com/status/403?password=123&username=test@example.com&author=User123&auth=1234567890abcdef" - ) - - -def test_update_span_with_otel_data_db_query(): - sentry_span = Span() - - otel_span = MagicMock() - otel_span.name = "Test OTel Span" - otel_span.attributes = { - "db.system": "postgresql", - "db.statement": "SELECT * FROM table where pwd = '123456'", - } - - span_processor = SentrySpanProcessor() - span_processor._update_span_with_otel_data(sentry_span, otel_span) - - assert sentry_span.op == "db" - assert sentry_span.description == "SELECT * FROM table where pwd = '123456'" - - assert sentry_span._data["db.system"] == "postgresql" - assert ( - sentry_span._data["db.statement"] == "SELECT * FROM table where pwd = '123456'" - ) - - -def test_on_start_transaction(): - otel_span = MagicMock() - otel_span.name = "Sample OTel Span" - otel_span.start_time = time.time_ns() - span_context = SpanContext( - trace_id=int("1234567890abcdef1234567890abcdef", 16), - span_id=int("1234567890abcdef", 16), - is_remote=True, - ) - otel_span.get_span_context.return_value = span_context - otel_span.parent = MagicMock() - otel_span.parent.span_id = int("abcdef1234567890", 16) - - parent_context = {} - - fake_start_transaction = MagicMock() - - fake_client = MagicMock() - fake_client.options = {"instrumenter": "otel"} - fake_client.dsn = "https://1234567890abcdef@o123456.ingest.sentry.io/123456" - sentry_sdk.get_global_scope().set_client(fake_client) - - with mock.patch( - "sentry_sdk.integrations.opentelemetry.span_processor.start_transaction", - fake_start_transaction, - ): - span_processor = SentrySpanProcessor() - span_processor.on_start(otel_span, parent_context) - - fake_start_transaction.assert_called_once_with( - name="Sample OTel Span", - span_id="1234567890abcdef", - parent_span_id="abcdef1234567890", - trace_id="1234567890abcdef1234567890abcdef", - baggage=None, - start_timestamp=datetime.fromtimestamp( - otel_span.start_time / 1e9, timezone.utc - ), - instrumenter="otel", - origin="auto.otel", - ) - - assert len(span_processor.otel_span_map.keys()) == 1 - assert list(span_processor.otel_span_map.keys())[0] == "1234567890abcdef" - - -def test_on_start_child(): - otel_span = MagicMock() - otel_span.name = "Sample OTel Span" - otel_span.start_time = time.time_ns() - span_context = SpanContext( - trace_id=int("1234567890abcdef1234567890abcdef", 16), - span_id=int("1234567890abcdef", 16), - is_remote=True, - ) - otel_span.get_span_context.return_value = span_context - otel_span.parent = MagicMock() - otel_span.parent.span_id = int("abcdef1234567890", 16) - - parent_context = {} - - fake_client = MagicMock() - fake_client.options = {"instrumenter": "otel"} - fake_client.dsn = "https://1234567890abcdef@o123456.ingest.sentry.io/123456" - sentry_sdk.get_global_scope().set_client(fake_client) - - fake_span = MagicMock() - - span_processor = SentrySpanProcessor() - span_processor.otel_span_map["abcdef1234567890"] = fake_span - span_processor.on_start(otel_span, parent_context) - - fake_span.start_child.assert_called_once_with( - span_id="1234567890abcdef", - name="Sample OTel Span", - start_timestamp=datetime.fromtimestamp( - otel_span.start_time / 1e9, timezone.utc - ), - instrumenter="otel", - origin="auto.otel", - ) - - assert len(span_processor.otel_span_map.keys()) == 2 - assert "abcdef1234567890" in span_processor.otel_span_map.keys() - assert "1234567890abcdef" in span_processor.otel_span_map.keys() - - -def test_on_end_no_sentry_span(): - """ - If on_end is called on a span that is not in the otel_span_map, it should be a no-op. - """ - otel_span = MagicMock() - otel_span.name = "Sample OTel Span" - otel_span.end_time = time.time_ns() - span_context = SpanContext( - trace_id=int("1234567890abcdef1234567890abcdef", 16), - span_id=int("1234567890abcdef", 16), - is_remote=True, - ) - otel_span.get_span_context.return_value = span_context - - span_processor = SentrySpanProcessor() - span_processor.otel_span_map = {} - span_processor._get_otel_context = MagicMock() - span_processor._update_span_with_otel_data = MagicMock() - - span_processor.on_end(otel_span) - - span_processor._get_otel_context.assert_not_called() - span_processor._update_span_with_otel_data.assert_not_called() - - -def test_on_end_sentry_transaction(): - """ - Test on_end for a sentry Transaction. - """ - otel_span = MagicMock() - otel_span.name = "Sample OTel Span" - otel_span.end_time = time.time_ns() - otel_span.status = Status(StatusCode.OK) - span_context = SpanContext( - trace_id=int("1234567890abcdef1234567890abcdef", 16), - span_id=int("1234567890abcdef", 16), - is_remote=True, - ) - otel_span.get_span_context.return_value = span_context - - fake_client = MagicMock() - fake_client.options = {"instrumenter": "otel"} - sentry_sdk.get_global_scope().set_client(fake_client) - - fake_sentry_span = MagicMock(spec=Transaction) - fake_sentry_span.set_context = MagicMock() - fake_sentry_span.finish = MagicMock() - - span_processor = SentrySpanProcessor() - span_processor._get_otel_context = MagicMock() - span_processor._update_span_with_otel_data = MagicMock() - span_processor.otel_span_map["1234567890abcdef"] = fake_sentry_span - - span_processor.on_end(otel_span) - - fake_sentry_span.set_context.assert_called_once() - span_processor._update_span_with_otel_data.assert_not_called() - fake_sentry_span.set_status.assert_called_once_with("ok") - fake_sentry_span.finish.assert_called_once() - - -def test_on_end_sentry_span(): - """ - Test on_end for a sentry Span. - """ - otel_span = MagicMock() - otel_span.name = "Sample OTel Span" - otel_span.end_time = time.time_ns() - otel_span.status = Status(StatusCode.OK) - span_context = SpanContext( - trace_id=int("1234567890abcdef1234567890abcdef", 16), - span_id=int("1234567890abcdef", 16), - is_remote=True, - ) - otel_span.get_span_context.return_value = span_context - - fake_client = MagicMock() - fake_client.options = {"instrumenter": "otel"} - sentry_sdk.get_global_scope().set_client(fake_client) - - fake_sentry_span = MagicMock(spec=Span) - fake_sentry_span.set_context = MagicMock() - fake_sentry_span.finish = MagicMock() - - span_processor = SentrySpanProcessor() - span_processor._get_otel_context = MagicMock() - span_processor._update_span_with_otel_data = MagicMock() - span_processor.otel_span_map["1234567890abcdef"] = fake_sentry_span - - span_processor.on_end(otel_span) - - fake_sentry_span.set_context.assert_not_called() - span_processor._update_span_with_otel_data.assert_called_once_with( - fake_sentry_span, otel_span - ) - fake_sentry_span.set_status.assert_called_once_with("ok") - fake_sentry_span.finish.assert_called_once() - - -def test_link_trace_context_to_error_event(): - """ - Test that the trace context is added to the error event. - """ - fake_client = MagicMock() - fake_client.options = {"instrumenter": "otel"} - sentry_sdk.get_global_scope().set_client(fake_client) - - span_id = "1234567890abcdef" - trace_id = "1234567890abcdef1234567890abcdef" - - fake_trace_context = { - "bla": "blub", - "foo": "bar", - "baz": 123, - } - - sentry_span = MagicMock() - sentry_span.get_trace_context = MagicMock(return_value=fake_trace_context) - - otel_span_map = { - span_id: sentry_span, - } - - span_context = SpanContext( - trace_id=int(trace_id, 16), - span_id=int(span_id, 16), - is_remote=True, - ) - otel_span = MagicMock() - otel_span.get_span_context = MagicMock(return_value=span_context) - - fake_event = {"event_id": "1234567890abcdef1234567890abcdef"} - - with mock.patch( - "sentry_sdk.integrations.opentelemetry.span_processor.get_current_span", - return_value=otel_span, - ): - event = link_trace_context_to_error_event(fake_event, otel_span_map) - - assert event - assert event == fake_event # the event is changed in place inside the function - assert "contexts" in event - assert "trace" in event["contexts"] - assert event["contexts"]["trace"] == fake_trace_context - - -def test_pruning_old_spans_on_start(): - otel_span = MagicMock() - otel_span.name = "Sample OTel Span" - otel_span.start_time = time.time_ns() - span_context = SpanContext( - trace_id=int("1234567890abcdef1234567890abcdef", 16), - span_id=int("1234567890abcdef", 16), - is_remote=True, - ) - otel_span.get_span_context.return_value = span_context - otel_span.parent = MagicMock() - otel_span.parent.span_id = int("abcdef1234567890", 16) - - parent_context = {} - fake_client = MagicMock() - fake_client.options = {"instrumenter": "otel", "debug": False} - fake_client.dsn = "https://1234567890abcdef@o123456.ingest.sentry.io/123456" - sentry_sdk.get_global_scope().set_client(fake_client) - - span_processor = SentrySpanProcessor() - - span_processor.otel_span_map = { - "111111111abcdef": MagicMock(), # should stay - "2222222222abcdef": MagicMock(), # should go - "3333333333abcdef": MagicMock(), # should go - } - current_time_minutes = int(time.time() / 60) - span_processor.open_spans = { - current_time_minutes - 3: {"111111111abcdef"}, # should stay - current_time_minutes - 11: { - "2222222222abcdef", - "3333333333abcdef", - }, # should go - } - - span_processor.on_start(otel_span, parent_context) - assert sorted(list(span_processor.otel_span_map.keys())) == [ - "111111111abcdef", - "1234567890abcdef", - ] - assert sorted(list(span_processor.open_spans.values())) == [ - {"111111111abcdef"}, - {"1234567890abcdef"}, - ] - - -def test_pruning_old_spans_on_end(): - otel_span = MagicMock() - otel_span.name = "Sample OTel Span" - otel_span.start_time = time.time_ns() - span_context = SpanContext( - trace_id=int("1234567890abcdef1234567890abcdef", 16), - span_id=int("1234567890abcdef", 16), - is_remote=True, - ) - otel_span.get_span_context.return_value = span_context - otel_span.parent = MagicMock() - otel_span.parent.span_id = int("abcdef1234567890", 16) - - fake_client = MagicMock() - fake_client.options = {"instrumenter": "otel"} - sentry_sdk.get_global_scope().set_client(fake_client) - - fake_sentry_span = MagicMock(spec=Span) - fake_sentry_span.set_context = MagicMock() - fake_sentry_span.finish = MagicMock() - - span_processor = SentrySpanProcessor() - span_processor._get_otel_context = MagicMock() - span_processor._update_span_with_otel_data = MagicMock() - - span_processor.otel_span_map = { - "111111111abcdef": MagicMock(), # should stay - "2222222222abcdef": MagicMock(), # should go - "3333333333abcdef": MagicMock(), # should go - "1234567890abcdef": fake_sentry_span, # should go (because it is closed) - } - current_time_minutes = int(time.time() / 60) - span_processor.open_spans = { - current_time_minutes: {"1234567890abcdef"}, # should go (because it is closed) - current_time_minutes - 3: {"111111111abcdef"}, # should stay - current_time_minutes - 11: { - "2222222222abcdef", - "3333333333abcdef", - }, # should go - } - - span_processor.on_end(otel_span) - assert sorted(list(span_processor.otel_span_map.keys())) == ["111111111abcdef"] - assert sorted(list(span_processor.open_spans.values())) == [{"111111111abcdef"}] - - -def test_no_memory_leak(): - span_processor_1 = SentrySpanProcessor() - cnt_before = len(global_event_processors) - - span_processor_2 = SentrySpanProcessor() - - cnt_after = len(global_event_processors) - assert span_processor_1 is span_processor_2 - assert cnt_before == cnt_after diff --git a/tests/integrations/otlp/test_otlp.py b/tests/integrations/otlp/test_otlp.py index 25e2a5f7fe..504507e274 100644 --- a/tests/integrations/otlp/test_otlp.py +++ b/tests/integrations/otlp/test_otlp.py @@ -16,7 +16,10 @@ ) from opentelemetry.util._once import Once -from sentry_sdk.integrations.otlp import OTLPIntegration, SentryOTLPPropagator +from sentry_sdk.integrations.otlp import ( + OTLPIntegration, + SentryOTLPPropagator, +) from sentry_sdk.scope import get_external_propagation_context original_propagator = get_global_textmap() diff --git a/tests/integrations/pure_eval/test_pure_eval.py b/tests/integrations/pure_eval/test_pure_eval.py index 497a8768d0..057960693c 100644 --- a/tests/integrations/pure_eval/test_pure_eval.py +++ b/tests/integrations/pure_eval/test_pure_eval.py @@ -8,7 +8,9 @@ @pytest.mark.parametrize("integrations", [[], [PureEvalIntegration()]]) def test_include_local_variables_enabled(sentry_init, capture_events, integrations): - sentry_init(include_local_variables=True, integrations=integrations) + sentry_init( + data_collection={"stack_frame_variables": True}, integrations=integrations + ) events = capture_events() def foo(): diff --git a/tests/integrations/pydantic_ai/test_pydantic_ai.py b/tests/integrations/pydantic_ai/test_pydantic_ai.py index e100e62671..7254a00e93 100644 --- a/tests/integrations/pydantic_ai/test_pydantic_ai.py +++ b/tests/integrations/pydantic_ai/test_pydantic_ai.py @@ -78,16 +78,11 @@ def sync_event_loop(): asyncio.set_event_loop(None) -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio async def test_agent_run_async( sentry_init, - capture_events, capture_items, get_test_agent, - stream_gen_ai_spans, - span_streaming, ): """ Test that the integration creates spans for async agent runs. @@ -96,156 +91,62 @@ async def test_agent_run_async( integrations=[PydanticAIIntegration()], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) test_agent = get_test_agent() + items = capture_items("span") - if span_streaming: - items = capture_items("span") - - result = await test_agent.run( - ["Message demonstrating the absence of truncation.", "Test input"] - ) - - assert result is not None - assert result.output is not None - - sentry_sdk.flush() - spans = [item.payload for item in items] - - assert spans[1]["name"] == "invoke_agent test_agent" - assert spans[1]["attributes"]["sentry.origin"] == "auto.ai.pydantic_ai" - - assert spans[1]["attributes"]["sentry.op"] == "gen_ai.invoke_agent" - - chat_spans = [ - s for s in spans if s["attributes"].get("sentry.op", "") == "gen_ai.chat" - ] - assert len(chat_spans) == 1 - - # Check chat span - chat_span = chat_spans[0] - assert "chat" in chat_span["name"] - assert chat_span["attributes"]["gen_ai.operation.name"] == "chat" - assert chat_span["attributes"]["gen_ai.response.streaming"] is False - assert json.loads( - chat_span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - ) == [ - { - "role": "user", - "content": [ - { - "type": "text", - "text": "Message demonstrating the absence of truncation.", - }, - { - "type": "text", - "text": "Test input", - }, - ], - } - ] - assert "gen_ai.usage.input_tokens" in chat_span["attributes"] - assert "gen_ai.usage.output_tokens" in chat_span["attributes"] - elif stream_gen_ai_spans: - items = capture_items("transaction", "span") - - result = await test_agent.run( - ["Message demonstrating the absence of truncation.", "Test input"] - ) - - assert result is not None - assert result.output is not None - - (transaction,) = (item.payload for item in items if item.type == "transaction") - - # Verify transaction (the transaction IS the invoke_agent span) - assert transaction["transaction"] == "invoke_agent test_agent" - assert transaction["contexts"]["trace"]["origin"] == "auto.ai.pydantic_ai" - - # The transaction itself should have invoke_agent data - assert transaction["contexts"]["trace"]["op"] == "gen_ai.invoke_agent" - - spans = [item.payload for item in items if item.type == "span"] - # Find child span types (invoke_agent is the transaction, not a child span) - chat_spans = [ - s for s in spans if s["attributes"].get("sentry.op", "") == "gen_ai.chat" - ] - assert len(chat_spans) == 1 - - # Check chat span - chat_span = chat_spans[0] - assert "chat" in chat_span["name"] - assert chat_span["attributes"]["gen_ai.operation.name"] == "chat" - assert chat_span["attributes"]["gen_ai.response.streaming"] is False - assert json.loads( - chat_span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - ) == [ - { - "role": "user", - "content": [ - { - "type": "text", - "text": "Message demonstrating the absence of truncation.", - }, - { - "type": "text", - "text": "Test input", - }, - ], - } - ] - assert "gen_ai.usage.input_tokens" in chat_span["attributes"] - assert "gen_ai.usage.output_tokens" in chat_span["attributes"] - else: - events = capture_events() - - result = await test_agent.run("Test input") + result = await test_agent.run( + ["Message demonstrating the absence of truncation.", "Test input"] + ) - assert result is not None - assert result.output is not None + assert result is not None + assert result.output is not None - (transaction,) = events - spans = transaction["spans"] + sentry_sdk.flush() + spans = [item.payload for item in items] - # Verify transaction (the transaction IS the invoke_agent span) - assert transaction["transaction"] == "invoke_agent test_agent" - assert transaction["contexts"]["trace"]["origin"] == "auto.ai.pydantic_ai" + assert spans[1]["name"] == "invoke_agent test_agent" + assert spans[1]["attributes"]["sentry.origin"] == "auto.ai.pydantic_ai" - # The transaction itself should have invoke_agent data - assert transaction["contexts"]["trace"]["op"] == "gen_ai.invoke_agent" + assert spans[1]["attributes"]["sentry.op"] == "gen_ai.invoke_agent" - # Find child span types (invoke_agent is the transaction, not a child span) - chat_spans = [s for s in spans if s["op"] == "gen_ai.chat"] - assert len(chat_spans) == 1 + chat_spans = [ + s for s in spans if s["attributes"].get("sentry.op", "") == "gen_ai.chat" + ] + assert len(chat_spans) == 1 - # Check chat span - chat_span = chat_spans[0] - assert "chat" in chat_span["description"] - assert chat_span["data"]["gen_ai.operation.name"] == "chat" - assert chat_span["data"]["gen_ai.response.streaming"] is False - assert "gen_ai.request.messages" in chat_span["data"] - assert "gen_ai.usage.input_tokens" in chat_span["data"] - assert "gen_ai.usage.output_tokens" in chat_span["data"] + # Check chat span + chat_span = chat_spans[0] + assert "chat" in chat_span["name"] + assert chat_span["attributes"]["gen_ai.operation.name"] == "chat" + assert json.loads(chat_span["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) == [ + { + "role": "user", + "content": [ + { + "type": "text", + "text": "Message demonstrating the absence of truncation.", + }, + { + "type": "text", + "text": "Test input", + }, + ], + } + ] + assert "gen_ai.usage.input_tokens" in chat_span["attributes"] + assert "gen_ai.usage.output_tokens" in chat_span["attributes"] -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio async def test_agent_run_async_model_error( sentry_init, - capture_events, capture_items, - stream_gen_ai_spans, - span_streaming, ): sentry_init( integrations=[PydanticAIIntegration()], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) def failing_model(messages, info): @@ -255,58 +156,25 @@ def failing_model(messages, info): FunctionModel(failing_model), name="test_agent", ) + items = capture_items("event", "span") - if span_streaming: - items = capture_items("event", "span") - - with pytest.raises(RuntimeError, match="model exploded"): - await agent.run("Test input") - - (error,) = (item.payload for item in items if item.type == "event") - assert error["level"] == "error" - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert len(spans) == 2 - - assert spans[0]["status"] == "error" - elif stream_gen_ai_spans: - items = capture_items("event", "span") - - with pytest.raises(RuntimeError, match="model exploded"): - await agent.run("Test input") - - (error,) = (item.payload for item in items if item.type == "event") - assert error["level"] == "error" - - spans = [item.payload for item in items if item.type == "span"] - assert len(spans) == 1 - - assert spans[0]["status"] == "error" - else: - events = capture_events() - - with pytest.raises(RuntimeError, match="model exploded"): - await agent.run("Test input") + with pytest.raises(RuntimeError, match="model exploded"): + await agent.run("Test input") - (error, transaction) = events - assert error["level"] == "error" + (error,) = (item.payload for item in items if item.type == "event") + assert error["level"] == "error" - spans = transaction["spans"] - assert len(spans) == 1 + sentry_sdk.flush() + spans = [item.payload for item in items if item.type == "span"] + assert len(spans) == 2 - assert spans[0]["status"] == "internal_error" + assert spans[0]["status"] == "error" -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_agent_run_sync( sentry_init, - capture_events, capture_items, get_test_agent, - stream_gen_ai_spans, - span_streaming, sync_event_loop, ): """ @@ -316,99 +184,38 @@ def test_agent_run_sync( integrations=[PydanticAIIntegration()], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) test_agent = get_test_agent() + items = capture_items("span") - if span_streaming: - items = capture_items("span") - - result = test_agent.run_sync( - ["Message demonstrating the absence of truncation.", "Test input"] - ) - - assert result is not None - assert result.output is not None - - sentry_sdk.flush() - spans = [item.payload for item in items] - - assert spans[1]["name"] == "invoke_agent test_agent" - assert spans[1]["attributes"]["sentry.origin"] == "auto.ai.pydantic_ai" - - chat_spans = [ - s for s in spans if s["attributes"].get("sentry.op", "") == "gen_ai.chat" - ] - assert len(chat_spans) == 1 - - # Verify streaming flag is False for sync - assert chat_spans[0]["attributes"]["gen_ai.response.streaming"] is False - elif stream_gen_ai_spans: - items = capture_items("transaction", "span") - - result = test_agent.run_sync( - ["Message demonstrating the absence of truncation.", "Test input"] - ) - - assert result is not None - assert result.output is not None - - # Verify transaction - (transaction,) = (item.payload for item in items if item.type == "transaction") - - # Verify transaction - assert transaction["transaction"] == "invoke_agent test_agent" - assert transaction["contexts"]["trace"]["origin"] == "auto.ai.pydantic_ai" - - # Find span types - spans = [item.payload for item in items if item.type == "span"] - chat_spans = [ - s for s in spans if s["attributes"].get("sentry.op", "") == "gen_ai.chat" - ] - assert len(chat_spans) == 1 - - # Verify streaming flag is False for sync - assert chat_spans[0]["attributes"]["gen_ai.response.streaming"] is False - else: - events = capture_events() - - result = test_agent.run_sync("Test input") - - assert result is not None - assert result.output is not None + result = test_agent.run_sync( + ["Message demonstrating the absence of truncation.", "Test input"] + ) - (transaction,) = events - spans = transaction["spans"] + assert result is not None + assert result.output is not None - # Verify transaction - assert transaction["transaction"] == "invoke_agent test_agent" - assert transaction["contexts"]["trace"]["origin"] == "auto.ai.pydantic_ai" + sentry_sdk.flush() + spans = [item.payload for item in items] - # Find span types - chat_spans = [s for s in spans if s["op"] == "gen_ai.chat"] - assert len(chat_spans) == 1 + assert spans[1]["name"] == "invoke_agent test_agent" + assert spans[1]["attributes"]["sentry.origin"] == "auto.ai.pydantic_ai" - # Verify streaming flag is False for sync - assert chat_spans[0]["data"]["gen_ai.response.streaming"] is False + chat_spans = [ + s for s in spans if s["attributes"].get("sentry.op", "") == "gen_ai.chat" + ] + assert len(chat_spans) == 1 -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_agent_run_sync_model_error( sentry_init, - capture_events, capture_items, - stream_gen_ai_spans, - span_streaming, sync_event_loop, ): sentry_init( integrations=[PydanticAIIntegration()], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) def failing_model(messages, info): @@ -418,59 +225,26 @@ def failing_model(messages, info): FunctionModel(failing_model), name="test_agent", ) + items = capture_items("event", "span") - if span_streaming: - items = capture_items("event", "span") + with pytest.raises(RuntimeError, match="model exploded"): + agent.run_sync("Test input") - with pytest.raises(RuntimeError, match="model exploded"): - agent.run_sync("Test input") - - (error,) = (item.payload for item in items if item.type == "event") - assert error["level"] == "error" - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - assert len(spans) == 2 - - assert spans[0]["status"] == "error" - elif stream_gen_ai_spans: - items = capture_items("event", "span") - - with pytest.raises(RuntimeError, match="model exploded"): - agent.run_sync("Test input") - - (error,) = (item.payload for item in items if item.type == "event") - assert error["level"] == "error" - - spans = [item.payload for item in items if item.type == "span"] - assert len(spans) == 1 - - assert spans[0]["status"] == "error" - else: - events = capture_events() - - with pytest.raises(RuntimeError, match="model exploded"): - agent.run_sync("Test input") - - (error, transaction) = events - assert error["level"] == "error" + (error,) = (item.payload for item in items if item.type == "event") + assert error["level"] == "error" - spans = transaction["spans"] - assert len(spans) == 1 + sentry_sdk.flush() + spans = [item.payload for item in items if item.type == "span"] + assert len(spans) == 2 - assert spans[0]["status"] == "internal_error" + assert spans[0]["status"] == "error" -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio async def test_agent_run_stream( sentry_init, - capture_events, capture_items, get_test_agent, - stream_gen_ai_spans, - span_streaming, ): """ Test that the integration creates spans for streaming agent runs. @@ -479,147 +253,59 @@ async def test_agent_run_stream( integrations=[PydanticAIIntegration()], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) test_agent = get_test_agent() + items = capture_items("span") - if span_streaming: - items = capture_items("span") - - async with test_agent.run_stream( - ["Message demonstrating the absence of truncation.", "Test input"] - ) as result: - # Consume the stream - async for _ in result.stream_output(): - pass - - sentry_sdk.flush() - spans = [item.payload for item in items] - - assert spans[1]["name"] == "invoke_agent test_agent" - assert spans[1]["attributes"]["sentry.origin"] == "auto.ai.pydantic_ai" - - chat_spans = [ - s for s in spans if s["attributes"].get("sentry.op", "") == "gen_ai.chat" - ] - assert len(chat_spans) == 1 - - # Verify streaming flag is True for streaming - assert chat_spans[0]["attributes"]["gen_ai.response.streaming"] is True - assert json.loads( - chat_spans[0]["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - ) == [ - { - "role": "user", - "content": [ - { - "type": "text", - "text": "Message demonstrating the absence of truncation.", - }, - { - "type": "text", - "text": "Test input", - }, - ], - } - ] - assert "gen_ai.usage.input_tokens" in chat_spans[0]["attributes"] - # Streaming responses should still have output data - assert ( - "gen_ai.response.text" in chat_spans[0]["attributes"] - or "gen_ai.response.model" in chat_spans[0]["attributes"] - ) - elif stream_gen_ai_spans: - items = capture_items("transaction", "span") - - async with test_agent.run_stream( - ["Message demonstrating the absence of truncation.", "Test input"] - ) as result: - # Consume the stream - async for _ in result.stream_output(): - pass - - # Verify transaction - (transaction,) = (item.payload for item in items if item.type == "transaction") - - # Verify transaction - assert transaction["transaction"] == "invoke_agent test_agent" - assert transaction["contexts"]["trace"]["origin"] == "auto.ai.pydantic_ai" + async with test_agent.run_stream( + ["Message demonstrating the absence of truncation.", "Test input"] + ) as result: + # Consume the stream + async for _ in result.stream_output(): + pass - # Find chat spans - spans = [item.payload for item in items if item.type == "span"] - chat_spans = [ - s for s in spans if s["attributes"].get("sentry.op", "") == "gen_ai.chat" - ] - assert len(chat_spans) == 1 + sentry_sdk.flush() + spans = [item.payload for item in items] - # Verify streaming flag is True for streaming - assert chat_spans[0]["attributes"]["gen_ai.response.streaming"] is True - assert json.loads( - chat_spans[0]["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - ) == [ - { - "role": "user", - "content": [ - { - "type": "text", - "text": "Message demonstrating the absence of truncation.", - }, - { - "type": "text", - "text": "Test input", - }, - ], - } - ] - assert "gen_ai.usage.input_tokens" in chat_spans[0]["attributes"] - # Streaming responses should still have output data - assert ( - "gen_ai.response.text" in chat_spans[0]["attributes"] - or "gen_ai.response.model" in chat_spans[0]["attributes"] - ) - else: - events = capture_events() + assert spans[1]["name"] == "invoke_agent test_agent" + assert spans[1]["attributes"]["sentry.origin"] == "auto.ai.pydantic_ai" - async with test_agent.run_stream("Test input") as result: - # Consume the stream - async for _ in result.stream_output(): - pass + chat_spans = [ + s for s in spans if s["attributes"].get("sentry.op", "") == "gen_ai.chat" + ] + assert len(chat_spans) == 1 - (transaction,) = events - spans = transaction["spans"] - - # Verify transaction - assert transaction["transaction"] == "invoke_agent test_agent" - assert transaction["contexts"]["trace"]["origin"] == "auto.ai.pydantic_ai" - - # Find chat spans - chat_spans = [s for s in spans if s["op"] == "gen_ai.chat"] - assert len(chat_spans) == 1 - - # Verify streaming flag is True for streaming - assert chat_spans[0]["data"]["gen_ai.response.streaming"] is True - assert "gen_ai.request.messages" in chat_spans[0]["data"] - assert "gen_ai.usage.input_tokens" in chat_spans[0]["data"] - # Streaming responses should still have output data - assert ( - "gen_ai.response.text" in chat_spans[0]["data"] - or "gen_ai.response.model" in chat_spans[0]["data"] - ) + assert json.loads( + chat_spans[0]["attributes"][SPANDATA.GEN_AI_REQUEST_MESSAGES] + ) == [ + { + "role": "user", + "content": [ + { + "type": "text", + "text": "Message demonstrating the absence of truncation.", + }, + { + "type": "text", + "text": "Test input", + }, + ], + } + ] + assert "gen_ai.usage.input_tokens" in chat_spans[0]["attributes"] + # Streaming responses should still have output data + assert ( + "gen_ai.response.text" in chat_spans[0]["attributes"] + or "gen_ai.response.model" in chat_spans[0]["attributes"] + ) -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio async def test_agent_run_stream_events( sentry_init, - capture_events, capture_items, get_test_agent, - stream_gen_ai_spans, - span_streaming, ): """ Test that run_stream_events creates spans (it uses run internally, so non-streaming). @@ -628,105 +314,40 @@ async def test_agent_run_stream_events( integrations=[PydanticAIIntegration()], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) # Consume all events test_agent = get_test_agent() + items = capture_items("span") - if span_streaming: - items = capture_items("span") - - if PYDANTIC_AI_VERSION > (2,): - async with test_agent.run_stream_events( - ["Message demonstrating the absence of truncation.", "Test input"] - ) as stream_events: - async for _ in stream_events: - pass - else: - async for _ in test_agent.run_stream_events( - ["Message demonstrating the absence of truncation.", "Test input"] - ): - pass - - sentry_sdk.flush() - spans = [item.payload for item in items] - - assert spans[-1]["name"] == "invoke_agent test_agent" - - chat_spans = [ - s for s in spans if s["attributes"].get("sentry.op", "") == "gen_ai.chat" - ] - assert len(chat_spans) == 1 - - # run_stream_events uses run() internally, so streaming should be False - assert chat_spans[0]["attributes"]["gen_ai.response.streaming"] is False - elif stream_gen_ai_spans: - items = capture_items("transaction", "span") - - if PYDANTIC_AI_VERSION > (2,): - async with test_agent.run_stream_events( - ["Message demonstrating the absence of truncation.", "Test input"] - ) as stream_events: - async for _ in stream_events: - pass - else: - async for _ in test_agent.run_stream_events( - ["Message demonstrating the absence of truncation.", "Test input"] - ): + if PYDANTIC_AI_VERSION > (2,): + async with test_agent.run_stream_events( + ["Message demonstrating the absence of truncation.", "Test input"] + ) as stream_events: + async for _ in stream_events: pass - - # Verify transaction - (transaction,) = (item.payload for item in items if item.type == "transaction") - - # Verify transaction - assert transaction["transaction"] == "invoke_agent test_agent" - - # Find chat spans - spans = [item.payload for item in items if item.type == "span"] - chat_spans = [ - s for s in spans if s["attributes"].get("sentry.op", "") == "gen_ai.chat" - ] - assert len(chat_spans) == 1 - - # run_stream_events uses run() internally, so streaming should be False - assert chat_spans[0]["attributes"]["gen_ai.response.streaming"] is False else: - events = capture_events() - - if PYDANTIC_AI_VERSION > (2,): - async with test_agent.run_stream_events("Test input") as stream_events: - async for _ in stream_events: - pass - else: - async for _ in test_agent.run_stream_events("Test input"): - pass - - (transaction,) = events + async for _ in test_agent.run_stream_events( + ["Message demonstrating the absence of truncation.", "Test input"] + ): + pass - # Verify transaction - assert transaction["transaction"] == "invoke_agent test_agent" + sentry_sdk.flush() + spans = [item.payload for item in items] - # Find chat spans - spans = transaction["spans"] - chat_spans = [s for s in spans if s["op"] == "gen_ai.chat"] - assert len(chat_spans) == 1 + assert spans[-1]["name"] == "invoke_agent test_agent" - # run_stream_events uses run() internally, so streaming should be False - assert chat_spans[0]["data"]["gen_ai.response.streaming"] is False + chat_spans = [ + s for s in spans if s["attributes"].get("sentry.op", "") == "gen_ai.chat" + ] + assert len(chat_spans) == 1 -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio async def test_agent_with_tools( sentry_init, - capture_events, capture_items, get_test_agent, - stream_gen_ai_spans, - span_streaming, ): """ Test that tool execution creates execute_tool spans. @@ -735,8 +356,6 @@ async def test_agent_with_tools( integrations=[PydanticAIIntegration()], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) test_agent = get_test_agent() @@ -746,80 +365,44 @@ def add_numbers(a: int, b: int) -> int: """Add two numbers together.""" return a + b - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - result = await test_agent.run("What is 5 + 3?") + items = capture_items("span") - assert result is not None - - sentry_sdk.flush() - spans = [item.payload for item in items] - - # Find child span types (invoke_agent is the transaction, not a child span) - chat_spans = [ - s for s in spans if s["attributes"].get("sentry.op", "") == "gen_ai.chat" - ] - tool_spans = [ - s - for s in spans - if s["attributes"].get("sentry.op", "") == "gen_ai.execute_tool" - ] - - # Should have tool spans - assert len(tool_spans) >= 1 - - # Check tool span - tool_span = tool_spans[0] - assert "execute_tool" in tool_span["name"] - assert tool_span["attributes"]["gen_ai.operation.name"] == "execute_tool" - assert tool_span["attributes"]["gen_ai.tool.name"] == "add_numbers" - assert "gen_ai.tool.input" in tool_span["attributes"] - assert "gen_ai.tool.output" in tool_span["attributes"] - - # Check chat spans have available_tools - for chat_span in chat_spans: - assert "gen_ai.request.available_tools" in chat_span["attributes"] - available_tools_str = chat_span["attributes"][ - "gen_ai.request.available_tools" - ] - # Available tools is serialized as a string - assert "add_numbers" in available_tools_str - else: - events = capture_events() - - result = await test_agent.run("What is 5 + 3?") + result = await test_agent.run("What is 5 + 3?") - assert result is not None + assert result is not None - (transaction,) = events - spans = transaction["spans"] + sentry_sdk.flush() + spans = [item.payload for item in items] - # Find child span types (invoke_agent is the transaction, not a child span) - chat_spans = [s for s in spans if s["op"] == "gen_ai.chat"] - tool_spans = [s for s in spans if s["op"] == "gen_ai.execute_tool"] + # Find child span types (invoke_agent is the transaction, not a child span) + chat_spans = [ + s for s in spans if s["attributes"].get("sentry.op", "") == "gen_ai.chat" + ] + tool_spans = [ + s + for s in spans + if s["attributes"].get("sentry.op", "") == "gen_ai.execute_tool" + ] - # Should have tool spans - assert len(tool_spans) >= 1 + # Should have tool spans + assert len(tool_spans) >= 1 - # Check tool span - tool_span = tool_spans[0] - assert "execute_tool" in tool_span["description"] - assert tool_span["data"]["gen_ai.operation.name"] == "execute_tool" - assert tool_span["data"]["gen_ai.tool.name"] == "add_numbers" - assert "gen_ai.tool.input" in tool_span["data"] - assert "gen_ai.tool.output" in tool_span["data"] + # Check tool span + tool_span = tool_spans[0] + assert "execute_tool" in tool_span["name"] + assert tool_span["attributes"]["gen_ai.operation.name"] == "execute_tool" + assert tool_span["attributes"]["gen_ai.tool.name"] == "add_numbers" + assert "gen_ai.tool.input" in tool_span["attributes"] + assert "gen_ai.tool.output" in tool_span["attributes"] - # Check chat spans have available_tools - for chat_span in chat_spans: - assert "gen_ai.request.available_tools" in chat_span["data"] - available_tools_str = chat_span["data"]["gen_ai.request.available_tools"] - # Available tools is serialized as a string - assert "add_numbers" in available_tools_str + # Check chat spans have available_tools + for chat_span in chat_spans: + assert "gen_ai.request.available_tools" in chat_span["attributes"] + available_tools_str = chat_span["attributes"]["gen_ai.request.available_tools"] + # Available tools is serialized as a string + assert "add_numbers" in available_tools_str -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize( "handled_tool_call_exceptions", [False, True], @@ -827,12 +410,9 @@ def add_numbers(a: int, b: int) -> int: @pytest.mark.asyncio async def test_agent_with_tool_model_retry( sentry_init, - capture_events, capture_items, get_test_agent, handled_tool_call_exceptions, - stream_gen_ai_spans, - span_streaming, ): """ Test that a handled exception is captured when a tool raises ModelRetry. @@ -845,8 +425,6 @@ async def test_agent_with_tool_model_retry( ], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) retries = 0 @@ -862,107 +440,57 @@ def add_numbers(a: int, b: int) -> float: raise ModelRetry(message="Try again with the same arguments.") return a + b - if span_streaming or stream_gen_ai_spans: - items = capture_items("event", "span") - - result = await test_agent.run("What is 5 + 3?") - - assert result is not None - - if handled_tool_call_exceptions: - (error,) = (item.payload for item in items if item.type == "event") - assert error["level"] == "error" - assert error["exception"]["values"][0]["mechanism"]["handled"] + items = capture_items("event", "span") - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - # Find child span types (invoke_agent is the transaction, not a child span) - chat_spans = [ - s for s in spans if s["attributes"].get("sentry.op", "") == "gen_ai.chat" - ] - tool_spans = [ - s - for s in spans - if s["attributes"].get("sentry.op", "") == "gen_ai.execute_tool" - ] + result = await test_agent.run("What is 5 + 3?") - # Should have tool spans - assert len(tool_spans) >= 1 + assert result is not None - # Check tool spans - model_retry_tool_span = tool_spans[0] - assert "execute_tool" in model_retry_tool_span["name"] - assert ( - model_retry_tool_span["attributes"]["gen_ai.operation.name"] - == "execute_tool" - ) - assert model_retry_tool_span["attributes"]["gen_ai.tool.name"] == "add_numbers" - assert "gen_ai.tool.input" in model_retry_tool_span["attributes"] + if handled_tool_call_exceptions: + (error,) = (item.payload for item in items if item.type == "event") + assert error["level"] == "error" + assert error["exception"]["values"][0]["mechanism"]["handled"] - tool_span = tool_spans[1] - assert "execute_tool" in tool_span["name"] - assert tool_span["attributes"]["gen_ai.operation.name"] == "execute_tool" - assert tool_span["attributes"]["gen_ai.tool.name"] == "add_numbers" - assert "gen_ai.tool.input" in tool_span["attributes"] - assert "gen_ai.tool.output" in tool_span["attributes"] + sentry_sdk.flush() + spans = [item.payload for item in items if item.type == "span"] + # Find child span types (invoke_agent is the transaction, not a child span) + chat_spans = [ + s for s in spans if s["attributes"].get("sentry.op", "") == "gen_ai.chat" + ] + tool_spans = [ + s + for s in spans + if s["attributes"].get("sentry.op", "") == "gen_ai.execute_tool" + ] - # Check chat spans have available_tools - for chat_span in chat_spans: - assert "gen_ai.request.available_tools" in chat_span["attributes"] - available_tools_str = chat_span["attributes"][ - "gen_ai.request.available_tools" - ] + # Should have tool spans + assert len(tool_spans) >= 1 - # Available tools is serialized as a string - assert "add_numbers" in available_tools_str - else: - events = capture_events() + # Check tool spans + model_retry_tool_span = tool_spans[0] + assert "execute_tool" in model_retry_tool_span["name"] + assert ( + model_retry_tool_span["attributes"]["gen_ai.operation.name"] == "execute_tool" + ) + assert model_retry_tool_span["attributes"]["gen_ai.tool.name"] == "add_numbers" + assert "gen_ai.tool.input" in model_retry_tool_span["attributes"] - result = await test_agent.run("What is 5 + 3?") + tool_span = tool_spans[1] + assert "execute_tool" in tool_span["name"] + assert tool_span["attributes"]["gen_ai.operation.name"] == "execute_tool" + assert tool_span["attributes"]["gen_ai.tool.name"] == "add_numbers" + assert "gen_ai.tool.input" in tool_span["attributes"] + assert "gen_ai.tool.output" in tool_span["attributes"] - assert result is not None + # Check chat spans have available_tools + for chat_span in chat_spans: + assert "gen_ai.request.available_tools" in chat_span["attributes"] + available_tools_str = chat_span["attributes"]["gen_ai.request.available_tools"] - if handled_tool_call_exceptions: - (error, transaction) = events - else: - (transaction,) = events - spans = transaction["spans"] - - if handled_tool_call_exceptions: - assert error["level"] == "error" - assert error["exception"]["values"][0]["mechanism"]["handled"] - - # Find child span types (invoke_agent is the transaction, not a child span) - chat_spans = [s for s in spans if s["op"] == "gen_ai.chat"] - tool_spans = [s for s in spans if s["op"] == "gen_ai.execute_tool"] - - # Should have tool spans - assert len(tool_spans) >= 1 - - # Check tool spans - model_retry_tool_span = tool_spans[0] - assert "execute_tool" in model_retry_tool_span["description"] - assert model_retry_tool_span["data"]["gen_ai.operation.name"] == "execute_tool" - assert model_retry_tool_span["data"]["gen_ai.tool.name"] == "add_numbers" - assert "gen_ai.tool.input" in model_retry_tool_span["data"] - - tool_span = tool_spans[1] - assert "execute_tool" in tool_span["description"] - assert tool_span["data"]["gen_ai.operation.name"] == "execute_tool" - assert tool_span["data"]["gen_ai.tool.name"] == "add_numbers" - assert "gen_ai.tool.input" in tool_span["data"] - assert "gen_ai.tool.output" in tool_span["data"] - - # Check chat spans have available_tools - for chat_span in chat_spans: - assert "gen_ai.request.available_tools" in chat_span["data"] - available_tools_str = chat_span["data"]["gen_ai.request.available_tools"] - # Available tools is serialized as a string - assert "add_numbers" in available_tools_str + # Available tools is serialized as a string + assert "add_numbers" in available_tools_str -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize( "handled_tool_call_exceptions", [False, True], @@ -970,12 +498,9 @@ def add_numbers(a: int, b: int) -> float: @pytest.mark.asyncio async def test_agent_with_tool_validation_error( sentry_init, - capture_events, capture_items, get_test_agent, handled_tool_call_exceptions, - stream_gen_ai_spans, - span_streaming, ): """ Test that a handled exception is captured when a tool has unsatisfiable constraints. @@ -988,8 +513,6 @@ async def test_agent_with_tool_validation_error( ], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) test_agent = get_test_agent() @@ -999,80 +522,40 @@ def add_numbers(a: Annotated[int, Field(gt=0, lt=0)], b: int) -> int: """Add two numbers together.""" return a + b - if span_streaming or stream_gen_ai_spans: - items = capture_items("event", "span") + items = capture_items("event", "span") - result = None - with pytest.raises(UnexpectedModelBehavior): - result = await test_agent.run("What is 5 + 3?") - - assert result is None - - if handled_tool_call_exceptions: - ( - error, - model_behaviour_error, - ) = (item.payload for item in items if item.type == "event") + result = None + with pytest.raises(UnexpectedModelBehavior): + result = await test_agent.run("What is 5 + 3?") - assert error["level"] == "error" - assert error["exception"]["values"][0]["mechanism"]["handled"] + assert result is None - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - chat_spans = [ - s for s in spans if s["attributes"].get("sentry.op", "") == "gen_ai.chat" - ] + if handled_tool_call_exceptions: + events = [item.payload for item in items if item.type == "event"] + error = events[0] - # Check chat spans have available_tools - assert "gen_ai.request.available_tools" in chat_spans[0]["attributes"] - available_tools_str = chat_spans[0]["attributes"][ - "gen_ai.request.available_tools" - ] - - # Available tools is serialized as a string - assert "add_numbers" in available_tools_str - else: - events = capture_events() + assert error["level"] == "error" + assert error["exception"]["values"][0]["mechanism"]["handled"] - result = None - with pytest.raises(UnexpectedModelBehavior): - result = await test_agent.run("What is 5 + 3?") + sentry_sdk.flush() + spans = [item.payload for item in items if item.type == "span"] + chat_spans = [ + s for s in spans if s["attributes"].get("sentry.op", "") == "gen_ai.chat" + ] - assert result is None + # Check chat spans have available_tools + assert "gen_ai.request.available_tools" in chat_spans[0]["attributes"] + available_tools_str = chat_spans[0]["attributes"]["gen_ai.request.available_tools"] - if handled_tool_call_exceptions: - (error, model_behaviour_error, transaction) = events - else: - ( - model_behaviour_error, - transaction, - ) = events - spans = transaction["spans"] - - if handled_tool_call_exceptions: - assert error["level"] == "error" - assert error["exception"]["values"][0]["mechanism"]["handled"] - - # Find child span types (invoke_agent is the transaction, not a child span) - chat_spans = [s for s in spans if s["op"] == "gen_ai.chat"] - - # Check chat spans have available_tools - assert "gen_ai.request.available_tools" in chat_spans[0]["data"] - available_tools_str = chat_spans[0]["data"]["gen_ai.request.available_tools"] - # Available tools is serialized as a string - assert "add_numbers" in available_tools_str + # Available tools is serialized as a string + assert "add_numbers" in available_tools_str -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio async def test_agent_with_tools_streaming( sentry_init, - capture_events, capture_items, get_test_agent, - stream_gen_ai_spans, - span_streaming, ): """ Test that tool execution works correctly with streaming. @@ -1081,8 +564,6 @@ async def test_agent_with_tools_streaming( integrations=[PydanticAIIntegration()], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) test_agent = get_test_agent() @@ -1092,74 +573,36 @@ def multiply(a: int, b: int) -> int: """Multiply two numbers.""" return a * b - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - async with test_agent.run_stream("What is 7 times 8?") as result: - async for _ in result.stream_output(): - pass - - sentry_sdk.flush() - spans = [item.payload for item in items] + items = capture_items("span") - # Find span types - chat_spans = [ - s for s in spans if s["attributes"].get("sentry.op", "") == "gen_ai.chat" - ] - tool_spans = [ - s - for s in spans - if s["attributes"].get("sentry.op", "") == "gen_ai.execute_tool" - ] - - # Should have tool spans - assert len(tool_spans) >= 1 - - # Verify streaming flag is True - assert chat_spans[0]["attributes"]["gen_ai.response.streaming"] is True - - # Check tool span - tool_span = tool_spans[0] - assert tool_span["attributes"]["gen_ai.tool.name"] == "multiply" - assert "gen_ai.tool.input" in tool_span["attributes"] - assert "gen_ai.tool.output" in tool_span["attributes"] - else: - events = capture_events() - - async with test_agent.run_stream("What is 7 times 8?") as result: - async for _ in result.stream_output(): - pass - - (transaction,) = events - spans = transaction["spans"] + async with test_agent.run_stream("What is 7 times 8?") as result: + async for _ in result.stream_output(): + pass - # Find span types - chat_spans = [s for s in spans if s["op"] == "gen_ai.chat"] - tool_spans = [s for s in spans if s["op"] == "gen_ai.execute_tool"] + sentry_sdk.flush() + spans = [item.payload for item in items] - # Should have tool spans - assert len(tool_spans) >= 1 + tool_spans = [ + s + for s in spans + if s["attributes"].get("sentry.op", "") == "gen_ai.execute_tool" + ] - # Verify streaming flag is True - assert chat_spans[0]["data"]["gen_ai.response.streaming"] is True + # Should have tool spans + assert len(tool_spans) >= 1 - # Check tool span - tool_span = tool_spans[0] - assert tool_span["data"]["gen_ai.tool.name"] == "multiply" - assert "gen_ai.tool.input" in tool_span["data"] - assert "gen_ai.tool.output" in tool_span["data"] + # Check tool span + tool_span = tool_spans[0] + assert tool_span["attributes"]["gen_ai.tool.name"] == "multiply" + assert "gen_ai.tool.input" in tool_span["attributes"] + assert "gen_ai.tool.output" in tool_span["attributes"] -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio async def test_model_settings( sentry_init, - capture_events, capture_items, get_test_agent_with_settings, - stream_gen_ai_spans, - span_streaming, ): """ Test that model settings are captured in spans. @@ -1167,70 +610,38 @@ async def test_model_settings( sentry_init( integrations=[PydanticAIIntegration()], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) test_agent_with_settings = get_test_agent_with_settings() + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - await test_agent_with_settings.run("Test input") - - sentry_sdk.flush() - spans = [item.payload for item in items] - - # Find chat span - chat_spans = [ - s for s in spans if s["attributes"].get("sentry.op", "") == "gen_ai.chat" - ] - assert len(chat_spans) == 1 - - chat_span = chat_spans[0] - # Check that model settings are captured - assert chat_span["attributes"].get("gen_ai.request.temperature") == 0.7 - assert chat_span["attributes"].get("gen_ai.request.max_tokens") == 100 - assert chat_span["attributes"].get("gen_ai.request.top_p") == 0.9 - else: - events = capture_events() - - await test_agent_with_settings.run("Test input") + await test_agent_with_settings.run("Test input") - (transaction,) = events - spans = transaction["spans"] + sentry_sdk.flush() + spans = [item.payload for item in items] - # Find chat span - chat_spans = [s for s in spans if s["op"] == "gen_ai.chat"] - assert len(chat_spans) == 1 + # Find chat span + chat_spans = [ + s for s in spans if s["attributes"].get("sentry.op", "") == "gen_ai.chat" + ] + assert len(chat_spans) == 1 - chat_span = chat_spans[0] - # Check that model settings are captured - assert chat_span["data"].get("gen_ai.request.temperature") == 0.7 - assert chat_span["data"].get("gen_ai.request.max_tokens") == 100 - assert chat_span["data"].get("gen_ai.request.top_p") == 0.9 + chat_span = chat_spans[0] + # Check that model settings are captured + assert chat_span["attributes"].get("gen_ai.request.temperature") == 0.7 + assert chat_span["attributes"].get("gen_ai.request.max_tokens") == 100 + assert chat_span["attributes"].get("gen_ai.request.top_p") == 0.9 -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio @pytest.mark.parametrize( - "send_default_pii, include_prompts", - [ - (True, True), - (True, False), - (False, True), - (False, False), - ], + "send_default_pii", + [True, False], ) async def test_system_prompt_attribute( sentry_init, - capture_events, capture_items, send_default_pii, - include_prompts, - stream_gen_ai_spans, - span_streaming, ): """ Test that system prompts are included as the first message. @@ -1241,705 +652,264 @@ async def test_system_prompt_attribute( system_prompt="You are a helpful assistant specialized in testing.", ) - sentry_init( - integrations=[PydanticAIIntegration(include_prompts=include_prompts)], - traces_sample_rate=1.0, - send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", - ) - - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - await agent.run("Hello") - - sentry_sdk.flush() - spans = [item.payload for item in items] - - # The transaction IS the invoke_agent span, check for messages in chat spans instead - chat_spans = [ - s for s in spans if s["attributes"].get("sentry.op", "") == "gen_ai.chat" - ] - assert len(chat_spans) == 1 - - chat_span = chat_spans[0] - - if send_default_pii and include_prompts: - system_instructions = chat_span["attributes"][ - SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS - ] - assert json.loads(system_instructions) == [ - { - "type": "text", - "content": "You are a helpful assistant specialized in testing.", - } - ] - else: - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in chat_span["attributes"] - else: - events = capture_events() - - await agent.run("Hello") - - (transaction,) = events - spans = transaction["spans"] - - # The transaction IS the invoke_agent span, check for messages in chat spans instead - chat_spans = [s for s in spans if s["op"] == "gen_ai.chat"] - assert len(chat_spans) == 1 - - chat_span = chat_spans[0] - - if send_default_pii and include_prompts: - system_instructions = chat_span["data"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS] - assert json.loads(system_instructions) == [ - { - "type": "text", - "content": "You are a helpful assistant specialized in testing.", - } - ] - else: - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in chat_span["data"] - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) -@pytest.mark.asyncio -async def test_error_handling( - sentry_init, - capture_events, - capture_items, - stream_gen_ai_spans, - span_streaming, -): - """ - Test error handling in agent execution. - """ - # Use a simpler test that doesn't cause tool failures - # as pydantic-ai has complex error handling for tool errors - agent = Agent( - "test", - name="test_error", - ) - sentry_init( integrations=[PydanticAIIntegration()], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", + send_default_pii=send_default_pii, ) + items = capture_items("span") - if span_streaming: - items = capture_items("span") - - # Simple run that should succeed - await agent.run("Hello") - - sentry_sdk.flush() - spans = [item.payload for item in items] + await agent.run("Hello") - assert spans[1]["is_segment"] is True - assert spans[1]["status"] != "error" # Could be None or some other status - elif stream_gen_ai_spans: - items = capture_items("transaction") + sentry_sdk.flush() + spans = [item.payload for item in items] - # Simple run that should succeed - await agent.run("Hello") - - # At minimum, we should have a transaction - transaction = next(item.payload for item in items) - - assert transaction["transaction"] == "invoke_agent test_error" - # Transaction should complete successfully (status key may not exist if no error) - trace_status = transaction["contexts"]["trace"].get("status") - assert trace_status != "error" # Could be None or some other status - else: - events = capture_events() - - # Simple run that should succeed - await agent.run("Hello") - - # At minimum, we should have a transaction - assert len(events) == 1 - transaction = [e for e in events if e.get("type") == "transaction"][0] - - assert transaction["transaction"] == "invoke_agent test_error" - # Transaction should complete successfully (status key may not exist if no error) - trace_status = transaction["contexts"]["trace"].get("status") - assert trace_status != "error" # Could be None or some other status - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) -@pytest.mark.asyncio -async def test_without_pii( - sentry_init, - capture_events, - capture_items, - get_test_agent, - stream_gen_ai_spans, - span_streaming, -): - """ - Test that PII is not captured when send_default_pii is False. - """ - sentry_init( - integrations=[PydanticAIIntegration()], - traces_sample_rate=1.0, - send_default_pii=False, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", - ) - - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - test_agent = get_test_agent() - await test_agent.run("Sensitive input") + # The transaction IS the invoke_agent span, check for messages in chat spans instead + chat_spans = [ + s for s in spans if s["attributes"].get("sentry.op", "") == "gen_ai.chat" + ] + assert len(chat_spans) == 1 - sentry_sdk.flush() - spans = [item.payload for item in items] + chat_span = chat_spans[0] - # Find child spans (invoke_agent is the transaction, not a child span) - chat_spans = [ - s for s in spans if s["attributes"].get("sentry.op", "") == "gen_ai.chat" + if send_default_pii: + system_instructions = chat_span["attributes"][ + SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS ] - - # Verify that messages and response text are not captured - for span in chat_spans: - assert "gen_ai.request.messages" not in span["attributes"] - assert "gen_ai.response.text" not in span["attributes"] - else: - events = capture_events() - - test_agent = get_test_agent() - await test_agent.run("Sensitive input") - - (transaction,) = events - spans = transaction["spans"] - - # Find child spans (invoke_agent is the transaction, not a child span) - chat_spans = [s for s in spans if s["op"] == "gen_ai.chat"] - - # Verify that messages and response text are not captured - for span in chat_spans: - assert "gen_ai.request.messages" not in span["data"] - assert "gen_ai.response.text" not in span["data"] - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) -@pytest.mark.asyncio -async def test_without_pii_tools( - sentry_init, - capture_events, - capture_items, - get_test_agent, - stream_gen_ai_spans, - span_streaming, -): - """ - Test that tool input/output are not captured when send_default_pii is False. - """ - sentry_init( - integrations=[PydanticAIIntegration()], - traces_sample_rate=1.0, - send_default_pii=False, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", - ) - - test_agent = get_test_agent() - - @test_agent.tool_plain - def sensitive_tool(data: str) -> str: - """A tool with sensitive data.""" - return f"Processed: {data}" - - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - await test_agent.run("Use sensitive tool with private data") - - sentry_sdk.flush() - spans = [item.payload for item in items] - - # Find tool spans - tool_spans = [ - s - for s in spans - if s["attributes"].get("sentry.op", "") == "gen_ai.execute_tool" + assert json.loads(system_instructions) == [ + { + "type": "text", + "content": "You are a helpful assistant specialized in testing.", + } ] - - # If tool was executed, verify input/output are not captured - for tool_span in tool_spans: - assert "gen_ai.tool.input" not in tool_span["attributes"] - assert "gen_ai.tool.output" not in tool_span["attributes"] - else: - events = capture_events() - - await test_agent.run("Use sensitive tool with private data") - - (transaction,) = events - spans = transaction["spans"] - - # Find tool spans - tool_spans = [s for s in spans if s["op"] == "gen_ai.execute_tool"] - - # If tool was executed, verify input/output are not captured - for tool_span in tool_spans: - assert "gen_ai.tool.input" not in tool_span["data"] - assert "gen_ai.tool.output" not in tool_span["data"] - - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) -@pytest.mark.asyncio -async def test_multiple_agents_concurrent( - sentry_init, - capture_events, - capture_items, - get_test_agent, - stream_gen_ai_spans, - span_streaming, -): - """ - Test that multiple agents can run concurrently without interfering. - """ - sentry_init( - integrations=[PydanticAIIntegration()], - traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", - ) - - test_agent = get_test_agent() - - async def run_agent(input_text): - return await test_agent.run(input_text) - - if span_streaming: - items = capture_items("span") - - # Run 3 agents concurrently - results = await asyncio.gather(*[run_agent(f"Input {i}") for i in range(3)]) - - assert len(results) == 3 - - sentry_sdk.flush() - spans = [item.payload for item in items] - for span in spans: - if span["is_segment"] is False: - continue - assert span["name"] == "invoke_agent test_agent" - elif stream_gen_ai_spans: - items = capture_items("transaction") - - # Run 3 agents concurrently - results = await asyncio.gather(*[run_agent(f"Input {i}") for i in range(3)]) - - assert len(results) == 3 - - # Verify each transaction is separate - events = [item.payload for item in items] - assert len(events) == 3 - for i, transaction in enumerate(events): - assert transaction["transaction"] == "invoke_agent test_agent" else: - events = capture_events() - - # Run 3 agents concurrently - results = await asyncio.gather(*[run_agent(f"Input {i}") for i in range(3)]) - - assert len(results) == 3 - assert len(events) == 3 + assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in chat_span["attributes"] - # Verify each transaction is separate - for i, transaction in enumerate(events): - assert transaction["type"] == "transaction" - assert transaction["transaction"] == "invoke_agent test_agent" - # Each should have its own spans - assert len(transaction["spans"]) == 1 - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio -async def test_message_history( +async def test_error_handling( sentry_init, - capture_events, capture_items, - stream_gen_ai_spans, - span_streaming, ): """ - Test that full conversation history is captured in chat spans. + Test error handling in agent execution. """ + # Use a simpler test that doesn't cause tool failures + # as pydantic-ai has complex error handling for tool errors agent = Agent( "test", - name="test_history", + name="test_error", ) sentry_init( integrations=[PydanticAIIntegration()], traces_sample_rate=1.0, - send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) + items = capture_items("span") - # Second message with history - from pydantic_ai import messages - - history = [ - messages.ModelRequest( - parts=[messages.UserPromptPart(content="Hello, I'm Alice")] - ), - messages.ModelResponse( - parts=[messages.TextPart(content="Hello Alice! How can I help you?")], - model_name="test", - ), - ] - - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - # First message - await agent.run("Hello, I'm Alice") - - await agent.run("What is my name?", message_history=history) - - sentry_sdk.flush() - spans = [item.payload for item in items] - chat_spans = [ - s for s in spans if s["attributes"].get("sentry.op", "") == "gen_ai.chat" - ] - - if chat_spans: - chat_span = chat_spans[0] - if "gen_ai.request.messages" in chat_span["attributes"]: - messages_data = chat_span["attributes"]["gen_ai.request.messages"] - # Should have multiple messages including history - assert len(messages_data) > 1 - else: - events = capture_events() - - # First message - await agent.run("Hello, I'm Alice") - - await agent.run("What is my name?", message_history=history) + # Simple run that should succeed + await agent.run("Hello") - # We should have 2 transactions - assert len(events) == 2 + sentry_sdk.flush() + spans = [item.payload for item in items] - # Check the second transaction has the full history - second_transaction = events[1] - spans = second_transaction["spans"] - chat_spans = [s for s in spans if s["op"] == "gen_ai.chat"] + assert spans[1]["is_segment"] is True + assert spans[1]["status"] != "error" # Could be None or some other status - if chat_spans: - chat_span = chat_spans[0] - if "gen_ai.request.messages" in chat_span["data"]: - messages_data = chat_span["data"]["gen_ai.request.messages"] - # Should have multiple messages including history - assert len(messages_data) > 1 - -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio -async def test_gen_ai_system( +async def test_without_pii( sentry_init, - capture_events, capture_items, get_test_agent, - stream_gen_ai_spans, - span_streaming, ): """ - Test that gen_ai.system is set from the model. + Test that PII is not captured when send_default_pii is False. """ sentry_init( integrations=[PydanticAIIntegration()], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", + send_default_pii=False, ) + items = capture_items("span") test_agent = get_test_agent() + await test_agent.run("Sensitive input") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - await test_agent.run("Test input") - - sentry_sdk.flush() - spans = [item.payload for item in items] - - # Find chat span - chat_spans = [ - s for s in spans if s["attributes"].get("sentry.op", "") == "gen_ai.chat" - ] - assert len(chat_spans) == 1 - - chat_span = chat_spans[0] - # gen_ai.system should be set from the model (TestModel -> 'test') - assert "gen_ai.system" in chat_span["attributes"] - assert chat_span["attributes"]["gen_ai.system"] == "test" - else: - events = capture_events() - - await test_agent.run("Test input") + sentry_sdk.flush() + spans = [item.payload for item in items] - (transaction,) = events - spans = transaction["spans"] - - # Find chat span - chat_spans = [s for s in spans if s["op"] == "gen_ai.chat"] - assert len(chat_spans) == 1 + # Find child spans (invoke_agent is the transaction, not a child span) + chat_spans = [ + s for s in spans if s["attributes"].get("sentry.op", "") == "gen_ai.chat" + ] - chat_span = chat_spans[0] - # gen_ai.system should be set from the model (TestModel -> 'test') - assert "gen_ai.system" in chat_span["data"] - assert chat_span["data"]["gen_ai.system"] == "test" + # Verify that messages and response text are not captured + for span in chat_spans: + assert "gen_ai.request.messages" not in span["attributes"] + assert "gen_ai.response.text" not in span["attributes"] -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio -async def test_include_prompts_false( +async def test_without_pii_tools( sentry_init, - capture_events, capture_items, get_test_agent, - stream_gen_ai_spans, - span_streaming, ): """ - Test that prompts are not captured when include_prompts=False. + Test that tool input/output are not captured when send_default_pii is False. """ sentry_init( - integrations=[PydanticAIIntegration(include_prompts=False)], + integrations=[PydanticAIIntegration()], traces_sample_rate=1.0, - send_default_pii=True, # Even with PII enabled, prompts should not be captured - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", + send_default_pii=False, ) test_agent = get_test_agent() - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - await test_agent.run("Sensitive prompt") - - sentry_sdk.flush() - spans = [item.payload for item in items] - - # Find child spans (invoke_agent is the transaction, not a child span) - chat_spans = [ - s for s in spans if s["attributes"].get("sentry.op", "") == "gen_ai.chat" - ] + @test_agent.tool_plain + def sensitive_tool(data: str) -> str: + """A tool with sensitive data.""" + return f"Processed: {data}" - # Verify that messages and response text are not captured - for span in chat_spans: - assert "gen_ai.request.messages" not in span["attributes"] - assert "gen_ai.response.text" not in span["attributes"] - else: - events = capture_events() + items = capture_items("span") - await test_agent.run("Sensitive prompt") + await test_agent.run("Use sensitive tool with private data") - (transaction,) = events - spans = transaction["spans"] + sentry_sdk.flush() + spans = [item.payload for item in items] - # Find child spans (invoke_agent is the transaction, not a child span) - chat_spans = [s for s in spans if s["op"] == "gen_ai.chat"] + # Find tool spans + tool_spans = [ + s + for s in spans + if s["attributes"].get("sentry.op", "") == "gen_ai.execute_tool" + ] - # Verify that messages and response text are not captured - for span in chat_spans: - assert "gen_ai.request.messages" not in span["data"] - assert "gen_ai.response.text" not in span["data"] + # If tool was executed, verify input/output are not captured + for tool_span in tool_spans: + assert "gen_ai.tool.input" not in tool_span["attributes"] + assert "gen_ai.tool.output" not in tool_span["attributes"] -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio -async def test_include_prompts_true( +async def test_multiple_agents_concurrent( sentry_init, - capture_events, capture_items, get_test_agent, - stream_gen_ai_spans, - span_streaming, ): """ - Test that prompts are captured when include_prompts=True (default). + Test that multiple agents can run concurrently without interfering. """ sentry_init( - integrations=[PydanticAIIntegration(include_prompts=True)], + integrations=[PydanticAIIntegration()], traces_sample_rate=1.0, - send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) test_agent = get_test_agent() - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - await test_agent.run("Test prompt") - - sentry_sdk.flush() - spans = [item.payload for item in items] - - # Find child spans (invoke_agent is the transaction, not a child span) - chat_spans = [ - s for s in spans if s["attributes"].get("sentry.op", "") == "gen_ai.chat" - ] - - # Verify that messages are captured in chat spans - assert len(chat_spans) == 1 - assert "gen_ai.request.messages" in chat_spans[0]["attributes"] - else: - events = capture_events() + async def run_agent(input_text): + return await test_agent.run(input_text) - await test_agent.run("Test prompt") + items = capture_items("span") - (transaction,) = events - spans = transaction["spans"] + # Run 3 agents concurrently + results = await asyncio.gather(*[run_agent(f"Input {i}") for i in range(3)]) - # Find child spans (invoke_agent is the transaction, not a child span) - chat_spans = [s for s in spans if s["op"] == "gen_ai.chat"] + assert len(results) == 3 - # Verify that messages are captured in chat spans - assert len(chat_spans) == 1 - assert "gen_ai.request.messages" in chat_spans[0]["data"] + sentry_sdk.flush() + spans = [item.payload for item in items] + for span in spans: + if span["is_segment"] is False: + continue + assert span["name"] == "invoke_agent test_agent" -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio -async def test_include_prompts_false_with_tools( +async def test_message_history( sentry_init, - capture_events, capture_items, - get_test_agent, - stream_gen_ai_spans, - span_streaming, ): """ - Test that tool input/output are not captured when include_prompts=False. + Test that full conversation history is captured in chat spans. """ + agent = Agent( + "test", + name="test_history", + ) + sentry_init( - integrations=[PydanticAIIntegration(include_prompts=False)], + integrations=[PydanticAIIntegration()], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) - test_agent = get_test_agent() - - @test_agent.tool_plain - def test_tool(value: int) -> int: - """A test tool.""" - return value * 2 - - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - await test_agent.run("Use the test tool with value 5") - - sentry_sdk.flush() - spans = [item.payload for item in items] - - # Find tool spans - tool_spans = [ - s - for s in spans - if s["attributes"].get("sentry.op", "") == "gen_ai.execute_tool" - ] + # Second message with history + from pydantic_ai import messages - # If tool was executed, verify input/output are not captured - for tool_span in tool_spans: - assert "gen_ai.tool.input" not in tool_span["attributes"] - assert "gen_ai.tool.output" not in tool_span["attributes"] - else: - events = capture_events() + history = [ + messages.ModelRequest( + parts=[messages.UserPromptPart(content="Hello, I'm Alice")] + ), + messages.ModelResponse( + parts=[messages.TextPart(content="Hello Alice! How can I help you?")], + model_name="test", + ), + ] + items = capture_items("span") - await test_agent.run("Use the test tool with value 5") + # First message + await agent.run("Hello, I'm Alice") - (transaction,) = events - spans = transaction["spans"] + await agent.run("What is my name?", message_history=history) - # Find tool spans - tool_spans = [s for s in spans if s["op"] == "gen_ai.execute_tool"] + sentry_sdk.flush() + spans = [item.payload for item in items] + chat_spans = [ + s for s in spans if s["attributes"].get("sentry.op", "") == "gen_ai.chat" + ] - # If tool was executed, verify input/output are not captured - for tool_span in tool_spans: - assert "gen_ai.tool.input" not in tool_span["data"] - assert "gen_ai.tool.output" not in tool_span["data"] + if chat_spans: + chat_span = chat_spans[0] + if "gen_ai.request.messages" in chat_span["attributes"]: + messages_data = chat_span["attributes"]["gen_ai.request.messages"] + # Should have multiple messages including history + assert len(messages_data) > 1 -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio -async def test_include_prompts_requires_pii( +async def test_gen_ai_system( sentry_init, - capture_events, capture_items, get_test_agent, - stream_gen_ai_spans, - span_streaming, ): """ - Test that include_prompts requires send_default_pii=True. + Test that gen_ai.system is set from the model. """ sentry_init( - integrations=[PydanticAIIntegration(include_prompts=True)], + integrations=[PydanticAIIntegration()], traces_sample_rate=1.0, - send_default_pii=False, # PII disabled - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) test_agent = get_test_agent() + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - await test_agent.run("Test prompt") - - sentry_sdk.flush() - spans = [item.payload for item in items] - - # Find child spans (invoke_agent is the transaction, not a child span) - chat_spans = [ - s for s in spans if s["attributes"].get("sentry.op", "") == "gen_ai.chat" - ] - - # Even with include_prompts=True, if PII is disabled, messages should not be captured - for span in chat_spans: - assert "gen_ai.request.messages" not in span["attributes"] - assert "gen_ai.response.text" not in span["attributes"] - else: - events = capture_events() - - await test_agent.run("Test prompt") + await test_agent.run("Test input") - (transaction,) = events - spans = transaction["spans"] + sentry_sdk.flush() + spans = [item.payload for item in items] - # Find child spans (invoke_agent is the transaction, not a child span) - chat_spans = [s for s in spans if s["op"] == "gen_ai.chat"] + # Find chat span + chat_spans = [ + s for s in spans if s["attributes"].get("sentry.op", "") == "gen_ai.chat" + ] + assert len(chat_spans) == 1 - # Even with include_prompts=True, if PII is disabled, messages should not be captured - for span in chat_spans: - assert "gen_ai.request.messages" not in span["data"] - assert "gen_ai.response.text" not in span["data"] + chat_span = chat_spans[0] + # gen_ai.system should be set from the model (TestModel -> 'test') + assert SPANDATA.GEN_AI_PROVIDER_NAME in chat_span["attributes"] + assert chat_span["attributes"][SPANDATA.GEN_AI_PROVIDER_NAME] == "test" @pytest.mark.asyncio @@ -2100,15 +1070,10 @@ async def run_and_check_context(agent, agent_name): # ==================== Additional Coverage Tests ==================== -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio async def test_invoke_agent_with_list_user_prompt( sentry_init, - capture_events, capture_items, - stream_gen_ai_spans, - span_streaming, ): """ Test that invoke_agent span handles list user prompts correctly. @@ -2122,77 +1087,30 @@ async def test_invoke_agent_with_list_user_prompt( integrations=[PydanticAIIntegration()], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) + items = capture_items("span") - if span_streaming: - items = capture_items("span") - - # Use a list as user prompt - await agent.run(["First part", "Second part"]) - - sentry_sdk.flush() - spans = [item.payload for item in items] - - if "gen_ai.request.messages" in spans[0]["attributes"]: - messages_str = spans[0]["attributes"]["gen_ai.request.messages"] - assert "First part" in messages_str - assert "Second part" in messages_str - elif stream_gen_ai_spans: - items = capture_items("transaction") - - # Use a list as user prompt - await agent.run(["First part", "Second part"]) - - (transaction,) = [item.payload for item in items] - - # Check that the invoke_agent transaction has messages data - # The invoke_agent is the transaction itself - if "gen_ai.request.messages" in transaction["contexts"]["trace"]["data"]: - messages_str = transaction["contexts"]["trace"]["data"][ - "gen_ai.request.messages" - ] - assert "First part" in messages_str - assert "Second part" in messages_str - else: - events = capture_events() - - # Use a list as user prompt - await agent.run(["First part", "Second part"]) + # Use a list as user prompt + await agent.run(["First part", "Second part"]) - (transaction,) = events + sentry_sdk.flush() + spans = [item.payload for item in items] - # Check that the invoke_agent transaction has messages data - # The invoke_agent is the transaction itself - if "gen_ai.request.messages" in transaction["contexts"]["trace"]["data"]: - messages_str = transaction["contexts"]["trace"]["data"][ - "gen_ai.request.messages" - ] - assert "First part" in messages_str - assert "Second part" in messages_str + if "gen_ai.request.messages" in spans[0]["attributes"]: + messages_str = spans[0]["attributes"]["gen_ai.request.messages"] + assert "First part" in messages_str + assert "Second part" in messages_str -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio @pytest.mark.parametrize( - "send_default_pii, include_prompts", - [ - (True, True), - (True, False), - (False, True), - (False, False), - ], + "send_default_pii", + [True, False], ) async def test_invoke_agent_with_instructions( sentry_init, - capture_events, capture_items, send_default_pii, - include_prompts, - stream_gen_ai_spans, - span_streaming, ): """ Test that invoke_agent span handles instructions correctly. @@ -2210,72 +1128,44 @@ async def test_invoke_agent_with_instructions( instructions_separator = "\n\n" if PYDANTIC_AI_VERSION >= (2, 36) else "\n" sentry_init( - integrations=[PydanticAIIntegration(include_prompts=include_prompts)], + integrations=[PydanticAIIntegration()], traces_sample_rate=1.0, send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - await agent.run("Test input") - - sentry_sdk.flush() - spans = [item.payload for item in items] + await agent.run("Test input") - # The transaction IS the invoke_agent span, check for messages in chat spans instead - chat_spans = [ - s for s in spans if s["attributes"].get("sentry.op", "") == "gen_ai.chat" - ] - assert len(chat_spans) == 1 + sentry_sdk.flush() + spans = [item.payload for item in items] - chat_span = chat_spans[0] + # The transaction IS the invoke_agent span, check for messages in chat spans instead + chat_spans = [ + s for s in spans if s["attributes"].get("sentry.op", "") == "gen_ai.chat" + ] + assert len(chat_spans) == 1 - if send_default_pii and include_prompts: - system_instructions = chat_span["attributes"][ - SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS - ] - assert json.loads(system_instructions) == [ - {"type": "text", "content": "System prompt"}, - { - "type": "text", - "content": f"Instruction 1{instructions_separator}Instruction 2", - }, - ] - else: - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in chat_span["attributes"] + chat_span = chat_spans[0] + if send_default_pii: + system_instructions = chat_span["attributes"][ + SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS + ] + assert json.loads(system_instructions) == [ + {"type": "text", "content": "System prompt"}, + { + "type": "text", + "content": f"Instruction 1{instructions_separator}Instruction 2", + }, + ] else: - events = capture_events() - - await agent.run("Test input") - - (transaction,) = events - spans = transaction["spans"] - - # The transaction IS the invoke_agent span, check for messages in chat spans instead - chat_spans = [s for s in spans if s["op"] == "gen_ai.chat"] - assert len(chat_spans) == 1 - - chat_span = chat_spans[0] - - if send_default_pii and include_prompts: - system_instructions = chat_span["data"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS] - assert json.loads(system_instructions) == [ - {"type": "text", "content": "System prompt"}, - { - "type": "text", - "content": f"Instruction 1{instructions_separator}Instruction 2", - }, - ] - else: - assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in chat_span["data"] + assert SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS not in chat_span["attributes"] @pytest.mark.asyncio -async def test_model_name_extraction_with_callable(sentry_init, capture_items): +async def test_model_name_extraction_with_callable( + sentry_init, +): """ Test model name extraction when model has a callable name() method. """ @@ -2302,7 +1192,9 @@ async def test_model_name_extraction_with_callable(sentry_init, capture_items): @pytest.mark.asyncio -async def test_model_name_extraction_fallback_to_str(sentry_init, capture_items): +async def test_model_name_extraction_fallback_to_str( + sentry_init, +): """ Test model name extraction falls back to str() when no name attribute exists. """ @@ -2329,15 +1221,10 @@ async def test_model_name_extraction_fallback_to_str(sentry_init, capture_items) assert isinstance(result, str) -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio async def test_usage_data_partial( sentry_init, - capture_events, capture_items, - stream_gen_ai_spans, - span_streaming, ): """ Test that usage data is correctly handled when only some fields are present. @@ -2350,30 +1237,17 @@ async def test_usage_data_partial( sentry_init( integrations=[PydanticAIIntegration()], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - await agent.run("Test input") - - sentry_sdk.flush() - spans = [item.payload for item in items] - - chat_spans = [ - s for s in spans if s["attributes"].get("sentry.op", "") == "gen_ai.chat" - ] - else: - events = capture_events() - - await agent.run("Test input") + await agent.run("Test input") - (transaction,) = events - spans = transaction["spans"] + sentry_sdk.flush() + spans = [item.payload for item in items] - chat_spans = [s for s in spans if s["op"] == "gen_ai.chat"] + chat_spans = [ + s for s in spans if s["attributes"].get("sentry.op", "") == "gen_ai.chat" + ] assert len(chat_spans) == 1 @@ -2383,15 +1257,10 @@ async def test_usage_data_partial( assert chat_span is not None -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio async def test_agent_data_from_scope( sentry_init, - capture_events, capture_items, - stream_gen_ai_spans, - span_streaming, ): """ Test that agent data can be retrieved from Sentry scope when not passed directly. @@ -2405,54 +1274,23 @@ async def test_agent_data_from_scope( sentry_init( integrations=[PydanticAIIntegration()], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) + items = capture_items("span") - if span_streaming: - items = capture_items("span") - - # The integration automatically sets agent in scope during execution - await agent.run("Test input") - - sentry_sdk.flush() - spans = [item.payload for item in items] - - assert spans[1]["name"] == "invoke_agent test_scope_agent" - elif stream_gen_ai_spans: - items = capture_items("transaction") - - # The integration automatically sets agent in scope during execution - await agent.run("Test input") - - # Verify agent name is capture - (transaction,) = (item.payload for item in items) - - # Verify agent name is captured - assert transaction["transaction"] == "invoke_agent test_scope_agent" - else: - events = capture_events() - - # The integration automatically sets agent in scope during execution - await agent.run("Test input") + # The integration automatically sets agent in scope during execution + await agent.run("Test input") - # Verify agent name is capture - (transaction,) = events + sentry_sdk.flush() + spans = [item.payload for item in items] - # Verify agent name is captured - assert transaction["transaction"] == "invoke_agent test_scope_agent" + assert spans[1]["name"] == "invoke_agent test_scope_agent" -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio async def test_available_tools_without_description( sentry_init, - capture_events, capture_items, get_test_agent, - stream_gen_ai_spans, - span_streaming, ): """ Test that available tools are captured even when description is missing. @@ -2460,8 +1298,6 @@ async def test_available_tools_without_description( sentry_init( integrations=[PydanticAIIntegration()], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) test_agent = get_test_agent() @@ -2471,48 +1307,28 @@ def tool_without_desc(x: int) -> int: # No docstring = no description return x * 2 - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - await test_agent.run("Use the tool with 5") - - sentry_sdk.flush() - spans = [item.payload for item in items] - - chat_spans = [ - s for s in spans if s["attributes"].get("sentry.op", "") == "gen_ai.chat" - ] - if chat_spans: - chat_span = chat_spans[0] - if "gen_ai.request.available_tools" in chat_span["attributes"]: - tools_str = chat_span["attributes"]["gen_ai.request.available_tools"] - assert "tool_without_desc" in tools_str - else: - events = capture_events() + items = capture_items("span") - await test_agent.run("Use the tool with 5") + await test_agent.run("Use the tool with 5") - (transaction,) = events - spans = transaction["spans"] + sentry_sdk.flush() + spans = [item.payload for item in items] - chat_spans = [s for s in spans if s["op"] == "gen_ai.chat"] - if chat_spans: - chat_span = chat_spans[0] - if "gen_ai.request.available_tools" in chat_span["data"]: - tools_str = chat_span["data"]["gen_ai.request.available_tools"] - assert "tool_without_desc" in tools_str + chat_spans = [ + s for s in spans if s["attributes"].get("sentry.op", "") == "gen_ai.chat" + ] + if chat_spans: + chat_span = chat_spans[0] + if "gen_ai.request.available_tools" in chat_span["attributes"]: + tools_str = chat_span["attributes"]["gen_ai.request.available_tools"] + assert "tool_without_desc" in tools_str -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio async def test_output_with_tool_calls( sentry_init, - capture_events, capture_items, get_test_agent, - stream_gen_ai_spans, - span_streaming, ): """ Test that tool calls in model response are captured correctly. @@ -2521,8 +1337,6 @@ async def test_output_with_tool_calls( integrations=[PydanticAIIntegration()], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) test_agent = get_test_agent() @@ -2532,53 +1346,30 @@ def calc_tool(value: int) -> int: """Calculate something.""" return value + 10 - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - await test_agent.run("Use calc_tool with 5") - - sentry_sdk.flush() - spans = [item.payload for item in items] - - chat_spans = [ - s for s in spans if s["attributes"].get("sentry.op", "") == "gen_ai.chat" - ] - - # At least one chat span should exist - assert len(chat_spans) >= 1 - - # Check if tool calls are captured in response - # Tool calls may or may not be in response depending on TestModel behavior - # Just verify the span was created and has basic data - assert "gen_ai.operation.name" in chat_spans[0]["attributes"] - else: - events = capture_events() + items = capture_items("span") - await test_agent.run("Use calc_tool with 5") + await test_agent.run("Use calc_tool with 5") - (transaction,) = events - spans = transaction["spans"] + sentry_sdk.flush() + spans = [item.payload for item in items] - chat_spans = [s for s in spans if s["op"] == "gen_ai.chat"] + chat_spans = [ + s for s in spans if s["attributes"].get("sentry.op", "") == "gen_ai.chat" + ] - # At least one chat span should exist - assert len(chat_spans) >= 1 + # At least one chat span should exist + assert len(chat_spans) >= 1 - # Check if tool calls are captured in response - # Tool calls may or may not be in response depending on TestModel behavior - # Just verify the span was created and has basic data - assert "gen_ai.operation.name" in chat_spans[0]["data"] + # Check if tool calls are captured in response + # Tool calls may or may not be in response depending on TestModel behavior + # Just verify the span was created and has basic data + assert "gen_ai.operation.name" in chat_spans[0]["attributes"] -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio async def test_message_formatting_with_different_parts( sentry_init, - capture_events, capture_items, - stream_gen_ai_spans, - span_streaming, ): """ Test that different message part types are handled correctly in ai_client span. @@ -2594,8 +1385,6 @@ async def test_message_formatting_with_different_parts( integrations=[PydanticAIIntegration()], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) # Create message history with different part types @@ -2608,50 +1397,31 @@ async def test_message_formatting_with_different_parts( model_name="test", ), ] + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - await agent.run("What did I say?", message_history=history) - - sentry_sdk.flush() - spans = [item.payload for item in items] - - chat_spans = [ - s for s in spans if s["attributes"].get("sentry.op", "") == "gen_ai.chat" - ] - - # Should have chat spans - assert len(chat_spans) == 1 - - # Check that messages are captured - chat_span = chat_spans[0] - if "gen_ai.request.messages" in chat_span["attributes"]: - messages_data = chat_span["attributes"]["gen_ai.request.messages"] - assert messages_data is not None - else: - events = capture_events() - - await agent.run("What did I say?", message_history=history) + await agent.run("What did I say?", message_history=history) - (transaction,) = events - spans = transaction["spans"] + sentry_sdk.flush() + spans = [item.payload for item in items] - chat_spans = [s for s in spans if s["op"] == "gen_ai.chat"] + chat_spans = [ + s for s in spans if s["attributes"].get("sentry.op", "") == "gen_ai.chat" + ] - # Should have chat spans - assert len(chat_spans) == 1 + # Should have chat spans + assert len(chat_spans) == 1 - # Check that messages are captured - chat_span = chat_spans[0] - if "gen_ai.request.messages" in chat_span["data"]: - messages_data = chat_span["data"]["gen_ai.request.messages"] - # Should contain message history - assert messages_data is not None + # Check that messages are captured + chat_span = chat_spans[0] + if "gen_ai.request.messages" in chat_span["attributes"]: + messages_data = chat_span["attributes"]["gen_ai.request.messages"] + assert messages_data is not None @pytest.mark.asyncio -async def test_update_invoke_agent_span_with_none_output(sentry_init, capture_items): +async def test_update_invoke_agent_span_with_none_output( + sentry_init, +): """ Test that update_invoke_agent_span handles None output gracefully. """ @@ -2666,20 +1436,18 @@ async def test_update_invoke_agent_span_with_none_output(sentry_init, capture_it send_default_pii=True, ) - with sentry_sdk.start_transaction(op="test", name="test") as transaction: - span = sentry_sdk.start_span(op="test_span") - - # Update with None output - should not raise - update_invoke_agent_span(span, None) + span = sentry_sdk.start_span(name="test_span") - span.finish() + # Update with None output - should not raise + update_invoke_agent_span(span, None) - # Should not crash - assert transaction is not None + span.end() @pytest.mark.asyncio -async def test_update_ai_client_span_with_none_response(sentry_init, capture_items): +async def test_update_ai_client_span_with_none_response( + sentry_init, +): """ Test that update_ai_client_span handles None response gracefully. """ @@ -2693,27 +1461,18 @@ async def test_update_ai_client_span_with_none_response(sentry_init, capture_ite traces_sample_rate=1.0, ) - with sentry_sdk.start_transaction(op="test", name="test") as transaction: - span = sentry_sdk.start_span(op="test_span") - - # Update with None response - should not raise - update_ai_client_span(span, None) + span = sentry_sdk.start_span(name="test_span") - span.finish() + # Update with None response - should not raise + update_ai_client_span(span, None) - # Should not crash - assert transaction is not None + span.end() -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio async def test_agent_without_name( sentry_init, - capture_events, capture_items, - stream_gen_ai_spans, - span_streaming, ): """ Test that agent without a name is handled correctly. @@ -2724,45 +1483,21 @@ async def test_agent_without_name( sentry_init( integrations=[PydanticAIIntegration()], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) + items = capture_items("span") - if span_streaming: - items = capture_items("span") - - await agent.run("Test input") - - sentry_sdk.flush() - spans = [item.payload for item in items] + await agent.run("Test input") - assert "invoke_agent" in spans[1]["name"] - elif stream_gen_ai_spans: - items = capture_items("transaction") + sentry_sdk.flush() + spans = [item.payload for item in items] - await agent.run("Test input") - - # Should still create transaction, just with default name - (transaction,) = (item.payload for item in items) - - # Transaction name should be "invoke_agent agent" or similar default - assert "invoke_agent" in transaction["transaction"] - else: - events = capture_events() - - await agent.run("Test input") - - (transaction,) = events - - # Should still create transaction, just with default name - assert transaction["type"] == "transaction" - - # Transaction name should be "invoke_agent agent" or similar default - assert "invoke_agent" in transaction["transaction"] + assert "invoke_agent" in spans[1]["name"] @pytest.mark.asyncio -async def test_input_messages_error_handling(sentry_init, capture_items): +async def test_input_messages_error_handling( + sentry_init, +): """ Test that _set_input_messages handles errors gracefully. """ @@ -2774,23 +1509,21 @@ async def test_input_messages_error_handling(sentry_init, capture_items): send_default_pii=True, ) - with sentry_sdk.start_transaction(op="test", name="test") as transaction: - span = sentry_sdk.start_span(op="test_span") - - # Pass invalid messages that would cause an error - invalid_messages = [object()] # Plain object without expected attributes + span = sentry_sdk.start_span(name="test_span") - # Should not raise, error is caught internally - _set_input_messages(span, invalid_messages) + # Pass invalid messages that would cause an error + invalid_messages = [object()] # Plain object without expected attributes - span.finish() + # Should not raise, error is caught internally + _set_input_messages(span, invalid_messages) - # Should not crash - assert transaction is not None + span.end() @pytest.mark.asyncio -async def test_available_tools_error_handling(sentry_init, capture_items): +async def test_available_tools_error_handling( + sentry_init, +): """ Test that _set_available_tools handles errors gracefully. """ @@ -2804,24 +1537,22 @@ async def test_available_tools_error_handling(sentry_init, capture_items): traces_sample_rate=1.0, ) - with sentry_sdk.start_transaction(op="test", name="test") as transaction: - span = sentry_sdk.start_span(op="test_span") - - # Create mock agent with invalid toolset - mock_agent = MagicMock() - mock_agent._function_toolset.tools.items.side_effect = Exception("Error") + span = sentry_sdk.start_span(name="test_span") - # Should not raise, error is caught internally - _set_available_tools(span, mock_agent) + # Create mock agent with invalid toolset + mock_agent = MagicMock() + mock_agent._function_toolset.tools.items.side_effect = Exception("Error") - span.finish() + # Should not raise, error is caught internally + _set_available_tools(span, mock_agent) - # Should not crash - assert transaction is not None + span.end() @pytest.mark.asyncio -async def test_set_usage_data_with_none_usage(sentry_init, capture_items): +async def test_set_usage_data_with_none_usage( + sentry_init, +): """ Test that _set_usage_data handles None usage gracefully. """ @@ -2833,20 +1564,18 @@ async def test_set_usage_data_with_none_usage(sentry_init, capture_items): traces_sample_rate=1.0, ) - with sentry_sdk.start_transaction(op="test", name="test") as transaction: - span = sentry_sdk.start_span(op="test_span") - - # Pass None usage - should not raise - _set_usage_data(span, None) + span = sentry_sdk.start_span(name="test_span") - span.finish() + # Pass None usage - should not raise + _set_usage_data(span, None) - # Should not crash - assert transaction is not None + span.end() @pytest.mark.asyncio -async def test_set_usage_data_with_partial_fields(sentry_init, capture_items): +async def test_set_usage_data_with_partial_fields( + sentry_init, +): """ Test that _set_usage_data handles usage with only some fields. """ @@ -2860,33 +1589,24 @@ async def test_set_usage_data_with_partial_fields(sentry_init, capture_items): traces_sample_rate=1.0, ) - with sentry_sdk.start_transaction(op="test", name="test") as transaction: - span = sentry_sdk.start_span(op="test_span") - - # Create usage object with only some fields - mock_usage = MagicMock() - mock_usage.input_tokens = 100 - mock_usage.output_tokens = None # Missing - mock_usage.total_tokens = 100 + span = sentry_sdk.start_span(name="test_span") - # Should only set the non-None fields - _set_usage_data(span, mock_usage) + # Create usage object with only some fields + mock_usage = MagicMock() + mock_usage.input_tokens = 100 + mock_usage.output_tokens = None # Missing + mock_usage.total_tokens = 100 - span.finish() + # Should only set the non-None fields + _set_usage_data(span, mock_usage) - # Should not crash - assert transaction is not None + span.end() -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio async def test_message_parts_with_tool_return( sentry_init, - capture_events, capture_items, - stream_gen_ai_spans, - span_streaming, ): """ Test that ToolReturnPart messages are handled correctly. @@ -2907,39 +1627,27 @@ def test_tool(x: int) -> int: integrations=[PydanticAIIntegration()], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - # Run with history containing tool return - await agent.run("Use test_tool with 5") - - sentry_sdk.flush() - spans = [item.payload for item in items] - - chat_spans = [ - s for s in spans if s["attributes"].get("sentry.op", "") == "gen_ai.chat" - ] - else: - events = capture_events() + # Run with history containing tool return + await agent.run("Use test_tool with 5") - # Run with history containing tool return - await agent.run("Use test_tool with 5") + sentry_sdk.flush() + spans = [item.payload for item in items] - (transaction,) = events - spans = transaction["spans"] - - chat_spans = [s for s in spans if s["op"] == "gen_ai.chat"] + chat_spans = [ + s for s in spans if s["attributes"].get("sentry.op", "") == "gen_ai.chat" + ] # Should have chat spans assert len(chat_spans) == 2 @pytest.mark.asyncio -async def test_message_parts_with_list_content(sentry_init, capture_items): +async def test_message_parts_with_list_content( + sentry_init, +): """ Test that message parts with list content are handled correctly. """ @@ -2953,32 +1661,27 @@ async def test_message_parts_with_list_content(sentry_init, capture_items): send_default_pii=True, ) - with sentry_sdk.start_transaction(op="test", name="test") as transaction: - span = sentry_sdk.start_span(op="test_span") + span = sentry_sdk.start_span(name="test_span") - # Create message with list content - mock_msg = MagicMock() - mock_part = MagicMock() - mock_part.content = ["item1", "item2", {"complex": "item"}] - mock_msg.parts = [mock_part] - mock_msg.instructions = None + # Create message with list content + mock_msg = MagicMock() + mock_part = MagicMock() + mock_part.content = ["item1", "item2", {"complex": "item"}] + mock_msg.parts = [mock_part] + mock_msg.instructions = None - messages = [mock_msg] + messages = [mock_msg] - # Should handle list content - _set_input_messages(span, messages) + # Should handle list content + _set_input_messages(span, messages) - span.finish() - - # Should not crash - assert transaction is not None + span.end() -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio async def test_output_data_transformations( - sentry_init, capture_items, capture_events, span_streaming, stream_gen_ai_spans + sentry_init, + capture_items, ): """ Test transformation of the model response from `Hooks.on.after_model_request`. @@ -2987,8 +1690,6 @@ async def test_output_data_transformations( integrations=[PydanticAIIntegration()], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) def response_model(messages, info): @@ -3011,134 +1712,52 @@ def multiply(a: int, b: int) -> int: """Multiply two numbers.""" return a * b - if span_streaming: - items = capture_items("span") - - await agent.run("What is 5 times 3?") - sentry_sdk.flush() - - spans = [item.payload for item in items] + items = capture_items("span") - invoke_agent_span = next( - span - for span in spans - if span["attributes"].get("sentry.op") == "gen_ai.invoke_agent" - ) - assert invoke_agent_span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == ( - "The answer is 15." - ) - - chat_spans = [ - span - for span in spans - if span["attributes"].get("sentry.op") == "gen_ai.chat" - ] - assert json.loads( - chat_spans[0]["attributes"][SPANDATA.GEN_AI_OUTPUT_MESSAGES] - ) == [ - { - "role": "assistant", - "parts": [ - { - "type": "tool_call", - "name": "multiply", - "arguments": '{"a": 5, "b": 3}', - } - ], - } - ] - assert json.loads( - chat_spans[1]["attributes"][SPANDATA.GEN_AI_OUTPUT_MESSAGES] - ) == [ - { - "role": "assistant", - "parts": [ - {"type": "reasoning", "content": "5 times 3 is 15."}, - {"type": "text", "content": "The answer is 15."}, - ], - } - ] - elif stream_gen_ai_spans: - items = capture_items("transaction", "span") - - await agent.run("What is 5 times 3?") - - (transaction,) = (item.payload for item in items if item.type == "transaction") - assert transaction["contexts"]["trace"]["op"] == "gen_ai.invoke_agent" - assert transaction["contexts"]["trace"]["data"][ - SPANDATA.GEN_AI_RESPONSE_TEXT - ] == ("The answer is 15.") - - spans = [item.payload for item in items if item.type == "span"] - chat_spans = [ - span - for span in spans - if span["attributes"].get("sentry.op") == "gen_ai.chat" - ] - assert json.loads( - chat_spans[0]["attributes"][SPANDATA.GEN_AI_OUTPUT_MESSAGES] - ) == [ - { - "role": "assistant", - "parts": [ - { - "type": "tool_call", - "name": "multiply", - "arguments": '{"a": 5, "b": 3}', - } - ], - } - ] - assert json.loads( - chat_spans[1]["attributes"][SPANDATA.GEN_AI_OUTPUT_MESSAGES] - ) == [ - { - "role": "assistant", - "parts": [ - {"type": "reasoning", "content": "5 times 3 is 15."}, - {"type": "text", "content": "The answer is 15."}, - ], - } - ] - else: - events = capture_events() + await agent.run("What is 5 times 3?") + sentry_sdk.flush() - await agent.run("What is 5 times 3?") + spans = [item.payload for item in items] - (transaction,) = events - assert transaction["contexts"]["trace"]["op"] == "gen_ai.invoke_agent" - assert transaction["contexts"]["trace"]["data"][ - SPANDATA.GEN_AI_RESPONSE_TEXT - ] == ("The answer is 15.") + invoke_agent_span = next( + span + for span in spans + if span["attributes"].get("sentry.op") == "gen_ai.invoke_agent" + ) + assert invoke_agent_span["attributes"][SPANDATA.GEN_AI_RESPONSE_TEXT] == ( + "The answer is 15." + ) - chat_spans = [ - span for span in transaction["spans"] if span["op"] == "gen_ai.chat" - ] - assert json.loads(chat_spans[0]["data"][SPANDATA.GEN_AI_OUTPUT_MESSAGES]) == [ - { - "role": "assistant", - "parts": [ - { - "type": "tool_call", - "name": "multiply", - "arguments": '{"a": 5, "b": 3}', - } - ], - } - ] - assert json.loads(chat_spans[1]["data"][SPANDATA.GEN_AI_OUTPUT_MESSAGES]) == [ - { - "role": "assistant", - "parts": [ - {"type": "reasoning", "content": "5 times 3 is 15."}, - {"type": "text", "content": "The answer is 15."}, - ], - } - ] + chat_spans = [ + span for span in spans if span["attributes"].get("sentry.op") == "gen_ai.chat" + ] + assert json.loads(chat_spans[0]["attributes"][SPANDATA.GEN_AI_OUTPUT_MESSAGES]) == [ + { + "role": "assistant", + "parts": [ + { + "type": "tool_call", + "name": "multiply", + "arguments": '{"a": 5, "b": 3}', + } + ], + } + ] + assert json.loads(chat_spans[1]["attributes"][SPANDATA.GEN_AI_OUTPUT_MESSAGES]) == [ + { + "role": "assistant", + "parts": [ + {"type": "reasoning", "content": "5 times 3 is 15."}, + {"type": "text", "content": "The answer is 15."}, + ], + } + ] @pytest.mark.asyncio -async def test_output_data_error_handling(sentry_init, capture_items): +async def test_output_data_error_handling( + sentry_init, +): """ Test that _set_output_data handles errors in formatting gracefully. """ @@ -3153,25 +1772,23 @@ async def test_output_data_error_handling(sentry_init, capture_items): send_default_pii=True, ) - with sentry_sdk.start_transaction(op="test", name="test") as transaction: - span = sentry_sdk.start_span(op="test_span") + span = sentry_sdk.start_span(name="test_span") - # Create mock response that will cause error - mock_response = MagicMock() - mock_response.model_name = "test-model" - mock_response.parts = [MagicMock(side_effect=Exception("Error"))] + # Create mock response that will cause error + mock_response = MagicMock() + mock_response.model_name = "test-model" + mock_response.parts = [MagicMock(side_effect=Exception("Error"))] - # Should catch error and not crash - _set_output_data(span, mock_response) + # Should catch error and not crash + _set_output_data(span, mock_response) - span.finish() - - # Should not crash - assert transaction is not None + span.end() @pytest.mark.asyncio -async def test_message_with_system_prompt_part(sentry_init, capture_items): +async def test_message_with_system_prompt_part( + sentry_init, +): """ Test that SystemPromptPart is handled with correct role. """ @@ -3187,29 +1804,27 @@ async def test_message_with_system_prompt_part(sentry_init, capture_items): send_default_pii=True, ) - with sentry_sdk.start_transaction(op="test", name="test") as transaction: - span = sentry_sdk.start_span(op="test_span") + span = sentry_sdk.start_span(name="test_span") - # Create message with SystemPromptPart - system_part = messages.SystemPromptPart(content="You are a helpful assistant") + # Create message with SystemPromptPart + system_part = messages.SystemPromptPart(content="You are a helpful assistant") - mock_msg = MagicMock() - mock_msg.parts = [system_part] - mock_msg.instructions = None + mock_msg = MagicMock() + mock_msg.parts = [system_part] + mock_msg.instructions = None - msgs = [mock_msg] + msgs = [mock_msg] - # Should handle system prompt - _set_input_messages(span, msgs) + # Should handle system prompt + _set_input_messages(span, msgs) - span.finish() - - # Should not crash - assert transaction is not None + span.end() @pytest.mark.asyncio -async def test_message_with_instructions(sentry_init, capture_items): +async def test_message_with_instructions( + sentry_init, +): """ Test that messages with instructions field are handled correctly. """ @@ -3223,55 +1838,51 @@ async def test_message_with_instructions(sentry_init, capture_items): send_default_pii=True, ) - with sentry_sdk.start_transaction(op="test", name="test") as transaction: - span = sentry_sdk.start_span(op="test_span") + span = sentry_sdk.start_span(name="test_span") - # Create message with instructions - mock_msg = MagicMock() - mock_msg.instructions = "System instructions here" - mock_part = MagicMock() - mock_part.content = "User message" - mock_msg.parts = [mock_part] + # Create message with instructions + mock_msg = MagicMock() + mock_msg.instructions = "System instructions here" + mock_part = MagicMock() + mock_part.content = "User message" + mock_msg.parts = [mock_part] - msgs = [mock_msg] + msgs = [mock_msg] - # Should extract system prompt from instructions - _set_input_messages(span, msgs) + # Should extract system prompt from instructions + _set_input_messages(span, msgs) - span.finish() - - # Should not crash - assert transaction is not None + span.end() @pytest.mark.asyncio -async def test_set_input_messages_without_prompts(sentry_init, capture_items): +async def test_set_input_messages_without_prompts( + sentry_init, +): """ Test that _set_input_messages respects _should_send_prompts(). """ import sentry_sdk sentry_init( - integrations=[PydanticAIIntegration(include_prompts=False)], + integrations=[PydanticAIIntegration()], traces_sample_rate=1.0, send_default_pii=True, ) - with sentry_sdk.start_transaction(op="test", name="test") as transaction: - span = sentry_sdk.start_span(op="test_span") - - # Even with messages, should not set them - messages = ["test"] - _set_input_messages(span, messages) + span = sentry_sdk.start_span(name="test_span") - span.finish() + # Even with messages, should not set them + messages = ["test"] + _set_input_messages(span, messages) - # Should not crash and should not set messages - assert transaction is not None + span.end() @pytest.mark.asyncio -async def test_get_model_name_with_exception_in_callable(sentry_init, capture_items): +async def test_get_model_name_with_exception_in_callable( + sentry_init, +): """ Test that _get_model_name handles exceptions in name() callable. """ @@ -3296,7 +1907,9 @@ async def test_get_model_name_with_exception_in_callable(sentry_init, capture_it @pytest.mark.asyncio -async def test_get_model_name_with_string_model(sentry_init, capture_items): +async def test_get_model_name_with_string_model( + sentry_init, +): """ Test that _get_model_name handles string models. """ @@ -3315,7 +1928,9 @@ async def test_get_model_name_with_string_model(sentry_init, capture_items): @pytest.mark.asyncio -async def test_get_model_name_with_none(sentry_init, capture_items): +async def test_get_model_name_with_none( + sentry_init, +): """ Test that _get_model_name handles None model. """ @@ -3334,7 +1949,9 @@ async def test_get_model_name_with_none(sentry_init, capture_items): @pytest.mark.asyncio -async def test_should_send_prompts_without_pii(sentry_init, capture_items): +async def test_should_send_prompts_without_pii( + sentry_init, +): """ Test that _should_send_inputs/_should_send_outputs return False when PII disabled. """ @@ -3344,9 +1961,9 @@ async def test_should_send_prompts_without_pii(sentry_init, capture_items): ) sentry_init( - integrations=[PydanticAIIntegration(include_prompts=True)], + integrations=[PydanticAIIntegration()], traces_sample_rate=1.0, - send_default_pii=False, # PII disabled + send_default_pii=False, # PII disabled, ) # Should return False @@ -3355,7 +1972,9 @@ async def test_should_send_prompts_without_pii(sentry_init, capture_items): @pytest.mark.asyncio -async def test_set_available_tools_without_toolset(sentry_init, capture_items): +async def test_set_available_tools_without_toolset( + sentry_init, +): """ Test that _set_available_tools handles agent without toolset. """ @@ -3369,24 +1988,22 @@ async def test_set_available_tools_without_toolset(sentry_init, capture_items): traces_sample_rate=1.0, ) - with sentry_sdk.start_transaction(op="test", name="test") as transaction: - span = sentry_sdk.start_span(op="test_span") - - # Create agent without _function_toolset - mock_agent = MagicMock() - del mock_agent._function_toolset + span = sentry_sdk.start_span(name="test_span") - # Should handle gracefully - _set_available_tools(span, mock_agent) + # Create agent without _function_toolset + mock_agent = MagicMock() + del mock_agent._function_toolset - span.finish() + # Should handle gracefully + _set_available_tools(span, mock_agent) - # Should not crash - assert transaction is not None + span.end() @pytest.mark.asyncio -async def test_set_available_tools_with_schema(sentry_init, capture_items): +async def test_set_available_tools_with_schema( + sentry_init, +): """ Test that _set_available_tools extracts tool schema correctly. """ @@ -3400,34 +2017,31 @@ async def test_set_available_tools_with_schema(sentry_init, capture_items): traces_sample_rate=1.0, ) - with sentry_sdk.start_transaction(op="test", name="test") as transaction: - span = sentry_sdk.start_span(op="test_span") - - # Create agent with toolset containing schema - mock_agent = MagicMock() - mock_tool = MagicMock() - mock_schema = MagicMock() - mock_schema.description = "Test tool description" - mock_schema.json_schema = {"type": "object", "properties": {}} - mock_tool.function_schema = mock_schema + span = sentry_sdk.start_span(name="test_span") - mock_agent._function_toolset.tools = {"test_tool": mock_tool} + # Create agent with toolset containing schema + mock_agent = MagicMock() + mock_tool = MagicMock() + mock_schema = MagicMock() + mock_schema.description = "Test tool description" + mock_schema.json_schema = {"type": "object", "properties": {}} + mock_tool.function_schema = mock_schema - # Should extract schema - _set_available_tools(span, mock_agent) + mock_agent._function_toolset.tools = {"test_tool": mock_tool} - span.finish() + # Should extract schema + _set_available_tools(span, mock_agent) - # Should not crash - assert transaction is not None + span.end() @pytest.mark.asyncio -async def test_execute_tool_span_creation(sentry_init, capture_items): +async def test_execute_tool_span_creation( + sentry_init, +): """ Test direct creation of execute_tool span. """ - import sentry_sdk from sentry_sdk.integrations.pydantic_ai.spans.execute_tool import ( execute_tool_span, update_execute_tool_span, @@ -3439,22 +2053,19 @@ async def test_execute_tool_span_creation(sentry_init, capture_items): send_default_pii=True, ) - with sentry_sdk.start_transaction(op="test", name="test") as transaction: - # Create execute_tool span - with execute_tool_span("test_tool", {"arg": "value"}, None, "function") as span: - # Update with result - update_execute_tool_span(span, {"result": "success"}) - - # Should not crash - assert transaction is not None + # Create execute_tool span + with execute_tool_span("test_tool", {"arg": "value"}, None, "function") as span: + # Update with result + update_execute_tool_span(span, {"result": "success"}) @pytest.mark.asyncio -async def test_execute_tool_span_with_mcp_type(sentry_init, capture_items): +async def test_execute_tool_span_with_mcp_type( + sentry_init, +): """ Test execute_tool span with MCP tool type. """ - import sentry_sdk from sentry_sdk.integrations.pydantic_ai.spans.execute_tool import ( execute_tool_span, ) @@ -3465,49 +2076,43 @@ async def test_execute_tool_span_with_mcp_type(sentry_init, capture_items): send_default_pii=True, ) - with sentry_sdk.start_transaction(op="test", name="test") as transaction: - # Create execute_tool span with mcp type - with execute_tool_span("mcp_tool", {"arg": "value"}, None, "mcp") as span: - # Verify type is set - assert span is not None - - # Should not crash - assert transaction is not None + # Create execute_tool span with mcp type + with execute_tool_span("mcp_tool", {"arg": "value"}, None, "mcp") as span: + # Verify type is set + assert span is not None @pytest.mark.asyncio -async def test_execute_tool_span_without_prompts(sentry_init, capture_items): +async def test_execute_tool_span_without_prompts( + sentry_init, +): """ Test that execute_tool span respects _should_send_prompts(). """ - import sentry_sdk from sentry_sdk.integrations.pydantic_ai.spans.execute_tool import ( execute_tool_span, update_execute_tool_span, ) sentry_init( - integrations=[PydanticAIIntegration(include_prompts=False)], + integrations=[PydanticAIIntegration()], traces_sample_rate=1.0, send_default_pii=True, ) - with sentry_sdk.start_transaction(op="test", name="test") as transaction: - # Create execute_tool span - with execute_tool_span("test_tool", {"arg": "value"}, None, "function") as span: - # Update with result - should not set input/output - update_execute_tool_span(span, {"result": "success"}) - - # Should not crash - assert transaction is not None + # Create execute_tool span + with execute_tool_span("test_tool", {"arg": "value"}, None, "function") as span: + # Update with result - should not set input/output + update_execute_tool_span(span, {"result": "success"}) @pytest.mark.asyncio -async def test_execute_tool_span_with_none_args(sentry_init, capture_items): +async def test_execute_tool_span_with_none_args( + sentry_init, +): """ Test execute_tool span with None args. """ - import sentry_sdk from sentry_sdk.integrations.pydantic_ai.spans.execute_tool import execute_tool_span sentry_init( @@ -3516,17 +2121,15 @@ async def test_execute_tool_span_with_none_args(sentry_init, capture_items): send_default_pii=True, ) - with sentry_sdk.start_transaction(op="test", name="test") as transaction: - # Create execute_tool span with None args - with execute_tool_span("test_tool", None, None, "function") as span: - assert span is not None - - # Should not crash - assert transaction is not None + # Create execute_tool span with None args + with execute_tool_span("test_tool", None, None, "function") as span: + assert span is not None @pytest.mark.asyncio -async def test_update_execute_tool_span_with_none_span(sentry_init, capture_items): +async def test_update_execute_tool_span_with_none_span( + sentry_init, +): """ Test that update_execute_tool_span handles None span gracefully. """ @@ -3547,11 +2150,12 @@ async def test_update_execute_tool_span_with_none_span(sentry_init, capture_item @pytest.mark.asyncio -async def test_update_execute_tool_span_with_none_result(sentry_init, capture_items): +async def test_update_execute_tool_span_with_none_result( + sentry_init, +): """ Test that update_execute_tool_span handles None result gracefully. """ - import sentry_sdk from sentry_sdk.integrations.pydantic_ai.spans.execute_tool import ( execute_tool_span, update_execute_tool_span, @@ -3563,18 +2167,16 @@ async def test_update_execute_tool_span_with_none_result(sentry_init, capture_it send_default_pii=True, ) - with sentry_sdk.start_transaction(op="test", name="test") as transaction: - # Create execute_tool span - with execute_tool_span("test_tool", {"arg": "value"}, None, "function") as span: - # Update with None result - update_execute_tool_span(span, None) - - # Should not crash - assert transaction is not None + # Create execute_tool span + with execute_tool_span("test_tool", {"arg": "value"}, None, "function") as span: + # Update with None result + update_execute_tool_span(span, None) @pytest.mark.asyncio -async def test_tool_execution_without_span_context(sentry_init, capture_items): +async def test_tool_execution_without_span_context( + sentry_init, +): """ Test that tool execution patch handles case when no span context exists. This tests the code path where current_span is None in _patch_tool_execution. @@ -3603,13 +2205,14 @@ async def test_tool_execution_without_span_context(sentry_init, capture_items): @pytest.mark.asyncio -async def test_invoke_agent_span_with_callable_instruction(sentry_init, capture_items): +async def test_invoke_agent_span_with_callable_instruction( + sentry_init, +): """ Test that invoke_agent_span skips callable instructions correctly. """ from unittest.mock import MagicMock - import sentry_sdk from sentry_sdk.integrations.pydantic_ai.spans.invoke_agent import invoke_agent_span sentry_init( @@ -3618,32 +2221,29 @@ async def test_invoke_agent_span_with_callable_instruction(sentry_init, capture_ send_default_pii=True, ) - with sentry_sdk.start_transaction(op="test", name="test") as transaction: - # Create mock agent with callable instruction - mock_agent = MagicMock() - mock_agent.name = "test_agent" - mock_agent._system_prompts = [] + # Create mock agent with callable instruction + mock_agent = MagicMock() + mock_agent.name = "test_agent" + mock_agent._system_prompts = [] - # Add both string and callable instructions - mock_callable = lambda: "Dynamic instruction" - mock_agent._instructions = ["Static instruction", mock_callable] + # Add both string and callable instructions + mock_callable = lambda: "Dynamic instruction" + mock_agent._instructions = ["Static instruction", mock_callable] - # Create span - span = invoke_agent_span("Test prompt", mock_agent, None, None) - span.finish() - - # Should not crash (callable should be skipped) - assert transaction is not None + # Create span + span = invoke_agent_span("Test prompt", mock_agent, None, None) + span.end() @pytest.mark.asyncio -async def test_invoke_agent_span_with_string_instructions(sentry_init, capture_items): +async def test_invoke_agent_span_with_string_instructions( + sentry_init, +): """ Test that invoke_agent_span handles string instructions (not list). """ from unittest.mock import MagicMock - import sentry_sdk from sentry_sdk.integrations.pydantic_ai.spans.invoke_agent import invoke_agent_span sentry_init( @@ -3652,77 +2252,69 @@ async def test_invoke_agent_span_with_string_instructions(sentry_init, capture_i send_default_pii=True, ) - with sentry_sdk.start_transaction(op="test", name="test") as transaction: - # Create mock agent with string instruction - mock_agent = MagicMock() - mock_agent.name = "test_agent" - mock_agent._system_prompts = [] - mock_agent._instructions = "Single instruction string" + # Create mock agent with string instruction + mock_agent = MagicMock() + mock_agent.name = "test_agent" + mock_agent._system_prompts = [] + mock_agent._instructions = "Single instruction string" - # Create span - span = invoke_agent_span("Test prompt", mock_agent, None, None) - span.finish() - - # Should not crash - assert transaction is not None + # Create span + span = invoke_agent_span("Test prompt", mock_agent, None, None) + span.end() @pytest.mark.asyncio -async def test_ai_client_span_with_streaming_flag(sentry_init, capture_items): +async def test_ai_client_span_with_streaming_flag( + sentry_init, +): """ Test that ai_client_span reads streaming flag from scope. """ import sentry_sdk - from sentry_sdk.integrations.pydantic_ai.spans.ai_client import ai_client_span + from sentry_sdk.integrations.pydantic_ai.spans.ai_client import ai_client_context sentry_init( integrations=[PydanticAIIntegration()], traces_sample_rate=1.0, ) - with sentry_sdk.start_transaction(op="test", name="test") as transaction: - # Set streaming flag in scope - scope = sentry_sdk.get_current_scope() - scope._contexts["pydantic_ai_agent"] = {"_streaming": True} - - # Create ai_client span - span = ai_client_span([], None, None, None) - span.finish() + # Set streaming flag in scope + scope = sentry_sdk.get_current_scope() + scope._contexts["pydantic_ai_agent"] = {"_streaming": True} - # Should not crash - assert transaction is not None + # Create ai_client span + span = ai_client_context([], None, None, None).span + span.end() @pytest.mark.asyncio -async def test_ai_client_span_gets_agent_from_scope(sentry_init, capture_items): +async def test_ai_client_span_gets_agent_from_scope( + sentry_init, +): """ Test that ai_client_span gets agent from scope when not passed. """ from unittest.mock import MagicMock import sentry_sdk - from sentry_sdk.integrations.pydantic_ai.spans.ai_client import ai_client_span + from sentry_sdk.integrations.pydantic_ai.spans.ai_client import ai_client_context sentry_init( integrations=[PydanticAIIntegration()], traces_sample_rate=1.0, ) - with sentry_sdk.start_transaction(op="test", name="test") as transaction: - # Set agent in scope - scope = sentry_sdk.get_current_scope() - mock_agent = MagicMock() - mock_agent.name = "test_agent" - mock_agent._function_toolset = MagicMock() - mock_agent._function_toolset.tools = {} - scope._contexts["pydantic_ai_agent"] = {"_agent": mock_agent} - - # Create ai_client span without passing agent - span = ai_client_span([], None, None, None) - span.finish() + # Set agent in scope + scope = sentry_sdk.get_current_scope() + mock_agent = MagicMock() + mock_agent.name = "test_agent" + mock_agent._function_toolset = MagicMock() + mock_agent._function_toolset.tools = {} + scope._contexts["pydantic_ai_agent"] = {"_agent": mock_agent} - # Should not crash - assert transaction is not None + # Create ai_client span without passing agent + span = ai_client_context([], None, None, None).span + span.end() def _get_messages_from_span(span_data): @@ -3747,222 +2339,89 @@ def _find_binary_content(messages_data, expected_modality, expected_mime_type): return False -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio async def test_binary_content_encoding_image( sentry_init, - capture_events, capture_items, - stream_gen_ai_spans, - span_streaming, ): """Test that BinaryContent with image data is properly encoded in messages.""" sentry_init( integrations=[PydanticAIIntegration()], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) + items = capture_items("span") - if span_streaming: - items = capture_items("span") - - with sentry_sdk.traces.start_span( - name="test", attributes={"sentry.op": "test"} - ): - span = sentry_sdk.traces.start_span( - name="custom span", attributes={"sentry.op": "test_span"} - ) - binary_content = BinaryContent( - data=b"fake_image_data_12345", media_type="image/png" - ) - user_part = UserPromptPart(content=["Look at this image:", binary_content]) - mock_msg = MagicMock() - mock_msg.parts = [user_part] - mock_msg.instructions = None - - _set_input_messages(span, [mock_msg]) - span.finish() - - sentry_sdk.flush() - spans = [item.payload for item in items] - - span_data = spans[0]["attributes"] - messages_data = _get_messages_from_span(span_data) - assert _find_binary_content(messages_data, "image", "image/png") - elif stream_gen_ai_spans: - items = capture_items("transaction") - - with sentry_sdk.start_transaction(op="test", name="test"): - span = sentry_sdk.start_span(op="test_span") - binary_content = BinaryContent( - data=b"fake_image_data_12345", media_type="image/png" - ) - user_part = UserPromptPart(content=["Look at this image:", binary_content]) - mock_msg = MagicMock() - mock_msg.parts = [user_part] - mock_msg.instructions = None - - _set_input_messages(span, [mock_msg]) - span.finish() - - (event,) = (item.payload for item in items) - span_data = event["spans"][0]["data"] - messages_data = _get_messages_from_span(span_data) - assert _find_binary_content(messages_data, "image", "image/png") - else: - events = capture_events() + span = sentry_sdk.start_span( + name="custom span", attributes={"sentry.op": "test_span"} + ) + binary_content = BinaryContent( + data=b"fake_image_data_12345", media_type="image/png" + ) + user_part = UserPromptPart(content=["Look at this image:", binary_content]) + mock_msg = MagicMock() + mock_msg.parts = [user_part] + mock_msg.instructions = None - with sentry_sdk.start_transaction(op="test", name="test"): - span = sentry_sdk.start_span(op="test_span") - binary_content = BinaryContent( - data=b"fake_image_data_12345", media_type="image/png" - ) - user_part = UserPromptPart(content=["Look at this image:", binary_content]) - mock_msg = MagicMock() - mock_msg.parts = [user_part] - mock_msg.instructions = None + _set_input_messages(span, [mock_msg]) + span.end() - _set_input_messages(span, [mock_msg]) - span.finish() + sentry_sdk.flush() + spans = [item.payload for item in items] - (event,) = events - span_data = event["spans"][0]["data"] - messages_data = _get_messages_from_span(span_data) - assert _find_binary_content(messages_data, "image", "image/png") + span_data = spans[0]["attributes"] + messages_data = _get_messages_from_span(span_data) + assert _find_binary_content(messages_data, "image", "image/png") -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio async def test_binary_content_encoding_mixed_content( sentry_init, - capture_events, capture_items, - stream_gen_ai_spans, - span_streaming, ): """Test that BinaryContent mixed with text content is properly handled.""" sentry_init( integrations=[PydanticAIIntegration()], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) + items = capture_items("span") - if span_streaming: - items = capture_items("span") - - with sentry_sdk.traces.start_span( - name="test", attributes={"sentry.op": "test"} - ): - span = sentry_sdk.traces.start_span( - name="custom span", attributes={"sentry.op": "test_span"} - ) - binary_content = BinaryContent( - data=b"fake_image_bytes", media_type="image/jpeg" - ) - user_part = UserPromptPart( - content=["Here is an image:", binary_content, "What do you see?"] - ) - mock_msg = MagicMock() - mock_msg.parts = [user_part] - mock_msg.instructions = None - - _set_input_messages(span, [mock_msg]) - span.finish() + span = sentry_sdk.start_span( + name="custom span", attributes={"sentry.op": "test_span"} + ) + binary_content = BinaryContent(data=b"fake_image_bytes", media_type="image/jpeg") + user_part = UserPromptPart( + content=["Here is an image:", binary_content, "What do you see?"] + ) + mock_msg = MagicMock() + mock_msg.parts = [user_part] + mock_msg.instructions = None - sentry_sdk.flush() - spans = [item.payload for item in items] + _set_input_messages(span, [mock_msg]) + span.end() - span_data = spans[0]["attributes"] - messages_data = _get_messages_from_span(span_data) + sentry_sdk.flush() + spans = [item.payload for item in items] - # Verify both text and binary content are present - found_text = any( - content_item.get("type") == "text" - for msg in messages_data - if "content" in msg - for content_item in msg["content"] - ) - assert found_text, "Text content should be found" - assert _find_binary_content(messages_data, "image", "image/jpeg") - elif stream_gen_ai_spans: - items = capture_items("transaction") - - with sentry_sdk.start_transaction(op="test", name="test"): - span = sentry_sdk.start_span(op="test_span") - binary_content = BinaryContent( - data=b"fake_image_bytes", media_type="image/jpeg" - ) - user_part = UserPromptPart( - content=["Here is an image:", binary_content, "What do you see?"] - ) - mock_msg = MagicMock() - mock_msg.parts = [user_part] - mock_msg.instructions = None - - _set_input_messages(span, [mock_msg]) - span.finish() - - (event,) = (item.payload for item in items) - span_data = event["spans"][0]["data"] - messages_data = _get_messages_from_span(span_data) - - # Verify both text and binary content are present - found_text = any( - content_item.get("type") == "text" - for msg in messages_data - if "content" in msg - for content_item in msg["content"] - ) - assert found_text, "Text content should be found" - assert _find_binary_content(messages_data, "image", "image/jpeg") - else: - events = capture_events() + span_data = spans[0]["attributes"] + messages_data = _get_messages_from_span(span_data) - with sentry_sdk.start_transaction(op="test", name="test"): - span = sentry_sdk.start_span(op="test_span") - binary_content = BinaryContent( - data=b"fake_image_bytes", media_type="image/jpeg" - ) - user_part = UserPromptPart( - content=["Here is an image:", binary_content, "What do you see?"] - ) - mock_msg = MagicMock() - mock_msg.parts = [user_part] - mock_msg.instructions = None - - _set_input_messages(span, [mock_msg]) - span.finish() - - (event,) = events - span_data = event["spans"][0]["data"] - messages_data = _get_messages_from_span(span_data) - - # Verify both text and binary content are present - found_text = any( - content_item.get("type") == "text" - for msg in messages_data - if "content" in msg - for content_item in msg["content"] - ) - assert found_text, "Text content should be found" - assert _find_binary_content(messages_data, "image", "image/jpeg") + # Verify both text and binary content are present + found_text = any( + content_item.get("type") == "text" + for msg in messages_data + if "content" in msg + for content_item in msg["content"] + ) + assert found_text, "Text content should be found" + assert _find_binary_content(messages_data, "image", "image/jpeg") -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio async def test_binary_content_in_agent_run( sentry_init, - capture_events, capture_items, - stream_gen_ai_spans, - span_streaming, ): """Test that BinaryContent in actual agent run is properly captured in spans.""" agent = Agent("test", name="test_binary_agent") @@ -3971,133 +2430,62 @@ async def test_binary_content_in_agent_run( integrations=[PydanticAIIntegration()], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) binary_content = BinaryContent( data=b"fake_image_data_for_testing", media_type="image/png" ) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - await agent.run(["Analyze this image:", binary_content]) - - sentry_sdk.flush() - spans = [item.payload for item in items] - chat_spans = [ - s for s in spans if s["attributes"].get("sentry.op", "") == "gen_ai.chat" - ] - assert len(chat_spans) == 1 - - chat_span = chat_spans[0] - if "gen_ai.request.messages" in chat_span["attributes"]: - messages_str = str(chat_span["attributes"]["gen_ai.request.messages"]) - - assert any( - keyword in messages_str for keyword in ["blob", "image", "base64"] - ) - else: - events = capture_events() + await agent.run(["Analyze this image:", binary_content]) - await agent.run(["Analyze this image:", binary_content]) + sentry_sdk.flush() + spans = [item.payload for item in items] + chat_spans = [ + s for s in spans if s["attributes"].get("sentry.op", "") == "gen_ai.chat" + ] + assert len(chat_spans) == 1 - (transaction,) = events - chat_spans = [s for s in transaction["spans"] if s["op"] == "gen_ai.chat"] - assert len(chat_spans) == 1 + chat_span = chat_spans[0] + if "gen_ai.request.messages" in chat_span["attributes"]: + messages_str = str(chat_span["attributes"]["gen_ai.request.messages"]) - chat_span = chat_spans[0] - if "gen_ai.request.messages" in chat_span["data"]: - messages_str = str(chat_span["data"]["gen_ai.request.messages"]) - assert any( - keyword in messages_str for keyword in ["blob", "image", "base64"] - ) + assert any(keyword in messages_str for keyword in ["blob", "image", "base64"]) -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio async def test_set_usage_data_with_cache_tokens( sentry_init, - capture_events, capture_items, - stream_gen_ai_spans, - span_streaming, ): """Test that cache_read_tokens and cache_write_tokens are tracked.""" sentry_init( integrations=[PydanticAIIntegration()], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) + items = capture_items("span") - if span_streaming: - items = capture_items("span") - - with sentry_sdk.traces.start_span( - name="test", attributes={"sentry.op": "test"} - ): - span = sentry_sdk.traces.start_span( - name="custom span", attributes={"sentry.op": "test_span"} - ) - usage = RequestUsage( - input_tokens=100, - output_tokens=50, - cache_read_tokens=80, - cache_write_tokens=20, - ) - _set_usage_data(span, usage) - span.finish() - - sentry_sdk.flush() - spans = [item.payload for item in items] - - assert spans[0]["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHED] == 80 - assert ( - spans[0]["attributes"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHE_WRITE] == 20 - ) - elif stream_gen_ai_spans: - items = capture_items("transaction") - - with sentry_sdk.start_transaction(op="test", name="test"): - span = sentry_sdk.start_span(op="test_span") - usage = RequestUsage( - input_tokens=100, - output_tokens=50, - cache_read_tokens=80, - cache_write_tokens=20, - ) - _set_usage_data(span, usage) - span.finish() + span = sentry_sdk.start_span( + name="custom span", attributes={"sentry.op": "test_span"} + ) + usage = RequestUsage( + input_tokens=100, + output_tokens=50, + cache_read_tokens=80, + cache_write_tokens=20, + ) + _set_usage_data(span, usage) + span.end() - (event,) = (item.payload for item in items) - (span_data,) = event["spans"] - assert span_data["data"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHED] == 80 - assert span_data["data"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHE_WRITE] == 20 - else: - events = capture_events() - - with sentry_sdk.start_transaction(op="test", name="test"): - span = sentry_sdk.start_span(op="test_span") - usage = RequestUsage( - input_tokens=100, - output_tokens=50, - cache_read_tokens=80, - cache_write_tokens=20, - ) - _set_usage_data(span, usage) - span.finish() + sentry_sdk.flush() + spans = [item.payload for item in items] - (event,) = events - (span_data,) = event["spans"] - assert span_data["data"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHED] == 80 - assert span_data["data"][SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHE_WRITE] == 20 + assert spans[0]["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS] == 80 + assert ( + spans[0]["attributes"][SPANDATA.GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS] == 20 + ) -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize( "url,image_url_kwargs,expected_content", [ @@ -4141,84 +2529,50 @@ async def test_set_usage_data_with_cache_tokens( ) def test_image_url_base64_content_in_span( sentry_init, - capture_events, capture_items, url, image_url_kwargs, expected_content, - stream_gen_ai_spans, - span_streaming, ): - from sentry_sdk.integrations.pydantic_ai.spans.ai_client import ai_client_span + from sentry_sdk.integrations.pydantic_ai.spans.ai_client import ai_client_context sentry_init( integrations=[PydanticAIIntegration()], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) found_image = False - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - with sentry_sdk.start_transaction(op="test", name="test"): - image_url = ImageUrl(url=url, **image_url_kwargs) - user_part = UserPromptPart(content=["Look at this image:", image_url]) - mock_msg = MagicMock() - mock_msg.parts = [user_part] - mock_msg.instructions = None - - span = ai_client_span([mock_msg], None, None, None) - span.finish() - - sentry_sdk.flush() - spans = [item.payload for item in items] - chat_spans = [ - s for s in spans if s["attributes"].get("sentry.op", "") == "gen_ai.chat" - ] - assert len(chat_spans) == 1 - messages_data = _get_messages_from_span(chat_spans[0]["attributes"]) - - for msg in messages_data: - if "content" not in msg: - continue - for content_item in msg["content"]: - if content_item.get("type") == "image": - found_image = True - assert content_item["content"] == expected_content - else: - events = capture_events() - - with sentry_sdk.start_transaction(op="test", name="test"): - image_url = ImageUrl(url=url, **image_url_kwargs) - user_part = UserPromptPart(content=["Look at this image:", image_url]) - mock_msg = MagicMock() - mock_msg.parts = [user_part] - mock_msg.instructions = None - - span = ai_client_span([mock_msg], None, None, None) - span.finish() - - (event,) = events - chat_spans = [s for s in event["spans"] if s["op"] == "gen_ai.chat"] - assert len(chat_spans) == 1 - messages_data = _get_messages_from_span(chat_spans[0]["data"]) - - for msg in messages_data: - if "content" not in msg: - continue - for content_item in msg["content"]: - if content_item.get("type") == "image": - found_image = True - assert content_item["content"] == expected_content + items = capture_items("span") + + image_url = ImageUrl(url=url, **image_url_kwargs) + user_part = UserPromptPart(content=["Look at this image:", image_url]) + mock_msg = MagicMock() + mock_msg.parts = [user_part] + mock_msg.instructions = None + + span = ai_client_context([mock_msg], None, None, None).span + span.end() + + sentry_sdk.flush() + spans = [item.payload for item in items] + chat_spans = [ + s for s in spans if s["attributes"].get("sentry.op", "") == "gen_ai.chat" + ] + assert len(chat_spans) == 1 + messages_data = _get_messages_from_span(chat_spans[0]["attributes"]) + + for msg in messages_data: + if "content" not in msg: + continue + for content_item in msg["content"]: + if content_item.get("type") == "image": + found_image = True + assert content_item["content"] == expected_content assert found_image, "Image content item should be found in messages data" -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio @pytest.mark.parametrize( "url, image_url_kwargs, expected_content", @@ -4251,77 +2605,47 @@ def test_image_url_base64_content_in_span( ) async def test_invoke_agent_image_url( sentry_init, - capture_events, capture_items, url, image_url_kwargs, expected_content, - stream_gen_ai_spans, - span_streaming, ): sentry_init( integrations=[PydanticAIIntegration()], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) agent = Agent("test", name="test_image_url_agent") image_url = ImageUrl(url=url, **image_url_kwargs) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - await agent.run([image_url, "Describe this image"]) - - found_image = False - - sentry_sdk.flush() - spans = [item.payload for item in items] - chat_spans = [ - s for s in spans if s["attributes"].get("sentry.op", "") == "gen_ai.chat" - ] - messages_data = _get_messages_from_span(chat_spans[0]["attributes"]) - for msg in messages_data: - if "content" not in msg: - continue - for content_item in msg["content"]: - if content_item.get("type") == "image": - assert content_item["content"] == expected_content - found_image = True - else: - events = capture_events() - - await agent.run([image_url, "Describe this image"]) - - (transaction,) = events + await agent.run([image_url, "Describe this image"]) - found_image = False + found_image = False - chat_spans = [s for s in transaction["spans"] if s["op"] == "gen_ai.chat"] - messages_data = _get_messages_from_span(chat_spans[0]["data"]) - for msg in messages_data: - if "content" not in msg: - continue - for content_item in msg["content"]: - if content_item.get("type") == "image": - assert content_item["content"] == expected_content - found_image = True + sentry_sdk.flush() + spans = [item.payload for item in items] + chat_spans = [ + s for s in spans if s["attributes"].get("sentry.op", "") == "gen_ai.chat" + ] + messages_data = _get_messages_from_span(chat_spans[0]["attributes"]) + for msg in messages_data: + if "content" not in msg: + continue + for content_item in msg["content"]: + if content_item.get("type") == "image": + assert content_item["content"] == expected_content + found_image = True assert found_image, "Image content item should be found in messages data" -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio async def test_tool_description_in_execute_tool_span( sentry_init, - capture_events, capture_items, - stream_gen_ai_spans, - span_streaming, ): """ Test that tool description from the tool's docstring is included in execute_tool spans. @@ -4341,96 +2665,63 @@ def multiply_numbers(a: int, b: int) -> int: integrations=[PydanticAIIntegration()], traces_sample_rate=1.0, send_default_pii=True, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", ) + items = capture_items("span") - if span_streaming or stream_gen_ai_spans: - items = capture_items("span") - - result = await agent.run("What is 5 times 3?") - assert result is not None - - sentry_sdk.flush() - spans = [item.payload for item in items] - - tool_spans = [ - s - for s in spans - if s["attributes"].get("sentry.op", "") == "gen_ai.execute_tool" - ] - - assert len(tool_spans) >= 1 - - tool_span = tool_spans[0] - - assert tool_span["attributes"]["gen_ai.tool.name"] == "multiply_numbers" - assert SPANDATA.GEN_AI_TOOL_DESCRIPTION in tool_span["attributes"] - assert ( - "Multiply two numbers" - in tool_span["attributes"][SPANDATA.GEN_AI_TOOL_DESCRIPTION] - ) - else: - events = capture_events() - - result = await agent.run("What is 5 times 3?") - assert result is not None + result = await agent.run("What is 5 times 3?") + assert result is not None - (transaction,) = events - spans = transaction["spans"] + sentry_sdk.flush() + spans = [item.payload for item in items] - tool_spans = [s for s in spans if s["op"] == "gen_ai.execute_tool"] + tool_spans = [ + s + for s in spans + if s["attributes"].get("sentry.op", "") == "gen_ai.execute_tool" + ] - assert len(tool_spans) >= 1 + assert len(tool_spans) >= 1 - tool_span = tool_spans[0] + tool_span = tool_spans[0] - assert tool_span["data"]["gen_ai.tool.name"] == "multiply_numbers" - assert SPANDATA.GEN_AI_TOOL_DESCRIPTION in tool_span["data"] - assert ( - "Multiply two numbers" - in tool_span["data"][SPANDATA.GEN_AI_TOOL_DESCRIPTION] - ) + assert tool_span["attributes"]["gen_ai.tool.name"] == "multiply_numbers" + assert SPANDATA.GEN_AI_TOOL_DESCRIPTION in tool_span["attributes"] + assert ( + "Multiply two numbers" + in tool_span["attributes"][SPANDATA.GEN_AI_TOOL_DESCRIPTION] + ) -def _spans_by_op(items, events, streaming): +def _spans_by_op(items): """Normalize captured spans to a list of (op, data) tuples. Works for both the span-streaming/gen-AI-span-streaming payloads and the classic transaction payload so data collection assertions can be shared. """ - if streaming: - sentry_sdk.flush() - return [ - ( - item.payload["attributes"].get("sentry.op", ""), - item.payload["attributes"], - ) - for item in items - if item.type == "span" - ] - - (transaction,) = events - return [(span["op"], span["data"]) for span in transaction["spans"]] + sentry_sdk.flush() + return [ + ( + item.payload["attributes"].get("sentry.op", ""), + item.payload["attributes"], + ) + for item in items + if item.type == "span" + ] -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize( - "data_collection,send_default_pii,include_prompts,expect_inputs,expect_available_tools", + "data_collection,send_default_pii,expect_inputs,expect_available_tools", [ pytest.param( {"gen_ai": {"inputs": True}}, False, - False, True, True, - id="gen-ai-inputs-enabled-overrides-pii-and-include-prompts-disabled", + id="gen-ai-inputs-enabled-overrides-pii", ), pytest.param( {"gen_ai": {"inputs": False}}, True, - True, False, False, id="gen-ai-inputs-disabled-overrides-pii-enabled", @@ -4438,7 +2729,6 @@ def _spans_by_op(items, events, streaming): pytest.param( {}, False, - False, True, True, id="gen-ai-omitted-defaults-to-enabled", @@ -4446,7 +2736,6 @@ def _spans_by_op(items, events, streaming): pytest.param( {"gen_ai": {"outputs": False}}, False, - False, True, True, id="gen-ai-outputs-disabled-does-not-affect-inputs", @@ -4456,21 +2745,11 @@ def _spans_by_op(items, events, streaming): True, True, True, - True, - id="no-data-collection-pii-and-include-prompts-enabled-collects", - ), - pytest.param( - None, - True, - False, - False, - True, - id="no-data-collection-include-prompts-disabled", + id="no-data-collection-pii", ), pytest.param( None, False, - True, False, True, id="no-data-collection-pii-disabled", @@ -4480,23 +2759,17 @@ def _spans_by_op(items, events, streaming): @pytest.mark.asyncio async def test_data_collection_gen_ai_inputs_gates_request_messages_tool_inputs_and_available_tools( sentry_init, - capture_events, capture_items, get_test_agent, data_collection, send_default_pii, - include_prompts, expect_inputs, expect_available_tools, - stream_gen_ai_spans, - span_streaming, ): init_kwargs = { - "integrations": [PydanticAIIntegration(include_prompts=include_prompts)], + "integrations": [PydanticAIIntegration()], "traces_sample_rate": 1.0, "send_default_pii": send_default_pii, - "stream_gen_ai_spans": stream_gen_ai_spans, - "trace_lifecycle": "stream" if span_streaming else "static", } if data_collection is not None: init_kwargs["data_collection"] = data_collection @@ -4509,18 +2782,12 @@ async def test_data_collection_gen_ai_inputs_gates_request_messages_tool_inputs_ def add_numbers(a: int, b: int) -> int: return a + b - streaming = span_streaming or stream_gen_ai_spans - if streaming: - items = capture_items("span") - events = None - else: - items = None - events = capture_events() + items = capture_items("span") result = await test_agent.run("What is 5 + 3?") assert result is not None - spans = _spans_by_op(items, events, streaming) + spans = _spans_by_op(items) chat_spans = [data for op, data in spans if op == "gen_ai.chat"] tool_spans = [data for op, data in spans if op == "gen_ai.execute_tool"] @@ -4543,10 +2810,7 @@ def add_numbers(a: int, b: int) -> int: assert SPANDATA.GEN_AI_REQUEST_MODEL in chat_span # Both the chat and the invoke_agent spans list the agent's available tools - for op, span_data in spans: - if op not in ("gen_ai.chat", "gen_ai.invoke_agent"): - continue - + for span_data in chat_spans: if expect_available_tools: assert "add_numbers" in span_data[SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS] else: @@ -4562,36 +2826,30 @@ def add_numbers(a: int, b: int) -> int: assert tool_span[SPANDATA.GEN_AI_TOOL_NAME] == "add_numbers" -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize( - "data_collection,send_default_pii,include_prompts,expect_outputs", + "data_collection,send_default_pii,expect_outputs", [ pytest.param( {"gen_ai": {"outputs": True}}, False, - False, True, - id="gen-ai-outputs-enabled-overrides-pii-and-include-prompts-disabled", + id="gen-ai-outputs-enabled-overrides-pii", ), pytest.param( {"gen_ai": {"outputs": False}}, True, - True, False, id="gen-ai-outputs-disabled-overrides-pii-enabled", ), pytest.param( {}, False, - False, True, id="gen-ai-omitted-defaults-to-enabled", ), pytest.param( {"gen_ai": {"inputs": False}}, False, - False, True, id="gen-ai-inputs-disabled-does-not-affect-outputs", ), @@ -4599,20 +2857,11 @@ def add_numbers(a: int, b: int) -> int: None, True, True, - True, - id="no-data-collection-pii-and-include-prompts-enabled-collects", - ), - pytest.param( - None, - True, - False, - False, - id="no-data-collection-include-prompts-disabled", + id="no-data-collection-pii", ), pytest.param( None, False, - True, False, id="no-data-collection-pii-disabled", ), @@ -4621,22 +2870,16 @@ def add_numbers(a: int, b: int) -> int: @pytest.mark.asyncio async def test_data_collection_gen_ai_outputs_gates_response_text_and_tool_outputs( sentry_init, - capture_events, capture_items, get_test_agent, data_collection, send_default_pii, - include_prompts, expect_outputs, - stream_gen_ai_spans, - span_streaming, ): init_kwargs = { - "integrations": [PydanticAIIntegration(include_prompts=include_prompts)], + "integrations": [PydanticAIIntegration()], "traces_sample_rate": 1.0, "send_default_pii": send_default_pii, - "stream_gen_ai_spans": stream_gen_ai_spans, - "trace_lifecycle": "stream" if span_streaming else "static", } if data_collection is not None: init_kwargs["data_collection"] = data_collection @@ -4649,32 +2892,18 @@ async def test_data_collection_gen_ai_outputs_gates_response_text_and_tool_outpu def add_numbers(a: int, b: int) -> int: return a + b - streaming = span_streaming or stream_gen_ai_spans - if streaming: - items = capture_items("transaction", "span") - events = None - else: - items = None - events = capture_events() + items = capture_items("span") result = await test_agent.run("What is 5 + 3?") assert result is not None - spans = _spans_by_op(items, events, streaming) + spans = _spans_by_op(items) # The invoke_agent span is either a child span or, when it is the segment # span, the transaction itself. invoke_agent_data = next( (data for op, data in spans if op == "gen_ai.invoke_agent"), None ) - if invoke_agent_data is None: - if streaming: - (transaction,) = ( - item.payload for item in items if item.type == "transaction" - ) - else: - (transaction,) = events - invoke_agent_data = transaction["contexts"]["trace"]["data"] chat_spans = [data for op, data in spans if op == "gen_ai.chat"] tool_spans = [data for op, data in spans if op == "gen_ai.execute_tool"] @@ -4712,8 +2941,6 @@ def add_numbers(a: int, b: int) -> int: assert tool_span[SPANDATA.GEN_AI_TOOL_NAME] == "add_numbers" -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.parametrize( "gen_ai,expect_outputs", [ @@ -4742,19 +2969,14 @@ def add_numbers(a: int, b: int) -> int: @pytest.mark.asyncio async def test_data_collection_gen_ai_output_message_parts_follow_outputs_gate( sentry_init, - capture_events, capture_items, get_test_agent, gen_ai, expect_outputs, - stream_gen_ai_spans, - span_streaming, ): sentry_init( integrations=[PydanticAIIntegration()], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", data_collection={"gen_ai": gen_ai}, ) @@ -4764,18 +2986,12 @@ async def test_data_collection_gen_ai_output_message_parts_follow_outputs_gate( def add_numbers(a: int, b: int) -> int: return a + b - streaming = span_streaming or stream_gen_ai_spans - if streaming: - items = capture_items("transaction", "span") - events = None - else: - items = None - events = capture_events() + items = capture_items("transaction", "span") result = await test_agent.run("What is 5 + 3?") assert result is not None - spans = _spans_by_op(items, events, streaming) + spans = _spans_by_op(items) chat_spans = [data for op, data in spans if op == "gen_ai.chat"] # The test model calls the tool on the first response and answers with text @@ -4807,16 +3023,11 @@ def add_numbers(a: int, b: int) -> int: assert SPANDATA.GEN_AI_OUTPUT_MESSAGES not in chat_span -@pytest.mark.parametrize("span_streaming", [True, False]) -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) @pytest.mark.asyncio async def test_data_collection_gen_ai_request_messages_keep_tool_returns_when_outputs_disabled( sentry_init, - capture_events, capture_items, get_test_agent, - stream_gen_ai_spans, - span_streaming, ): """ A tool return value is an output on the `gen_ai.execute_tool` span, so @@ -4828,8 +3039,6 @@ async def test_data_collection_gen_ai_request_messages_keep_tool_returns_when_ou sentry_init( integrations=[PydanticAIIntegration()], traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - trace_lifecycle="stream" if span_streaming else "static", data_collection={"gen_ai": {"inputs": True, "outputs": False}}, ) @@ -4839,18 +3048,12 @@ async def test_data_collection_gen_ai_request_messages_keep_tool_returns_when_ou def add_numbers(a: int, b: int) -> int: return a + b - streaming = span_streaming or stream_gen_ai_spans - if streaming: - items = capture_items("transaction", "span") - events = None - else: - items = None - events = capture_events() + items = capture_items("transaction", "span") result = await test_agent.run("What is 5 + 3?") assert result is not None - spans = _spans_by_op(items, events, streaming) + spans = _spans_by_op(items) chat_spans = [data for op, data in spans if op == "gen_ai.chat"] tool_spans = [data for op, data in spans if op == "gen_ai.execute_tool"] diff --git a/tests/integrations/pymongo/test_pymongo.py b/tests/integrations/pymongo/test_pymongo.py index 9e296982f5..c2918fafd1 100644 --- a/tests/integrations/pymongo/test_pymongo.py +++ b/tests/integrations/pymongo/test_pymongo.py @@ -3,7 +3,7 @@ from pymongo import MongoClient import sentry_sdk -from sentry_sdk import capture_message, start_transaction +from sentry_sdk import capture_message from sentry_sdk.consts import SPANDATA from sentry_sdk.integrations.pymongo import PyMongoIntegration, _strip_pii @@ -25,91 +25,6 @@ def mongo_server(): server.stop() -@pytest.mark.parametrize("with_pii", [False, True]) -def test_transactions(sentry_init, capture_events, mongo_server, with_pii): - sentry_init( - integrations=[PyMongoIntegration()], - traces_sample_rate=1.0, - send_default_pii=with_pii, - ) - events = capture_events() - - connection = MongoClient(mongo_server.uri) - - with start_transaction(): - list( - connection["test_db"]["test_collection"].find({"foobar": 1}) - ) # force query execution - connection["test_db"]["test_collection"].insert_one({"foo": 2}) - try: - connection["test_db"]["erroneous"].insert_many([{"bar": 3}, {"baz": 4}]) - pytest.fail("Request should raise") - except Exception: - pass - - (event,) = events - (find, insert_success, insert_fail) = event["spans"] - - common_tags = { - "db.name": "test_db", - "db.system": "mongodb", - "db.driver.name": "pymongo", - "net.peer.name": mongo_server.host, - "net.peer.port": str(mongo_server.port), - } - for span in find, insert_success, insert_fail: - assert span["data"][SPANDATA.DB_SYSTEM] == "mongodb" - assert span["data"][SPANDATA.DB_DRIVER_NAME] == "pymongo" - assert span["data"][SPANDATA.DB_NAME] == "test_db" - assert span["data"][SPANDATA.SERVER_ADDRESS] == "localhost" - assert span["data"][SPANDATA.SERVER_PORT] == mongo_server.port - for field, value in common_tags.items(): - assert span["tags"][field] == value - assert span["data"][field] == value - - assert find["op"] == "db" - assert insert_success["op"] == "db" - assert insert_fail["op"] == "db" - - assert find["data"]["db.operation"] == "find" - assert find["tags"]["db.operation"] == "find" - assert insert_success["data"]["db.operation"] == "insert" - assert insert_success["tags"]["db.operation"] == "insert" - assert insert_fail["data"]["db.operation"] == "insert" - assert insert_fail["tags"]["db.operation"] == "insert" - - assert find["description"].startswith('{"find') - assert insert_success["description"].startswith('{"insert') - assert insert_fail["description"].startswith('{"insert') - - assert find["data"][SPANDATA.DB_MONGODB_COLLECTION] == "test_collection" - assert find["tags"][SPANDATA.DB_MONGODB_COLLECTION] == "test_collection" - assert insert_success["data"][SPANDATA.DB_MONGODB_COLLECTION] == "test_collection" - assert insert_success["tags"][SPANDATA.DB_MONGODB_COLLECTION] == "test_collection" - assert insert_fail["data"][SPANDATA.DB_MONGODB_COLLECTION] == "erroneous" - assert insert_fail["tags"][SPANDATA.DB_MONGODB_COLLECTION] == "erroneous" - if with_pii: - assert "1" in find["description"] - assert "2" in insert_success["description"] - assert "3" in insert_fail["description"] and "4" in insert_fail["description"] - else: - # All values in filter replaced by "%s" - assert "1" not in find["description"] - # All keys below top level replaced by "%s" - assert "2" not in insert_success["description"] - assert ( - "3" not in insert_fail["description"] - and "4" not in insert_fail["description"] - ) - - assert find["status"] == "ok" - assert find["tags"]["status"] == "ok" - assert insert_success["status"] == "ok" - assert insert_success["tags"]["status"] == "ok" - assert insert_fail["status"] == "internal_error" - assert insert_fail["tags"]["status"] == "internal_error" - - DATA_COLLECTION_DATABASE_QUERY_DATA_USE_CASES = [ pytest.param( {"data_collection": {"database_query_data": True}}, @@ -145,65 +60,18 @@ def test_transactions(sentry_init, capture_events, mongo_server, with_pii): ] -@pytest.mark.parametrize( - "init_kwargs,expect_query_values", DATA_COLLECTION_DATABASE_QUERY_DATA_USE_CASES -) -def test_transactions_with_data_collection( - sentry_init, capture_events, mongo_server, init_kwargs, expect_query_values -): - sentry_init( - integrations=[PyMongoIntegration()], - traces_sample_rate=1.0, - **init_kwargs, - ) - events = capture_events() - - connection = MongoClient(mongo_server.uri) - - with start_transaction(): - list( - connection["test_db"]["test_collection"].find({"foobar": 1}) - ) # force query execution - connection["test_db"]["test_collection"].insert_one({"foo": 2}) - try: - connection["test_db"]["erroneous"].insert_many([{"bar": 3}, {"baz": 4}]) - pytest.fail("Request should raise") - except Exception: - pass - - (event,) = events - (find, insert_success, insert_fail) = event["spans"] - - assert find["description"].startswith('{"find') - assert insert_success["description"].startswith('{"insert') - assert insert_fail["description"].startswith('{"insert') - - if expect_query_values: - assert "1" in find["description"] - assert "2" in insert_success["description"] - assert "3" in insert_fail["description"] and "4" in insert_fail["description"] - else: - assert "1" not in find["description"] - assert "2" not in insert_success["description"] - assert ( - "3" not in insert_fail["description"] - and "4" not in insert_fail["description"] - ) - - @pytest.mark.parametrize("with_pii", [False, True]) -def test_segment_span_streaming(sentry_init, capture_items, mongo_server, with_pii): +def test_segment(sentry_init, capture_items, mongo_server, with_pii): sentry_init( integrations=[PyMongoIntegration()], traces_sample_rate=1.0, send_default_pii=with_pii, - trace_lifecycle="stream", ) items = capture_items("span") connection = MongoClient(mongo_server.uri) - with sentry_sdk.traces.start_span(name="test_segment"): + with sentry_sdk.start_span(name="test_segment"): list( connection["test_db"]["test_collection"].find({"foobar": 1}) ) # force query execution @@ -213,6 +81,7 @@ def test_segment_span_streaming(sentry_init, capture_items, mongo_server, with_p pytest.fail("Request should raise") except Exception: pass + sentry_sdk.flush() spans = [item.payload for item in items] @@ -263,20 +132,19 @@ def test_segment_span_streaming(sentry_init, capture_items, mongo_server, with_p @pytest.mark.parametrize( "init_kwargs,expect_query_values", DATA_COLLECTION_DATABASE_QUERY_DATA_USE_CASES ) -def test_segment_span_streaming_with_data_collection( +def test_segment_with_data_collection( sentry_init, capture_items, mongo_server, init_kwargs, expect_query_values ): sentry_init( integrations=[PyMongoIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", **init_kwargs, ) items = capture_items("span") connection = MongoClient(mongo_server.uri) - with sentry_sdk.traces.start_span(name="test_segment"): + with sentry_sdk.start_span(name="test_segment"): list( connection["test_db"]["test_collection"].find({"foobar": 1}) ) # force query execution @@ -312,81 +180,11 @@ def test_segment_span_streaming_with_data_collection( @pytest.mark.parametrize("with_pii", [False, True]) -def test_breadcrumbs(sentry_init, capture_events, mongo_server, with_pii): - sentry_init( - integrations=[PyMongoIntegration()], - traces_sample_rate=1.0, - send_default_pii=with_pii, - ) - events = capture_events() - - connection = MongoClient(mongo_server.uri) - - list( - connection["test_db"]["test_collection"].find({"foobar": 1}) - ) # force query execution - capture_message("hi") - - (event,) = events - (crumb,) = event["breadcrumbs"]["values"] - - assert crumb["category"] == "query" - assert crumb["message"].startswith('{"find') - if with_pii: - assert "1" in crumb["message"] - else: - assert "1" not in crumb["message"] - assert crumb["type"] == "db" - assert crumb["data"] == { - "db.name": "test_db", - "db.system": "mongodb", - "db.driver.name": "pymongo", - "db.operation": "find", - "net.peer.name": mongo_server.host, - "net.peer.port": str(mongo_server.port), - "db.mongodb.collection": "test_collection", - } - - -@pytest.mark.parametrize( - "init_kwargs,expect_query_values", DATA_COLLECTION_DATABASE_QUERY_DATA_USE_CASES -) -def test_breadcrumbs_with_data_collection( - sentry_init, capture_events, mongo_server, init_kwargs, expect_query_values -): - sentry_init( - integrations=[PyMongoIntegration()], - traces_sample_rate=1.0, - **init_kwargs, - ) - events = capture_events() - - connection = MongoClient(mongo_server.uri) - - list( - connection["test_db"]["test_collection"].find({"foobar": 1}) - ) # force query execution - capture_message("hi") - - (event,) = events - (crumb,) = event["breadcrumbs"]["values"] - - assert crumb["category"] == "query" - assert crumb["message"].startswith('{"find') - if expect_query_values: - assert "1" in crumb["message"] - else: - assert "1" not in crumb["message"] - assert crumb["type"] == "db" - - -@pytest.mark.parametrize("with_pii", [False, True]) -def test_breadcrumbs_span_streaming(sentry_init, capture_items, mongo_server, with_pii): +def test_breadcrumbs(sentry_init, capture_items, mongo_server, with_pii): sentry_init( integrations=[PyMongoIntegration()], traces_sample_rate=1.0, send_default_pii=with_pii, - trace_lifecycle="stream", ) items = capture_items("event") @@ -424,13 +222,12 @@ def test_breadcrumbs_span_streaming(sentry_init, capture_items, mongo_server, wi @pytest.mark.parametrize( "init_kwargs,expect_query_values", DATA_COLLECTION_DATABASE_QUERY_DATA_USE_CASES ) -def test_breadcrumbs_span_streaming_with_data_collection( +def test_breadcrumbs_with_data_collection( sentry_init, capture_items, mongo_server, init_kwargs, expect_query_values ): sentry_init( integrations=[PyMongoIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", **init_kwargs, ) items = capture_items("event") @@ -751,37 +548,16 @@ def test_strip_pii(testcase): assert _strip_pii(testcase["command"]) == testcase["command_stripped"] -def test_span_origin(sentry_init, capture_events, mongo_server): - sentry_init( - integrations=[PyMongoIntegration()], - traces_sample_rate=1.0, - ) - events = capture_events() - - connection = MongoClient(mongo_server.uri) - - with start_transaction(): - list( - connection["test_db"]["test_collection"].find({"foobar": 1}) - ) # force query execution - - (event,) = events - - assert event["contexts"]["trace"]["origin"] == "manual" - assert event["spans"][0]["origin"] == "auto.db.pymongo" - - -def test_span_origin_span_streaming(sentry_init, capture_items, mongo_server): +def test_span_origin(sentry_init, capture_items, mongo_server): sentry_init( integrations=[PyMongoIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", ) items = capture_items("span") connection = MongoClient(mongo_server.uri) - with sentry_sdk.traces.start_span(name="test_segment"): + with sentry_sdk.start_span(name="test_segment"): list( connection["test_db"]["test_collection"].find({"foobar": 1}) ) # force query execution @@ -794,17 +570,16 @@ def test_span_origin_span_streaming(sentry_init, capture_items, mongo_server): assert db_span["attributes"]["sentry.origin"] == "auto.db.pymongo" -def test_span_streaming_status_on_success(sentry_init, capture_items, mongo_server): +def test_status_on_success(sentry_init, capture_items, mongo_server): sentry_init( integrations=[PyMongoIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", ) items = capture_items("span") connection = MongoClient(mongo_server.uri) - with sentry_sdk.traces.start_span(name="test_segment"): + with sentry_sdk.start_span(name="test_segment"): connection["test_db"]["test_collection"].insert_one({"foo": 1}) sentry_sdk.flush() @@ -815,17 +590,16 @@ def test_span_streaming_status_on_success(sentry_init, capture_items, mongo_serv assert db_span["status"] == "ok" -def test_span_streaming_status_on_failure(sentry_init, capture_items, mongo_server): +def test_status_on_failure(sentry_init, capture_items, mongo_server): sentry_init( integrations=[PyMongoIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", ) items = capture_items("span") connection = MongoClient(mongo_server.uri) - with sentry_sdk.traces.start_span(name="test_segment"): + with sentry_sdk.start_span(name="test_segment"): try: connection["test_db"]["erroneous"].insert_many([{"bar": 3}]) pytest.fail("Request should raise") diff --git a/tests/integrations/pyramid/test_pyramid.py b/tests/integrations/pyramid/test_pyramid.py index 4c80298e44..798accbf73 100644 --- a/tests/integrations/pyramid/test_pyramid.py +++ b/tests/integrations/pyramid/test_pyramid.py @@ -4,7 +4,6 @@ import pyramid.testing import pytest -from packaging.version import Version from pyramid.authorization import ACLAuthorizationPolicy from pyramid.response import Response from werkzeug.test import Client @@ -18,19 +17,6 @@ from tests.conftest import unpack_werkzeug_response from tests.integrations.utils import DATA_COLLECTION_USER_INFO_CASES -try: - from importlib.metadata import version - - PYRAMID_VERSION = Version(version("pyramid")).release - -except ImportError: - # < py3.8 - import pkg_resources - - PYRAMID_VERSION = tuple( - map(int, pkg_resources.get_distribution("pyramid").version.split(".")) - ) - def hi(request): capture_message("hi") @@ -130,7 +116,6 @@ def hi2(request): assert event["transaction"] == "hi2" -@pytest.mark.parametrize("span_streaming", [True, False]) @pytest.mark.parametrize( "url,transaction_style,expected_transaction,expected_source", [ @@ -143,39 +128,29 @@ def hi2(request): def test_transaction_style( sentry_init, get_client, - capture_events, capture_items, url, transaction_style, expected_transaction, expected_source, - span_streaming, ): sentry_init( integrations=[PyramidIntegration(transaction_style=transaction_style)], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("event", "span") - else: - events = capture_events() + items = capture_items("event", "span") client = get_client() client.get(url) - if span_streaming: - sentry_sdk.flush() - spans = [i.payload for i in items if i.type == "span"] - assert len(spans) == 1 - (segment,) = spans - assert segment["name"] == expected_transaction - assert segment["attributes"]["sentry.segment.name.source"] == expected_source - else: - (_, transaction_event) = events - assert transaction_event["transaction"] == expected_transaction - assert transaction_event["transaction_info"] == {"source": expected_source} + sentry_sdk.flush() + + spans = [i.payload for i in items if i.type == "span"] + assert len(spans) == 1 + (segment,) = spans + assert segment["name"] == expected_transaction + assert segment["attributes"]["sentry.segment.name.source"] == expected_source def test_http_route( @@ -186,7 +161,6 @@ def test_http_route( sentry_init( integrations=[PyramidIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", ) items = capture_items("span") @@ -371,10 +345,6 @@ def errorhandler(exc, request): assert not errors -@pytest.mark.skipif( - PYRAMID_VERSION < (1, 9), - reason="We don't have the right hooks in older Pyramid versions", -) def test_errorhandler_500( sentry_init, pyramid_config, capture_exceptions, route, get_client ): @@ -498,20 +468,18 @@ def index(request): assert not errors -@pytest.mark.parametrize("span_streaming", [True, False]) def test_tracing_error( - sentry_init, capture_events, capture_items, route, get_client, span_streaming + sentry_init, + capture_items, + route, + get_client, ): sentry_init( integrations=[PyramidIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("event", "span") - else: - events = capture_events() + items = capture_items("event", "span") @route("/tracing-error") def tracing_error(request): @@ -521,66 +489,46 @@ def tracing_error(request): with pytest.raises(ZeroDivisionError): client.get("/tracing-error") - if span_streaming: - sentry_sdk.flush() - spans = [i.payload for i in items if i.type == "span"] - error_events = [i.payload for i in items if i.type == "event"] - - assert len(spans) == 1 - assert len(error_events) == 1 - - (segment,) = spans - (error_event,) = error_events + sentry_sdk.flush() + spans = [i.payload for i in items if i.type == "span"] + error_events = [i.payload for i in items if i.type == "event"] - assert segment["name"] == "tracing_error" - assert segment["status"] == SpanStatus.ERROR - assert segment["attributes"]["sentry.origin"] == "auto.http.pyramid" + assert len(spans) == 1 + assert len(error_events) == 1 - assert error_event["exception"]["values"][-1]["type"] == "ZeroDivisionError" - assert error_event["exception"]["values"][-1]["mechanism"]["type"] == "pyramid" - else: - error_event, transaction_event = events + (segment,) = spans + (error_event,) = error_events - assert transaction_event["type"] == "transaction" - assert transaction_event["transaction"] == "tracing_error" - assert transaction_event["contexts"]["trace"]["status"] == "internal_error" + assert segment["name"] == "tracing_error" + assert segment["status"] == SpanStatus.ERROR + assert segment["attributes"]["sentry.origin"] == "auto.http.pyramid" - assert error_event["exception"]["values"][-1]["type"] == "ZeroDivisionError" - assert error_event["exception"]["values"][-1]["mechanism"]["type"] == "pyramid" + assert error_event["exception"]["values"][-1]["type"] == "ZeroDivisionError" + assert error_event["exception"]["values"][-1]["mechanism"]["type"] == "pyramid" -@pytest.mark.parametrize("span_streaming", [True, False]) def test_span_origin( sentry_init, pyramid_config, - capture_events, capture_items, get_client, - span_streaming, ): sentry_init( integrations=[PyramidIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("event", "span") - else: - events = capture_events() + items = capture_items("event", "span") client = get_client() client.get("/message") - if span_streaming: - sentry_sdk.flush() - spans = [i.payload for i in items if i.type == "span"] - assert len(spans) == 1 - (segment,) = spans - assert segment["attributes"]["sentry.origin"] == "auto.http.pyramid" - else: - (_, event) = events - assert event["contexts"]["trace"]["origin"] == "auto.http.pyramid" + sentry_sdk.flush() + + spans = [i.payload for i in items if i.type == "span"] + assert len(spans) == 1 + (segment,) = spans + assert segment["attributes"]["sentry.origin"] == "auto.http.pyramid" @pytest.mark.parametrize("init_kwargs, expect_user", DATA_COLLECTION_USER_INFO_CASES) @@ -595,7 +543,6 @@ def test_span_sets_user_id_on_segment( sentry_init( integrations=[PyramidIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", **init_kwargs, ) @@ -736,33 +683,6 @@ def index(request): assert "data" not in event.get("_meta", {}).get("request", {}) -def test_transaction_request_body_data_collection( - sentry_init, capture_events, route, get_client -): - sentry_init( - integrations=[PyramidIntegration()], - traces_sample_rate=1.0, - data_collection={"http_bodies": []}, - ) - - data = {"username": "sentry-user", "age": "26"} - - @route("/") - def index(request): - capture_message("hi") - return Response("ok") - - events = capture_events() - - client = get_client() - response = client.post("/", content_type="application/json", data=json.dumps(data)) - assert response[1] == "200 OK" - - event, transaction_event = events - assert "data" not in event["request"] - assert "data" not in transaction_event["request"] - - def test_oversized_request_body_not_annotated_data_collection( sentry_init, capture_events, route, get_client ): diff --git a/tests/integrations/pyreqwest/test_pyreqwest.py b/tests/integrations/pyreqwest/test_pyreqwest.py index 9c70aa9896..44255df8ea 100644 --- a/tests/integrations/pyreqwest/test_pyreqwest.py +++ b/tests/integrations/pyreqwest/test_pyreqwest.py @@ -11,7 +11,7 @@ from pyreqwest.simple.sync_request import pyreqwest_get as sync_pyreqwest_get import sentry_sdk -from sentry_sdk import capture_message, start_transaction +from sentry_sdk import capture_message from sentry_sdk.consts import MATCH_ALL, SPANDATA from sentry_sdk.integrations.pyreqwest import PyreqwestIntegration from tests.conftest import ApproxDict, get_free_port @@ -60,406 +60,256 @@ def clear_captured_requests(): @pytest.mark.parametrize("send_default_pii", [True, False]) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_sync_client_spans( sentry_init, - capture_events, capture_items, server_port, - span_streaming, send_default_pii, ): sentry_init( integrations=[PyreqwestIntegration()], traces_sample_rate=1.0, send_default_pii=send_default_pii, - trace_lifecycle="stream" if span_streaming else "static", ) url = f"http://localhost:{server_port}/hello?q=test#frag" - if span_streaming: - items = capture_items("span") - - with sentry_sdk.traces.start_span(name="custom parent"): - client = SyncClientBuilder().build() - response = client.get(url).build().send() - assert response.status == 200 + items = capture_items("span") - sentry_sdk.flush() - spans = [item.payload for item in items] - assert len(spans) == 2 - span = spans[0] - assert span["attributes"]["sentry.op"] == "http.client" - assert span["name"] == f"GET http://localhost:{server_port}/hello" - assert span["attributes"][SPANDATA.HTTP_REQUEST_METHOD] == "GET" - assert span["attributes"][SPANDATA.HTTP_STATUS_CODE] == 200 - assert span["attributes"]["sentry.origin"] == "auto.http.pyreqwest" - - if send_default_pii: - assert ( - span["attributes"]["url.full"] - == f"http://localhost:{server_port}/hello?q=test#frag" - ) - assert span["attributes"][SPANDATA.URL_QUERY] == "q=test" - assert span["attributes"][SPANDATA.URL_FRAGMENT] == "frag" - else: - assert "url.full" not in span["attributes"] - assert SPANDATA.URL_QUERY not in span["attributes"] - assert SPANDATA.URL_FRAGMENT not in span["attributes"] - else: - events = capture_events() + with sentry_sdk.start_span(name="custom parent"): + client = SyncClientBuilder().build() + response = client.get(url).build().send() + assert response.status == 200 - with start_transaction(name="test_transaction"): - client = SyncClientBuilder().build() - response = client.get(url).build().send() - assert response.status == 200 + sentry_sdk.flush() + spans = [item.payload for item in items] + assert len(spans) == 2 + span = spans[0] + assert span["attributes"]["sentry.op"] == "http.client" + assert span["name"] == f"GET http://localhost:{server_port}/hello" + assert span["attributes"][SPANDATA.HTTP_REQUEST_METHOD] == "GET" + assert span["attributes"][SPANDATA.HTTP_STATUS_CODE] == 200 + assert span["attributes"]["sentry.origin"] == "auto.http.pyreqwest" - (event,) = events - assert len(event["spans"]) == 1 - span = event["spans"][0] - assert span["op"] == "http.client" - assert span["description"] == f"GET http://localhost:{server_port}/hello" - assert span["data"]["url"] == f"http://localhost:{server_port}/hello" - assert span["data"][SPANDATA.HTTP_METHOD] == "GET" - assert span["data"][SPANDATA.HTTP_STATUS_CODE] == 200 - assert span["data"][SPANDATA.HTTP_QUERY] == "q=test" - assert span["data"][SPANDATA.HTTP_FRAGMENT] == "frag" - assert span["origin"] == "auto.http.pyreqwest" + if send_default_pii: + assert ( + span["attributes"]["url.full"] + == f"http://localhost:{server_port}/hello?q=test#frag" + ) + assert span["attributes"][SPANDATA.URL_QUERY] == "q=test" + assert span["attributes"][SPANDATA.URL_FRAGMENT] == "frag" + else: + assert "url.full" not in span["attributes"] + assert SPANDATA.URL_QUERY not in span["attributes"] + assert SPANDATA.URL_FRAGMENT not in span["attributes"] @pytest.mark.asyncio @pytest.mark.parametrize("send_default_pii", [True, False]) -@pytest.mark.parametrize("span_streaming", [True, False]) async def test_async_client_spans( sentry_init, - capture_events, capture_items, server_port, - span_streaming, send_default_pii, ): sentry_init( integrations=[PyreqwestIntegration()], traces_sample_rate=1.0, send_default_pii=send_default_pii, - trace_lifecycle="stream" if span_streaming else "static", ) url = f"http://localhost:{server_port}/hello" - if span_streaming: - items = capture_items("span") + items = capture_items("span") - async with ClientBuilder().build() as client: - with sentry_sdk.traces.start_span(name="custom parent"): - response = await client.get(url).build().send() - assert response.status == 200 - - sentry_sdk.flush() - spans = [item.payload for item in items] - assert len(spans) == 2 - span = spans[0] - assert span["attributes"]["sentry.op"] == "http.client" - assert span["name"] == f"GET {url}" - assert span["attributes"][SPANDATA.HTTP_REQUEST_METHOD] == "GET" - assert span["attributes"][SPANDATA.HTTP_STATUS_CODE] == 200 - assert span["attributes"]["sentry.origin"] == "auto.http.pyreqwest" - - if send_default_pii: - assert span["attributes"]["url.full"] == url - else: - assert "url.full" not in span["attributes"] - else: - events = capture_events() + async with ClientBuilder().build() as client: + with sentry_sdk.start_span(name="custom parent"): + response = await client.get(url).build().send() + assert response.status == 200 - async with ClientBuilder().build() as client: - with start_transaction(name="test_transaction"): - response = await client.get(url).build().send() - assert response.status == 200 + sentry_sdk.flush() + spans = [item.payload for item in items] + assert len(spans) == 2 + span = spans[0] + assert span["attributes"]["sentry.op"] == "http.client" + assert span["name"] == f"GET {url}" + assert span["attributes"][SPANDATA.HTTP_REQUEST_METHOD] == "GET" + assert span["attributes"][SPANDATA.HTTP_STATUS_CODE] == 200 + assert span["attributes"]["sentry.origin"] == "auto.http.pyreqwest" - (event,) = events - assert len(event["spans"]) == 1 - span = event["spans"][0] - assert span["op"] == "http.client" - assert span["description"] == f"GET {url}" - assert span["data"]["url"] == url - assert span["data"][SPANDATA.HTTP_METHOD] == "GET" - assert span["data"][SPANDATA.HTTP_STATUS_CODE] == 200 - assert span["origin"] == "auto.http.pyreqwest" + if send_default_pii: + assert span["attributes"]["url.full"] == url + else: + assert "url.full" not in span["attributes"] @pytest.mark.parametrize("send_default_pii", [True, False]) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_sync_simple_request_spans( sentry_init, - capture_events, capture_items, server_port, - span_streaming, send_default_pii, ): sentry_init( integrations=[PyreqwestIntegration()], traces_sample_rate=1.0, send_default_pii=send_default_pii, - trace_lifecycle="stream" if span_streaming else "static", ) url = f"http://localhost:{server_port}/hello-simple" - if span_streaming: - items = capture_items("span") - - with sentry_sdk.traces.start_span(name="custom parent"): - response = sync_pyreqwest_get(url).send() - assert response.status == 200 + items = capture_items("span") - sentry_sdk.flush() - spans = [item.payload for item in items] - assert len(spans) == 2 - span = spans[0] - assert span["attributes"]["sentry.op"] == "http.client" - assert span["name"] == f"GET {url}" - assert span["attributes"][SPANDATA.HTTP_REQUEST_METHOD] == "GET" - assert span["attributes"][SPANDATA.HTTP_STATUS_CODE] == 200 - assert span["attributes"]["sentry.origin"] == "auto.http.pyreqwest" - - if send_default_pii: - assert span["attributes"]["url.full"] == url - else: - assert "url.full" not in span["attributes"] - else: - events = capture_events() + with sentry_sdk.start_span(name="custom parent"): + response = sync_pyreqwest_get(url).send() + assert response.status == 200 - with start_transaction(name="test_transaction"): - response = sync_pyreqwest_get(url).send() - assert response.status == 200 + sentry_sdk.flush() + spans = [item.payload for item in items] + assert len(spans) == 2 + span = spans[0] + assert span["attributes"]["sentry.op"] == "http.client" + assert span["name"] == f"GET {url}" + assert span["attributes"][SPANDATA.HTTP_REQUEST_METHOD] == "GET" + assert span["attributes"][SPANDATA.HTTP_STATUS_CODE] == 200 + assert span["attributes"]["sentry.origin"] == "auto.http.pyreqwest" - (event,) = events - assert len(event["spans"]) == 1 - span = event["spans"][0] - assert span["op"] == "http.client" - assert span["description"] == f"GET {url}" - assert span["data"]["url"] == url - assert span["data"][SPANDATA.HTTP_METHOD] == "GET" - assert span["data"][SPANDATA.HTTP_STATUS_CODE] == 200 - assert span["origin"] == "auto.http.pyreqwest" + if send_default_pii: + assert span["attributes"]["url.full"] == url + else: + assert "url.full" not in span["attributes"] @pytest.mark.asyncio @pytest.mark.parametrize("send_default_pii", [True, False]) -@pytest.mark.parametrize("span_streaming", [True, False]) async def test_async_simple_request_spans( sentry_init, - capture_events, capture_items, server_port, - span_streaming, send_default_pii, ): sentry_init( integrations=[PyreqwestIntegration()], traces_sample_rate=1.0, send_default_pii=send_default_pii, - trace_lifecycle="stream" if span_streaming else "static", ) url = f"http://localhost:{server_port}/hello-simple-async" - if span_streaming: - items = capture_items("span") - - with sentry_sdk.traces.start_span(name="custom parent"): - response = await async_pyreqwest_get(url).send() - assert response.status == 200 + items = capture_items("span") - sentry_sdk.flush() - spans = [item.payload for item in items] - assert len(spans) == 2 - span = spans[0] - assert span["attributes"]["sentry.op"] == "http.client" - assert span["name"] == f"GET {url}" - assert span["attributes"][SPANDATA.HTTP_REQUEST_METHOD] == "GET" - assert span["attributes"][SPANDATA.HTTP_STATUS_CODE] == 200 - assert span["attributes"]["sentry.origin"] == "auto.http.pyreqwest" - - if send_default_pii: - assert span["attributes"]["url.full"] == url - else: - assert "url.full" not in span["attributes"] - else: - events = capture_events() + with sentry_sdk.start_span(name="custom parent"): + response = await async_pyreqwest_get(url).send() + assert response.status == 200 - with start_transaction(name="test_transaction"): - response = await async_pyreqwest_get(url).send() - assert response.status == 200 + sentry_sdk.flush() + spans = [item.payload for item in items] + assert len(spans) == 2 + span = spans[0] + assert span["attributes"]["sentry.op"] == "http.client" + assert span["name"] == f"GET {url}" + assert span["attributes"][SPANDATA.HTTP_REQUEST_METHOD] == "GET" + assert span["attributes"][SPANDATA.HTTP_STATUS_CODE] == 200 + assert span["attributes"]["sentry.origin"] == "auto.http.pyreqwest" - (event,) = events - assert len(event["spans"]) == 1 - span = event["spans"][0] - assert span["op"] == "http.client" - assert span["description"] == f"GET {url}" - assert span["data"]["url"] == url - assert span["data"][SPANDATA.HTTP_METHOD] == "GET" - assert span["data"][SPANDATA.HTTP_STATUS_CODE] == 200 - assert span["origin"] == "auto.http.pyreqwest" + if send_default_pii: + assert span["attributes"]["url.full"] == url + else: + assert "url.full" not in span["attributes"] -@pytest.mark.parametrize("span_streaming", [True, False]) def test_span_origin( sentry_init, - capture_events, capture_items, server_port, - span_streaming, ): sentry_init( integrations=[PyreqwestIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) url = f"http://localhost:{server_port}/origin" - if span_streaming: - items = capture_items("span") - - with sentry_sdk.traces.start_span(name="custom parent"): - client = SyncClientBuilder().build() - client.get(url).build().send() - - sentry_sdk.flush() - spans = [item.payload for item in items] - assert spans[0]["attributes"]["sentry.origin"] == "auto.http.pyreqwest" - else: - events = capture_events() + items = capture_items("span") - with start_transaction(name="test_transaction"): - client = SyncClientBuilder().build() - client.get(url).build().send() + with sentry_sdk.start_span(name="custom parent"): + client = SyncClientBuilder().build() + client.get(url).build().send() - (event,) = events - assert event["spans"][0]["origin"] == "auto.http.pyreqwest" + sentry_sdk.flush() + spans = [item.payload for item in items] + assert spans[0]["attributes"]["sentry.origin"] == "auto.http.pyreqwest" -@pytest.mark.parametrize("span_streaming", [True, False]) def test_outgoing_trace_headers( sentry_init, server_port, capture_items, - span_streaming, ): sentry_init( integrations=[PyreqwestIntegration()], traces_sample_rate=1.0, trace_propagation_targets=["localhost"], - trace_lifecycle="stream" if span_streaming else "static", ) url = f"http://localhost:{server_port}/trace" - if span_streaming: - items = capture_items("span") - - with sentry_sdk.traces.start_span( - name="custom parent", - ): - client = SyncClientBuilder().build() - response = client.get(url).build().send() - assert response.status == 200 - - assert len(PyreqwestMockHandler.captured_requests) == 1 - headers = PyreqwestMockHandler.captured_requests[0]["headers"] + items = capture_items("span") - sentry_sdk.flush() - spans = [item.payload for item in items] - http_span = next( - span - for span in spans - if span["attributes"].get("sentry.op") == "http.client" - ) + with sentry_sdk.start_span( + name="custom parent", + ): + client = SyncClientBuilder().build() + response = client.get(url).build().send() + assert response.status == 200 - assert "sentry-trace" in headers - assert headers["sentry-trace"].startswith(http_span["trace_id"]) - assert "baggage" in headers - assert f"sentry-trace_id={http_span['trace_id']}" in headers["baggage"] - else: - with start_transaction( - name="test_transaction", trace_id="01234567890123456789012345678901" - ): - client = SyncClientBuilder().build() - response = client.get(url).build().send() - assert response.status == 200 + assert len(PyreqwestMockHandler.captured_requests) == 1 + headers = PyreqwestMockHandler.captured_requests[0]["headers"] - assert len(PyreqwestMockHandler.captured_requests) == 1 - headers = PyreqwestMockHandler.captured_requests[0]["headers"] + sentry_sdk.flush() + spans = [item.payload for item in items] + http_span = next( + span for span in spans if span["attributes"].get("sentry.op") == "http.client" + ) - assert "sentry-trace" in headers - assert headers["sentry-trace"].startswith("01234567890123456789012345678901") - assert "baggage" in headers - assert "sentry-trace_id=01234567890123456789012345678901" in headers["baggage"] + assert "sentry-trace" in headers + assert headers["sentry-trace"].startswith(http_span["trace_id"]) + assert "baggage" in headers + assert f"sentry-trace_id={http_span['trace_id']}" in headers["baggage"] -@pytest.mark.parametrize("span_streaming", [True, False]) def test_outgoing_trace_headers_append_to_baggage( sentry_init, server_port, capture_items, - span_streaming, ): sentry_init( integrations=[PyreqwestIntegration()], traces_sample_rate=1.0, trace_propagation_targets=["localhost"], release="d08ebdb9309e1b004c6f52202de58a09c2268e42", - trace_lifecycle="stream" if span_streaming else "static", ) url = f"http://localhost:{server_port}/baggage" - if span_streaming: - items = capture_items("span") + items = capture_items("span") - with mock.patch( - "sentry_sdk.tracing_utils.Random.randrange", return_value=500000 + with mock.patch("sentry_sdk.tracing_utils.Random.randrange", return_value=500000): + with sentry_sdk.start_span( + name="/interactions/other-dogs/new-dog", + attributes={ + "sentry.op": "greeting.sniff", + }, ): - with sentry_sdk.traces.start_span( - name="/interactions/other-dogs/new-dog", - attributes={ - "sentry.op": "greeting.sniff", - }, - ): - client = SyncClientBuilder().build() - client.get(url).header("baggage", "custom=data").build().send() - - assert len(PyreqwestMockHandler.captured_requests) == 1 - headers = PyreqwestMockHandler.captured_requests[0]["headers"] - - sentry_sdk.flush() - spans = [item.payload for item in items] - http_span = next( - span - for span in spans - if span["attributes"].get("sentry.op") == "http.client" - ) + client = SyncClientBuilder().build() + client.get(url).header("baggage", "custom=data").build().send() - assert "baggage" in headers - baggage = headers["baggage"] - assert "custom=data" in baggage - assert f"sentry-trace_id={http_span['trace_id']}" in baggage - else: - with mock.patch( - "sentry_sdk.tracing_utils.Random.randrange", return_value=500000 - ): - with start_transaction( - name="/interactions/other-dogs/new-dog", - op="greeting.sniff", - trace_id="01234567890123456789012345678901", - ): - client = SyncClientBuilder().build() - client.get(url).header("baggage", "custom=data").build().send() - - assert len(PyreqwestMockHandler.captured_requests) == 1 - headers = PyreqwestMockHandler.captured_requests[0]["headers"] - - assert "baggage" in headers - baggage = headers["baggage"] - assert "custom=data" in baggage - assert "sentry-trace_id=01234567890123456789012345678901" in baggage + assert len(PyreqwestMockHandler.captured_requests) == 1 + headers = PyreqwestMockHandler.captured_requests[0]["headers"] + + sentry_sdk.flush() + spans = [item.payload for item in items] + http_span = next( + span for span in spans if span["attributes"].get("sentry.op") == "http.client" + ) + + assert "baggage" in headers + baggage = headers["baggage"] + assert "custom=data" in baggage + assert f"sentry-trace_id={http_span['trace_id']}" in baggage assert "sentry-sample_rand=0.500000" in baggage assert "sentry-environment=production" in baggage assert "sentry-release=d08ebdb9309e1b004c6f52202de58a09c2268e42" in baggage @@ -478,26 +328,22 @@ def test_outgoing_trace_headers_append_to_baggage( [[r"https?:\/\/[\w\-]+(\.[\w\-]+)+\.net"], False], ], ) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_trace_propagation_targets( sentry_init, server_port, trace_propagation_targets, trace_propagated, - span_streaming, ): sentry_init( integrations=[PyreqwestIntegration()], trace_propagation_targets=trace_propagation_targets, traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) url = f"http://localhost:{server_port}/propagation" - with start_transaction(): - client = SyncClientBuilder().build() - client.get(url).build().send() + client = SyncClientBuilder().build() + client.get(url).build().send() assert len(PyreqwestMockHandler.captured_requests) == 1 headers = PyreqwestMockHandler.captured_requests[0]["headers"] @@ -509,128 +355,80 @@ def test_trace_propagation_targets( @pytest.mark.tests_internal_exceptions -@pytest.mark.parametrize("span_streaming", [True, False]) def test_omit_url_data_if_parsing_fails( sentry_init, - capture_events, capture_items, server_port, - span_streaming, ): sentry_init( integrations=[PyreqwestIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) url = f"http://localhost:{server_port}/parse-fail" - if span_streaming: - items = capture_items("span") - - with sentry_sdk.traces.start_span(name="custom parent"): - with mock.patch( - "sentry_sdk.integrations.pyreqwest.parse_url", - side_effect=ValueError, - ): - client = SyncClientBuilder().build() - client.get(url).build().send() - - sentry_sdk.flush() - spans = [item.payload for item in items] - span = spans[0] - - assert span["name"] == "GET [Filtered]" - assert span["attributes"][SPANDATA.HTTP_REQUEST_METHOD] == "GET" - assert span["attributes"][SPANDATA.HTTP_STATUS_CODE] == 200 - assert "url.full" not in span["attributes"] - assert SPANDATA.URL_QUERY not in span["attributes"] - assert SPANDATA.URL_FRAGMENT not in span["attributes"] - else: - events = capture_events() + items = capture_items("span") - with start_transaction(name="test_transaction"): - with mock.patch( - "sentry_sdk.integrations.pyreqwest.parse_url", - side_effect=ValueError, - ): - client = SyncClientBuilder().build() - client.get(url).build().send() + with sentry_sdk.start_span(name="custom parent"): + with mock.patch( + "sentry_sdk.integrations.pyreqwest.parse_url", + side_effect=ValueError, + ): + client = SyncClientBuilder().build() + client.get(url).build().send() - (event,) = events - span = event["spans"][0] + sentry_sdk.flush() + spans = [item.payload for item in items] + span = spans[0] - assert span["description"] == "GET [Filtered]" - assert span["data"][SPANDATA.HTTP_METHOD] == "GET" - assert span["data"][SPANDATA.HTTP_STATUS_CODE] == 200 - assert "url" not in span["data"] - assert SPANDATA.HTTP_QUERY not in span["data"] - assert SPANDATA.HTTP_FRAGMENT not in span["data"] + assert span["name"] == "GET [Filtered]" + assert span["attributes"][SPANDATA.HTTP_REQUEST_METHOD] == "GET" + assert span["attributes"][SPANDATA.HTTP_STATUS_CODE] == 200 + assert "url.full" not in span["attributes"] + assert SPANDATA.URL_QUERY not in span["attributes"] + assert SPANDATA.URL_FRAGMENT not in span["attributes"] -@pytest.mark.parametrize("span_streaming", [True, False]) def test_request_source_disabled( sentry_init, - capture_events, capture_items, server_port, - span_streaming, ): sentry_init( integrations=[PyreqwestIntegration()], traces_sample_rate=1.0, enable_http_request_source=False, http_request_source_threshold_ms=0, - trace_lifecycle="stream" if span_streaming else "static", ) url = f"http://localhost:{server_port}/hello" - if span_streaming: - items = capture_items("span") - - with sentry_sdk.traces.start_span(name="custom parent"): - client = SyncClientBuilder().build() - client.get(url).build().send() - - sentry_sdk.flush() - spans = [item.payload for item in items] - span = spans[0] - data = span.get("attributes", {}) - - assert SPANDATA.CODE_LINE_NUMBER not in data - assert SPANDATA.CODE_NAMESPACE not in data - assert SPANDATA.CODE_FILE_PATH not in data - else: - events = capture_events() + items = capture_items("span") - with start_transaction(name="test_transaction"): - client = SyncClientBuilder().build() - client.get(url).build().send() + with sentry_sdk.start_span(name="custom parent"): + client = SyncClientBuilder().build() + client.get(url).build().send() - (event,) = events - span = event["spans"][0] - data = span.get("data", {}) + sentry_sdk.flush() + spans = [item.payload for item in items] + span = spans[0] + data = span.get("attributes", {}) - assert SPANDATA.CODE_LINENO not in data - assert SPANDATA.CODE_NAMESPACE not in data - assert SPANDATA.CODE_FILEPATH not in data + assert SPANDATA.CODE_LINE_NUMBER not in data + assert SPANDATA.CODE_NAMESPACE not in data + assert SPANDATA.CODE_FILE_PATH not in data assert SPANDATA.CODE_FUNCTION not in data @pytest.mark.parametrize("enable_http_request_source", [None, True]) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_request_source_enabled( sentry_init, - capture_events, capture_items, server_port, enable_http_request_source, - span_streaming, ): sentry_options = { "integrations": [PyreqwestIntegration()], "traces_sample_rate": 1.0, "http_request_source_threshold_ms": 0, - "trace_lifecycle": "stream" if span_streaming else "static", } if enable_http_request_source is not None: sentry_options["enable_http_request_source"] = enable_http_request_source @@ -638,334 +436,198 @@ def test_request_source_enabled( sentry_init(**sentry_options) url = f"http://localhost:{server_port}/hello" - if span_streaming: - items = capture_items("span") - - with sentry_sdk.traces.start_span(name="custom parent"): - client = SyncClientBuilder().build() - client.get(url).build().send() - - sentry_sdk.flush() - spans = [item.payload for item in items] - span = spans[0] - data = span.get("attributes", {}) - - assert SPANDATA.CODE_LINE_NUMBER in data - assert SPANDATA.CODE_NAMESPACE in data - assert SPANDATA.CODE_FILE_PATH in data - else: - events = capture_events() + items = capture_items("span") - with start_transaction(name="test_transaction"): - client = SyncClientBuilder().build() - client.get(url).build().send() + with sentry_sdk.start_span(name="custom parent"): + client = SyncClientBuilder().build() + client.get(url).build().send() - (event,) = events - span = event["spans"][0] - data = span.get("data", {}) + sentry_sdk.flush() + spans = [item.payload for item in items] + span = spans[0] + data = span.get("attributes", {}) - assert SPANDATA.CODE_LINENO in data - assert SPANDATA.CODE_NAMESPACE in data - assert SPANDATA.CODE_FILEPATH in data + assert SPANDATA.CODE_LINE_NUMBER in data + assert SPANDATA.CODE_NAMESPACE in data + assert SPANDATA.CODE_FILE_PATH in data assert SPANDATA.CODE_FUNCTION in data -@pytest.mark.parametrize("span_streaming", [True, False]) def test_request_source( sentry_init, - capture_events, capture_items, server_port, - span_streaming, ): sentry_init( integrations=[PyreqwestIntegration()], traces_sample_rate=1.0, enable_http_request_source=True, http_request_source_threshold_ms=0, - trace_lifecycle="stream" if span_streaming else "static", ) url = f"http://localhost:{server_port}/hello" - if span_streaming: - items = capture_items("span") - - with sentry_sdk.traces.start_span(name="custom parent"): - client = SyncClientBuilder().build() - client.get(url).build().send() - - sentry_sdk.flush() - spans = [item.payload for item in items] - span = spans[0] - data = span.get("attributes", {}) - - assert type(data.get(SPANDATA.CODE_LINE_NUMBER)) == int - assert data.get(SPANDATA.CODE_LINE_NUMBER) > 0 - assert ( - data.get(SPANDATA.CODE_NAMESPACE) - == "tests.integrations.pyreqwest.test_pyreqwest" - ) - assert data.get(SPANDATA.CODE_FILE_PATH).endswith( - "tests/integrations/pyreqwest/test_pyreqwest.py" - ) - - is_relative_path = data.get(SPANDATA.CODE_FILE_PATH)[0] != os.sep - else: - events = capture_events() - - with start_transaction(name="test_transaction"): - client = SyncClientBuilder().build() - client.get(url).build().send() + items = capture_items("span") - (event,) = events - span = event["spans"][0] - data = span.get("data", {}) + with sentry_sdk.start_span(name="custom parent"): + client = SyncClientBuilder().build() + client.get(url).build().send() - assert type(data.get(SPANDATA.CODE_LINENO)) == int - assert data.get(SPANDATA.CODE_LINENO) > 0 - assert ( - data.get(SPANDATA.CODE_NAMESPACE) - == "tests.integrations.pyreqwest.test_pyreqwest" - ) - assert data.get(SPANDATA.CODE_FILEPATH).endswith( - "tests/integrations/pyreqwest/test_pyreqwest.py" - ) + sentry_sdk.flush() + spans = [item.payload for item in items] + span = spans[0] + data = span.get("attributes", {}) + + assert type(data.get(SPANDATA.CODE_LINE_NUMBER)) == int + assert data.get(SPANDATA.CODE_LINE_NUMBER) > 0 + assert ( + data.get(SPANDATA.CODE_NAMESPACE) + == "tests.integrations.pyreqwest.test_pyreqwest" + ) + assert data.get(SPANDATA.CODE_FILE_PATH).endswith( + "tests/integrations/pyreqwest/test_pyreqwest.py" + ) - is_relative_path = data.get(SPANDATA.CODE_FILEPATH)[0] != os.sep + is_relative_path = data.get(SPANDATA.CODE_FILE_PATH)[0] != os.sep assert is_relative_path assert data.get(SPANDATA.CODE_FUNCTION) == "test_request_source" -@pytest.mark.parametrize("span_streaming", [True, False]) def test_request_source_with_module_in_search_path( sentry_init, - capture_events, capture_items, server_port, - span_streaming, ): sentry_init( integrations=[PyreqwestIntegration()], traces_sample_rate=1.0, enable_http_request_source=True, http_request_source_threshold_ms=0, - trace_lifecycle="stream" if span_streaming else "static", ) url = f"http://localhost:{server_port}/hello" - if span_streaming: - items = capture_items("span") - - with sentry_sdk.traces.start_span(name="custom parent"): - from pyreqwest_helpers.helpers import get_request_with_client - - client = SyncClientBuilder().build() - get_request_with_client(client, url) - - sentry_sdk.flush() - spans = [item.payload for item in items] - span = spans[0] - data = span.get("attributes", {}) - - assert type(data.get(SPANDATA.CODE_LINE_NUMBER)) == int - assert data.get(SPANDATA.CODE_LINE_NUMBER) > 0 - assert data.get(SPANDATA.CODE_NAMESPACE) == "pyreqwest_helpers.helpers" - assert data.get(SPANDATA.CODE_FILE_PATH) == "pyreqwest_helpers/helpers.py" - - is_relative_path = data.get(SPANDATA.CODE_FILE_PATH)[0] != os.sep - else: - events = capture_events() + items = capture_items("span") - with start_transaction(name="test_transaction"): - from pyreqwest_helpers.helpers import get_request_with_client + with sentry_sdk.start_span(name="custom parent"): + from pyreqwest_helpers.helpers import get_request_with_client - client = SyncClientBuilder().build() - get_request_with_client(client, url) + client = SyncClientBuilder().build() + get_request_with_client(client, url) - (event,) = events - span = event["spans"][0] - data = span.get("data", {}) + sentry_sdk.flush() + spans = [item.payload for item in items] + span = spans[0] + data = span.get("attributes", {}) - assert type(data.get(SPANDATA.CODE_LINENO)) == int - assert data.get(SPANDATA.CODE_LINENO) > 0 - assert data.get(SPANDATA.CODE_NAMESPACE) == "pyreqwest_helpers.helpers" - assert data.get(SPANDATA.CODE_FILEPATH) == "pyreqwest_helpers/helpers.py" + assert type(data.get(SPANDATA.CODE_LINE_NUMBER)) == int + assert data.get(SPANDATA.CODE_LINE_NUMBER) > 0 + assert data.get(SPANDATA.CODE_NAMESPACE) == "pyreqwest_helpers.helpers" + assert data.get(SPANDATA.CODE_FILE_PATH) == "pyreqwest_helpers/helpers.py" - is_relative_path = data.get(SPANDATA.CODE_FILEPATH)[0] != os.sep + is_relative_path = data.get(SPANDATA.CODE_FILE_PATH)[0] != os.sep assert is_relative_path assert data.get(SPANDATA.CODE_FUNCTION) == "get_request_with_client" -@pytest.mark.parametrize("span_streaming", [True, False]) def test_no_request_source_if_duration_too_short( sentry_init, - capture_events, capture_items, server_port, - span_streaming, ): sentry_init( integrations=[PyreqwestIntegration()], traces_sample_rate=1.0, enable_http_request_source=True, http_request_source_threshold_ms=100, - trace_lifecycle="stream" if span_streaming else "static", ) url = f"http://localhost:{server_port}/hello" - if span_streaming: - items = capture_items("span") - - with sentry_sdk.traces.start_span(name="custom parent"): - original_start_span = sentry_sdk.traces.start_span - - @contextmanager - def fake_start_span(*args, **kwargs): - with original_start_span(*args, **kwargs) as span: - span._start_timestamp = datetime.datetime(2024, 1, 1, microsecond=0) - span._end_timestamp = datetime.datetime( - 2024, 1, 1, microsecond=99999 - ) - - yield span - - span._end_timestamp = None - - with mock.patch( - "sentry_sdk.integrations.pyreqwest.sentry_sdk.traces.start_span", - fake_start_span, - ): - client = SyncClientBuilder().build() - client.get(url).build().send() - - sentry_sdk.flush() - spans = [item.payload for item in items] - span = spans[0] - data = span.get("attributes", {}) - - assert SPANDATA.CODE_LINE_NUMBER not in data - assert SPANDATA.CODE_NAMESPACE not in data - assert SPANDATA.CODE_FILE_PATH not in data - else: - events = capture_events() + items = capture_items("span") - with start_transaction(name="test_transaction"): + with sentry_sdk.start_span(name="custom parent"): + original_start_span = sentry_sdk.start_span + + @contextmanager + def fake_start_span(*args, **kwargs): + with original_start_span(*args, **kwargs) as span: + span._start_timestamp = datetime.datetime(2024, 1, 1, microsecond=0) + span._end_timestamp = datetime.datetime(2024, 1, 1, microsecond=99999) - @contextmanager - def fake_start_span(*args, **kwargs): - with sentry_sdk.start_span(*args, **kwargs) as span: - pass - span.start_timestamp = datetime.datetime(2024, 1, 1, microsecond=0) - span.timestamp = datetime.datetime(2024, 1, 1, microsecond=99999) yield span - with mock.patch( - "sentry_sdk.integrations.pyreqwest.start_span", - fake_start_span, - ): - client = SyncClientBuilder().build() - client.get(url).build().send() + span._end_timestamp = None + + with mock.patch( + "sentry_sdk.integrations.pyreqwest.sentry_sdk.start_span", + fake_start_span, + ): + client = SyncClientBuilder().build() + client.get(url).build().send() - (event,) = events - span = event["spans"][-1] - data = span.get("data", {}) + sentry_sdk.flush() + spans = [item.payload for item in items] + span = spans[0] + data = span.get("attributes", {}) - assert SPANDATA.CODE_LINENO not in data - assert SPANDATA.CODE_NAMESPACE not in data - assert SPANDATA.CODE_FILEPATH not in data + assert SPANDATA.CODE_LINE_NUMBER not in data + assert SPANDATA.CODE_NAMESPACE not in data + assert SPANDATA.CODE_FILE_PATH not in data assert SPANDATA.CODE_FUNCTION not in data -@pytest.mark.parametrize("span_streaming", [True, False]) def test_request_source_if_duration_over_threshold( sentry_init, - capture_events, capture_items, server_port, - span_streaming, ): sentry_init( integrations=[PyreqwestIntegration()], traces_sample_rate=1.0, enable_http_request_source=True, http_request_source_threshold_ms=100, - trace_lifecycle="stream" if span_streaming else "static", ) url = f"http://localhost:{server_port}/hello" - if span_streaming: - items = capture_items("span") - - with sentry_sdk.traces.start_span(name="custom parent"): - original_start_span = sentry_sdk.traces.start_span - - @contextmanager - def fake_start_span(*args, **kwargs): - with original_start_span(*args, **kwargs) as span: - span._start_timestamp = datetime.datetime(2024, 1, 1, microsecond=0) - span._end_timestamp = datetime.datetime( - 2024, 1, 1, microsecond=100001 - ) - - yield span - - span._end_timestamp = None - - with mock.patch( - "sentry_sdk.integrations.pyreqwest.sentry_sdk.traces.start_span", - fake_start_span, - ): - client = SyncClientBuilder().build() - client.get(url).build().send() - - sentry_sdk.flush() - spans = [item.payload for item in items] - span = spans[0] - data = span.get("attributes", {}) - - assert SPANDATA.CODE_LINE_NUMBER in data - assert SPANDATA.CODE_NAMESPACE in data - assert SPANDATA.CODE_FILE_PATH in data - else: - events = capture_events() + items = capture_items("span") + + with sentry_sdk.start_span(name="custom parent"): + original_start_span = sentry_sdk.start_span - with start_transaction(name="test_transaction"): + @contextmanager + def fake_start_span(*args, **kwargs): + with original_start_span(*args, **kwargs) as span: + span._start_timestamp = datetime.datetime(2024, 1, 1, microsecond=0) + span._end_timestamp = datetime.datetime(2024, 1, 1, microsecond=100001) - @contextmanager - def fake_start_span(*args, **kwargs): - with sentry_sdk.start_span(*args, **kwargs) as span: - pass - span.start_timestamp = datetime.datetime(2024, 1, 1, microsecond=0) - span.timestamp = datetime.datetime(2024, 1, 1, microsecond=100001) yield span - with mock.patch( - "sentry_sdk.integrations.pyreqwest.start_span", - fake_start_span, - ): - client = SyncClientBuilder().build() - client.get(url).build().send() + span._end_timestamp = None - (event,) = events - span = event["spans"][-1] - data = span.get("data", {}) + with mock.patch( + "sentry_sdk.integrations.pyreqwest.sentry_sdk.start_span", + fake_start_span, + ): + client = SyncClientBuilder().build() + client.get(url).build().send() - assert SPANDATA.CODE_LINENO in data - assert SPANDATA.CODE_NAMESPACE in data - assert SPANDATA.CODE_FILEPATH in data + sentry_sdk.flush() + spans = [item.payload for item in items] + span = spans[0] + data = span.get("attributes", {}) + + assert SPANDATA.CODE_LINE_NUMBER in data + assert SPANDATA.CODE_NAMESPACE in data + assert SPANDATA.CODE_FILE_PATH in data assert SPANDATA.CODE_FUNCTION in data @pytest.mark.parametrize("send_default_pii", [True, False]) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_crumb_capture( sentry_init, capture_events, server_port, send_default_pii, - span_streaming, ): def before_breadcrumb(crumb, hint): crumb["data"]["extra"] = "foo" @@ -975,7 +637,6 @@ def before_breadcrumb(crumb, hint): integrations=[PyreqwestIntegration()], before_breadcrumb=before_breadcrumb, send_default_pii=send_default_pii, - trace_lifecycle="stream" if span_streaming else "static", ) url = f"http://localhost:{server_port}/hello?q=test#frag" @@ -1000,11 +661,7 @@ def before_breadcrumb(crumb, hint): "extra": "foo", } if send_default_pii: - expected["url"] = ( - f"http://localhost:{server_port}/hello?q=test#frag" - if span_streaming - else f"http://localhost:{server_port}/hello" - ) + expected["url"] = f"http://localhost:{server_port}/hello?q=test#frag" expected[SPANDATA.HTTP_QUERY] = "q=test" expected[SPANDATA.HTTP_FRAGMENT] = "frag" @@ -1028,56 +685,7 @@ async def test_async_crumb_capture( events = capture_events() - # Ensure the isolation scope contextvar is set before pyreqwest spawns - # its middleware on a separate asyncio Task. Without this, the child task - # lazily creates its own isolation scope, and breadcrumbs added there - # don't propagate back to this task's context. - sentry_sdk.get_isolation_scope() - - with sentry_sdk.start_transaction(): - async with ClientBuilder().build() as client: - response = await client.get(url).build().send() - assert response.status == 200 - - capture_message("Testing!") - - (event,) = events - - crumb = event["breadcrumbs"]["values"][0] - assert crumb["type"] == "http" - assert crumb["category"] == "httplib" - - expected = { - SPANDATA.HTTP_METHOD: "GET", - SPANDATA.HTTP_STATUS_CODE: 200, - } - if send_default_pii: - expected["url"] = f"http://localhost:{server_port}/hello" - expected[SPANDATA.HTTP_QUERY] = "q=test" - expected[SPANDATA.HTTP_FRAGMENT] = "frag" - - assert crumb["data"] == ApproxDict(expected) - - -@pytest.mark.asyncio -@pytest.mark.parametrize("send_default_pii", [True, False]) -async def test_async_crumb_capture_span_streaming( - sentry_init, - capture_events, - server_port, - send_default_pii, -): - sentry_init( - integrations=[PyreqwestIntegration()], - send_default_pii=send_default_pii, - trace_lifecycle="stream", - ) - - url = f"http://localhost:{server_port}/hello?q=test#frag" - - events = capture_events() - - with sentry_sdk.traces.start_span(name="segment"): + with sentry_sdk.start_span(name="segment"): async with ClientBuilder().build() as client: response = await client.get(url).build().send() assert response.status == 200 @@ -1127,58 +735,7 @@ def test_crumb_capture_client_error( events = capture_events() - with sentry_sdk.start_transaction(): - client = SyncClientBuilder().build() - response = client.get(url).build().send() - assert response.status == status_code - - capture_message("Testing!") - - (event,) = events - - crumb = event["breadcrumbs"]["values"][0] - assert crumb["type"] == "http" - assert crumb["category"] == "httplib" - - if level is None: - assert "level" not in crumb - else: - assert crumb["level"] == level - - assert crumb["data"] == ApproxDict( - { - SPANDATA.HTTP_METHOD: "GET", - SPANDATA.HTTP_STATUS_CODE: status_code, - } - ) - - -@pytest.mark.parametrize( - "status_code,level", - [ - (200, None), - (301, None), - (403, "warning"), - (405, "warning"), - (500, "error"), - ], -) -def test_crumb_capture_client_error_span_streaming( - sentry_init, - capture_events, - server_port, - status_code, - level, -): - sentry_init( - integrations=[PyreqwestIntegration()], - ) - - url = f"http://localhost:{server_port}/status/{status_code}" - - events = capture_events() - - with sentry_sdk.traces.start_span(name="segment"): + with sentry_sdk.start_span(name="segment"): client = SyncClientBuilder().build() response = client.get(url).build().send() assert response.status == status_code @@ -1269,7 +826,7 @@ def test_crumb_capture_client_error_span_streaming( ), ], ) -def test_url_query_data_collection_span_streaming_sync( +def test_url_query_data_collection_sync( sentry_init, capture_items, server_port, @@ -1279,7 +836,6 @@ def test_url_query_data_collection_span_streaming_sync( sentry_init( integrations=[PyreqwestIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", **init_kwargs, ) @@ -1287,7 +843,7 @@ def test_url_query_data_collection_span_streaming_sync( url = f"http://localhost:{server_port}/hello?toy=tennisball&color=red&auth=secret#frag" - with sentry_sdk.traces.start_span(name="custom parent"): + with sentry_sdk.start_span(name="custom parent"): client = SyncClientBuilder().build() response = client.get(url).build().send() assert response.status == 200 @@ -1368,7 +924,7 @@ def test_url_query_data_collection_span_streaming_sync( ), ], ) -async def test_url_query_data_collection_span_streaming_async( +async def test_url_query_data_collection_async( sentry_init, capture_items, server_port, @@ -1378,7 +934,6 @@ async def test_url_query_data_collection_span_streaming_async( sentry_init( integrations=[PyreqwestIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", **init_kwargs, ) @@ -1387,7 +942,7 @@ async def test_url_query_data_collection_span_streaming_async( url = f"http://localhost:{server_port}/hello?toy=tennisball&color=red&auth=secret#frag" async with ClientBuilder().build() as client: - with sentry_sdk.traces.start_span(name="custom parent"): + with sentry_sdk.start_span(name="custom parent"): response = await client.get(url).build().send() assert response.status == 200 @@ -1425,7 +980,7 @@ async def test_url_query_data_collection_span_streaming_async( ), ], ) -def test_url_full_reassembly_span_streaming_sync( +def test_url_full_reassembly_sync( sentry_init, capture_items, server_port, @@ -1435,7 +990,6 @@ def test_url_full_reassembly_span_streaming_sync( sentry_init( integrations=[PyreqwestIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", **init_kwargs, ) @@ -1444,7 +998,7 @@ def test_url_full_reassembly_span_streaming_sync( base_url = f"http://localhost:{server_port}/hello" url = f"{base_url}?toy=tennisball&color=red&auth=secret#frag" - with sentry_sdk.traces.start_span(name="custom parent"): + with sentry_sdk.start_span(name="custom parent"): client = SyncClientBuilder().build() response = client.get(url).build().send() assert response.status == 200 @@ -1481,7 +1035,7 @@ def test_url_full_reassembly_span_streaming_sync( ), ], ) -async def test_url_full_reassembly_span_streaming_async( +async def test_url_full_reassembly_async( sentry_init, capture_items, server_port, @@ -1491,7 +1045,6 @@ async def test_url_full_reassembly_span_streaming_async( sentry_init( integrations=[PyreqwestIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", **init_kwargs, ) @@ -1501,7 +1054,7 @@ async def test_url_full_reassembly_span_streaming_async( url = f"{base_url}?toy=tennisball&color=red&auth=secret#frag" async with ClientBuilder().build() as client: - with sentry_sdk.traces.start_span(name="custom parent"): + with sentry_sdk.start_span(name="custom parent"): response = await client.get(url).build().send() assert response.status == 200 @@ -1535,7 +1088,7 @@ async def test_url_full_reassembly_span_streaming_async( ), ], ) -def test_url_query_params_off_keeps_bare_url_span_streaming_sync( +def test_url_query_params_off_keeps_bare_url_sync( sentry_init, capture_items, server_port, @@ -1545,7 +1098,6 @@ def test_url_query_params_off_keeps_bare_url_span_streaming_sync( sentry_init( integrations=[PyreqwestIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", **init_kwargs, ) @@ -1554,7 +1106,7 @@ def test_url_query_params_off_keeps_bare_url_span_streaming_sync( base_url = f"http://localhost:{server_port}/hello" url = f"{base_url}?toy=tennisball&color=red&auth=secret#frag" - with sentry_sdk.traces.start_span(name="custom parent"): + with sentry_sdk.start_span(name="custom parent"): client = SyncClientBuilder().build() response = client.get(url).build().send() assert response.status == 200 @@ -1597,7 +1149,7 @@ def test_url_query_params_off_keeps_bare_url_span_streaming_sync( ), ], ) -async def test_url_query_params_off_keeps_bare_url_span_streaming_async( +async def test_url_query_params_off_keeps_bare_url_async( sentry_init, capture_items, server_port, @@ -1607,7 +1159,6 @@ async def test_url_query_params_off_keeps_bare_url_span_streaming_async( sentry_init( integrations=[PyreqwestIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", **init_kwargs, ) @@ -1617,7 +1168,7 @@ async def test_url_query_params_off_keeps_bare_url_span_streaming_async( url = f"{base_url}?toy=tennisball&color=red&auth=secret#frag" async with ClientBuilder().build() as client: - with sentry_sdk.traces.start_span(name="custom parent"): + with sentry_sdk.start_span(name="custom parent"): response = await client.get(url).build().send() assert response.status == 200 @@ -1668,7 +1219,6 @@ def test_crumb_url_query_data_collection_sync( ): sentry_init( integrations=[PyreqwestIntegration()], - trace_lifecycle="stream", **init_kwargs, ) @@ -1677,7 +1227,7 @@ def test_crumb_url_query_data_collection_sync( events = capture_events() - with sentry_sdk.traces.start_span(name="segment"): + with sentry_sdk.start_span(name="segment"): client = SyncClientBuilder().build() response = client.get(url).build().send() assert response.status == 200 @@ -1732,7 +1282,6 @@ async def test_crumb_url_query_data_collection_async( ): sentry_init( integrations=[PyreqwestIntegration()], - trace_lifecycle="stream", **init_kwargs, ) @@ -1741,7 +1290,7 @@ async def test_crumb_url_query_data_collection_async( events = capture_events() - with sentry_sdk.traces.start_span(name="segment"): + with sentry_sdk.start_span(name="segment"): async with ClientBuilder().build() as client: response = await client.get(url).build().send() assert response.status == 200 @@ -1762,130 +1311,8 @@ async def test_crumb_url_query_data_collection_async( assert crumb["data"][SPANDATA.HTTP_FRAGMENT] == "frag" -@pytest.mark.parametrize( - "init_kwargs, expected_query", - [ - pytest.param( - {"data_collection": {}}, - "toy=tennisball&color=red&auth=%5BFiltered%5D", - id="data_collection_denylist_default", - ), - pytest.param( - { - "data_collection": { - "url_query_params": {"mode": "allowlist", "terms": ["toy"]} - } - }, - "toy=tennisball&color=%5BFiltered%5D&auth=%5BFiltered%5D", - id="data_collection_allowlist", - ), - pytest.param( - {"data_collection": {"url_query_params": {"mode": "off"}}}, - "", - id="data_collection_off", - ), - ], -) -def test_crumb_url_query_data_collection_legacy_sync( - sentry_init, - capture_events, - server_port, - init_kwargs, - expected_query, -): - """ - Legacy (non span streaming) breadcrumbs report the bare URL, but the query - is still filtered according to the data collection configuration. Remove - when we've dropped transaction support and have fully migrated to span - streaming. - """ - sentry_init(integrations=[PyreqwestIntegration()], **init_kwargs) - - base_url = f"http://localhost:{server_port}/hello" - url = f"{base_url}?toy=tennisball&color=red&auth=secret#frag" - - events = capture_events() - - client = SyncClientBuilder().build() - response = client.get(url).build().send() - assert response.status == 200 - - capture_message("Testing!") - - (event,) = events - - crumb = event["breadcrumbs"]["values"][0] - - assert crumb["data"]["url"] == base_url - assert crumb["data"][SPANDATA.HTTP_QUERY] == expected_query - assert crumb["data"][SPANDATA.HTTP_FRAGMENT] == "frag" - - -@pytest.mark.asyncio -@pytest.mark.parametrize( - "init_kwargs, expected_query", - [ - pytest.param( - {"data_collection": {}}, - "toy=tennisball&color=red&auth=%5BFiltered%5D", - id="data_collection_denylist_default", - ), - pytest.param( - { - "data_collection": { - "url_query_params": {"mode": "allowlist", "terms": ["toy"]} - } - }, - "toy=tennisball&color=%5BFiltered%5D&auth=%5BFiltered%5D", - id="data_collection_allowlist", - ), - pytest.param( - {"data_collection": {"url_query_params": {"mode": "off"}}}, - "", - id="data_collection_off", - ), - ], -) -async def test_crumb_url_query_data_collection_legacy_async( - sentry_init, - capture_events, - server_port, - init_kwargs, - expected_query, -): - """ - Legacy (non span streaming) breadcrumbs report the bare URL, but the query - is still filtered according to the data collection configuration. Remove - when we've dropped transaction support and have fully migrated to span - streaming. - """ - sentry_init(integrations=[PyreqwestIntegration()], **init_kwargs) - - base_url = f"http://localhost:{server_port}/hello" - url = f"{base_url}?toy=tennisball&color=red&auth=secret#frag" - - events = capture_events() - - sentry_sdk.get_isolation_scope() - - with sentry_sdk.start_transaction(): - async with ClientBuilder().build() as client: - response = await client.get(url).build().send() - assert response.status == 200 - - capture_message("Testing!") - - event = next(e for e in events if e.get("breadcrumbs")) - - crumb = event["breadcrumbs"]["values"][0] - - assert crumb["data"]["url"] == base_url - assert crumb["data"][SPANDATA.HTTP_QUERY] == expected_query - assert crumb["data"][SPANDATA.HTTP_FRAGMENT] == "frag" - - @pytest.mark.tests_internal_exceptions -def test_omit_url_data_if_parsing_fails_span_streaming( +def test_omit_url_data_if_parsing_fails_data_collection( sentry_init, capture_events, capture_items, @@ -1894,7 +1321,6 @@ def test_omit_url_data_if_parsing_fails_span_streaming( sentry_init( integrations=[PyreqwestIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", data_collection={}, ) @@ -1904,7 +1330,7 @@ def test_omit_url_data_if_parsing_fails_span_streaming( events = capture_events() - with sentry_sdk.traces.start_span(name="segment"): + with sentry_sdk.start_span(name="segment"): with mock.patch( "sentry_sdk.integrations.pyreqwest.parse_url", side_effect=ValueError, diff --git a/tests/integrations/quart/test_quart.py b/tests/integrations/quart/test_quart.py index d8e2a58f8e..e2653b25d3 100644 --- a/tests/integrations/quart/test_quart.py +++ b/tests/integrations/quart/test_quart.py @@ -1,8 +1,6 @@ import importlib -import json import sys import threading -from unittest import mock import pytest @@ -143,40 +141,6 @@ async def test_has_context(sentry_init, capture_events): assert event["request"]["url"] == "http://localhost/message" -@pytest.mark.asyncio -@pytest.mark.parametrize( - "url,transaction_style,expected_transaction,expected_source", - [ - ("/message", "endpoint", "hi", "component"), - ("/message", "url", "/message", "route"), - ("/message/123456", "endpoint", "hi_with_id", "component"), - ("/message/123456", "url", "/message/", "route"), - ], -) -async def test_transaction_style( - sentry_init, - capture_events, - url, - transaction_style, - expected_transaction, - expected_source, -): - sentry_init( - integrations=[ - quart_sentry.QuartIntegration(transaction_style=transaction_style) - ] - ) - app = quart_app_factory() - events = capture_events() - - client = app.test_client() - response = await client.get(url) - assert response.status_code == 200 - - (event,) = events - assert event["transaction"] == expected_transaction - - @pytest.mark.asyncio async def test_http_route( sentry_init, @@ -185,7 +149,6 @@ async def test_http_route( sentry_init( integrations=[quart_sentry.QuartIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", ) app = quart_app_factory() @@ -572,8 +535,11 @@ async def zerodivision(e): @pytest.mark.asyncio -async def test_tracing_success(sentry_init, capture_events): - sentry_init(traces_sample_rate=1.0, integrations=[quart_sentry.QuartIntegration()]) +async def test_tracing_success(sentry_init, capture_items): + sentry_init( + traces_sample_rate=1.0, + integrations=[quart_sentry.QuartIntegration()], + ) app = quart_app_factory() @app.before_request @@ -586,31 +552,33 @@ async def hi_tx(): capture_message("hi") return "ok" - events = capture_events() + items = capture_items("span", "event") async with app.test_client() as client: response = await client.get("/message_tx") assert response.status_code == 200 - message_event, transaction_event = events + sentry_sdk.flush() + + message, span = [item.payload for item in items] - assert transaction_event["type"] == "transaction" - assert transaction_event["transaction"] == "hi_tx" - assert transaction_event["tags"]["view"] == "yes" - assert transaction_event["tags"]["before_request"] == "yes" + assert span["name"] == "hi_tx" - assert message_event["message"] == "hi" - assert message_event["transaction"] == "hi_tx" - assert message_event["tags"]["view"] == "yes" - assert message_event["tags"]["before_request"] == "yes" + assert message["message"] == "hi" + assert message["transaction"] == "hi_tx" + assert message["tags"]["view"] == "yes" + assert message["tags"]["before_request"] == "yes" @pytest.mark.asyncio -async def test_tracing_error(sentry_init, capture_events): - sentry_init(traces_sample_rate=1.0, integrations=[quart_sentry.QuartIntegration()]) +async def test_tracing_error(sentry_init, capture_items): + sentry_init( + traces_sample_rate=1.0, + integrations=[quart_sentry.QuartIntegration()], + ) app = quart_app_factory() - events = capture_events() + items = capture_items("span", "event") @app.route("/error") async def error(): @@ -620,10 +588,11 @@ async def error(): response = await client.get("/error") assert response.status_code == 500 - error_event, transaction_event = events + sentry_sdk.flush() + + error_event, span = [item.payload for item in items] - assert transaction_event["type"] == "transaction" - assert transaction_event["transaction"] == "error" + assert span["name"] == "error" assert error_event["transaction"] == "error" (exception,) = error_event["exception"]["values"] @@ -658,105 +627,30 @@ async def dispatch_request(self): assert event["transaction"] == "hello_class" -@pytest.mark.parametrize("endpoint", ["/sync/thread_ids", "/async/thread_ids"]) -@pytest.mark.asyncio -async def test_active_thread_id( - sentry_init, capture_envelopes, teardown_profiling, endpoint -): - with mock.patch( - "sentry_sdk.profiler.transaction_profiler.PROFILE_MINIMUM_SAMPLES", 0 - ): - sentry_init( - traces_sample_rate=1.0, - profiles_sample_rate=1.0, - ) - app = quart_app_factory() - - envelopes = capture_envelopes() - - async with app.test_client() as client: - response = await client.get(endpoint) - assert response.status_code == 200 - - data = json.loads(await response.get_data(as_text=True)) - - envelopes = [envelope for envelope in envelopes] - assert len(envelopes) == 1 - - profiles = [item for item in envelopes[0].items if item.type == "profile"] - assert len(profiles) == 1, envelopes[0].items - - for item in profiles: - transactions = item.payload.json["transactions"] - assert len(transactions) == 1 - assert str(data["active"]) == transactions[0]["active_thread_id"] - - transactions = [ - item for item in envelopes[0].items if item.type == "transaction" - ] - assert len(transactions) == 1 - - for item in transactions: - transaction = item.payload.json - trace_context = transaction["contexts"]["trace"] - assert str(data["active"]) == trace_context["data"]["thread.id"] - - -@pytest.mark.parametrize("endpoint", ["/sync/thread_ids", "/async/thread_ids"]) @pytest.mark.asyncio -async def test_active_thread_id_span_streaming( - sentry_init, capture_items, teardown_profiling, endpoint -): - with mock.patch( - "sentry_sdk.profiler.transaction_profiler.PROFILE_MINIMUM_SAMPLES", 0 - ): - sentry_init( - traces_sample_rate=1.0, - profiles_sample_rate=1.0, - trace_lifecycle="stream", - ) - app = quart_app_factory() - - items = capture_items("span") - - async with app.test_client() as client: - response = await client.get(endpoint) - assert response.status_code == 200 - - data = json.loads(await response.get_data(as_text=True)) - - sentry_sdk.flush() - - spans = [item.payload for item in items] - assert len(spans) == 1 - - segment = spans[0] - assert str(data["active"]) == segment["attributes"]["thread.id"] - - -@pytest.mark.asyncio -async def test_span_origin(sentry_init, capture_events): +async def test_span_origin(sentry_init, capture_items): sentry_init( integrations=[quart_sentry.QuartIntegration()], traces_sample_rate=1.0, ) app = quart_app_factory() - events = capture_events() + items = capture_items("span") client = app.test_client() await client.get("/message") - (_, event) = events + sentry_sdk.flush() - assert event["contexts"]["trace"]["origin"] == "auto.http.quart" + (span,) = [item.payload for item in items] + + assert span["attributes"]["sentry.origin"] == "auto.http.quart" @pytest.mark.asyncio -async def test_span_streaming_basic(sentry_init, capture_items): +async def test_basic(sentry_init, capture_items): sentry_init( integrations=[quart_sentry.QuartIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", ) items = capture_items("span") @@ -790,7 +684,7 @@ async def test_span_streaming_basic(sentry_init, capture_items): ("/message/123456", "url", "/message/", "route"), ], ) -async def test_span_streaming_transaction_style( +async def test_transaction_style( sentry_init, capture_items, url, @@ -803,7 +697,6 @@ async def test_span_streaming_transaction_style( quart_sentry.QuartIntegration(transaction_style=transaction_style) ], traces_sample_rate=1.0, - trace_lifecycle="stream", ) items = capture_items("span") @@ -824,11 +717,10 @@ async def test_span_streaming_transaction_style( @pytest.mark.asyncio -async def test_span_streaming_with_error(sentry_init, capture_items): +async def test_with_error(sentry_init, capture_items): sentry_init( integrations=[quart_sentry.QuartIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", ) items = capture_items("event", "span") @@ -867,12 +759,11 @@ async def error(): @pytest.mark.asyncio -async def test_span_streaming_request_attributes_no_pii(sentry_init, capture_items): +async def test_request_attributes_no_pii(sentry_init, capture_items): sentry_init( integrations=[quart_sentry.QuartIntegration()], traces_sample_rate=1.0, send_default_pii=False, - trace_lifecycle="stream", ) items = capture_items("span") @@ -898,12 +789,11 @@ async def test_span_streaming_request_attributes_no_pii(sentry_init, capture_ite @pytest.mark.asyncio -async def test_span_streaming_request_attributes_with_pii(sentry_init, capture_items): +async def test_request_attributes_with_pii(sentry_init, capture_items): sentry_init( integrations=[quart_sentry.QuartIntegration()], traces_sample_rate=1.0, send_default_pii=True, - trace_lifecycle="stream", ) items = capture_items("span") @@ -1044,14 +934,13 @@ async def test_span_streaming_request_attributes_with_pii(sentry_init, capture_i ], ) @pytest.mark.asyncio -async def test_span_streaming_sensitive_header_scrubbing( +async def test_sensitive_header_scrubbing( sentry_init, capture_items, options, expected, request ): sentry_init( integrations=[quart_sentry.QuartIntegration()], traces_sample_rate=1.0, send_default_pii=options["send_default_pii"], - trace_lifecycle="stream", data_collection=options["data_collection"], ) items = capture_items("span") @@ -1090,14 +979,11 @@ async def test_span_streaming_sensitive_header_scrubbing( @pytest.mark.asyncio -async def test_span_streaming_sensitive_header_without_data_collection( - sentry_init, capture_items -): +async def test_sensitive_header_without_data_collection(sentry_init, capture_items): sentry_init( integrations=[quart_sentry.QuartIntegration()], traces_sample_rate=1.0, send_default_pii=False, - trace_lifecycle="stream", ) items = capture_items("span") @@ -1128,7 +1014,7 @@ async def test_span_streaming_sensitive_header_without_data_collection( @pytest.mark.asyncio @pytest.mark.parametrize("send_default_pii", [True, False]) @pytest.mark.parametrize("user_id", [None, "42"]) -async def test_span_streaming_quart_auth_user_id( +async def test_quart_auth_user_id( send_default_pii, sentry_init, user_id, @@ -1140,7 +1026,6 @@ async def test_span_streaming_quart_auth_user_id( integrations=[quart_sentry.QuartIntegration()], traces_sample_rate=1.0, send_default_pii=send_default_pii, - trace_lifecycle="stream", ) items = capture_items("span") @@ -1233,7 +1118,7 @@ async def login(): @pytest.mark.asyncio @pytest.mark.parametrize("init_kwargs, expect_user_info", QUART_USER_INFO_CASES) -async def test_span_streaming_quart_auth_user_id_data_collection( +async def test_quart_auth_user_id_data_collection( sentry_init, capture_items, init_kwargs, @@ -1244,7 +1129,6 @@ async def test_span_streaming_quart_auth_user_id_data_collection( sentry_init( integrations=[quart_sentry.QuartIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", **init_kwargs, ) items = capture_items("span") @@ -1276,13 +1160,12 @@ async def login(): @pytest.mark.asyncio @pytest.mark.parametrize("init_kwargs, expect_user_info", QUART_USER_INFO_CASES) -async def test_span_streaming_request_attributes_data_collection( +async def test_request_attributes_data_collection( sentry_init, capture_items, init_kwargs, expect_user_info ): sentry_init( integrations=[quart_sentry.QuartIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", **init_kwargs, ) items = capture_items("span") @@ -1307,14 +1190,13 @@ async def test_span_streaming_request_attributes_data_collection( @pytest.mark.asyncio -async def test_span_streaming_sensitive_header_passthrough_with_pii_and_no_data_collection( +async def test_sensitive_header_passthrough_with_pii_and_no_data_collection( sentry_init, capture_items ): sentry_init( integrations=[quart_sentry.QuartIntegration()], traces_sample_rate=1.0, send_default_pii=True, - trace_lifecycle="stream", ) items = capture_items("span") @@ -1406,13 +1288,12 @@ async def test_span_streaming_sensitive_header_passthrough_with_pii_and_no_data_ @pytest.mark.parametrize( "init_kwargs, expected_query", _QUERY_PARAM_DATA_COLLECTION_CASES ) -async def test_span_streaming_url_query_data_collection( +async def test_url_query_data_collection( sentry_init, capture_items, init_kwargs, expected_query ): sentry_init( integrations=[quart_sentry.QuartIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", **init_kwargs, ) items = capture_items("span") @@ -1450,13 +1331,10 @@ async def test_span_streaming_url_query_data_collection( @pytest.mark.asyncio -async def test_span_streaming_url_query_multi_and_blank_values( - sentry_init, capture_items -): +async def test_url_query_multi_and_blank_values(sentry_init, capture_items): sentry_init( integrations=[quart_sentry.QuartIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", data_collection={}, ) items = capture_items("span") diff --git a/tests/integrations/ray/test_ray.py b/tests/integrations/ray/test_ray.py index aa8b00dc00..a4ce462e97 100644 --- a/tests/integrations/ray/test_ray.py +++ b/tests/integrations/ray/test_ray.py @@ -39,19 +39,13 @@ def setup_sentry_with_logging_transport(): setup_sentry(transport=RayLoggingTransport()) -def setup_sentry_with_logging_transport_and_span_streaming(): - setup_sentry(span_streaming=True, transport=RayLoggingTransport()) - - -def setup_sentry(span_streaming=False, transport=None): - if span_streaming: - sentry_sdk._span_batcher.SpanBatcher.MAX_BEFORE_FLUSH = 1 +def setup_sentry(transport=None): + sentry_sdk._span_batcher.SpanBatcher.MAX_BEFORE_FLUSH = 1 sentry_sdk.init( integrations=[RayIntegration()], transport=RayTestTransport() if transport is None else transport, traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) @@ -141,34 +135,22 @@ def read_spans_from_log(job_id, ray_temp_dir, min_spans=1, timeout=10): time.sleep(0.1) -def example_task(span_streaming: bool): - if span_streaming: - with sentry_sdk.traces.start_span( - name="example task step", - attributes={ - "sentry.op": "task", - }, - ): - ... - else: - with sentry_sdk.start_span(op="task", name="example task step"): - ... - - return sentry_sdk.get_client().transport.envelopes +def example_task(): + with sentry_sdk.start_span( + name="example task step", + attributes={ + "sentry.op": "task", + }, + ): + ... # RayIntegration must leave variadic keyword arguments at the end -def example_task_with_kwargs(span_streaming: bool, **kwargs): - if span_streaming: - with sentry_sdk.traces.start_span( - name="example task step", attributes={"sentry.op": "task"} - ): - ... - else: - with sentry_sdk.start_span(op="task", name="example task step"): - ... - - return sentry_sdk.get_client().transport.envelopes +def example_task_with_kwargs(**kwargs): + with sentry_sdk.start_span( + name="example task step", attributes={"sentry.op": "task"} + ): + ... @pytest.mark.parametrize( @@ -178,14 +160,16 @@ def example_task_with_kwargs(span_streaming: bool, **kwargs): "task", [example_task, example_task_with_kwargs], ) -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_tracing_in_ray_tasks(sentry_init, task_options, task, span_streaming): +def test_tracing_in_ray_tasks( + sentry_init, + task_options, + task, +): sentry_init( integrations=[RayIntegration()], disabled_integrations=[StdlibIntegration], transport=RayTestTransport(), traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) # Setup ray task, calling decorator directly instead of @, @@ -200,121 +184,66 @@ def test_tracing_in_ray_tasks(sentry_init, task_options, task, span_streaming): example_task._function_name == f"tests.integrations.ray.test_ray.{task.__name__}" ) + ray_temp_dir = os.path.join("/tmp", f"ray_test_{uuid.uuid4().hex[:8]}") + os.makedirs(ray_temp_dir, exist_ok=True) - if span_streaming: - ray_temp_dir = os.path.join("/tmp", f"ray_test_{uuid.uuid4().hex[:8]}") - os.makedirs(ray_temp_dir, exist_ok=True) - - try: - ray.init( - runtime_env={ - "worker_process_setup_hook": setup_sentry_with_logging_transport_and_span_streaming, - "working_dir": "./", - }, - _temp_dir=ray_temp_dir, - ) - - with sentry_sdk.traces.start_span( - name="ray test parent", attributes={"sentry.op": "task"} - ): - future = example_task.remote(span_streaming) - ray.get(future) - - job_id = future.job_id().hex() - worker_spans = read_spans_from_log(job_id, ray_temp_dir, min_spans=2) - finally: - if os.path.exists(ray_temp_dir): - shutil.rmtree(ray_temp_dir, ignore_errors=True) - - sentry_sdk.flush() - client_envelope = sentry_sdk.get_client().transport.envelopes[0] - client_spans = [ - span - for item in client_envelope.items - for span in item.payload.json["items"] - ] - assert client_spans[1]["name"] == "ray test parent" - - assert ( - worker_spans[1]["name"] - == f"tests.integrations.ray.test_ray.{task.__name__}" - ) - assert ( - worker_spans[1]["attributes"]["sentry.segment.name.source"]["value"] - == SegmentNameSource.TASK - ) - - span = client_spans[0] - assert span["attributes"]["sentry.op"]["value"] == "queue.submit.ray" - assert span["attributes"]["sentry.origin"]["value"] == "auto.queue.ray" - assert span["name"] == f"tests.integrations.ray.test_ray.{task.__name__}" - assert span["parent_span_id"] == client_spans[1]["span_id"] - assert span["trace_id"] == client_spans[1]["trace_id"] - - span = worker_spans[0] - assert span["attributes"]["sentry.op"]["value"] == "task" - assert span["attributes"]["sentry.origin"]["value"] == "manual" - assert span["name"] == "example task step" - assert span["parent_span_id"] == worker_spans[1]["span_id"] - assert span["trace_id"] == worker_spans[1]["trace_id"] - - assert client_spans[1]["trace_id"] == worker_spans[1]["trace_id"] - else: + try: ray.init( runtime_env={ - "worker_process_setup_hook": setup_sentry, + "worker_process_setup_hook": setup_sentry_with_logging_transport, "working_dir": "./", - } + }, + _temp_dir=ray_temp_dir, ) - with sentry_sdk.start_transaction(op="task", name="ray test transaction"): - worker_envelopes = ray.get(example_task.remote(span_streaming)) + with sentry_sdk.start_span( + name="ray test parent", attributes={"sentry.op": "task"} + ): + future = example_task.remote() + ray.get(future) - client_envelope = sentry_sdk.get_client().transport.envelopes[0] - client_transaction = client_envelope.get_transaction_event() - assert client_transaction["transaction"] == "ray test transaction" - assert client_transaction["transaction_info"] == {"source": "custom"} + job_id = future.job_id().hex() + worker_spans = read_spans_from_log(job_id, ray_temp_dir, min_spans=2) + finally: + if os.path.exists(ray_temp_dir): + shutil.rmtree(ray_temp_dir, ignore_errors=True) - worker_envelope = worker_envelopes[0] - worker_transaction = worker_envelope.get_transaction_event() - assert ( - worker_transaction["transaction"] - == f"tests.integrations.ray.test_ray.{task.__name__}" - ) - assert worker_transaction["transaction_info"] == {"source": "task"} + sentry_sdk.flush() + client_envelope = sentry_sdk.get_client().transport.envelopes[0] + client_spans = [ + span for item in client_envelope.items for span in item.payload.json["items"] + ] + assert client_spans[1]["name"] == "ray test parent" - (span,) = client_transaction["spans"] - assert span["op"] == "queue.submit.ray" - assert span["origin"] == "auto.queue.ray" - assert span["description"] == f"tests.integrations.ray.test_ray.{task.__name__}" - assert ( - span["parent_span_id"] == client_transaction["contexts"]["trace"]["span_id"] - ) - assert span["trace_id"] == client_transaction["contexts"]["trace"]["trace_id"] + assert worker_spans[1]["name"] == f"tests.integrations.ray.test_ray.{task.__name__}" + assert ( + worker_spans[1]["attributes"]["sentry.segment.name.source"]["value"] + == SegmentNameSource.TASK + ) - (span,) = worker_transaction["spans"] - assert span["op"] == "task" - assert span["origin"] == "manual" - assert span["description"] == "example task step" - assert ( - span["parent_span_id"] == worker_transaction["contexts"]["trace"]["span_id"] - ) - assert span["trace_id"] == worker_transaction["contexts"]["trace"]["trace_id"] + span = client_spans[0] + assert span["attributes"]["sentry.op"]["value"] == "queue.submit.ray" + assert span["attributes"]["sentry.origin"]["value"] == "auto.queue.ray" + assert span["name"] == f"tests.integrations.ray.test_ray.{task.__name__}" + assert span["parent_span_id"] == client_spans[1]["span_id"] + assert span["trace_id"] == client_spans[1]["trace_id"] - assert ( - client_transaction["contexts"]["trace"]["trace_id"] - == worker_transaction["contexts"]["trace"]["trace_id"] - ) + span = worker_spans[0] + assert span["attributes"]["sentry.op"]["value"] == "task" + assert span["attributes"]["sentry.origin"]["value"] == "manual" + assert span["name"] == "example task step" + assert span["parent_span_id"] == worker_spans[1]["span_id"] + assert span["trace_id"] == worker_spans[1]["trace_id"] + assert client_spans[1]["trace_id"] == worker_spans[1]["trace_id"] -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_errors_in_ray_tasks(sentry_init, span_streaming): + +def test_errors_in_ray_tasks(sentry_init): sentry_init( integrations=[RayIntegration()], disabled_integrations=[StdlibIntegration], transport=RayTestTransport(), traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) ray_temp_dir = os.path.join("/tmp", f"ray_test_{uuid.uuid4().hex[:8]}") @@ -323,9 +252,7 @@ def test_errors_in_ray_tasks(sentry_init, span_streaming): try: ray.init( runtime_env={ - "worker_process_setup_hook": setup_sentry_with_logging_transport_and_span_streaming - if span_streaming - else setup_sentry_with_logging_transport, + "worker_process_setup_hook": setup_sentry_with_logging_transport, "working_dir": "./", }, _temp_dir=ray_temp_dir, @@ -336,18 +263,12 @@ def test_errors_in_ray_tasks(sentry_init, span_streaming): def example_task(): 1 / 0 - if span_streaming: - with sentry_sdk.traces.start_span( - name="ray test parent", attributes={"sentry.op": "task"} - ): - with pytest.raises(ZeroDivisionError): - future = example_task.remote() - ray.get(future) - else: - with sentry_sdk.start_transaction(op="task", name="ray test transaction"): - with pytest.raises(ZeroDivisionError): - future = example_task.remote() - ray.get(future) + with sentry_sdk.start_span( + name="ray test parent", attributes={"sentry.op": "task"} + ): + with pytest.raises(ZeroDivisionError): + future = example_task.remote() + ray.get(future) job_id = future.job_id().hex() error = read_error_from_log(job_id, ray_temp_dir) @@ -367,14 +288,15 @@ def example_task(): # Arbitrary keyword argument to test all decorator paths @pytest.mark.parametrize("remote_kwargs", [{}, {"namespace": "actors"}]) -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_tracing_in_ray_actors(sentry_init, remote_kwargs, span_streaming): +def test_tracing_in_ray_actors( + sentry_init, + remote_kwargs, +): sentry_init( integrations=[RayIntegration()], disabled_integrations=[StdlibIntegration], transport=RayTestTransport(), traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) # Setup ray actor @@ -386,18 +308,10 @@ def __init__(self): self.n = 0 def increment(self): - if span_streaming: - with sentry_sdk.traces.start_span( - name="example actor execution", attributes={"sentry.op": "task"} - ): - self.n += 1 - else: - with sentry_sdk.start_span( - op="task", name="example actor execution" - ): - self.n += 1 - - return sentry_sdk.get_client().transport.envelopes + with sentry_sdk.start_span( + name="example actor execution", attributes={"sentry.op": "task"} + ): + self.n += 1 else: @ray.remote @@ -406,90 +320,57 @@ def __init__(self): self.n = 0 def increment(self): - if span_streaming: - with sentry_sdk.traces.start_span( - name="example actor execution", attributes={"sentry.op": "task"} - ): - self.n += 1 - else: - with sentry_sdk.start_span( - op="task", name="example actor execution" - ): - self.n += 1 - - return sentry_sdk.get_client().transport.envelopes - - if span_streaming: - ray_temp_dir = os.path.join("/tmp", f"ray_test_{uuid.uuid4().hex[:8]}") - os.makedirs(ray_temp_dir, exist_ok=True) + with sentry_sdk.start_span( + name="example actor execution", attributes={"sentry.op": "task"} + ): + self.n += 1 - try: - ray.init( - runtime_env={ - "worker_process_setup_hook": setup_sentry_with_logging_transport_and_span_streaming, - "working_dir": "./", - }, - _temp_dir=ray_temp_dir, - ) - - with sentry_sdk.traces.start_span( - name="ray test parent", attributes={"sentry.op": "task"} - ): - counter = Counter.remote() - future = counter.increment.remote() - ray.get(future) + ray_temp_dir = os.path.join("/tmp", f"ray_test_{uuid.uuid4().hex[:8]}") + os.makedirs(ray_temp_dir, exist_ok=True) - job_id = future.job_id().hex() - worker_spans = read_spans_from_log(job_id, ray_temp_dir) - finally: - if os.path.exists(ray_temp_dir): - shutil.rmtree(ray_temp_dir, ignore_errors=True) - - sentry_sdk.flush() - client_envelope = sentry_sdk.get_client().transport.envelopes[0] - client_spans = [ - span - for item in client_envelope.items - for span in item.payload.json["items"] - ] - - # Spans for submitting the actor task are not created (actors are not supported yet) - # Only the manual "example actor execution" span is recorded. - assert len(client_spans) == 1 - - # Transaction are not yet created when executing ray actors (actors are not supported yet) - # Only the manual "example actor execution" span is recorded. - assert len(worker_spans) == 1 - else: + try: ray.init( runtime_env={ - "worker_process_setup_hook": setup_sentry, + "worker_process_setup_hook": setup_sentry_with_logging_transport, "working_dir": "./", - } + }, + _temp_dir=ray_temp_dir, ) - with sentry_sdk.start_transaction(op="task", name="ray test transaction"): + with sentry_sdk.start_span( + name="ray test parent", attributes={"sentry.op": "task"} + ): counter = Counter.remote() - worker_envelopes = ray.get(counter.increment.remote()) + future = counter.increment.remote() + ray.get(future) + + job_id = future.job_id().hex() + worker_spans = read_spans_from_log(job_id, ray_temp_dir) + finally: + if os.path.exists(ray_temp_dir): + shutil.rmtree(ray_temp_dir, ignore_errors=True) - client_envelope = sentry_sdk.get_client().transport.envelopes[0] - client_transaction = client_envelope.get_transaction_event() + sentry_sdk.flush() + client_envelope = sentry_sdk.get_client().transport.envelopes[0] + client_spans = [ + span for item in client_envelope.items for span in item.payload.json["items"] + ] - # Spans for submitting the actor task are not created (actors are not supported yet) - assert client_transaction["spans"] == [] + # Spans for submitting the actor task are not created (actors are not supported yet) + # Only the manual "example actor execution" span is recorded. + assert len(client_spans) == 1 - # Transaction are not yet created when executing ray actors (actors are not supported yet) - assert worker_envelopes == [] + # Spans are not yet created when executing ray actors (actors are not supported yet) + # Only the manual "example actor execution" span is recorded. + assert len(worker_spans) == 1 -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_errors_in_ray_actors(sentry_init, span_streaming): +def test_errors_in_ray_actors(sentry_init): sentry_init( integrations=[RayIntegration()], disabled_integrations=[StdlibIntegration], transport=RayLoggingTransport(), traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) ray_temp_dir = os.path.join("/tmp", f"ray_test_{uuid.uuid4().hex[:8]}") @@ -498,9 +379,7 @@ def test_errors_in_ray_actors(sentry_init, span_streaming): try: ray.init( runtime_env={ - "worker_process_setup_hook": setup_sentry_with_logging_transport_and_span_streaming - if span_streaming - else setup_sentry_with_logging_transport, + "worker_process_setup_hook": setup_sentry_with_logging_transport, "working_dir": "./", }, _temp_dir=ray_temp_dir, @@ -513,33 +392,20 @@ def __init__(self): self.n = 0 def increment(self): - if span_streaming: - with sentry_sdk.traces.start_span( - name="example actor execution", attributes={"sentry.op": "task"} - ): - 1 / 0 - else: - with sentry_sdk.start_span( - op="task", name="example actor execution" - ): - 1 / 0 + with sentry_sdk.start_span( + name="example actor execution", attributes={"sentry.op": "task"} + ): + 1 / 0 return sentry_sdk.get_client().transport.envelopes - if span_streaming: - with sentry_sdk.traces.start_span( - name="ray test parent", attributes={"sentry.op": "task"} - ): - with pytest.raises(ZeroDivisionError): - counter = Counter.remote() - future = counter.increment.remote() - ray.get(future) - else: - with sentry_sdk.start_transaction(op="task", name="ray test transaction"): - with pytest.raises(ZeroDivisionError): - counter = Counter.remote() - future = counter.increment.remote() - ray.get(future) + with sentry_sdk.start_span( + name="ray test parent", attributes={"sentry.op": "task"} + ): + with pytest.raises(ZeroDivisionError): + counter = Counter.remote() + future = counter.increment.remote() + ray.get(future) job_id = future.job_id().hex() error = read_error_from_log(job_id, ray_temp_dir) diff --git a/tests/integrations/redis/asyncio/test_redis_asyncio.py b/tests/integrations/redis/asyncio/test_redis_asyncio.py index 4ecdbacaf1..f2a07bc0a4 100644 --- a/tests/integrations/redis/asyncio/test_redis_asyncio.py +++ b/tests/integrations/redis/asyncio/test_redis_asyncio.py @@ -2,10 +2,9 @@ from fakeredis.aioredis import FakeRedis import sentry_sdk -from sentry_sdk import capture_message, start_transaction +from sentry_sdk import capture_message from sentry_sdk.consts import SPANDATA from sentry_sdk.integrations.redis import RedisIntegration -from tests.conftest import ApproxDict @pytest.mark.asyncio @@ -35,7 +34,6 @@ async def test_async_basic(sentry_init, capture_events): } -@pytest.mark.parametrize("span_streaming", [True, False]) @pytest.mark.parametrize( "is_transaction, send_default_pii, expected_first_ten", [ @@ -51,122 +49,67 @@ async def test_async_redis_pipeline( is_transaction, send_default_pii, expected_first_ten, - span_streaming, ): sentry_init( integrations=[RedisIntegration()], traces_sample_rate=1.0, send_default_pii=send_default_pii, - trace_lifecycle="stream" if span_streaming else "static", ) connection = FakeRedis() - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="custom parent"): - pipeline = connection.pipeline(transaction=is_transaction) - pipeline.get("foo") - pipeline.set("bar", 1) - pipeline.set("baz", 2) - await pipeline.execute() - sentry_sdk.flush() - - assert len(items) == 2 - pipeline_span, parent_span = items[0].payload, items[1].payload - - assert parent_span["name"] == "custom parent" - assert pipeline_span["name"] == "redis.pipeline.execute" - attrs = pipeline_span["attributes"] - assert attrs["sentry.op"] == "db.redis" - assert attrs[SPANDATA.DB_SYSTEM_NAME] == "redis" - assert attrs[SPANDATA.DB_DRIVER_NAME] == "redis-py" - assert attrs[SPANDATA.DB_NAMESPACE] == "0" - assert attrs[SPANDATA.SERVER_ADDRESS] == ( - connection.connection_pool.connection_kwargs.get("host") - ) - assert attrs[SPANDATA.SERVER_PORT] == 6379 - else: - events = capture_events() - with start_transaction(): - pipeline = connection.pipeline(transaction=is_transaction) - pipeline.get("foo") - pipeline.set("bar", 1) - pipeline.set("baz", 2) - await pipeline.execute() - - (event,) = events - (span,) = event["spans"] - assert span["op"] == "db.redis" - assert span["description"] == "redis.pipeline.execute" - assert span["data"] == ApproxDict( - { - "redis.commands": { - "count": 3, - "first_ten": expected_first_ten, - }, - SPANDATA.DB_SYSTEM: "redis", - SPANDATA.DB_NAME: "0", - SPANDATA.SERVER_ADDRESS: connection.connection_pool.connection_kwargs.get( - "host" - ), - SPANDATA.SERVER_PORT: 6379, - } - ) - assert span["tags"] == { - "redis.transaction": is_transaction, - "redis.is_cluster": False, - } + items = capture_items("span") + + with sentry_sdk.start_span(name="custom parent"): + pipeline = connection.pipeline(transaction=is_transaction) + pipeline.get("foo") + pipeline.set("bar", 1) + pipeline.set("baz", 2) + await pipeline.execute() + + sentry_sdk.flush() + + assert len(items) == 2 + pipeline_span, parent_span = items[0].payload, items[1].payload + + assert parent_span["name"] == "custom parent" + assert pipeline_span["name"] == "redis.pipeline.execute" + attrs = pipeline_span["attributes"] + assert attrs["sentry.op"] == "db.redis" + assert attrs[SPANDATA.DB_SYSTEM_NAME] == "redis" + assert attrs[SPANDATA.DB_DRIVER_NAME] == "redis-py" + assert attrs[SPANDATA.DB_NAMESPACE] == "0" + assert attrs[SPANDATA.SERVER_ADDRESS] == ( + connection.connection_pool.connection_kwargs.get("host") + ) + assert attrs[SPANDATA.SERVER_PORT] == 6379 -@pytest.mark.parametrize("span_streaming", [True, False]) @pytest.mark.asyncio -async def test_async_span_origin( - sentry_init, capture_events, capture_items, span_streaming -): +async def test_async_span_origin(sentry_init, capture_events, capture_items): sentry_init( integrations=[RedisIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) connection = FakeRedis() - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="custom parent"): - # default case - await connection.set("somekey", "somevalue") - - # pipeline - pipeline = connection.pipeline(transaction=False) - pipeline.get("somekey") - pipeline.set("anotherkey", 1) - await pipeline.execute() - sentry_sdk.flush() - - assert len(items) == 3 - set_span, pipeline_span, parent_span = [item.payload for item in items] - - assert parent_span["name"] == "custom parent" - assert parent_span["attributes"]["sentry.origin"] == "manual" - assert set_span["attributes"]["sentry.origin"] == "auto.db.redis" - assert pipeline_span["attributes"]["sentry.origin"] == "auto.db.redis" - else: - events = capture_events() - with start_transaction(name="custom_transaction"): - # default case - await connection.set("somekey", "somevalue") - - # pipeline - pipeline = connection.pipeline(transaction=False) - pipeline.get("somekey") - pipeline.set("anotherkey", 1) - await pipeline.execute() - - (event,) = events - - assert event["contexts"]["trace"]["origin"] == "manual" - - for span in event["spans"]: - assert span["origin"] == "auto.db.redis" + items = capture_items("span") + with sentry_sdk.start_span(name="custom parent"): + # default case + await connection.set("somekey", "somevalue") + + # pipeline + pipeline = connection.pipeline(transaction=False) + pipeline.get("somekey") + pipeline.set("anotherkey", 1) + await pipeline.execute() + sentry_sdk.flush() + + assert len(items) == 3 + set_span, pipeline_span, parent_span = [item.payload for item in items] + + assert parent_span["name"] == "custom parent" + assert parent_span["attributes"]["sentry.origin"] == "manual" + assert set_span["attributes"]["sentry.origin"] == "auto.db.redis" + assert pipeline_span["attributes"]["sentry.origin"] == "auto.db.redis" diff --git a/tests/integrations/redis/cluster/test_redis_cluster.py b/tests/integrations/redis/cluster/test_redis_cluster.py index 2877081fc8..2f6072f844 100644 --- a/tests/integrations/redis/cluster/test_redis_cluster.py +++ b/tests/integrations/redis/cluster/test_redis_cluster.py @@ -5,10 +5,8 @@ import sentry_sdk from sentry_sdk import capture_message -from sentry_sdk.api import start_transaction from sentry_sdk.consts import SPANDATA from sentry_sdk.integrations.redis import RedisIntegration -from tests.conftest import ApproxDict @pytest.fixture(autouse=True) @@ -58,7 +56,6 @@ def test_rediscluster_breadcrumb(sentry_init, capture_events): } -@pytest.mark.parametrize("span_streaming", [True, False]) @pytest.mark.parametrize( "send_default_pii, description", [ @@ -72,75 +69,42 @@ def test_rediscluster_basic( capture_items, send_default_pii, description, - span_streaming, ): sentry_init( integrations=[RedisIntegration()], traces_sample_rate=1.0, send_default_pii=send_default_pii, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="custom parent"): - rc = redis.RedisCluster(host="localhost", port=6379) - rc.set("bar", 1) - sentry_sdk.flush() - - # on initializing a RedisCluster, a COMMAND call may be emitted - payloads = [item.payload for item in items] - parent_span = payloads[-1] - redis_spans = payloads[:-1] - assert parent_span["name"] == "custom parent" - assert len(redis_spans) in (1, 2) - assert len(redis_spans) == 1 or redis_spans[0]["name"] == "COMMAND" - - span = redis_spans[-1] - assert span["name"] == description - attrs = span["attributes"] - assert attrs["sentry.op"] == "db.redis" - assert attrs[SPANDATA.DB_SYSTEM_NAME] == "redis" - assert attrs[SPANDATA.DB_DRIVER_NAME] == "redis-py" - # ClusterNode converts localhost to 127.0.0.1 - assert attrs[SPANDATA.SERVER_ADDRESS] == "127.0.0.1" - assert attrs[SPANDATA.SERVER_PORT] == 6379 - assert attrs[SPANDATA.DB_OPERATION_NAME] == "SET" - assert attrs["db.redis.key"] == "bar" - else: - events = capture_events() - with start_transaction(): - rc = redis.RedisCluster(host="localhost", port=6379) - rc.set("bar", 1) - - (event,) = events - spans = event["spans"] - - # on initializing a RedisCluster, a COMMAND call is made - this is not important for the test - # but must be accounted for - assert len(spans) in (1, 2) - assert len(spans) == 1 or spans[0]["description"] == "COMMAND" - - span = spans[-1] - assert span["op"] == "db.redis" - assert span["description"] == description - assert span["data"] == ApproxDict( - { - SPANDATA.DB_SYSTEM: "redis", - # ClusterNode converts localhost to 127.0.0.1 - SPANDATA.SERVER_ADDRESS: "127.0.0.1", - SPANDATA.SERVER_PORT: 6379, - } - ) - assert span["tags"] == { - "db.operation": "SET", - "redis.command": "SET", - "redis.is_cluster": True, - "redis.key": "bar", - } + items = capture_items("span") + + with sentry_sdk.start_span(name="custom parent"): + rc = redis.RedisCluster(host="localhost", port=6379) + rc.set("bar", 1) + + sentry_sdk.flush() + + # on initializing a RedisCluster, a COMMAND call may be emitted + payloads = [item.payload for item in items] + parent_span = payloads[-1] + redis_spans = payloads[:-1] + assert parent_span["name"] == "custom parent" + assert len(redis_spans) in (1, 2) + assert len(redis_spans) == 1 or redis_spans[0]["name"] == "COMMAND" + + span = redis_spans[-1] + assert span["name"] == description + attrs = span["attributes"] + assert attrs["sentry.op"] == "db.redis" + assert attrs[SPANDATA.DB_SYSTEM_NAME] == "redis" + assert attrs[SPANDATA.DB_DRIVER_NAME] == "redis-py" + # ClusterNode converts localhost to 127.0.0.1 + assert attrs[SPANDATA.SERVER_ADDRESS] == "127.0.0.1" + assert attrs[SPANDATA.SERVER_PORT] == 6379 + assert attrs[SPANDATA.DB_OPERATION_NAME] == "SET" + assert attrs["db.redis.key"] == "bar" -@pytest.mark.parametrize("span_streaming", [True, False]) @pytest.mark.parametrize( "send_default_pii, expected_first_ten", [ @@ -154,124 +118,76 @@ def test_rediscluster_pipeline( capture_items, send_default_pii, expected_first_ten, - span_streaming, ): sentry_init( integrations=[RedisIntegration()], traces_sample_rate=1.0, send_default_pii=send_default_pii, - trace_lifecycle="stream" if span_streaming else "static", ) rc = redis.RedisCluster(host="localhost", port=6379) - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="custom parent"): - pipeline = rc.pipeline() - pipeline.get("foo") - pipeline.set("bar", 1) - pipeline.set("baz", 2) - pipeline.execute() - sentry_sdk.flush() - - # on initializing a RedisCluster, a COMMAND call may be emitted - payloads = [item.payload for item in items] - parent_span = payloads[-1] - redis_spans = payloads[:-1] - assert parent_span["name"] == "custom parent" - assert len(redis_spans) in (1, 2) - assert len(redis_spans) == 1 or redis_spans[0]["name"] == "COMMAND" - - pipeline_span = redis_spans[-1] - assert pipeline_span["name"] == "redis.pipeline.execute" - attrs = pipeline_span["attributes"] - assert attrs["sentry.op"] == "db.redis" - assert attrs[SPANDATA.DB_SYSTEM_NAME] == "redis" - assert attrs[SPANDATA.DB_DRIVER_NAME] == "redis-py" - # ClusterNode converts localhost to 127.0.0.1 - assert attrs[SPANDATA.SERVER_ADDRESS] == "127.0.0.1" - assert attrs[SPANDATA.SERVER_PORT] == 6379 - else: - events = capture_events() - with start_transaction(): - pipeline = rc.pipeline() - pipeline.get("foo") - pipeline.set("bar", 1) - pipeline.set("baz", 2) - pipeline.execute() - - (event,) = events - (span,) = event["spans"] - assert span["op"] == "db.redis" - assert span["description"] == "redis.pipeline.execute" - assert span["data"] == ApproxDict( - { - "redis.commands": { - "count": 3, - "first_ten": expected_first_ten, - }, - SPANDATA.DB_SYSTEM: "redis", - # ClusterNode converts localhost to 127.0.0.1 - SPANDATA.SERVER_ADDRESS: "127.0.0.1", - SPANDATA.SERVER_PORT: 6379, - } - ) - assert span["tags"] == { - "redis.transaction": False, # For Cluster, this is always False - "redis.is_cluster": True, - } + items = capture_items("span") + with sentry_sdk.start_span(name="custom parent"): + pipeline = rc.pipeline() + pipeline.get("foo") + pipeline.set("bar", 1) + pipeline.set("baz", 2) + pipeline.execute() + sentry_sdk.flush() + + # on initializing a RedisCluster, a COMMAND call may be emitted + payloads = [item.payload for item in items] + parent_span = payloads[-1] + redis_spans = payloads[:-1] + assert parent_span["name"] == "custom parent" + assert len(redis_spans) in (1, 2) + assert len(redis_spans) == 1 or redis_spans[0]["name"] == "COMMAND" + + pipeline_span = redis_spans[-1] + assert pipeline_span["name"] == "redis.pipeline.execute" + attrs = pipeline_span["attributes"] + assert attrs["sentry.op"] == "db.redis" + assert attrs[SPANDATA.DB_SYSTEM_NAME] == "redis" + assert attrs[SPANDATA.DB_DRIVER_NAME] == "redis-py" + # ClusterNode converts localhost to 127.0.0.1 + assert attrs[SPANDATA.SERVER_ADDRESS] == "127.0.0.1" + assert attrs[SPANDATA.SERVER_PORT] == 6379 -@pytest.mark.parametrize("span_streaming", [True, False]) def test_rediscluster_span_origin( - sentry_init, capture_events, capture_items, span_streaming + sentry_init, + capture_events, + capture_items, ): sentry_init( integrations=[RedisIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) rc = redis.RedisCluster(host="localhost", port=6379) - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="custom parent"): - # default case - rc.set("somekey", "somevalue") - - # pipeline - pipeline = rc.pipeline(transaction=False) - pipeline.get("somekey") - pipeline.set("anotherkey", 1) - pipeline.execute() - sentry_sdk.flush() - - payloads = [item.payload for item in items] - parent_span = payloads[-1] - redis_spans = payloads[:-1] - - assert parent_span["name"] == "custom parent" - assert parent_span["attributes"]["sentry.origin"] == "manual" - assert len(redis_spans) >= 2 - for span in redis_spans: - assert span["attributes"]["sentry.origin"] == "auto.db.redis" - else: - events = capture_events() - with start_transaction(name="custom_transaction"): - # default case - rc.set("somekey", "somevalue") - - # pipeline - pipeline = rc.pipeline(transaction=False) - pipeline.get("somekey") - pipeline.set("anotherkey", 1) - pipeline.execute() - - (event,) = events - - assert event["contexts"]["trace"]["origin"] == "manual" - - for span in event["spans"]: - assert span["origin"] == "auto.db.redis" + items = capture_items("span") + + with sentry_sdk.start_span(name="custom parent"): + # default case + rc.set("somekey", "somevalue") + + # pipeline + pipeline = rc.pipeline(transaction=False) + pipeline.get("somekey") + pipeline.set("anotherkey", 1) + pipeline.execute() + + sentry_sdk.flush() + + payloads = [item.payload for item in items] + parent_span = payloads[-1] + redis_spans = payloads[:-1] + + assert parent_span["name"] == "custom parent" + assert parent_span["attributes"]["sentry.origin"] == "manual" + assert len(redis_spans) >= 2 + + for span in redis_spans: + assert span["attributes"]["sentry.origin"] == "auto.db.redis" diff --git a/tests/integrations/redis/cluster_asyncio/test_redis_cluster_asyncio.py b/tests/integrations/redis/cluster_asyncio/test_redis_cluster_asyncio.py index 2ca139dc20..adaf968272 100644 --- a/tests/integrations/redis/cluster_asyncio/test_redis_cluster_asyncio.py +++ b/tests/integrations/redis/cluster_asyncio/test_redis_cluster_asyncio.py @@ -2,7 +2,7 @@ from redis.asyncio import cluster import sentry_sdk -from sentry_sdk import capture_message, start_transaction +from sentry_sdk import capture_message from sentry_sdk.consts import SPANDATA from sentry_sdk.integrations.redis import RedisIntegration from tests.conftest import ApproxDict @@ -61,7 +61,6 @@ async def test_async_breadcrumb(sentry_init, capture_events): } -@pytest.mark.parametrize("span_streaming", [True, False]) @pytest.mark.parametrize( "send_default_pii, description", [ @@ -76,62 +75,37 @@ async def test_async_basic( capture_items, send_default_pii, description, - span_streaming, ): sentry_init( integrations=[RedisIntegration()], traces_sample_rate=1.0, send_default_pii=send_default_pii, - trace_lifecycle="stream" if span_streaming else "static", ) connection = cluster.RedisCluster(host="localhost", port=6379) - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="custom parent"): - await connection.set("bar", 1) - sentry_sdk.flush() - - assert len(items) == 2 - redis_span, parent_span = items[0].payload, items[1].payload - - assert parent_span["name"] == "custom parent" - assert redis_span["name"] == description - attrs = redis_span["attributes"] - assert attrs["sentry.op"] == "db.redis" - assert attrs[SPANDATA.DB_SYSTEM_NAME] == "redis" - assert attrs[SPANDATA.DB_DRIVER_NAME] == "redis-py" - assert attrs[SPANDATA.SERVER_ADDRESS] == "127.0.0.1" - assert attrs[SPANDATA.SERVER_PORT] == 6379 - assert attrs[SPANDATA.DB_OPERATION_NAME] == "SET" - assert attrs["db.redis.key"] == "bar" - else: - events = capture_events() - with start_transaction(): - await connection.set("bar", 1) - - (event,) = events - (span,) = event["spans"] - assert span["op"] == "db.redis" - assert span["description"] == description - assert span["data"] == ApproxDict( - { - SPANDATA.DB_SYSTEM: "redis", - # ClusterNode converts localhost to 127.0.0.1 - SPANDATA.SERVER_ADDRESS: "127.0.0.1", - SPANDATA.SERVER_PORT: 6379, - } - ) - assert span["tags"] == { - "redis.is_cluster": True, - "db.operation": "SET", - "redis.command": "SET", - "redis.key": "bar", - } + items = capture_items("span") + + with sentry_sdk.start_span(name="custom parent"): + await connection.set("bar", 1) + + sentry_sdk.flush() + + assert len(items) == 2 + redis_span, parent_span = items[0].payload, items[1].payload + + assert parent_span["name"] == "custom parent" + assert redis_span["name"] == description + attrs = redis_span["attributes"] + assert attrs["sentry.op"] == "db.redis" + assert attrs[SPANDATA.DB_SYSTEM_NAME] == "redis" + assert attrs[SPANDATA.DB_DRIVER_NAME] == "redis-py" + assert attrs[SPANDATA.SERVER_ADDRESS] == "127.0.0.1" + assert attrs[SPANDATA.SERVER_PORT] == 6379 + assert attrs[SPANDATA.DB_OPERATION_NAME] == "SET" + assert attrs["db.redis.key"] == "bar" -@pytest.mark.parametrize("span_streaming", [True, False]) @pytest.mark.parametrize( "send_default_pii, expected_first_ten", [ @@ -142,121 +116,69 @@ async def test_async_basic( @pytest.mark.asyncio async def test_async_redis_pipeline( sentry_init, - capture_events, capture_items, send_default_pii, expected_first_ten, - span_streaming, ): sentry_init( integrations=[RedisIntegration()], traces_sample_rate=1.0, send_default_pii=send_default_pii, - trace_lifecycle="stream" if span_streaming else "static", ) connection = cluster.RedisCluster(host="localhost", port=6379) - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="custom parent"): - pipeline = connection.pipeline() - pipeline.get("foo") - pipeline.set("bar", 1) - pipeline.set("baz", 2) - await pipeline.execute() - sentry_sdk.flush() - - assert len(items) == 2 - pipeline_span, parent_span = items[0].payload, items[1].payload - - assert parent_span["name"] == "custom parent" - assert pipeline_span["name"] == "redis.pipeline.execute" - attrs = pipeline_span["attributes"] - assert attrs["sentry.op"] == "db.redis" - assert attrs[SPANDATA.DB_SYSTEM_NAME] == "redis" - assert attrs[SPANDATA.DB_DRIVER_NAME] == "redis-py" - assert attrs[SPANDATA.SERVER_ADDRESS] == "127.0.0.1" - assert attrs[SPANDATA.SERVER_PORT] == 6379 - else: - events = capture_events() - with start_transaction(): - pipeline = connection.pipeline() - pipeline.get("foo") - pipeline.set("bar", 1) - pipeline.set("baz", 2) - await pipeline.execute() - - (event,) = events - (span,) = event["spans"] - assert span["op"] == "db.redis" - assert span["description"] == "redis.pipeline.execute" - assert span["data"] == ApproxDict( - { - "redis.commands": { - "count": 3, - "first_ten": expected_first_ten, - }, - SPANDATA.DB_SYSTEM: "redis", - # ClusterNode converts localhost to 127.0.0.1 - SPANDATA.SERVER_ADDRESS: "127.0.0.1", - SPANDATA.SERVER_PORT: 6379, - } - ) - assert span["tags"] == { - "redis.transaction": False, - "redis.is_cluster": True, - } + items = capture_items("span") + + with sentry_sdk.start_span(name="custom parent"): + pipeline = connection.pipeline() + pipeline.get("foo") + pipeline.set("bar", 1) + pipeline.set("baz", 2) + await pipeline.execute() + + sentry_sdk.flush() + + assert len(items) == 2 + pipeline_span, parent_span = items[0].payload, items[1].payload + + assert parent_span["name"] == "custom parent" + assert pipeline_span["name"] == "redis.pipeline.execute" + attrs = pipeline_span["attributes"] + assert attrs["sentry.op"] == "db.redis" + assert attrs[SPANDATA.DB_SYSTEM_NAME] == "redis" + assert attrs[SPANDATA.DB_DRIVER_NAME] == "redis-py" + assert attrs[SPANDATA.SERVER_ADDRESS] == "127.0.0.1" + assert attrs[SPANDATA.SERVER_PORT] == 6379 -@pytest.mark.parametrize("span_streaming", [True, False]) @pytest.mark.asyncio -async def test_async_span_origin( - sentry_init, capture_events, capture_items, span_streaming -): +async def test_async_span_origin(sentry_init, capture_items): sentry_init( integrations=[RedisIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) connection = cluster.RedisCluster(host="localhost", port=6379) - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="custom parent"): - # default case - await connection.set("somekey", "somevalue") - - # pipeline - pipeline = connection.pipeline(transaction=False) - pipeline.get("somekey") - pipeline.set("anotherkey", 1) - await pipeline.execute() - sentry_sdk.flush() - - assert len(items) == 3 - set_span, pipeline_span, parent_span = [item.payload for item in items] - - assert parent_span["name"] == "custom parent" - assert parent_span["attributes"]["sentry.origin"] == "manual" - assert set_span["attributes"]["sentry.origin"] == "auto.db.redis" - assert pipeline_span["attributes"]["sentry.origin"] == "auto.db.redis" - else: - events = capture_events() - with start_transaction(name="custom_transaction"): - # default case - await connection.set("somekey", "somevalue") - - # pipeline - pipeline = connection.pipeline(transaction=False) - pipeline.get("somekey") - pipeline.set("anotherkey", 1) - await pipeline.execute() - - (event,) = events - - assert event["contexts"]["trace"]["origin"] == "manual" - - for span in event["spans"]: - assert span["origin"] == "auto.db.redis" + items = capture_items("span") + + with sentry_sdk.start_span(name="custom parent"): + # default case + await connection.set("somekey", "somevalue") + + # pipeline + pipeline = connection.pipeline(transaction=False) + pipeline.get("somekey") + pipeline.set("anotherkey", 1) + await pipeline.execute() + + sentry_sdk.flush() + + assert len(items) == 3 + set_span, pipeline_span, parent_span = [item.payload for item in items] + + assert parent_span["name"] == "custom parent" + assert parent_span["attributes"]["sentry.origin"] == "manual" + assert set_span["attributes"]["sentry.origin"] == "auto.db.redis" + assert pipeline_span["attributes"]["sentry.origin"] == "auto.db.redis" diff --git a/tests/integrations/redis/test_redis.py b/tests/integrations/redis/test_redis.py index cea9b51e19..7d3bcf3378 100644 --- a/tests/integrations/redis/test_redis.py +++ b/tests/integrations/redis/test_redis.py @@ -1,10 +1,10 @@ from unittest import mock import pytest -from fakeredis import FakeStrictRedis +from fakeredis import FakeRedis import sentry_sdk -from sentry_sdk import capture_message, start_transaction +from sentry_sdk import capture_message from sentry_sdk.consts import SPANDATA from sentry_sdk.integrations.redis import RedisIntegration @@ -20,7 +20,7 @@ def test_basic(sentry_init, capture_events): sentry_init(integrations=[RedisIntegration()]) events = capture_events() - connection = FakeStrictRedis() + connection = FakeRedis() connection.get("foobar") capture_message("hi") @@ -42,7 +42,6 @@ def test_basic(sentry_init, capture_events): } -@pytest.mark.parametrize("span_streaming", [True, False]) @pytest.mark.parametrize( "is_transaction, send_default_pii, expected_first_ten", [ @@ -57,62 +56,38 @@ def test_redis_pipeline( is_transaction, send_default_pii, expected_first_ten, - span_streaming, ): sentry_init( integrations=[RedisIntegration()], traces_sample_rate=1.0, send_default_pii=send_default_pii, - trace_lifecycle="stream" if span_streaming else "static", ) - connection = FakeStrictRedis() + connection = FakeRedis() - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="custom parent"): - pipeline = connection.pipeline(transaction=is_transaction) - pipeline.get("foo") - pipeline.set("bar", 1) - pipeline.set("baz", 2) - pipeline.execute() - sentry_sdk.flush() + items = capture_items("span") - assert len(items) == 2 - pipeline_span, parent_span = items[0].payload, items[1].payload + with sentry_sdk.start_span(name="custom parent"): + pipeline = connection.pipeline(transaction=is_transaction) + pipeline.get("foo") + pipeline.set("bar", 1) + pipeline.set("baz", 2) + pipeline.execute() - assert parent_span["name"] == "custom parent" - assert parent_span["is_segment"] is True - - assert pipeline_span["name"] == "redis.pipeline.execute" - assert pipeline_span["attributes"]["sentry.op"] == "db.redis" - assert pipeline_span["attributes"]["sentry.origin"] == "auto.db.redis" - assert pipeline_span["attributes"][SPANDATA.DB_SYSTEM_NAME] == "redis" - else: - events = capture_events() - with start_transaction(): - pipeline = connection.pipeline(transaction=is_transaction) - pipeline.get("foo") - pipeline.set("bar", 1) - pipeline.set("baz", 2) - pipeline.execute() - - (event,) = events - (span,) = event["spans"] - assert span["op"] == "db.redis" - assert span["description"] == "redis.pipeline.execute" - assert span["data"][SPANDATA.DB_SYSTEM] == "redis" - assert span["data"]["redis.commands"] == { - "count": 3, - "first_ten": expected_first_ten, - } - assert span["tags"] == { - "redis.transaction": is_transaction, - "redis.is_cluster": False, - } + sentry_sdk.flush() + + assert len(items) == 2 + pipeline_span, parent_span = items[0].payload, items[1].payload + + assert parent_span["name"] == "custom parent" + assert parent_span["is_segment"] is True + + assert pipeline_span["name"] == "redis.pipeline.execute" + assert pipeline_span["attributes"]["sentry.op"] == "db.redis" + assert pipeline_span["attributes"]["sentry.origin"] == "auto.db.redis" + assert pipeline_span["attributes"][SPANDATA.DB_SYSTEM_NAME] == "redis" -@pytest.mark.parametrize("span_streaming", [True, False]) @pytest.mark.parametrize( "data_collection, expected_first_ten", [ @@ -132,54 +107,39 @@ def test_redis_pipeline_data_collection( capture_items, data_collection, expected_first_ten, - span_streaming, ): sentry_init( integrations=[RedisIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", data_collection=data_collection, ) - connection = FakeStrictRedis() + connection = FakeRedis() - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="custom parent"): - pipeline = connection.pipeline(transaction=False) - pipeline.get("foo") - pipeline.set("bar", 1) - pipeline.set("baz", 2) - pipeline.execute() - sentry_sdk.flush() + items = capture_items("span") - assert len(items) == 2 - pipeline_span, parent_span = items[0].payload, items[1].payload + with sentry_sdk.start_span(name="custom parent"): + pipeline = connection.pipeline(transaction=False) + pipeline.get("foo") + pipeline.set("bar", 1) + pipeline.set("baz", 2) + pipeline.execute() - assert parent_span["name"] == "custom parent" - assert pipeline_span["name"] == "redis.pipeline.execute" - assert pipeline_span["attributes"]["sentry.op"] == "db.redis" - else: - events = capture_events() - with start_transaction(): - pipeline = connection.pipeline(transaction=False) - pipeline.get("foo") - pipeline.set("bar", 1) - pipeline.set("baz", 2) - pipeline.execute() - - (event,) = events - (span,) = event["spans"] - assert span["op"] == "db.redis" - assert span["description"] == "redis.pipeline.execute" - assert span["data"]["redis.commands"] == { - "count": 3, - "first_ten": expected_first_ten, - } - - -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_sensitive_data(sentry_init, capture_events, capture_items, span_streaming): + sentry_sdk.flush() + + assert len(items) == 2 + pipeline_span, parent_span = items[0].payload, items[1].payload + + assert parent_span["name"] == "custom parent" + assert pipeline_span["name"] == "redis.pipeline.execute" + assert pipeline_span["attributes"]["sentry.op"] == "db.redis" + + +def test_sensitive_data( + sentry_init, + capture_events, + capture_items, +): # fakeredis does not support the AUTH command, so we need to mock it with mock.patch( "sentry_sdk.integrations.redis.utils._COMMANDS_INCLUDING_SENSITIVE_DATA", @@ -189,85 +149,59 @@ def test_sensitive_data(sentry_init, capture_events, capture_items, span_streami integrations=[RedisIntegration()], traces_sample_rate=1.0, send_default_pii=True, - trace_lifecycle="stream" if span_streaming else "static", ) - connection = FakeStrictRedis() - - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="custom parent"): - connection.get("this is super secret") - sentry_sdk.flush() + connection = FakeRedis() - assert len(items) == 2 - redis_span, parent_span = items[0].payload, items[1].payload + items = capture_items("span") + with sentry_sdk.start_span(name="custom parent"): + connection.get("this is super secret") + sentry_sdk.flush() - assert parent_span["name"] == "custom parent" - assert redis_span["name"] == "GET [Filtered]" - assert redis_span["attributes"][SPANDATA.DB_QUERY_TEXT] == "GET [Filtered]" - assert redis_span["attributes"]["sentry.op"] == "db.redis" - else: - events = capture_events() - with start_transaction(): - connection.get( - "this is super secret" - ) # because fakeredis does not support AUTH we use GET instead + assert len(items) == 2 + redis_span, parent_span = items[0].payload, items[1].payload - (event,) = events - spans = event["spans"] - assert spans[0]["op"] == "db.redis" - assert spans[0]["description"] == "GET [Filtered]" + assert parent_span["name"] == "custom parent" + assert redis_span["name"] == "GET [Filtered]" + assert redis_span["attributes"][SPANDATA.DB_QUERY_TEXT] == "GET [Filtered]" + assert redis_span["attributes"]["sentry.op"] == "db.redis" -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_pii_data_redacted(sentry_init, capture_events, capture_items, span_streaming): +def test_pii_data_redacted( + sentry_init, + capture_events, + capture_items, +): sentry_init( integrations=[RedisIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - connection = FakeStrictRedis() + connection = FakeRedis() + + items = capture_items("span") + + with sentry_sdk.start_span(name="custom parent"): + connection.set("somekey1", "my secret string1") + connection.set("somekey2", "my secret string2") + connection.get("somekey2") + connection.delete("somekey1", "somekey2") + + sentry_sdk.flush() + + assert len(items) == 5 + set1, set2, get, delete, parent = [item.payload for item in items] + + assert parent["name"] == "custom parent" + assert set1["name"] == "SET 'somekey1' [Filtered]" + assert set1["attributes"][SPANDATA.DB_QUERY_TEXT] == "SET 'somekey1' [Filtered]" + assert set1["attributes"]["sentry.op"] == "db.redis" + assert set2["name"] == "SET 'somekey2' [Filtered]" + assert set2["attributes"][SPANDATA.DB_QUERY_TEXT] == "SET 'somekey2' [Filtered]" + assert get["name"] == "GET 'somekey2'" + assert delete["name"] == "DEL 'somekey1' [Filtered]" - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="custom parent"): - connection.set("somekey1", "my secret string1") - connection.set("somekey2", "my secret string2") - connection.get("somekey2") - connection.delete("somekey1", "somekey2") - sentry_sdk.flush() - assert len(items) == 5 - set1, set2, get, delete, parent = [item.payload for item in items] - - assert parent["name"] == "custom parent" - assert set1["name"] == "SET 'somekey1' [Filtered]" - assert set1["attributes"][SPANDATA.DB_QUERY_TEXT] == "SET 'somekey1' [Filtered]" - assert set1["attributes"]["sentry.op"] == "db.redis" - assert set2["name"] == "SET 'somekey2' [Filtered]" - assert set2["attributes"][SPANDATA.DB_QUERY_TEXT] == "SET 'somekey2' [Filtered]" - assert get["name"] == "GET 'somekey2'" - assert delete["name"] == "DEL 'somekey1' [Filtered]" - else: - events = capture_events() - with start_transaction(): - connection.set("somekey1", "my secret string1") - connection.set("somekey2", "my secret string2") - connection.get("somekey2") - connection.delete("somekey1", "somekey2") - - (event,) = events - spans = event["spans"] - assert spans[0]["op"] == "db.redis" - assert spans[0]["description"] == "SET 'somekey1' [Filtered]" - assert spans[1]["description"] == "SET 'somekey2' [Filtered]" - assert spans[2]["description"] == "GET 'somekey2'" - assert spans[3]["description"] == "DEL 'somekey1' [Filtered]" - - -@pytest.mark.parametrize("span_streaming", [True, False]) @pytest.mark.parametrize( "data_collection, expected_description", [ @@ -285,44 +219,33 @@ def test_data_collection_database_query_data( sentry_init, capture_events, capture_items, - span_streaming, data_collection, expected_description, ): sentry_init( integrations=[RedisIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", data_collection=data_collection, ) - connection = FakeStrictRedis() + connection = FakeRedis() - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="custom parent"): - connection.set("somekey1", "my secret string1") - sentry_sdk.flush() + items = capture_items("span") - assert len(items) == 2 - set_span, parent = [item.payload for item in items] + with sentry_sdk.start_span(name="custom parent"): + connection.set("somekey1", "my secret string1") + + sentry_sdk.flush() - assert parent["name"] == "custom parent" - assert set_span["name"] == expected_description - assert set_span["attributes"][SPANDATA.DB_QUERY_TEXT] == expected_description - assert set_span["attributes"]["sentry.op"] == "db.redis" - else: - events = capture_events() - with start_transaction(): - connection.set("somekey1", "my secret string1") + assert len(items) == 2 + set_span, parent = [item.payload for item in items] - (event,) = events - spans = event["spans"] - assert spans[0]["op"] == "db.redis" - assert spans[0]["description"] == expected_description + assert parent["name"] == "custom parent" + assert set_span["name"] == expected_description + assert set_span["attributes"][SPANDATA.DB_QUERY_TEXT] == expected_description + assert set_span["attributes"]["sentry.op"] == "db.redis" -@pytest.mark.parametrize("span_streaming", [True, False]) @pytest.mark.parametrize( "data_collection, send_default_pii, expected_description", [ @@ -339,7 +262,6 @@ def test_database_query_data_takes_precedence_over_send_default_pii( sentry_init, capture_events, capture_items, - span_streaming, data_collection, send_default_pii, expected_description, @@ -348,204 +270,109 @@ def test_database_query_data_takes_precedence_over_send_default_pii( integrations=[RedisIntegration()], traces_sample_rate=1.0, send_default_pii=send_default_pii, - trace_lifecycle="stream" if span_streaming else "static", data_collection=data_collection, ) - connection = FakeStrictRedis() + connection = FakeRedis() - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="custom parent"): - connection.set("somekey1", "my secret string1") - sentry_sdk.flush() + items = capture_items("span") - assert len(items) == 2 - set_span, parent = [item.payload for item in items] + with sentry_sdk.start_span(name="custom parent"): + connection.set("somekey1", "my secret string1") - assert parent["name"] == "custom parent" - assert set_span["name"] == expected_description - assert set_span["attributes"][SPANDATA.DB_QUERY_TEXT] == expected_description - assert set_span["attributes"]["sentry.op"] == "db.redis" - else: - events = capture_events() - with start_transaction(): - connection.set("somekey1", "my secret string1") + sentry_sdk.flush() - (event,) = events - spans = event["spans"] - assert spans[0]["op"] == "db.redis" - assert spans[0]["description"] == expected_description + assert len(items) == 2 + set_span, parent = [item.payload for item in items] + assert parent["name"] == "custom parent" + assert set_span["name"] == expected_description + assert set_span["attributes"][SPANDATA.DB_QUERY_TEXT] == expected_description + assert set_span["attributes"]["sentry.op"] == "db.redis" -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_pii_data_sent(sentry_init, capture_events, capture_items, span_streaming): + +def test_pii_data_sent(sentry_init, capture_items): sentry_init( integrations=[RedisIntegration()], traces_sample_rate=1.0, send_default_pii=True, - trace_lifecycle="stream" if span_streaming else "static", ) - connection = FakeStrictRedis() + connection = FakeRedis() - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="custom parent"): - connection.set("somekey1", "my secret string1") - connection.set("somekey2", "my secret string2") - connection.get("somekey2") - connection.delete("somekey1", "somekey2") - sentry_sdk.flush() + items = capture_items("span") - assert len(items) == 5 - set1, set2, get, delete, parent = [item.payload for item in items] + with sentry_sdk.start_span(name="custom parent"): + connection.set("somekey1", "my secret string1") + connection.set("somekey2", "my secret string2") + connection.get("somekey2") + connection.delete("somekey1", "somekey2") - assert parent["name"] == "custom parent" - assert set1["name"] == "SET 'somekey1' 'my secret string1'" - assert ( - set1["attributes"][SPANDATA.DB_QUERY_TEXT] - == "SET 'somekey1' 'my secret string1'" - ) - assert set1["attributes"]["sentry.op"] == "db.redis" - assert set2["name"] == "SET 'somekey2' 'my secret string2'" - assert ( - set2["attributes"][SPANDATA.DB_QUERY_TEXT] - == "SET 'somekey2' 'my secret string2'" - ) - assert get["name"] == "GET 'somekey2'" - assert delete["name"] == "DEL 'somekey1' 'somekey2'" - else: - events = capture_events() - with start_transaction(): - connection.set("somekey1", "my secret string1") - connection.set("somekey2", "my secret string2") - connection.get("somekey2") - connection.delete("somekey1", "somekey2") - - (event,) = events - spans = event["spans"] - assert spans[0]["op"] == "db.redis" - assert spans[0]["description"] == "SET 'somekey1' 'my secret string1'" - assert spans[1]["description"] == "SET 'somekey2' 'my secret string2'" - assert spans[2]["description"] == "GET 'somekey2'" - assert spans[3]["description"] == "DEL 'somekey1' 'somekey2'" - - -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_no_data_truncation_by_default( - sentry_init, capture_events, capture_items, span_streaming -): - sentry_init( - integrations=[RedisIntegration()], - traces_sample_rate=1.0, - send_default_pii=True, - trace_lifecycle="stream" if span_streaming else "static", - ) + sentry_sdk.flush() - connection = FakeStrictRedis() - long_string = "a" * 100000 - short_string = "b" * 10 + assert len(items) == 5 + set1, set2, get, delete, parent = [item.payload for item in items] - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="custom parent"): - connection.set("somekey1", long_string) - connection.set("somekey2", short_string) - sentry_sdk.flush() + assert parent["name"] == "custom parent" + assert set1["name"] == "SET 'somekey1' 'my secret string1'" + assert ( + set1["attributes"][SPANDATA.DB_QUERY_TEXT] + == "SET 'somekey1' 'my secret string1'" + ) + assert set1["attributes"]["sentry.op"] == "db.redis" + assert set2["name"] == "SET 'somekey2' 'my secret string2'" + assert ( + set2["attributes"][SPANDATA.DB_QUERY_TEXT] + == "SET 'somekey2' 'my secret string2'" + ) + assert get["name"] == "GET 'somekey2'" + assert delete["name"] == "DEL 'somekey1' 'somekey2'" - assert len(items) == 3 - set1, set2, parent = [item.payload for item in items] - assert parent["name"] == "custom parent" - assert set1["name"] == f"SET 'somekey1' '{long_string}'" - assert ( - set1["attributes"][SPANDATA.DB_QUERY_TEXT] - == f"SET 'somekey1' '{long_string}'" - ) - assert set1["attributes"]["sentry.op"] == "db.redis" - assert set2["name"] == f"SET 'somekey2' '{short_string}'" - assert ( - set2["attributes"][SPANDATA.DB_QUERY_TEXT] - == f"SET 'somekey2' '{short_string}'" - ) - else: - events = capture_events() - with start_transaction(): - connection.set("somekey1", long_string) - connection.set("somekey2", short_string) - - (event,) = events - spans = event["spans"] - assert spans[0]["op"] == "db.redis" - assert spans[0]["description"] == f"SET 'somekey1' '{long_string}'" - assert spans[1]["description"] == f"SET 'somekey2' '{short_string}'" - - -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_data_truncation_custom( - sentry_init, capture_events, capture_items, span_streaming -): +def test_no_data_truncation_by_default(sentry_init, capture_items): sentry_init( - integrations=[RedisIntegration(max_data_size=30)], + integrations=[RedisIntegration()], traces_sample_rate=1.0, send_default_pii=True, - trace_lifecycle="stream" if span_streaming else "static", ) - connection = FakeStrictRedis() + connection = FakeRedis() long_string = "a" * 100000 short_string = "b" * 10 - expected_long = "SET 'somekey1' '%s..." % ( - long_string[: 30 - len("...") - len("SET 'somekey1' '")], - ) - expected_short = "SET 'somekey2' '%s'" % (short_string,) - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="custom parent"): - connection.set("somekey1", long_string) - connection.set("somekey2", short_string) - sentry_sdk.flush() + items = capture_items("span") - assert len(items) == 3 - set1, set2, parent = [item.payload for item in items] + with sentry_sdk.start_span(name="custom parent"): + connection.set("somekey1", long_string) + connection.set("somekey2", short_string) - assert parent["name"] == "custom parent" - assert set1["name"] == expected_long - assert ( - set1["attributes"][SPANDATA.DB_QUERY_TEXT] - == f"SET 'somekey1' '{long_string}'" - ) - assert set1["attributes"]["sentry.op"] == "db.redis" - assert set2["name"] == expected_short - assert ( - set2["attributes"][SPANDATA.DB_QUERY_TEXT] - == f"SET 'somekey2' '{short_string}'" - ) - else: - events = capture_events() - with start_transaction(): - connection.set("somekey1", long_string) - connection.set("somekey2", short_string) + sentry_sdk.flush() + + assert len(items) == 3 + set1, set2, parent = [item.payload for item in items] - (event,) = events - spans = event["spans"] - assert spans[0]["op"] == "db.redis" - assert spans[0]["description"] == expected_long - assert spans[1]["description"] == expected_short + assert parent["name"] == "custom parent" + assert set1["name"] == f"SET 'somekey1' '{long_string}'" + assert ( + set1["attributes"][SPANDATA.DB_QUERY_TEXT] == f"SET 'somekey1' '{long_string}'" + ) + assert set1["attributes"]["sentry.op"] == "db.redis" + assert set2["name"] == f"SET 'somekey2' '{short_string}'" + assert ( + set2["attributes"][SPANDATA.DB_QUERY_TEXT] == f"SET 'somekey2' '{short_string}'" + ) def test_breadcrumbs(sentry_init, capture_events): sentry_init( - integrations=[RedisIntegration(max_data_size=30)], + integrations=[RedisIntegration()], send_default_pii=True, ) events = capture_events() - connection = FakeStrictRedis() + connection = FakeRedis() - long_string = "a" * 100000 + long_string = "a" * 30 connection.set("somekey1", long_string) short_string = "b" * 10 connection.set("somekey2", short_string) @@ -556,7 +383,7 @@ def test_breadcrumbs(sentry_init, capture_events): crumbs = event["breadcrumbs"]["values"] assert crumbs[0] == { - "message": "SET 'somekey1' 'aaaaaaaaaaa...", + "message": "SET 'somekey1' '" + 30 * "a" + "'", "type": "redis", "category": "redis", "data": { @@ -581,157 +408,94 @@ def test_breadcrumbs(sentry_init, capture_events): } -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_db_connection_attributes_client( - sentry_init, capture_events, capture_items, span_streaming -): +def test_db_connection_attributes_client(sentry_init, capture_items): sentry_init( traces_sample_rate=1.0, integrations=[RedisIntegration()], - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="custom parent"): - connection = FakeStrictRedis(connection_pool=MOCK_CONNECTION_POOL) - connection.get("foobar") - sentry_sdk.flush() + items = capture_items("span") - assert len(items) == 2 - redis_span, parent_span = items[0].payload, items[1].payload + with sentry_sdk.start_span(name="custom parent"): + connection = FakeRedis(connection_pool=MOCK_CONNECTION_POOL) + connection.get("foobar") - assert parent_span["name"] == "custom parent" - assert redis_span["name"] == "GET 'foobar'" - attrs = redis_span["attributes"] - assert attrs["sentry.op"] == "db.redis" - assert attrs[SPANDATA.DB_QUERY_TEXT] == "GET 'foobar'" - assert attrs[SPANDATA.DB_SYSTEM_NAME] == "redis" - assert attrs[SPANDATA.DB_DRIVER_NAME] == "redis-py" - assert attrs[SPANDATA.DB_NAMESPACE] == "1" - assert attrs[SPANDATA.SERVER_ADDRESS] == "localhost" - assert attrs[SPANDATA.SERVER_PORT] == 63791 - else: - events = capture_events() - with start_transaction(): - connection = FakeStrictRedis(connection_pool=MOCK_CONNECTION_POOL) - connection.get("foobar") - - (event,) = events - (span,) = event["spans"] - - assert span["op"] == "db.redis" - assert span["description"] == "GET 'foobar'" - assert span["data"][SPANDATA.DB_SYSTEM] == "redis" - assert span["data"][SPANDATA.DB_DRIVER_NAME] == "redis-py" - assert span["data"][SPANDATA.DB_NAME] == "1" - assert span["data"][SPANDATA.SERVER_ADDRESS] == "localhost" - assert span["data"][SPANDATA.SERVER_PORT] == 63791 - - -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_db_connection_attributes_pipeline( - sentry_init, capture_events, capture_items, span_streaming -): + sentry_sdk.flush() + + assert len(items) == 2 + redis_span, parent_span = items[0].payload, items[1].payload + + assert parent_span["name"] == "custom parent" + assert redis_span["name"] == "GET 'foobar'" + attrs = redis_span["attributes"] + assert attrs["sentry.op"] == "db.redis" + assert attrs[SPANDATA.DB_QUERY_TEXT] == "GET 'foobar'" + assert attrs[SPANDATA.DB_SYSTEM_NAME] == "redis" + assert attrs[SPANDATA.DB_DRIVER_NAME] == "redis-py" + assert attrs[SPANDATA.DB_NAMESPACE] == "1" + assert attrs[SPANDATA.SERVER_ADDRESS] == "localhost" + assert attrs[SPANDATA.SERVER_PORT] == 63791 + + +def test_db_connection_attributes_pipeline(sentry_init, capture_items): sentry_init( traces_sample_rate=1.0, integrations=[RedisIntegration()], - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="custom parent"): - connection = FakeStrictRedis(connection_pool=MOCK_CONNECTION_POOL) - pipeline = connection.pipeline(transaction=False) - pipeline.get("foo") - pipeline.set("bar", 1) - pipeline.set("baz", 2) - pipeline.execute() - sentry_sdk.flush() + items = capture_items("span") - assert len(items) == 2 - pipeline_span, parent_span = items[0].payload, items[1].payload + with sentry_sdk.start_span(name="custom parent"): + connection = FakeRedis(connection_pool=MOCK_CONNECTION_POOL) + pipeline = connection.pipeline(transaction=False) + pipeline.get("foo") + pipeline.set("bar", 1) + pipeline.set("baz", 2) + pipeline.execute() - assert parent_span["name"] == "custom parent" - assert pipeline_span["name"] == "redis.pipeline.execute" - attrs = pipeline_span["attributes"] - assert attrs["sentry.op"] == "db.redis" - assert attrs[SPANDATA.DB_SYSTEM_NAME] == "redis" - assert attrs[SPANDATA.DB_DRIVER_NAME] == "redis-py" - assert attrs[SPANDATA.DB_NAMESPACE] == "1" - assert attrs[SPANDATA.SERVER_ADDRESS] == "localhost" - assert attrs[SPANDATA.SERVER_PORT] == 63791 - else: - events = capture_events() - with start_transaction(): - connection = FakeStrictRedis(connection_pool=MOCK_CONNECTION_POOL) - pipeline = connection.pipeline(transaction=False) - pipeline.get("foo") - pipeline.set("bar", 1) - pipeline.set("baz", 2) - pipeline.execute() - - (event,) = events - (span,) = event["spans"] - - assert span["op"] == "db.redis" - assert span["description"] == "redis.pipeline.execute" - assert span["data"][SPANDATA.DB_SYSTEM] == "redis" - assert span["data"][SPANDATA.DB_DRIVER_NAME] == "redis-py" - assert span["data"][SPANDATA.DB_NAME] == "1" - assert span["data"][SPANDATA.SERVER_ADDRESS] == "localhost" - assert span["data"][SPANDATA.SERVER_PORT] == 63791 - - -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_span_origin(sentry_init, capture_events, capture_items, span_streaming): + sentry_sdk.flush() + + assert len(items) == 2 + pipeline_span, parent_span = items[0].payload, items[1].payload + + assert parent_span["name"] == "custom parent" + assert pipeline_span["name"] == "redis.pipeline.execute" + attrs = pipeline_span["attributes"] + assert attrs["sentry.op"] == "db.redis" + assert attrs[SPANDATA.DB_SYSTEM_NAME] == "redis" + assert attrs[SPANDATA.DB_DRIVER_NAME] == "redis-py" + assert attrs[SPANDATA.DB_NAMESPACE] == "1" + assert attrs[SPANDATA.SERVER_ADDRESS] == "localhost" + assert attrs[SPANDATA.SERVER_PORT] == 63791 + + +def test_span_origin(sentry_init, capture_items): sentry_init( integrations=[RedisIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - connection = FakeStrictRedis() - - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="custom parent"): - # default case - connection.set("somekey", "somevalue") - - # pipeline - pipeline = connection.pipeline(transaction=False) - pipeline.get("somekey") - pipeline.set("anotherkey", 1) - pipeline.execute() - sentry_sdk.flush() + connection = FakeRedis() - assert len(items) == 3 - set_span, pipeline_span, parent_span = [item.payload for item in items] + items = capture_items("span") - assert parent_span["name"] == "custom parent" - assert parent_span["attributes"]["sentry.origin"] == "manual" - assert set_span["attributes"]["sentry.origin"] == "auto.db.redis" - assert ( - set_span["attributes"][SPANDATA.DB_QUERY_TEXT] == "SET 'somekey' [Filtered]" - ) - assert pipeline_span["attributes"]["sentry.origin"] == "auto.db.redis" - else: - events = capture_events() - with start_transaction(name="custom_transaction"): - # default case - connection.set("somekey", "somevalue") + with sentry_sdk.start_span(name="custom parent"): + # default case + connection.set("somekey", "somevalue") - # pipeline - pipeline = connection.pipeline(transaction=False) - pipeline.get("somekey") - pipeline.set("anotherkey", 1) - pipeline.execute() + # pipeline + pipeline = connection.pipeline(transaction=False) + pipeline.get("somekey") + pipeline.set("anotherkey", 1) + pipeline.execute() - (event,) = events + sentry_sdk.flush() - assert event["contexts"]["trace"]["origin"] == "manual" + assert len(items) == 3 + set_span, pipeline_span, parent_span = [item.payload for item in items] - for span in event["spans"]: - assert span["origin"] == "auto.db.redis" + assert parent_span["name"] == "custom parent" + assert parent_span["attributes"]["sentry.origin"] == "manual" + assert set_span["attributes"]["sentry.origin"] == "auto.db.redis" + assert set_span["attributes"][SPANDATA.DB_QUERY_TEXT] == "SET 'somekey' [Filtered]" + assert pipeline_span["attributes"]["sentry.origin"] == "auto.db.redis" diff --git a/tests/integrations/redis/test_redis_cache_module.py b/tests/integrations/redis/test_redis_cache_module.py index fa673620e3..87984a2fc8 100644 --- a/tests/integrations/redis/test_redis_cache_module.py +++ b/tests/integrations/redis/test_redis_cache_module.py @@ -2,7 +2,7 @@ import fakeredis import pytest -from fakeredis import FakeStrictRedis +from fakeredis import FakeRedis import sentry_sdk from sentry_sdk.consts import SPANDATA @@ -13,41 +13,30 @@ FAKEREDIS_VERSION = parse_version(fakeredis.__version__) -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_no_cache_basic(sentry_init, capture_events, capture_items, span_streaming): +def test_no_cache_basic(sentry_init, capture_events, capture_items): sentry_init( integrations=[ RedisIntegration(), ], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - connection = FakeStrictRedis() + connection = FakeRedis() - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="custom parent"): - connection.get("mycachekey") - sentry_sdk.flush() + items = capture_items("span") - assert len(items) == 2 - db_span, parent_span = items[0].payload, items[1].payload - assert parent_span["name"] == "custom parent" - assert db_span["attributes"]["sentry.op"] == "db.redis" - else: - events = capture_events() - with sentry_sdk.start_transaction(): - connection.get("mycachekey") + with sentry_sdk.start_span(name="custom parent"): + connection.get("mycachekey") + + sentry_sdk.flush() - (event,) = events - spans = event["spans"] - assert len(spans) == 1 - assert spans[0]["op"] == "db.redis" + assert len(items) == 2 + db_span, parent_span = items[0].payload, items[1].payload + assert parent_span["name"] == "custom parent" + assert db_span["attributes"]["sentry.op"] == "db.redis" -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_cache_basic(sentry_init, capture_events, capture_items, span_streaming): +def test_cache_basic(sentry_init, capture_events, capture_items): sentry_init( integrations=[ RedisIntegration( @@ -55,100 +44,67 @@ def test_cache_basic(sentry_init, capture_events, capture_items, span_streaming) ), ], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - connection = FakeStrictRedis() - - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="custom parent"): - connection.hget("mycachekey", "myfield") - connection.get("mycachekey") - connection.set("mycachekey1", "bla") - connection.setex("mycachekey2", 10, "blub") - connection.mget("mycachekey1", "mycachekey2") - sentry_sdk.flush() - - # Close order: db spans close before their wrapping cache span, - # and the "custom parent" segment closes last. - assert len(items) == 10 - payloads = [item.payload for item in items] - - # hget: db only (HGET is not a cache command) - assert payloads[0]["attributes"]["sentry.op"] == "db.redis" - assert payloads[0]["attributes"][SPANDATA.DB_OPERATION_NAME] == "HGET" - - # get: db then cache.get - assert payloads[1]["attributes"]["sentry.op"] == "db.redis" - assert payloads[1]["attributes"][SPANDATA.DB_OPERATION_NAME] == "GET" - assert payloads[2]["attributes"]["sentry.op"] == "cache.get" - assert payloads[2]["attributes"][SPANDATA.DB_QUERY_TEXT] == "GET 'mycachekey'" - - # set: db then cache.put - assert payloads[3]["attributes"]["sentry.op"] == "db.redis" - assert payloads[3]["attributes"][SPANDATA.DB_OPERATION_NAME] == "SET" - assert payloads[4]["attributes"]["sentry.op"] == "cache.put" - assert ( - payloads[4]["attributes"][SPANDATA.DB_QUERY_TEXT] - == "SET 'mycachekey1' [Filtered]" - ) - - # setex: db then cache.put - assert payloads[5]["attributes"]["sentry.op"] == "db.redis" - assert payloads[5]["attributes"][SPANDATA.DB_OPERATION_NAME] == "SETEX" - assert payloads[6]["attributes"]["sentry.op"] == "cache.put" - assert ( - payloads[6]["attributes"][SPANDATA.DB_QUERY_TEXT] - == "SETEX 'mycachekey2' [Filtered] [Filtered]" - ) - - # mget: db then cache.get - assert payloads[7]["attributes"]["sentry.op"] == "db.redis" - assert payloads[7]["attributes"][SPANDATA.DB_OPERATION_NAME] == "MGET" - assert payloads[8]["attributes"]["sentry.op"] == "cache.get" - assert ( - payloads[8]["attributes"][SPANDATA.DB_QUERY_TEXT] - == "MGET 'mycachekey1' [Filtered]" - ) - - assert payloads[9]["name"] == "custom parent" - else: - events = capture_events() - with sentry_sdk.start_transaction(): - connection.hget("mycachekey", "myfield") - connection.get("mycachekey") - connection.set("mycachekey1", "bla") - connection.setex("mycachekey2", 10, "blub") - connection.mget("mycachekey1", "mycachekey2") - - (event,) = events - spans = event["spans"] - assert len(spans) == 9 - - # no cache support for hget command - assert spans[0]["op"] == "db.redis" - assert spans[0]["tags"]["redis.command"] == "HGET" - - assert spans[1]["op"] == "cache.get" - assert spans[2]["op"] == "db.redis" - assert spans[2]["tags"]["redis.command"] == "GET" + connection = FakeRedis() + + items = capture_items("span") + + with sentry_sdk.start_span(name="custom parent"): + connection.hget("mycachekey", "myfield") + connection.get("mycachekey") + connection.set("mycachekey1", "bla") + connection.setex("mycachekey2", 10, "blub") + connection.mget("mycachekey1", "mycachekey2") + + sentry_sdk.flush() + + # Close order: db spans close before their wrapping cache span, + # and the "custom parent" segment closes last. + assert len(items) == 10 + payloads = [item.payload for item in items] + + # hget: db only (HGET is not a cache command) + assert payloads[0]["attributes"]["sentry.op"] == "db.redis" + assert payloads[0]["attributes"][SPANDATA.DB_OPERATION_NAME] == "HGET" + + # get: db then cache.get + assert payloads[1]["attributes"]["sentry.op"] == "db.redis" + assert payloads[1]["attributes"][SPANDATA.DB_OPERATION_NAME] == "GET" + assert payloads[2]["attributes"]["sentry.op"] == "cache.get" + assert payloads[2]["attributes"][SPANDATA.DB_QUERY_TEXT] == "GET 'mycachekey'" + + # set: db then cache.put + assert payloads[3]["attributes"]["sentry.op"] == "db.redis" + assert payloads[3]["attributes"][SPANDATA.DB_OPERATION_NAME] == "SET" + assert payloads[4]["attributes"]["sentry.op"] == "cache.put" + assert ( + payloads[4]["attributes"][SPANDATA.DB_QUERY_TEXT] + == "SET 'mycachekey1' [Filtered]" + ) - assert spans[3]["op"] == "cache.put" - assert spans[4]["op"] == "db.redis" - assert spans[4]["tags"]["redis.command"] == "SET" + # setex: db then cache.put + assert payloads[5]["attributes"]["sentry.op"] == "db.redis" + assert payloads[5]["attributes"][SPANDATA.DB_OPERATION_NAME] == "SETEX" + assert payloads[6]["attributes"]["sentry.op"] == "cache.put" + assert ( + payloads[6]["attributes"][SPANDATA.DB_QUERY_TEXT] + == "SETEX 'mycachekey2' [Filtered] [Filtered]" + ) - assert spans[5]["op"] == "cache.put" - assert spans[6]["op"] == "db.redis" - assert spans[6]["tags"]["redis.command"] == "SETEX" + # mget: db then cache.get + assert payloads[7]["attributes"]["sentry.op"] == "db.redis" + assert payloads[7]["attributes"][SPANDATA.DB_OPERATION_NAME] == "MGET" + assert payloads[8]["attributes"]["sentry.op"] == "cache.get" + assert ( + payloads[8]["attributes"][SPANDATA.DB_QUERY_TEXT] + == "MGET 'mycachekey1' [Filtered]" + ) - assert spans[7]["op"] == "cache.get" - assert spans[8]["op"] == "db.redis" - assert spans[8]["tags"]["redis.command"] == "MGET" + assert payloads[9]["name"] == "custom parent" -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_cache_keys(sentry_init, capture_events, capture_items, span_streaming): +def test_cache_keys(sentry_init, capture_events, capture_items): sentry_init( integrations=[ RedisIntegration( @@ -156,76 +112,49 @@ def test_cache_keys(sentry_init, capture_events, capture_items, span_streaming): ), ], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - connection = FakeStrictRedis() - - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="custom parent"): - connection.get("somethingelse") - connection.get("blub") - connection.get("blubkeything") - connection.get("bl") - sentry_sdk.flush() - - assert len(items) == 7 - payloads = [item.payload for item in items] - - # somethingelse: db only - assert payloads[0]["attributes"]["sentry.op"] == "db.redis" - assert payloads[0]["name"] == "GET 'somethingelse'" - - # blub: db then cache.get - assert payloads[1]["attributes"]["sentry.op"] == "db.redis" - assert payloads[1]["name"] == "GET 'blub'" - assert payloads[2]["attributes"]["sentry.op"] == "cache.get" - assert payloads[2]["name"] == "blub" - assert payloads[2]["attributes"][SPANDATA.DB_QUERY_TEXT] == "GET 'blub'" - - # blubkeything: db then cache.get - assert payloads[3]["attributes"]["sentry.op"] == "db.redis" - assert payloads[3]["name"] == "GET 'blubkeything'" - assert payloads[4]["attributes"]["sentry.op"] == "cache.get" - assert payloads[4]["name"] == "blubkeything" - assert payloads[4]["attributes"][SPANDATA.DB_QUERY_TEXT] == "GET 'blubkeything'" - - # bl: db only (no prefix match) - assert payloads[5]["attributes"]["sentry.op"] == "db.redis" - assert payloads[5]["name"] == "GET 'bl'" - - assert payloads[6]["name"] == "custom parent" - else: - events = capture_events() - with sentry_sdk.start_transaction(): - connection.get("somethingelse") - connection.get("blub") - connection.get("blubkeything") - connection.get("bl") - - (event,) = events - spans = event["spans"] - assert len(spans) == 6 - assert spans[0]["op"] == "db.redis" - assert spans[0]["description"] == "GET 'somethingelse'" - - assert spans[1]["op"] == "cache.get" - assert spans[1]["description"] == "blub" - assert spans[2]["op"] == "db.redis" - assert spans[2]["description"] == "GET 'blub'" - - assert spans[3]["op"] == "cache.get" - assert spans[3]["description"] == "blubkeything" - assert spans[4]["op"] == "db.redis" - assert spans[4]["description"] == "GET 'blubkeything'" - - assert spans[5]["op"] == "db.redis" - assert spans[5]["description"] == "GET 'bl'" - - -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_cache_data(sentry_init, capture_events, capture_items, span_streaming): + connection = FakeRedis() + + items = capture_items("span") + + with sentry_sdk.start_span(name="custom parent"): + connection.get("somethingelse") + connection.get("blub") + connection.get("blubkeything") + connection.get("bl") + + sentry_sdk.flush() + + assert len(items) == 7 + payloads = [item.payload for item in items] + + # somethingelse: db only + assert payloads[0]["attributes"]["sentry.op"] == "db.redis" + assert payloads[0]["name"] == "GET 'somethingelse'" + + # blub: db then cache.get + assert payloads[1]["attributes"]["sentry.op"] == "db.redis" + assert payloads[1]["name"] == "GET 'blub'" + assert payloads[2]["attributes"]["sentry.op"] == "cache.get" + assert payloads[2]["name"] == "blub" + assert payloads[2]["attributes"][SPANDATA.DB_QUERY_TEXT] == "GET 'blub'" + + # blubkeything: db then cache.get + assert payloads[3]["attributes"]["sentry.op"] == "db.redis" + assert payloads[3]["name"] == "GET 'blubkeything'" + assert payloads[4]["attributes"]["sentry.op"] == "cache.get" + assert payloads[4]["name"] == "blubkeything" + assert payloads[4]["attributes"][SPANDATA.DB_QUERY_TEXT] == "GET 'blubkeything'" + + # bl: db only (no prefix match) + assert payloads[5]["attributes"]["sentry.op"] == "db.redis" + assert payloads[5]["name"] == "GET 'bl'" + + assert payloads[6]["name"] == "custom parent" + + +def test_cache_data(sentry_init, capture_events, capture_items): sentry_init( integrations=[ RedisIntegration( @@ -233,152 +162,80 @@ def test_cache_data(sentry_init, capture_events, capture_items, span_streaming): ), ], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) # Use a unique host per parametrized run so fakeredis (which shares state # keyed by host:port) doesn't leak the SET from a prior run into this one. host = f"mycacheserver-{uuid.uuid4().hex}.io" - connection = FakeStrictRedis(host=host, port=6378) - - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="custom parent"): - connection.get("mycachekey") - connection.set("mycachekey", "事实胜于雄辩") - connection.get("mycachekey") - sentry_sdk.flush() - - # Close order: db then cache for each command, then parent - assert len(items) == 7 - payloads = [item.payload for item in items] - - # First get (miss) - assert payloads[0]["attributes"]["sentry.op"] == "db.redis" - cache_get_miss = payloads[1] - assert cache_get_miss["attributes"]["sentry.op"] == "cache.get" - assert cache_get_miss["name"] == "mycachekey" - assert cache_get_miss["attributes"]["cache.key"] == ["mycachekey"] - assert cache_get_miss["attributes"]["cache.hit"] is False - assert "cache.item_size" not in cache_get_miss["attributes"] - if FAKEREDIS_VERSION <= (2, 7, 1): - assert "network.peer.port" not in cache_get_miss["attributes"] - else: - assert cache_get_miss["attributes"]["network.peer.port"] == 6378 - if FAKEREDIS_VERSION <= (1, 7, 1): - assert "network.peer.address" not in cache_get_miss["attributes"] - else: - assert cache_get_miss["attributes"]["network.peer.address"] == host - - # Set - assert payloads[2]["attributes"]["sentry.op"] == "db.redis" - cache_put = payloads[3] - assert cache_put["attributes"]["sentry.op"] == "cache.put" - assert cache_put["name"] == "mycachekey" - assert cache_put["attributes"]["cache.key"] == ["mycachekey"] - assert "cache.hit" not in cache_put["attributes"] - assert cache_put["attributes"]["cache.item_size"] == 18 - if FAKEREDIS_VERSION <= (2, 7, 1): - assert "network.peer.port" not in cache_put["attributes"] - else: - assert cache_put["attributes"]["network.peer.port"] == 6378 - if FAKEREDIS_VERSION <= (1, 7, 1): - assert "network.peer.address" not in cache_put["attributes"] - else: - assert cache_put["attributes"]["network.peer.address"] == host - - # Second get (hit) - assert payloads[4]["attributes"]["sentry.op"] == "db.redis" - cache_get_hit = payloads[5] - assert cache_get_hit["attributes"]["sentry.op"] == "cache.get" - assert cache_get_hit["attributes"]["cache.key"] == ["mycachekey"] - assert cache_get_hit["attributes"]["cache.hit"] is True - assert cache_get_hit["attributes"]["cache.item_size"] == 18 - if FAKEREDIS_VERSION <= (2, 7, 1): - assert "network.peer.port" not in cache_get_hit["attributes"] - else: - assert cache_get_hit["attributes"]["network.peer.port"] == 6378 - if FAKEREDIS_VERSION <= (1, 7, 1): - assert "network.peer.address" not in cache_get_hit["attributes"] - else: - assert cache_get_hit["attributes"]["network.peer.address"] == host - - assert payloads[6]["name"] == "custom parent" + connection = FakeRedis(host=host, port=6378) + + items = capture_items("span") + + with sentry_sdk.start_span(name="custom parent"): + connection.get("mycachekey") + connection.set("mycachekey", "事实胜于雄辩") + connection.get("mycachekey") + + sentry_sdk.flush() + + # Close order: db then cache for each command, then parent + assert len(items) == 7 + payloads = [item.payload for item in items] + + # First get (miss) + assert payloads[0]["attributes"]["sentry.op"] == "db.redis" + cache_get_miss = payloads[1] + assert cache_get_miss["attributes"]["sentry.op"] == "cache.get" + assert cache_get_miss["name"] == "mycachekey" + assert cache_get_miss["attributes"]["cache.key"] == ["mycachekey"] + assert cache_get_miss["attributes"]["cache.hit"] is False + assert "cache.item_size" not in cache_get_miss["attributes"] + if FAKEREDIS_VERSION <= (2, 7, 1): + assert "network.peer.port" not in cache_get_miss["attributes"] + else: + assert cache_get_miss["attributes"]["network.peer.port"] == 6378 + if FAKEREDIS_VERSION <= (1, 7, 1): + assert "network.peer.address" not in cache_get_miss["attributes"] + else: + assert cache_get_miss["attributes"]["network.peer.address"] == host + + # Set + assert payloads[2]["attributes"]["sentry.op"] == "db.redis" + cache_put = payloads[3] + assert cache_put["attributes"]["sentry.op"] == "cache.put" + assert cache_put["name"] == "mycachekey" + assert cache_put["attributes"]["cache.key"] == ["mycachekey"] + assert "cache.hit" not in cache_put["attributes"] + assert cache_put["attributes"]["cache.item_size"] == 18 + if FAKEREDIS_VERSION <= (2, 7, 1): + assert "network.peer.port" not in cache_put["attributes"] else: - events = capture_events() - with sentry_sdk.start_transaction(): - connection.get("mycachekey") - connection.set("mycachekey", "事实胜于雄辩") - connection.get("mycachekey") - - (event,) = events - spans = event["spans"] - - assert len(spans) == 6 - - assert spans[0]["op"] == "cache.get" - assert spans[0]["description"] == "mycachekey" - assert spans[0]["data"]["cache.key"] == [ - "mycachekey", - ] - assert spans[0]["data"]["cache.hit"] == False # noqa: E712 - assert "cache.item_size" not in spans[0]["data"] - # very old fakeredis can not handle port and/or host. - # only applicable for Redis v3 - if FAKEREDIS_VERSION <= (2, 7, 1): - assert "network.peer.port" not in spans[0]["data"] - else: - assert spans[0]["data"]["network.peer.port"] == 6378 - if FAKEREDIS_VERSION <= (1, 7, 1): - assert "network.peer.address" not in spans[0]["data"] - else: - assert spans[0]["data"]["network.peer.address"] == host - - assert spans[1]["op"] == "db.redis" # we ignore db spans in this test. - - assert spans[2]["op"] == "cache.put" - assert spans[2]["description"] == "mycachekey" - assert spans[2]["data"]["cache.key"] == [ - "mycachekey", - ] - assert "cache.hit" not in spans[1]["data"] - assert spans[2]["data"]["cache.item_size"] == 18 - # very old fakeredis can not handle port. - # only used with redis v3 - if FAKEREDIS_VERSION <= (2, 7, 1): - assert "network.peer.port" not in spans[2]["data"] - else: - assert spans[2]["data"]["network.peer.port"] == 6378 - if FAKEREDIS_VERSION <= (1, 7, 1): - assert "network.peer.address" not in spans[2]["data"] - else: - assert spans[2]["data"]["network.peer.address"] == host - - assert spans[3]["op"] == "db.redis" # we ignore db spans in this test. - - assert spans[4]["op"] == "cache.get" - assert spans[4]["description"] == "mycachekey" - assert spans[4]["data"]["cache.key"] == [ - "mycachekey", - ] - assert spans[4]["data"]["cache.hit"] == True # noqa: E712 - assert spans[4]["data"]["cache.item_size"] == 18 - # very old fakeredis can not handle port. - # only used with redis v3 - if FAKEREDIS_VERSION <= (2, 7, 1): - assert "network.peer.port" not in spans[4]["data"] - else: - assert spans[4]["data"]["network.peer.port"] == 6378 - if FAKEREDIS_VERSION <= (1, 7, 1): - assert "network.peer.address" not in spans[4]["data"] - else: - assert spans[4]["data"]["network.peer.address"] == host - - assert spans[5]["op"] == "db.redis" # we ignore db spans in this test. - - -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_cache_prefixes(sentry_init, capture_events, capture_items, span_streaming): + assert cache_put["attributes"]["network.peer.port"] == 6378 + if FAKEREDIS_VERSION <= (1, 7, 1): + assert "network.peer.address" not in cache_put["attributes"] + else: + assert cache_put["attributes"]["network.peer.address"] == host + + # Second get (hit) + assert payloads[4]["attributes"]["sentry.op"] == "db.redis" + cache_get_hit = payloads[5] + assert cache_get_hit["attributes"]["sentry.op"] == "cache.get" + assert cache_get_hit["attributes"]["cache.key"] == ["mycachekey"] + assert cache_get_hit["attributes"]["cache.hit"] is True + assert cache_get_hit["attributes"]["cache.item_size"] == 18 + if FAKEREDIS_VERSION <= (2, 7, 1): + assert "network.peer.port" not in cache_get_hit["attributes"] + else: + assert cache_get_hit["attributes"]["network.peer.port"] == 6378 + if FAKEREDIS_VERSION <= (1, 7, 1): + assert "network.peer.address" not in cache_get_hit["attributes"] + else: + assert cache_get_hit["attributes"]["network.peer.address"] == host + + assert payloads[6]["name"] == "custom parent" + + +def test_cache_prefixes(sentry_init, capture_events, capture_items): sentry_init( integrations=[ RedisIntegration( @@ -386,64 +243,39 @@ def test_cache_prefixes(sentry_init, capture_events, capture_items, span_streami ), ], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - connection = FakeStrictRedis() - - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="custom parent"): - connection.mget("yes", "no") - connection.mget("no", 1, "yes") - connection.mget("no", "yes.1", "yes.2") - connection.mget("no.1", "no.2", "no.3") - connection.mget("no.1", "no.2", "no.actually.yes") - connection.mget(b"no.3", b"yes.5") - connection.mget(uuid.uuid4().bytes) - connection.mget(uuid.uuid4().bytes, "yes") - sentry_sdk.flush() - - # 8 db spans + 5 cache spans + 1 parent - assert len(items) == 14 - payloads = [item.payload for item in items] - assert payloads[-1]["name"] == "custom parent" - - cache_spans = [ - p for p in payloads if p["attributes"].get("sentry.op") == "cache.get" - ] - assert len(cache_spans) == 5 - - assert cache_spans[0]["name"] == "yes, no" - assert cache_spans[1]["name"] == "no, 1, yes" - assert cache_spans[2]["name"] == "no, yes.1, yes.2" - assert cache_spans[3]["name"] == "no.3, yes.5" - assert cache_spans[4]["name"] == ", yes" - else: - events = capture_events() - with sentry_sdk.start_transaction(): - connection.mget("yes", "no") - connection.mget("no", 1, "yes") - connection.mget("no", "yes.1", "yes.2") - connection.mget("no.1", "no.2", "no.3") - connection.mget("no.1", "no.2", "no.actually.yes") - connection.mget(b"no.3", b"yes.5") - connection.mget(uuid.uuid4().bytes) - connection.mget(uuid.uuid4().bytes, "yes") - - (event,) = events - - spans = event["spans"] - assert len(spans) == 13 # 8 db spans + 5 cache spans - - cache_spans = [span for span in spans if span["op"] == "cache.get"] - assert len(cache_spans) == 5 - - assert cache_spans[0]["description"] == "yes, no" - assert cache_spans[1]["description"] == "no, 1, yes" - assert cache_spans[2]["description"] == "no, yes.1, yes.2" - assert cache_spans[3]["description"] == "no.3, yes.5" - assert cache_spans[4]["description"] == ", yes" + connection = FakeRedis() + + items = capture_items("span") + + with sentry_sdk.start_span(name="custom parent"): + connection.mget("yes", "no") + connection.mget("no", 1, "yes") + connection.mget("no", "yes.1", "yes.2") + connection.mget("no.1", "no.2", "no.3") + connection.mget("no.1", "no.2", "no.actually.yes") + connection.mget(b"no.3", b"yes.5") + connection.mget(uuid.uuid4().bytes) + connection.mget(uuid.uuid4().bytes, "yes") + + sentry_sdk.flush() + + # 8 db spans + 5 cache spans + 1 parent + assert len(items) == 14 + payloads = [item.payload for item in items] + assert payloads[-1]["name"] == "custom parent" + + cache_spans = [ + p for p in payloads if p["attributes"].get("sentry.op") == "cache.get" + ] + assert len(cache_spans) == 5 + + assert cache_spans[0]["name"] == "yes, no" + assert cache_spans[1]["name"] == "no, 1, yes" + assert cache_spans[2]["name"] == "no, yes.1, yes.2" + assert cache_spans[3]["name"] == "no.3, yes.5" + assert cache_spans[4]["name"] == ", yes" @pytest.mark.parametrize( diff --git a/tests/integrations/redis/test_redis_cache_module_async.py b/tests/integrations/redis/test_redis_cache_module_async.py index 96e486fd55..669efbe0ee 100644 --- a/tests/integrations/redis/test_redis_cache_module_async.py +++ b/tests/integrations/redis/test_redis_cache_module_async.py @@ -22,45 +22,30 @@ FAKEREDIS_VERSION = parse_version(fakeredis.__version__) -@pytest.mark.parametrize("span_streaming", [True, False]) @pytest.mark.asyncio -async def test_no_cache_basic( - sentry_init, capture_events, capture_items, span_streaming -): +async def test_no_cache_basic(sentry_init, capture_events, capture_items): sentry_init( integrations=[ RedisIntegration(), ], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) connection = FakeRedisAsync() - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="custom parent"): - await connection.get("myasynccachekey") - sentry_sdk.flush() + items = capture_items("span") + with sentry_sdk.start_span(name="custom parent"): + await connection.get("myasynccachekey") + sentry_sdk.flush() - assert len(items) == 2 - db_span, parent_span = items[0].payload, items[1].payload - assert parent_span["name"] == "custom parent" - assert db_span["attributes"]["sentry.op"] == "db.redis" - else: - events = capture_events() - with sentry_sdk.start_transaction(): - await connection.get("myasynccachekey") - - (event,) = events - spans = event["spans"] - assert len(spans) == 1 - assert spans[0]["op"] == "db.redis" + assert len(items) == 2 + db_span, parent_span = items[0].payload, items[1].payload + assert parent_span["name"] == "custom parent" + assert db_span["attributes"]["sentry.op"] == "db.redis" -@pytest.mark.parametrize("span_streaming", [True, False]) @pytest.mark.asyncio -async def test_cache_basic(sentry_init, capture_events, capture_items, span_streaming): +async def test_cache_basic(sentry_init, capture_events, capture_items): sentry_init( integrations=[ RedisIntegration( @@ -68,39 +53,25 @@ async def test_cache_basic(sentry_init, capture_events, capture_items, span_stre ), ], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) connection = FakeRedisAsync() - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="custom parent"): - await connection.get("myasynccachekey") - sentry_sdk.flush() - - assert len(items) == 3 - db_span, cache_span, parent_span = [item.payload for item in items] - assert parent_span["name"] == "custom parent" - assert db_span["attributes"]["sentry.op"] == "db.redis" - assert cache_span["attributes"]["sentry.op"] == "cache.get" - assert cache_span["attributes"][SPANDATA.CACHE_KEY] == ["myasynccachekey"] - else: - events = capture_events() - with sentry_sdk.start_transaction(): - await connection.get("myasynccachekey") + items = capture_items("span") + with sentry_sdk.start_span(name="custom parent"): + await connection.get("myasynccachekey") + sentry_sdk.flush() - (event,) = events - spans = event["spans"] - assert len(spans) == 2 + assert len(items) == 3 + db_span, cache_span, parent_span = [item.payload for item in items] + assert parent_span["name"] == "custom parent" + assert db_span["attributes"]["sentry.op"] == "db.redis" + assert cache_span["attributes"]["sentry.op"] == "cache.get" + assert cache_span["attributes"][SPANDATA.CACHE_KEY] == ["myasynccachekey"] - assert spans[0]["op"] == "cache.get" - assert spans[1]["op"] == "db.redis" - -@pytest.mark.parametrize("span_streaming", [True, False]) @pytest.mark.asyncio -async def test_cache_keys(sentry_init, capture_events, capture_items, span_streaming): +async def test_cache_keys(sentry_init, capture_events, capture_items): sentry_init( integrations=[ RedisIntegration( @@ -108,77 +79,48 @@ async def test_cache_keys(sentry_init, capture_events, capture_items, span_strea ), ], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) connection = FakeRedisAsync() - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="custom parent"): - await connection.get("asomethingelse") - await connection.get("ablub") - await connection.get("ablubkeything") - await connection.get("abl") - sentry_sdk.flush() - - assert len(items) == 7 - payloads = [item.payload for item in items] - - # asomethingelse: db only - assert payloads[0]["attributes"]["sentry.op"] == "db.redis" - assert payloads[0]["name"] == "GET 'asomethingelse'" - - # ablub: db then cache.get - assert payloads[1]["attributes"]["sentry.op"] == "db.redis" - assert payloads[1]["name"] == "GET 'ablub'" - assert payloads[2]["attributes"]["sentry.op"] == "cache.get" - assert payloads[2]["name"] == "ablub" - assert payloads[2]["attributes"][SPANDATA.CACHE_KEY] == ["ablub"] - - # ablubkeything: db then cache.get - assert payloads[3]["attributes"]["sentry.op"] == "db.redis" - assert payloads[3]["name"] == "GET 'ablubkeything'" - assert payloads[4]["attributes"]["sentry.op"] == "cache.get" - assert payloads[4]["name"] == "ablubkeything" - assert payloads[4]["attributes"][SPANDATA.CACHE_KEY] == ["ablubkeything"] - - # abl: db only (no prefix match) - assert payloads[5]["attributes"]["sentry.op"] == "db.redis" - assert payloads[5]["name"] == "GET 'abl'" - - assert payloads[6]["name"] == "custom parent" - else: - events = capture_events() - with sentry_sdk.start_transaction(): - await connection.get("asomethingelse") - await connection.get("ablub") - await connection.get("ablubkeything") - await connection.get("abl") - - (event,) = events - spans = event["spans"] - assert len(spans) == 6 - assert spans[0]["op"] == "db.redis" - assert spans[0]["description"] == "GET 'asomethingelse'" - - assert spans[1]["op"] == "cache.get" - assert spans[1]["description"] == "ablub" - assert spans[2]["op"] == "db.redis" - assert spans[2]["description"] == "GET 'ablub'" - - assert spans[3]["op"] == "cache.get" - assert spans[3]["description"] == "ablubkeything" - assert spans[4]["op"] == "db.redis" - assert spans[4]["description"] == "GET 'ablubkeything'" - - assert spans[5]["op"] == "db.redis" - assert spans[5]["description"] == "GET 'abl'" - - -@pytest.mark.parametrize("span_streaming", [True, False]) + items = capture_items("span") + with sentry_sdk.start_span(name="custom parent"): + await connection.get("asomethingelse") + await connection.get("ablub") + await connection.get("ablubkeything") + await connection.get("abl") + sentry_sdk.flush() + + assert len(items) == 7 + payloads = [item.payload for item in items] + + # asomethingelse: db only + assert payloads[0]["attributes"]["sentry.op"] == "db.redis" + assert payloads[0]["name"] == "GET 'asomethingelse'" + + # ablub: db then cache.get + assert payloads[1]["attributes"]["sentry.op"] == "db.redis" + assert payloads[1]["name"] == "GET 'ablub'" + assert payloads[2]["attributes"]["sentry.op"] == "cache.get" + assert payloads[2]["name"] == "ablub" + assert payloads[2]["attributes"][SPANDATA.CACHE_KEY] == ["ablub"] + + # ablubkeything: db then cache.get + assert payloads[3]["attributes"]["sentry.op"] == "db.redis" + assert payloads[3]["name"] == "GET 'ablubkeything'" + assert payloads[4]["attributes"]["sentry.op"] == "cache.get" + assert payloads[4]["name"] == "ablubkeything" + assert payloads[4]["attributes"][SPANDATA.CACHE_KEY] == ["ablubkeything"] + + # abl: db only (no prefix match) + assert payloads[5]["attributes"]["sentry.op"] == "db.redis" + assert payloads[5]["name"] == "GET 'abl'" + + assert payloads[6]["name"] == "custom parent" + + @pytest.mark.asyncio -async def test_cache_data(sentry_init, capture_events, capture_items, span_streaming): +async def test_cache_data(sentry_init, capture_events, capture_items): sentry_init( integrations=[ RedisIntegration( @@ -186,7 +128,6 @@ async def test_cache_data(sentry_init, capture_events, capture_items, span_strea ), ], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) # Use a unique host per parametrized run so fakeredis (which shares state @@ -194,136 +135,64 @@ async def test_cache_data(sentry_init, capture_events, capture_items, span_strea host = f"mycacheserver-{uuid.uuid4().hex}.io" connection = FakeRedisAsync(host=host, port=6378) - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="custom parent"): - await connection.get("myasynccachekey") - await connection.set("myasynccachekey", "事实胜于雄辩") - await connection.get("myasynccachekey") - sentry_sdk.flush() - - assert len(items) == 7 - payloads = [item.payload for item in items] - - # First get (miss) - assert payloads[0]["attributes"]["sentry.op"] == "db.redis" - cache_get_miss = payloads[1] - assert cache_get_miss["attributes"]["sentry.op"] == "cache.get" - assert cache_get_miss["name"] == "myasynccachekey" - assert cache_get_miss["attributes"]["cache.key"] == ["myasynccachekey"] - assert cache_get_miss["attributes"]["cache.hit"] is False - assert "cache.item_size" not in cache_get_miss["attributes"] - if FAKEREDIS_VERSION <= (2, 7, 1): - assert "network.peer.port" not in cache_get_miss["attributes"] - else: - assert cache_get_miss["attributes"]["network.peer.port"] == 6378 - if FAKEREDIS_VERSION <= (1, 7, 1): - assert "network.peer.address" not in cache_get_miss["attributes"] - else: - assert cache_get_miss["attributes"]["network.peer.address"] == host - - # Set - assert payloads[2]["attributes"]["sentry.op"] == "db.redis" - cache_put = payloads[3] - assert cache_put["attributes"]["sentry.op"] == "cache.put" - assert cache_put["name"] == "myasynccachekey" - assert cache_put["attributes"]["cache.key"] == ["myasynccachekey"] - assert "cache.hit" not in cache_put["attributes"] - assert cache_put["attributes"]["cache.item_size"] == 18 - if FAKEREDIS_VERSION <= (2, 7, 1): - assert "network.peer.port" not in cache_put["attributes"] - else: - assert cache_put["attributes"]["network.peer.port"] == 6378 - if FAKEREDIS_VERSION <= (1, 7, 1): - assert "network.peer.address" not in cache_put["attributes"] - else: - assert cache_put["attributes"]["network.peer.address"] == host - - # Second get (hit) - assert payloads[4]["attributes"]["sentry.op"] == "db.redis" - cache_get_hit = payloads[5] - assert cache_get_hit["attributes"]["sentry.op"] == "cache.get" - assert cache_get_hit["attributes"]["cache.key"] == ["myasynccachekey"] - assert cache_get_hit["attributes"]["cache.hit"] is True - assert cache_get_hit["attributes"]["cache.item_size"] == 18 - if FAKEREDIS_VERSION <= (2, 7, 1): - assert "network.peer.port" not in cache_get_hit["attributes"] - else: - assert cache_get_hit["attributes"]["network.peer.port"] == 6378 - if FAKEREDIS_VERSION <= (1, 7, 1): - assert "network.peer.address" not in cache_get_hit["attributes"] - else: - assert cache_get_hit["attributes"]["network.peer.address"] == host - - assert payloads[6]["name"] == "custom parent" + items = capture_items("span") + with sentry_sdk.start_span(name="custom parent"): + await connection.get("myasynccachekey") + await connection.set("myasynccachekey", "事实胜于雄辩") + await connection.get("myasynccachekey") + sentry_sdk.flush() + + assert len(items) == 7 + payloads = [item.payload for item in items] + + # First get (miss) + assert payloads[0]["attributes"]["sentry.op"] == "db.redis" + cache_get_miss = payloads[1] + assert cache_get_miss["attributes"]["sentry.op"] == "cache.get" + assert cache_get_miss["name"] == "myasynccachekey" + assert cache_get_miss["attributes"]["cache.key"] == ["myasynccachekey"] + assert cache_get_miss["attributes"]["cache.hit"] is False + assert "cache.item_size" not in cache_get_miss["attributes"] + if FAKEREDIS_VERSION <= (2, 7, 1): + assert "network.peer.port" not in cache_get_miss["attributes"] + else: + assert cache_get_miss["attributes"]["network.peer.port"] == 6378 + if FAKEREDIS_VERSION <= (1, 7, 1): + assert "network.peer.address" not in cache_get_miss["attributes"] + else: + assert cache_get_miss["attributes"]["network.peer.address"] == host + + # Set + assert payloads[2]["attributes"]["sentry.op"] == "db.redis" + cache_put = payloads[3] + assert cache_put["attributes"]["sentry.op"] == "cache.put" + assert cache_put["name"] == "myasynccachekey" + assert cache_put["attributes"]["cache.key"] == ["myasynccachekey"] + assert "cache.hit" not in cache_put["attributes"] + assert cache_put["attributes"]["cache.item_size"] == 18 + if FAKEREDIS_VERSION <= (2, 7, 1): + assert "network.peer.port" not in cache_put["attributes"] else: - events = capture_events() - with sentry_sdk.start_transaction(): - await connection.get("myasynccachekey") - await connection.set("myasynccachekey", "事实胜于雄辩") - await connection.get("myasynccachekey") - - (event,) = events - spans = event["spans"] - - assert len(spans) == 6 - - assert spans[0]["op"] == "cache.get" - assert spans[0]["description"] == "myasynccachekey" - assert spans[0]["data"]["cache.key"] == [ - "myasynccachekey", - ] - assert spans[0]["data"]["cache.hit"] == False # noqa: E712 - assert "cache.item_size" not in spans[0]["data"] - # very old fakeredis can not handle port and/or host. - # only applicable for Redis v3 - if FAKEREDIS_VERSION <= (2, 7, 1): - assert "network.peer.port" not in spans[0]["data"] - else: - assert spans[0]["data"]["network.peer.port"] == 6378 - if FAKEREDIS_VERSION <= (1, 7, 1): - assert "network.peer.address" not in spans[0]["data"] - else: - assert spans[0]["data"]["network.peer.address"] == host - - assert spans[1]["op"] == "db.redis" # we ignore db spans in this test. - - assert spans[2]["op"] == "cache.put" - assert spans[2]["description"] == "myasynccachekey" - assert spans[2]["data"]["cache.key"] == [ - "myasynccachekey", - ] - assert "cache.hit" not in spans[1]["data"] - assert spans[2]["data"]["cache.item_size"] == 18 - # very old fakeredis can not handle port. - # only used with redis v3 - if FAKEREDIS_VERSION <= (2, 7, 1): - assert "network.peer.port" not in spans[2]["data"] - else: - assert spans[2]["data"]["network.peer.port"] == 6378 - if FAKEREDIS_VERSION <= (1, 7, 1): - assert "network.peer.address" not in spans[2]["data"] - else: - assert spans[2]["data"]["network.peer.address"] == host - - assert spans[3]["op"] == "db.redis" # we ignore db spans in this test. - - assert spans[4]["op"] == "cache.get" - assert spans[4]["description"] == "myasynccachekey" - assert spans[4]["data"]["cache.key"] == [ - "myasynccachekey", - ] - assert spans[4]["data"]["cache.hit"] == True # noqa: E712 - assert spans[4]["data"]["cache.item_size"] == 18 - # very old fakeredis can not handle port. - # only used with redis v3 - if FAKEREDIS_VERSION <= (2, 7, 1): - assert "network.peer.port" not in spans[4]["data"] - else: - assert spans[4]["data"]["network.peer.port"] == 6378 - if FAKEREDIS_VERSION <= (1, 7, 1): - assert "network.peer.address" not in spans[4]["data"] - else: - assert spans[4]["data"]["network.peer.address"] == host - - assert spans[5]["op"] == "db.redis" # we ignore db spans in this test. + assert cache_put["attributes"]["network.peer.port"] == 6378 + if FAKEREDIS_VERSION <= (1, 7, 1): + assert "network.peer.address" not in cache_put["attributes"] + else: + assert cache_put["attributes"]["network.peer.address"] == host + + # Second get (hit) + assert payloads[4]["attributes"]["sentry.op"] == "db.redis" + cache_get_hit = payloads[5] + assert cache_get_hit["attributes"]["sentry.op"] == "cache.get" + assert cache_get_hit["attributes"]["cache.key"] == ["myasynccachekey"] + assert cache_get_hit["attributes"]["cache.hit"] is True + assert cache_get_hit["attributes"]["cache.item_size"] == 18 + if FAKEREDIS_VERSION <= (2, 7, 1): + assert "network.peer.port" not in cache_get_hit["attributes"] + else: + assert cache_get_hit["attributes"]["network.peer.port"] == 6378 + if FAKEREDIS_VERSION <= (1, 7, 1): + assert "network.peer.address" not in cache_get_hit["attributes"] + else: + assert cache_get_hit["attributes"]["network.peer.address"] == host + + assert payloads[6]["name"] == "custom parent" diff --git a/tests/integrations/redis_py_cluster_legacy/__init__.py b/tests/integrations/redis_py_cluster_legacy/__init__.py deleted file mode 100644 index b292f63ec8..0000000000 --- a/tests/integrations/redis_py_cluster_legacy/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -import pytest - -pytest.importorskip("rediscluster") diff --git a/tests/integrations/redis_py_cluster_legacy/test_redis_py_cluster_legacy.py b/tests/integrations/redis_py_cluster_legacy/test_redis_py_cluster_legacy.py deleted file mode 100644 index 1a536d3030..0000000000 --- a/tests/integrations/redis_py_cluster_legacy/test_redis_py_cluster_legacy.py +++ /dev/null @@ -1,171 +0,0 @@ -from unittest import mock - -import pytest -import rediscluster - -from sentry_sdk import capture_message -from sentry_sdk.api import start_transaction -from sentry_sdk.consts import SPANDATA -from sentry_sdk.integrations.redis import RedisIntegration -from tests.conftest import ApproxDict - -MOCK_CONNECTION_POOL = mock.MagicMock() -MOCK_CONNECTION_POOL.connection_kwargs = { - "host": "localhost", - "port": 63791, - "db": 1, -} - - -rediscluster_classes = [rediscluster.RedisCluster] - -if hasattr(rediscluster, "StrictRedisCluster"): - rediscluster_classes.append(rediscluster.StrictRedisCluster) - - -@pytest.fixture(autouse=True) -def monkeypatch_rediscluster_classes(reset_integrations): - try: - pipeline_cls = rediscluster.pipeline.ClusterPipeline - except AttributeError: - pipeline_cls = rediscluster.StrictClusterPipeline - rediscluster.RedisCluster.pipeline = lambda *_, **__: pipeline_cls( - connection_pool=MOCK_CONNECTION_POOL - ) - pipeline_cls.execute = lambda *_, **__: None - for cls in rediscluster_classes: - cls.execute_command = lambda *_, **__: None - - -@pytest.mark.parametrize("rediscluster_cls", rediscluster_classes) -def test_rediscluster_basic(rediscluster_cls, sentry_init, capture_events): - sentry_init(integrations=[RedisIntegration()]) - events = capture_events() - - rc = rediscluster_cls(connection_pool=MOCK_CONNECTION_POOL) - rc.get("foobar") - capture_message("hi") - - (event,) = events - (crumb,) = event["breadcrumbs"]["values"] - - assert crumb == { - "category": "redis", - "message": "GET 'foobar'", - "data": ApproxDict( - { - "db.operation": "GET", - "redis.key": "foobar", - "redis.command": "GET", - "redis.is_cluster": True, - } - ), - "timestamp": crumb["timestamp"], - "type": "redis", - } - - -@pytest.mark.parametrize( - "send_default_pii, expected_first_ten", - [ - (False, ["GET 'foo'", "SET 'bar' [Filtered]", "SET 'baz' [Filtered]"]), - (True, ["GET 'foo'", "SET 'bar' 1", "SET 'baz' 2"]), - ], -) -def test_rediscluster_pipeline( - sentry_init, capture_events, send_default_pii, expected_first_ten -): - sentry_init( - integrations=[RedisIntegration()], - traces_sample_rate=1.0, - send_default_pii=send_default_pii, - ) - events = capture_events() - - rc = rediscluster.RedisCluster(connection_pool=MOCK_CONNECTION_POOL) - with start_transaction(): - pipeline = rc.pipeline() - pipeline.get("foo") - pipeline.set("bar", 1) - pipeline.set("baz", 2) - pipeline.execute() - - (event,) = events - (span,) = event["spans"] - assert span["op"] == "db.redis" - assert span["description"] == "redis.pipeline.execute" - assert span["data"] == ApproxDict( - { - "redis.commands": { - "count": 3, - "first_ten": expected_first_ten, - }, - SPANDATA.DB_SYSTEM: "redis", - SPANDATA.DB_NAME: "1", - SPANDATA.SERVER_ADDRESS: "localhost", - SPANDATA.SERVER_PORT: 63791, - } - ) - assert span["tags"] == { - "redis.transaction": False, # For Cluster, this is always False - "redis.is_cluster": True, - } - - -@pytest.mark.parametrize("rediscluster_cls", rediscluster_classes) -def test_db_connection_attributes_client(sentry_init, capture_events, rediscluster_cls): - sentry_init( - traces_sample_rate=1.0, - integrations=[RedisIntegration()], - ) - events = capture_events() - - rc = rediscluster_cls(connection_pool=MOCK_CONNECTION_POOL) - with start_transaction(): - rc.get("foobar") - - (event,) = events - (span,) = event["spans"] - - assert span["data"] == ApproxDict( - { - SPANDATA.DB_SYSTEM: "redis", - SPANDATA.DB_NAME: "1", - SPANDATA.SERVER_ADDRESS: "localhost", - SPANDATA.SERVER_PORT: 63791, - } - ) - - -@pytest.mark.parametrize("rediscluster_cls", rediscluster_classes) -def test_db_connection_attributes_pipeline( - sentry_init, capture_events, rediscluster_cls -): - sentry_init( - traces_sample_rate=1.0, - integrations=[RedisIntegration()], - ) - events = capture_events() - - rc = rediscluster.RedisCluster(connection_pool=MOCK_CONNECTION_POOL) - with start_transaction(): - pipeline = rc.pipeline() - pipeline.get("foo") - pipeline.execute() - - (event,) = events - (span,) = event["spans"] - assert span["op"] == "db.redis" - assert span["description"] == "redis.pipeline.execute" - assert span["data"] == ApproxDict( - { - "redis.commands": { - "count": 1, - "first_ten": ["GET 'foo'"], - }, - SPANDATA.DB_SYSTEM: "redis", - SPANDATA.DB_NAME: "1", - SPANDATA.SERVER_ADDRESS: "localhost", - SPANDATA.SERVER_PORT: 63791, - } - ) diff --git a/tests/integrations/requests/test_requests.py b/tests/integrations/requests/test_requests.py index 7df431901b..427494202a 100644 --- a/tests/integrations/requests/test_requests.py +++ b/tests/integrations/requests/test_requests.py @@ -1,4 +1,3 @@ -import sys from unittest import mock import pytest @@ -12,36 +11,11 @@ PORT = create_mock_http_server() -def test_crumb_capture(sentry_init, capture_events): - sentry_init(integrations=[StdlibIntegration()], send_default_pii=True) - events = capture_events() - - url = f"http://localhost:{PORT}/hello-world" # noqa:E231 - response = requests.get(url) - capture_message("Testing!") - - (event,) = events - (crumb,) = event["breadcrumbs"]["values"] - assert crumb["type"] == "http" - assert crumb["category"] == "httplib" - assert crumb["data"] == ApproxDict( - { - "url": url, - SPANDATA.HTTP_METHOD: "GET", - SPANDATA.HTTP_FRAGMENT: "", - SPANDATA.HTTP_QUERY: "", - SPANDATA.HTTP_STATUS_CODE: response.status_code, - "reason": response.reason, - } - ) - - @pytest.mark.parametrize("send_default_pii", [True, False]) -def test_crumb_capture_span_streaming(sentry_init, capture_events, send_default_pii): +def test_crumb_capture(sentry_init, capture_events, send_default_pii): sentry_init( integrations=[StdlibIntegration()], send_default_pii=send_default_pii, - trace_lifecycle="stream", ) events = capture_events() @@ -71,58 +45,6 @@ def test_crumb_capture_span_streaming(sentry_init, capture_events, send_default_ ) -@pytest.mark.skipif( - sys.version_info < (3, 7), - reason="The response status is not set on the span early enough in 3.6", -) -@pytest.mark.parametrize( - "status_code,level", - [ - (200, None), - (301, None), - (403, "warning"), - (405, "warning"), - (500, "error"), - ], -) -def test_crumb_capture_client_error(sentry_init, capture_events, status_code, level): - sentry_init(integrations=[StdlibIntegration()], send_default_pii=True) - - events = capture_events() - - url = f"http://localhost:{PORT}/status/{status_code}" # noqa:E231 - response = requests.get(url) - - assert response.status_code == status_code - - capture_message("Testing!") - - (event,) = events - (crumb,) = event["breadcrumbs"]["values"] - assert crumb["type"] == "http" - assert crumb["category"] == "httplib" - - if level is None: - assert "level" not in crumb - else: - assert crumb["level"] == level - - assert crumb["data"] == ApproxDict( - { - "url": url, - SPANDATA.HTTP_METHOD: "GET", - SPANDATA.HTTP_FRAGMENT: "", - SPANDATA.HTTP_QUERY: "", - SPANDATA.HTTP_STATUS_CODE: response.status_code, - "reason": response.reason, - } - ) - - -@pytest.mark.skipif( - sys.version_info < (3, 7), - reason="The response status is not set on the span early enough in 3.6", -) @pytest.mark.parametrize( "status_code,level", [ @@ -134,13 +56,12 @@ def test_crumb_capture_client_error(sentry_init, capture_events, status_code, le ], ) @pytest.mark.parametrize("send_default_pii", [True, False]) -def test_crumb_capture_client_error_span_streaming( +def test_crumb_capture_client_error( sentry_init, capture_events, status_code, level, send_default_pii ): sentry_init( integrations=[StdlibIntegration()], send_default_pii=send_default_pii, - trace_lifecycle="stream", ) events = capture_events() @@ -181,39 +102,8 @@ def test_crumb_capture_client_error_span_streaming( @pytest.mark.tests_internal_exceptions def test_omit_url_data_if_parsing_fails(sentry_init, capture_events): - sentry_init(integrations=[StdlibIntegration()]) - - events = capture_events() - - url = f"http://localhost:{PORT}/ok" # noqa:E231 - - with mock.patch( - "sentry_sdk.integrations.stdlib.parse_url", - side_effect=ValueError, - ): - response = requests.get(url) - - capture_message("Testing!") - - (event,) = events - assert event["breadcrumbs"]["values"][0]["data"] == ApproxDict( - { - SPANDATA.HTTP_METHOD: "GET", - SPANDATA.HTTP_STATUS_CODE: response.status_code, - "reason": response.reason, - # no url related data - } - ) - assert "url" not in event["breadcrumbs"]["values"][0]["data"] - assert SPANDATA.HTTP_FRAGMENT not in event["breadcrumbs"]["values"][0]["data"] - assert SPANDATA.HTTP_QUERY not in event["breadcrumbs"]["values"][0]["data"] - - -@pytest.mark.tests_internal_exceptions -def test_omit_url_data_if_parsing_fails_span_streaming(sentry_init, capture_events): sentry_init( integrations=[StdlibIntegration()], - trace_lifecycle="stream", send_default_pii=True, ) diff --git a/tests/integrations/rq/test_rq.py b/tests/integrations/rq/test_rq.py index a56666efb1..68a3afae3b 100644 --- a/tests/integrations/rq/test_rq.py +++ b/tests/integrations/rq/test_rq.py @@ -2,10 +2,9 @@ import pytest import rq -from fakeredis import FakeStrictRedis +from fakeredis import FakeRedis import sentry_sdk -from sentry_sdk import start_transaction from sentry_sdk.consts import SPANDATA from sentry_sdk.integrations.rq import RqIntegration from sentry_sdk.utils import SENSITIVE_DATA_SUBSTITUTE, parse_version @@ -49,48 +48,29 @@ def do_trick(dog, trick): @pytest.mark.parametrize("send_default_pii", [True, False]) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_basic( sentry_init, - capture_events, capture_items, send_default_pii, - span_streaming, ): sentry_init( integrations=[RqIntegration()], send_default_pii=send_default_pii, - trace_lifecycle="stream" if span_streaming else "static", ) - queue = rq.Queue(connection=FakeStrictRedis()) + queue = rq.Queue(connection=FakeRedis()) worker = rq.SimpleWorker([queue], connection=queue.connection) + items = capture_items("event") - if span_streaming: - items = capture_items("event") - - queue.enqueue(crashing_job, foo=42) - worker.work(burst=True) - - (event,) = (item.payload for item in items) - - (exception,) = event["exception"]["values"] - assert exception["type"] == "ZeroDivisionError" - assert exception["mechanism"]["type"] == "rq" - assert exception["stacktrace"]["frames"][-1]["vars"]["foo"] == "42" - else: - events = capture_events() - - queue.enqueue(crashing_job, foo=42) - worker.work(burst=True) + queue.enqueue(crashing_job, foo=42) + worker.work(burst=True) - (event,) = events + (event,) = (item.payload for item in items) - (exception,) = event["exception"]["values"] - assert exception["type"] == "ZeroDivisionError" - assert exception["mechanism"]["type"] == "rq" - assert exception["stacktrace"]["frames"][-1]["vars"]["foo"] == "42" - assert event["transaction"] == "tests.integrations.rq.test_rq.crashing_job" + (exception,) = event["exception"]["values"] + assert exception["type"] == "ZeroDivisionError" + assert exception["mechanism"]["type"] == "rq" + assert exception["stacktrace"]["frames"][-1]["vars"]["foo"] == "42" extra = event["extra"]["rq-job"] if send_default_pii: @@ -113,39 +93,26 @@ def test_basic( "init_kwargs,expected_args,expected_kwargs", DATA_COLLECTION_QUEUES_CASES, ) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_job_args_kwargs_data_collection( sentry_init, - capture_events, capture_items, - span_streaming, init_kwargs, expected_args, expected_kwargs, ): sentry_init( integrations=[RqIntegration()], - trace_lifecycle="stream" if span_streaming else "static", **init_kwargs, ) - queue = rq.Queue(connection=FakeStrictRedis()) + queue = rq.Queue(connection=FakeRedis()) worker = rq.SimpleWorker([queue], connection=queue.connection) + items = capture_items("event") - if span_streaming: - items = capture_items("event") - - queue.enqueue(crashing_job, 1, b=0) - worker.work(burst=True) - - (event,) = (item.payload for item in items) - else: - events = capture_events() - - queue.enqueue(crashing_job, 1, b=0) - worker.work(burst=True) + queue.enqueue(crashing_job, 1, b=0) + worker.work(burst=True) - (event,) = events + (event,) = (item.payload for item in items) rq_job = event["extra"]["rq-job"] @@ -157,359 +124,200 @@ def test_job_args_kwargs_data_collection( assert rq_job["kwargs"] == expected_kwargs -@pytest.mark.parametrize("span_streaming", [True, False]) def test_transport_shutdown( - sentry_init, capture_events_forksafe, capture_items_forksafe, span_streaming + sentry_init, + capture_items_forksafe, ): sentry_init( integrations=[RqIntegration()], - trace_lifecycle="stream" if span_streaming else "static", ) - queue = rq.Queue(connection=FakeStrictRedis()) + queue = rq.Queue(connection=FakeRedis()) worker = rq.Worker([queue], connection=queue.connection) + items = capture_items_forksafe("event") - if span_streaming: - items = capture_items_forksafe("event") - - queue.enqueue(crashing_job, foo=42) - worker.work(burst=True) - - captured_items = items.read_event() - items.read_flush() - - event = next(item["payload"] for item in captured_items) - (exception,) = event["exception"]["values"] - assert exception["type"] == "ZeroDivisionError" - else: - events = capture_events_forksafe() - - queue.enqueue(crashing_job, foo=42) - worker.work(burst=True) + queue.enqueue(crashing_job, foo=42) + worker.work(burst=True) - event = events.read_event() - events.read_flush() + captured_items = items.read_event() + items.read_flush() - (exception,) = event["exception"]["values"] - assert exception["type"] == "ZeroDivisionError" + event = next(item["payload"] for item in captured_items) + (exception,) = event["exception"]["values"] + assert exception["type"] == "ZeroDivisionError" @pytest.mark.parametrize("send_default_pii", [True, False]) -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_transaction_with_error( +def test_worker_span_with_error( sentry_init, - capture_events, capture_items, - DictionaryContaining, send_default_pii, - span_streaming, ): sentry_init( integrations=[RqIntegration()], traces_sample_rate=1.0, send_default_pii=send_default_pii, - trace_lifecycle="stream" if span_streaming else "static", ) - queue = rq.Queue(connection=FakeStrictRedis()) + queue = rq.Queue(connection=FakeRedis()) worker = rq.SimpleWorker([queue], connection=queue.connection) + items = capture_items("event", "span") - if span_streaming: - items = capture_items("event", "span") - - queue.enqueue(chew_up_shoes, "Charlie", "Katie", shoes="flip-flops") - worker.work(burst=True) - - (error_event,) = (item.payload for item in items if item.type == "event") - - assert ( - error_event["transaction"] == "tests.integrations.rq.test_rq.chew_up_shoes" - ) - assert error_event["contexts"]["trace"]["op"] == "queue.task.rq" - assert error_event["exception"]["values"][0]["type"] == "Exception" - assert ( - error_event["exception"]["values"][0]["value"] - == "Charlie!! Why did you eat Katie's flip-flops??" - ) - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - (span,) = ( - span - for span in spans - if span["attributes"].get("sentry.op") == "queue.task.rq" - ) + queue.enqueue(chew_up_shoes, "Charlie", "Katie", shoes="flip-flops") + worker.work(burst=True) - assert span["trace_id"] == error_event["contexts"]["trace"]["trace_id"] - assert span["span_id"] == error_event["contexts"]["trace"]["span_id"] - assert span["attributes"]["sentry.op"] == error_event["contexts"]["trace"]["op"] - assert ( - span["attributes"]["sentry.origin"] - == error_event["contexts"]["trace"]["origin"] - ) - assert ( - span["attributes"][SPANDATA.CODE_FUNCTION_NAME] - == "tests.integrations.rq.test_rq.chew_up_shoes" - ) - else: - events = capture_events() + (error_event,) = (item.payload for item in items if item.type == "event") - queue.enqueue(chew_up_shoes, "Charlie", "Katie", shoes="flip-flops") - worker.work(burst=True) - - error_event, envelope = events + assert error_event["transaction"] == "tests.integrations.rq.test_rq.chew_up_shoes" + assert error_event["contexts"]["trace"]["op"] == "queue.task.rq" + assert error_event["exception"]["values"][0]["type"] == "Exception" + assert ( + error_event["exception"]["values"][0]["value"] + == "Charlie!! Why did you eat Katie's flip-flops??" + ) - assert ( - error_event["transaction"] == "tests.integrations.rq.test_rq.chew_up_shoes" - ) - assert error_event["contexts"]["trace"]["op"] == "queue.task.rq" - assert error_event["exception"]["values"][0]["type"] == "Exception" - assert ( - error_event["exception"]["values"][0]["value"] - == "Charlie!! Why did you eat Katie's flip-flops??" - ) + sentry_sdk.flush() + spans = [item.payload for item in items if item.type == "span"] + (span,) = ( + span for span in spans if span["attributes"].get("sentry.op") == "queue.task.rq" + ) - assert envelope["type"] == "transaction" - assert envelope["contexts"]["trace"] == error_event["contexts"]["trace"] - assert envelope["transaction"] == error_event["transaction"] - assert envelope["extra"]["rq-job"] == DictionaryContaining( - { - "args": ( - ["Charlie", "Katie"] - if send_default_pii - else SENSITIVE_DATA_SUBSTITUTE - ), - "kwargs": ( - {"shoes": "flip-flops"} - if send_default_pii - else SENSITIVE_DATA_SUBSTITUTE - ), - "func": "tests.integrations.rq.test_rq.chew_up_shoes", - "description": "tests.integrations.rq.test_rq.chew_up_shoes('Charlie', 'Katie', shoes='flip-flops')", - } - ) + assert span["trace_id"] == error_event["contexts"]["trace"]["trace_id"] + assert span["span_id"] == error_event["contexts"]["trace"]["span_id"] + assert span["attributes"]["sentry.op"] == error_event["contexts"]["trace"]["op"] + assert ( + span["attributes"]["sentry.origin"] + == error_event["contexts"]["trace"]["origin"] + ) + assert ( + span["attributes"][SPANDATA.CODE_FUNCTION_NAME] + == "tests.integrations.rq.test_rq.chew_up_shoes" + ) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_error_has_trace_context_if_tracing_disabled( sentry_init, - capture_events, capture_items, - span_streaming, ): sentry_init( integrations=[RqIntegration()], - trace_lifecycle="stream" if span_streaming else "static", ) - queue = rq.Queue(connection=FakeStrictRedis()) + queue = rq.Queue(connection=FakeRedis()) worker = rq.SimpleWorker([queue], connection=queue.connection) + items = capture_items("event") - if span_streaming: - items = capture_items("event") - - queue.enqueue(crashing_job, foo=None) - worker.work(burst=True) - - (error_event,) = (item.payload for item in items) - else: - events = capture_events() - - queue.enqueue(crashing_job, foo=None) - worker.work(burst=True) + queue.enqueue(crashing_job, foo=None) + worker.work(burst=True) - (error_event,) = events + (error_event,) = (item.payload for item in items) assert error_event["contexts"]["trace"] -@pytest.mark.parametrize("span_streaming", [True, False]) def test_tracing_enabled( sentry_init, - capture_events, capture_items, - span_streaming, ): sentry_init( integrations=[RqIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - queue = rq.Queue(connection=FakeStrictRedis()) + queue = rq.Queue(connection=FakeRedis()) worker = rq.SimpleWorker([queue], connection=queue.connection) + items = capture_items("event", "span") + + with sentry_sdk.start_span( + name="custom parent", + attributes={ + "sentry.op": "rq transaction", + }, + ) as span: + queue.enqueue(crashing_job, foo=None) + worker.work(burst=True) - if span_streaming: - items = capture_items("event", "span") - - with sentry_sdk.traces.start_span( - name="custom parent", - attributes={ - "sentry.op": "rq transaction", - }, - ) as span: - queue.enqueue(crashing_job, foo=None) - worker.work(burst=True) - - (error_event,) = (item.payload for item in items if item.type == "event") - - assert error_event["contexts"]["trace"]["trace_id"] == span.trace_id - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - (span,) = ( - span - for span in spans - if span["attributes"].get("sentry.op") == "queue.task.rq" - ) - - assert span["trace_id"] == error_event["contexts"]["trace"]["trace_id"] - assert span["span_id"] == error_event["contexts"]["trace"]["span_id"] - assert span["attributes"]["sentry.op"] == error_event["contexts"]["trace"]["op"] - assert ( - span["attributes"]["sentry.origin"] - == error_event["contexts"]["trace"]["origin"] - ) - else: - events = capture_events() - - with start_transaction(op="rq transaction") as transaction: - queue.enqueue(crashing_job, foo=None) - worker.work(burst=True) + (error_event,) = (item.payload for item in items if item.type == "event") - error_event, envelope, _ = events + assert error_event["contexts"]["trace"]["trace_id"] == span.trace_id - assert ( - error_event["transaction"] == "tests.integrations.rq.test_rq.crashing_job" - ) - assert error_event["contexts"]["trace"]["trace_id"] == transaction.trace_id + sentry_sdk.flush() + spans = [item.payload for item in items if item.type == "span"] + (span,) = ( + span for span in spans if span["attributes"].get("sentry.op") == "queue.task.rq" + ) - assert envelope["contexts"]["trace"] == error_event["contexts"]["trace"] + assert span["trace_id"] == error_event["contexts"]["trace"]["trace_id"] + assert span["span_id"] == error_event["contexts"]["trace"]["span_id"] + assert span["attributes"]["sentry.op"] == error_event["contexts"]["trace"]["op"] + assert ( + span["attributes"]["sentry.origin"] + == error_event["contexts"]["trace"]["origin"] + ) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_tracing_disabled( sentry_init, - capture_events, capture_items, - span_streaming, ): sentry_init( integrations=[RqIntegration()], - trace_lifecycle="stream" if span_streaming else "static", ) - queue = rq.Queue(connection=FakeStrictRedis()) + queue = rq.Queue(connection=FakeRedis()) worker = rq.SimpleWorker([queue], connection=queue.connection) + items = capture_items("event") - if span_streaming: - items = capture_items("event") - - queue.enqueue(crashing_job, foo=None) - worker.work(burst=True) - - (error_event,) = (item.payload for item in items) - - assert error_event["contexts"]["trace"]["trace_id"] - else: - events = capture_events() - - scope = sentry_sdk.get_isolation_scope() - queue.enqueue(crashing_job, foo=None) - worker.work(burst=True) + queue.enqueue(crashing_job, foo=None) + worker.work(burst=True) - (error_event,) = events + (error_event,) = (item.payload for item in items) - assert ( - error_event["transaction"] == "tests.integrations.rq.test_rq.crashing_job" - ) - assert ( - error_event["contexts"]["trace"]["trace_id"] - == scope._propagation_context.trace_id - ) + assert error_event["contexts"]["trace"]["trace_id"] @pytest.mark.parametrize("send_default_pii", [True, False]) -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_transaction_no_error( +def test_worker_span_no_error( sentry_init, - capture_events, capture_items, - DictionaryContaining, send_default_pii, - span_streaming, ): sentry_init( integrations=[RqIntegration()], traces_sample_rate=1.0, send_default_pii=send_default_pii, - trace_lifecycle="stream" if span_streaming else "static", ) - queue = rq.Queue(connection=FakeStrictRedis()) + queue = rq.Queue(connection=FakeRedis()) worker = rq.SimpleWorker([queue], connection=queue.connection) + items = capture_items("span") - if span_streaming: - items = capture_items("span") - - queue.enqueue(do_trick, "Maisey", trick="kangaroo") - worker.work(burst=True) - - sentry_sdk.flush() - spans = [item.payload for item in items] - (span,) = ( - span - for span in spans - if span["attributes"].get("sentry.op") == "queue.task.rq" - ) + queue.enqueue(do_trick, "Maisey", trick="kangaroo") + worker.work(burst=True) - assert span["attributes"]["sentry.op"] == "queue.task.rq" - assert span["name"] == "tests.integrations.rq.test_rq.do_trick" - assert span["attributes"][SPANDATA.MESSAGING_DESTINATION_NAME] == queue.name - else: - events = capture_events() + sentry_sdk.flush() + spans = [item.payload for item in items] + (span,) = ( + span for span in spans if span["attributes"].get("sentry.op") == "queue.task.rq" + ) - queue.enqueue(do_trick, "Maisey", trick="kangaroo") - worker.work(burst=True) + assert span["attributes"]["sentry.op"] == "queue.task.rq" + assert span["name"] == "tests.integrations.rq.test_rq.do_trick" + assert span["attributes"][SPANDATA.MESSAGING_DESTINATION_NAME] == queue.name - envelope = events[0] - assert envelope["type"] == "transaction" - assert envelope["contexts"]["trace"]["op"] == "queue.task.rq" - assert envelope["transaction"] == "tests.integrations.rq.test_rq.do_trick" - assert ( - envelope["contexts"]["trace"]["data"][SPANDATA.MESSAGING_DESTINATION_NAME] - == queue.name - ) - assert envelope["extra"]["rq-job"] == DictionaryContaining( - { - "args": ["Maisey"] if send_default_pii else SENSITIVE_DATA_SUBSTITUTE, - "kwargs": ( - {"trick": "kangaroo"} - if send_default_pii - else SENSITIVE_DATA_SUBSTITUTE - ), - "func": "tests.integrations.rq.test_rq.do_trick", - "description": "tests.integrations.rq.test_rq.do_trick('Maisey', trick='kangaroo')", - } - ) - - -@pytest.mark.parametrize("span_streaming", [True, False]) def test_traces_sampler_gets_correct_values_in_sampling_context( sentry_init, DictionaryContaining, ObjectDescribedBy, - span_streaming, # noqa:N803 ): traces_sampler = mock.Mock(return_value=True) sentry_init( integrations=[RqIntegration()], traces_sampler=traces_sampler, - trace_lifecycle="stream" if span_streaming else "static", ) - queue = rq.Queue(connection=FakeStrictRedis()) + queue = rq.Queue(connection=FakeRedis()) worker = rq.SimpleWorker([queue], connection=queue.connection) queue.enqueue(do_trick, "Bodhi", trick="roll over") @@ -536,73 +344,45 @@ def test_traces_sampler_gets_correct_values_in_sampling_context( @pytest.mark.skipif( parse_version(rq.__version__) < (1, 5), reason="At least rq-1.5 required" ) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_job_with_retries( sentry_init, - capture_events, capture_items, - span_streaming, ): sentry_init( integrations=[RqIntegration()], - trace_lifecycle="stream" if span_streaming else "static", ) - queue = rq.Queue(connection=FakeStrictRedis()) + queue = rq.Queue(connection=FakeRedis()) worker = rq.SimpleWorker([queue], connection=queue.connection) + items = capture_items("event") - if span_streaming: - items = capture_items("event") - - queue.enqueue(crashing_job, foo=42, retry=rq.Retry(max=1)) - worker.work(burst=True) - events = [item.payload for item in items] - else: - events = capture_events() - - queue.enqueue(crashing_job, foo=42, retry=rq.Retry(max=1)) - worker.work(burst=True) + queue.enqueue(crashing_job, foo=42, retry=rq.Retry(max=1)) + worker.work(burst=True) + events = [item.payload for item in items] assert len(events) == 1 -@pytest.mark.parametrize("span_streaming", [True, False]) def test_span_origin( sentry_init, - capture_events, capture_items, - span_streaming, ): sentry_init( integrations=[RqIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - queue = rq.Queue(connection=FakeStrictRedis()) + queue = rq.Queue(connection=FakeRedis()) worker = rq.SimpleWorker([queue], connection=queue.connection) + items = capture_items("span") - if span_streaming: - items = capture_items("span") - - queue.enqueue(do_trick, "Maisey", trick="kangaroo") - worker.work(burst=True) - - sentry_sdk.flush() - spans = [item.payload for item in items] - (span,) = ( - span - for span in spans - if span["attributes"].get("sentry.op") == "queue.task.rq" - ) - - assert span["attributes"]["sentry.origin"] == "auto.queue.rq" - else: - events = capture_events() - - queue.enqueue(do_trick, "Maisey", trick="kangaroo") - worker.work(burst=True) + queue.enqueue(do_trick, "Maisey", trick="kangaroo") + worker.work(burst=True) - (event,) = events + sentry_sdk.flush() + spans = [item.payload for item in items] + (span,) = ( + span for span in spans if span["attributes"].get("sentry.op") == "queue.task.rq" + ) - assert event["contexts"]["trace"]["origin"] == "auto.queue.rq" + assert span["attributes"]["sentry.origin"] == "auto.queue.rq" diff --git a/tests/integrations/rust_tracing/test_rust_tracing.py b/tests/integrations/rust_tracing/test_rust_tracing.py index afa6fa3333..a7ecb4cdb8 100644 --- a/tests/integrations/rust_tracing/test_rust_tracing.py +++ b/tests/integrations/rust_tracing/test_rust_tracing.py @@ -4,7 +4,7 @@ import pytest import sentry_sdk -from sentry_sdk import capture_message, start_transaction +from sentry_sdk import capture_message from sentry_sdk.integrations.rust_tracing import ( EventTypeMapping, RustTracingIntegration, @@ -63,12 +63,9 @@ def record(self, span_id: int): self.layer.on_record(str(span_id), """{"version": "memoized"}""", state) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_on_new_span_on_close( sentry_init, - capture_events, capture_items, - span_streaming, ): rust_tracing = FakeRustTracing() integration = RustTracingIntegration( @@ -79,82 +76,46 @@ def test_on_new_span_on_close( sentry_init( integrations=[integration], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="custom parent"): - rust_tracing.new_span(RustTracingLevel.Info, 3) - - sentry_first_rust_span = sentry_sdk.traces.get_current_span() - rust_first_rust_span = rust_tracing.spans[3] - - assert sentry_first_rust_span == rust_first_rust_span - - rust_tracing.close_span(3) - assert sentry_sdk.traces.get_current_span() != sentry_first_rust_span - - sentry_sdk.flush() - spans = [item.payload for item in items] - assert len(spans) == 2 - - # Ensure the span metadata is wired up - span = spans[0] - assert span["attributes"]["sentry.op"] == "function" - assert ( - span["attributes"]["sentry.origin"] - == "auto.function.rust_tracing.test_on_new_span_on_close" - ) - assert span["name"] == "_bindings::fibonacci" - - # Ensure the span was opened/closed appropriately - assert span["start_timestamp"] is not None - assert span["end_timestamp"] is not None - - # Ensure the extra data from Rust is hooked up - data = span["attributes"] - assert data["use_memoized"] - assert data["index"] == 10 - assert data["version"] == "None" - else: - events = capture_events() - with start_transaction(): - rust_tracing.new_span(RustTracingLevel.Info, 3) + items = capture_items("span") + with sentry_sdk.start_span(name="custom parent"): + rust_tracing.new_span(RustTracingLevel.Info, 3) - sentry_first_rust_span = sentry_sdk.get_current_span() - rust_first_rust_span = rust_tracing.spans[3] + sentry_first_rust_span = sentry_sdk.get_current_span() + rust_first_rust_span = rust_tracing.spans[3] - assert sentry_first_rust_span == rust_first_rust_span + assert sentry_first_rust_span == rust_first_rust_span - rust_tracing.close_span(3) - assert sentry_sdk.get_current_span() != sentry_first_rust_span + rust_tracing.close_span(3) + assert sentry_sdk.get_current_span() != sentry_first_rust_span - (event,) = events - assert len(event["spans"]) == 1 + sentry_sdk.flush() + spans = [item.payload for item in items] + assert len(spans) == 2 - # Ensure the span metadata is wired up - span = event["spans"][0] - assert span["op"] == "function" - assert span["origin"] == "auto.function.rust_tracing.test_on_new_span_on_close" - assert span["description"] == "_bindings::fibonacci" + # Ensure the span metadata is wired up + span = spans[0] + assert span["attributes"]["sentry.op"] == "function" + assert ( + span["attributes"]["sentry.origin"] + == "auto.function.rust_tracing.test_on_new_span_on_close" + ) + assert span["name"] == "_bindings::fibonacci" - # Ensure the span was opened/closed appropriately - assert span["start_timestamp"] is not None - assert span["timestamp"] is not None + # Ensure the span was opened/closed appropriately + assert span["start_timestamp"] is not None + assert span["end_timestamp"] is not None - # Ensure the extra data from Rust is hooked up - data = span["data"] - assert data["use_memoized"] - assert data["index"] == 10 - assert data["version"] is None + # Ensure the extra data from Rust is hooked up + data = span["attributes"] + assert data["use_memoized"] + assert data["index"] == 10 + assert data["version"] == "None" -@pytest.mark.parametrize("span_streaming", [True, False]) def test_nested_on_new_span_on_close( sentry_init, - capture_events, capture_items, - span_streaming, ): rust_tracing = FakeRustTracing() integration = RustTracingIntegration( @@ -165,170 +126,92 @@ def test_nested_on_new_span_on_close( sentry_init( integrations=[integration], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="custom parent"): - original_sentry_span = sentry_sdk.traces.get_current_span() + items = capture_items("span") + with sentry_sdk.start_span(name="custom parent"): + original_sentry_span = sentry_sdk.get_current_span() - rust_tracing.new_span(RustTracingLevel.Info, 3, index_arg=10) - sentry_first_rust_span = sentry_sdk.traces.get_current_span() - rust_first_rust_span = rust_tracing.spans[3] + rust_tracing.new_span(RustTracingLevel.Info, 3, index_arg=10) + sentry_first_rust_span = sentry_sdk.get_current_span() + rust_first_rust_span = rust_tracing.spans[3] - # Use a different `index_arg` value for the inner span to help - # distinguish the two at the end of the test - rust_tracing.new_span(RustTracingLevel.Info, 5, index_arg=9) - sentry_second_rust_span = sentry_sdk.traces.get_current_span() - rust_second_rust_span = rust_tracing.spans[5] - - assert rust_second_rust_span == sentry_second_rust_span - - rust_tracing.close_span(5) - - # Ensure the current sentry span was moved back to the parent - sentry_span_after_close = sentry_sdk.traces.get_current_span() - assert sentry_span_after_close == sentry_first_rust_span - assert sentry_span_after_close == rust_first_rust_span - - rust_tracing.close_span(3) - - assert sentry_sdk.traces.get_current_span() == original_sentry_span - - sentry_sdk.flush() - spans = [item.payload for item in items] - assert len(spans) == 3 - - # Ensure the span metadata is wired up for all spans - first_span, second_span, _ = spans - assert first_span["attributes"]["sentry.op"] == "function" - assert ( - first_span["attributes"]["sentry.origin"] - == "auto.function.rust_tracing.test_nested_on_new_span_on_close" - ) - assert first_span["name"] == "_bindings::fibonacci" - assert second_span["attributes"]["sentry.op"] == "function" - assert ( - second_span["attributes"]["sentry.origin"] - == "auto.function.rust_tracing.test_nested_on_new_span_on_close" - ) - assert second_span["name"] == "_bindings::fibonacci" - - # Ensure the spans were opened/closed appropriately - assert first_span["start_timestamp"] is not None - assert first_span["end_timestamp"] is not None - assert second_span["start_timestamp"] is not None - assert second_span["end_timestamp"] is not None - - # Ensure the extra data from Rust is hooked up in both spans - first_span_data = first_span["attributes"] - assert first_span_data["use_memoized"] - assert first_span_data["index"] == 9 - assert first_span_data["version"] == "None" - - second_span_data = second_span["attributes"] - assert second_span_data["use_memoized"] - assert second_span_data["index"] == 10 - assert second_span_data["version"] == "None" - else: - events = capture_events() - with start_transaction(): - original_sentry_span = sentry_sdk.get_current_span() + # Use a different `index_arg` value for the inner span to help + # distinguish the two at the end of the test + rust_tracing.new_span(RustTracingLevel.Info, 5, index_arg=9) + sentry_second_rust_span = sentry_sdk.get_current_span() + rust_second_rust_span = rust_tracing.spans[5] - rust_tracing.new_span(RustTracingLevel.Info, 3, index_arg=10) - sentry_first_rust_span = sentry_sdk.get_current_span() - rust_first_rust_span = rust_tracing.spans[3] + assert rust_second_rust_span == sentry_second_rust_span - # Use a different `index_arg` value for the inner span to help - # distinguish the two at the end of the test - rust_tracing.new_span(RustTracingLevel.Info, 5, index_arg=9) - sentry_second_rust_span = sentry_sdk.get_current_span() - rust_second_rust_span = rust_tracing.spans[5] + rust_tracing.close_span(5) - assert rust_second_rust_span == sentry_second_rust_span + # Ensure the current sentry span was moved back to the parent + sentry_span_after_close = sentry_sdk.get_current_span() + assert sentry_span_after_close == sentry_first_rust_span + assert sentry_span_after_close == rust_first_rust_span - rust_tracing.close_span(5) + rust_tracing.close_span(3) - # Ensure the current sentry span was moved back to the parent - sentry_span_after_close = sentry_sdk.get_current_span() - assert sentry_span_after_close == sentry_first_rust_span - assert sentry_span_after_close == rust_first_rust_span + assert sentry_sdk.get_current_span() == original_sentry_span - rust_tracing.close_span(3) + sentry_sdk.flush() + spans = [item.payload for item in items] + assert len(spans) == 3 - assert sentry_sdk.get_current_span() == original_sentry_span - - (event,) = events - assert len(event["spans"]) == 2 - - # Ensure the span metadata is wired up for all spans - first_span, second_span = event["spans"] - assert first_span["op"] == "function" - assert ( - first_span["origin"] - == "auto.function.rust_tracing.test_nested_on_new_span_on_close" - ) - assert first_span["description"] == "_bindings::fibonacci" - assert second_span["op"] == "function" - assert ( - second_span["origin"] - == "auto.function.rust_tracing.test_nested_on_new_span_on_close" - ) - assert second_span["description"] == "_bindings::fibonacci" + # Ensure the span metadata is wired up for all spans + first_span, second_span, _ = spans + assert first_span["attributes"]["sentry.op"] == "function" + assert ( + first_span["attributes"]["sentry.origin"] + == "auto.function.rust_tracing.test_nested_on_new_span_on_close" + ) + assert first_span["name"] == "_bindings::fibonacci" + assert second_span["attributes"]["sentry.op"] == "function" + assert ( + second_span["attributes"]["sentry.origin"] + == "auto.function.rust_tracing.test_nested_on_new_span_on_close" + ) + assert second_span["name"] == "_bindings::fibonacci" - # Ensure the spans were opened/closed appropriately - assert first_span["start_timestamp"] is not None - assert first_span["timestamp"] is not None - assert second_span["start_timestamp"] is not None - assert second_span["timestamp"] is not None + # Ensure the spans were opened/closed appropriately + assert first_span["start_timestamp"] is not None + assert first_span["end_timestamp"] is not None + assert second_span["start_timestamp"] is not None + assert second_span["end_timestamp"] is not None - # Ensure the extra data from Rust is hooked up in both spans - first_span_data = first_span["data"] - assert first_span_data["use_memoized"] - assert first_span_data["index"] == 10 - assert first_span_data["version"] is None + # Ensure the extra data from Rust is hooked up in both spans + first_span_data = first_span["attributes"] + assert first_span_data["use_memoized"] + assert first_span_data["index"] == 9 + assert first_span_data["version"] == "None" - second_span_data = second_span["data"] - assert second_span_data["use_memoized"] - assert second_span_data["index"] == 9 - assert second_span_data["version"] is None + second_span_data = second_span["attributes"] + assert second_span_data["use_memoized"] + assert second_span_data["index"] == 10 + assert second_span_data["version"] == "None" -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_on_new_span_without_transaction(sentry_init, span_streaming): +def test_on_new_span_without_active_span(sentry_init): rust_tracing = FakeRustTracing() integration = RustTracingIntegration( - "test_on_new_span_without_transaction", rust_tracing.set_layer_impl + "test_on_new_span_without_active_span", rust_tracing.set_layer_impl ) sentry_init( integrations=[integration], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - assert sentry_sdk.traces.get_current_span() is None + assert sentry_sdk.get_current_span() is None - # In streaming mode we do not create an orphan root segment when there - # is no active span - rust_tracing.new_span(RustTracingLevel.Info, 3) - assert sentry_sdk.traces.get_current_span() is None - else: - assert sentry_sdk.get_current_span() is None - - # Should still create a span hierarchy, it just will not be under a txn - rust_tracing.new_span(RustTracingLevel.Info, 3) - current_span = sentry_sdk.get_current_span() - assert current_span is not None - assert current_span.containing_transaction is None + # In streaming mode we do not create an orphan root segment when there + # is no active span + rust_tracing.new_span(RustTracingLevel.Info, 3) + assert sentry_sdk.get_current_span() is None -@pytest.mark.parametrize("span_streaming", [True, False]) def test_on_event_exception( sentry_init, - capture_events, capture_items, - span_streaming, ): rust_tracing = FakeRustTracing() integration = RustTracingIntegration( @@ -339,35 +222,19 @@ def test_on_event_exception( sentry_init( integrations=[integration], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("event") - sentry_sdk.get_isolation_scope().clear_breadcrumbs() + items = capture_items("event") + sentry_sdk.get_isolation_scope().clear_breadcrumbs() - with sentry_sdk.traces.start_span(name="custom parent"): - rust_tracing.new_span(RustTracingLevel.Info, 3) - - # Mapped to Exception - rust_tracing.event(RustTracingLevel.Error, 3) - - rust_tracing.close_span(3) - - (exc,) = (item.payload for item in items) - else: - events = capture_events() - sentry_sdk.get_isolation_scope().clear_breadcrumbs() - - with start_transaction(): - rust_tracing.new_span(RustTracingLevel.Info, 3) + with sentry_sdk.start_span(name="custom parent"): + rust_tracing.new_span(RustTracingLevel.Info, 3) - # Mapped to Exception - rust_tracing.event(RustTracingLevel.Error, 3) + # Mapped to Exception + rust_tracing.event(RustTracingLevel.Error, 3) - rust_tracing.close_span(3) + rust_tracing.close_span(3) - assert len(events) == 2 - exc, _tx = events + (exc,) = (item.payload for item in items) assert exc["level"] == "error" assert exc["logger"] == "_bindings" @@ -383,12 +250,9 @@ def test_on_event_exception( assert field_context["message"] == "Getting the 10th fibonacci number" -@pytest.mark.parametrize("span_streaming", [True, False]) def test_on_event_breadcrumb( sentry_init, - capture_events, capture_items, - span_streaming, ): rust_tracing = FakeRustTracing() integration = RustTracingIntegration( @@ -399,37 +263,20 @@ def test_on_event_breadcrumb( sentry_init( integrations=[integration], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("event") - sentry_sdk.get_isolation_scope().clear_breadcrumbs() - - with sentry_sdk.traces.start_span(name="custom parent"): - rust_tracing.new_span(RustTracingLevel.Info, 3) - - # Mapped to Breadcrumb - rust_tracing.event(RustTracingLevel.Info, 3) + items = capture_items("event") + sentry_sdk.get_isolation_scope().clear_breadcrumbs() - rust_tracing.close_span(3) - capture_message("test message") - - (message,) = (item.payload for item in items) - else: - events = capture_events() - sentry_sdk.get_isolation_scope().clear_breadcrumbs() - - with start_transaction(): - rust_tracing.new_span(RustTracingLevel.Info, 3) + with sentry_sdk.start_span(name="custom parent"): + rust_tracing.new_span(RustTracingLevel.Info, 3) - # Mapped to Breadcrumb - rust_tracing.event(RustTracingLevel.Info, 3) + # Mapped to Breadcrumb + rust_tracing.event(RustTracingLevel.Info, 3) - rust_tracing.close_span(3) - capture_message("test message") + rust_tracing.close_span(3) + capture_message("test message") - assert len(events) == 2 - message, _tx = events + (message,) = (item.payload for item in items) breadcrumbs = message["breadcrumbs"]["values"] assert len(breadcrumbs) == 1 @@ -438,12 +285,9 @@ def test_on_event_breadcrumb( assert breadcrumbs[0]["type"] == "default" -@pytest.mark.parametrize("span_streaming", [True, False]) def test_on_event_event( sentry_init, - capture_events, capture_items, - span_streaming, ): rust_tracing = FakeRustTracing() integration = RustTracingIntegration( @@ -454,35 +298,19 @@ def test_on_event_event( sentry_init( integrations=[integration], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("event") - sentry_sdk.get_isolation_scope().clear_breadcrumbs() - - with sentry_sdk.traces.start_span(name="custom parent"): - rust_tracing.new_span(RustTracingLevel.Info, 3) - - # Mapped to Event - rust_tracing.event(RustTracingLevel.Debug, 3) - - rust_tracing.close_span(3) + items = capture_items("event") + sentry_sdk.get_isolation_scope().clear_breadcrumbs() - (event,) = (item.payload for item in items) - else: - events = capture_events() - sentry_sdk.get_isolation_scope().clear_breadcrumbs() - - with start_transaction(): - rust_tracing.new_span(RustTracingLevel.Info, 3) + with sentry_sdk.start_span(name="custom parent"): + rust_tracing.new_span(RustTracingLevel.Info, 3) - # Mapped to Event - rust_tracing.event(RustTracingLevel.Debug, 3) + # Mapped to Event + rust_tracing.event(RustTracingLevel.Debug, 3) - rust_tracing.close_span(3) + rust_tracing.close_span(3) - assert len(events) == 2 - event, _tx = events + (event,) = (item.payload for item in items) assert event["logger"] == "_bindings" assert event["level"] == "debug" @@ -498,12 +326,9 @@ def test_on_event_event( assert field_context["message"] == "Getting the 10th fibonacci number" -@pytest.mark.parametrize("span_streaming", [True, False]) def test_on_event_ignored( sentry_init, - capture_events, capture_items, - span_streaming, ): rust_tracing = FakeRustTracing() integration = RustTracingIntegration( @@ -514,47 +339,26 @@ def test_on_event_ignored( sentry_init( integrations=[integration], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") - sentry_sdk.get_isolation_scope().clear_breadcrumbs() - - with sentry_sdk.traces.start_span(name="custom parent"): - rust_tracing.new_span(RustTracingLevel.Info, 3) - - # Ignored - rust_tracing.event(RustTracingLevel.Trace, 3) + items = capture_items("span") + sentry_sdk.get_isolation_scope().clear_breadcrumbs() - rust_tracing.close_span(3) - - sentry_sdk.flush() - spans = [item.payload for item in items] - assert spans[1]["is_segment"] is True - else: - events = capture_events() - sentry_sdk.get_isolation_scope().clear_breadcrumbs() - - with start_transaction(): - rust_tracing.new_span(RustTracingLevel.Info, 3) + with sentry_sdk.start_span(name="custom parent"): + rust_tracing.new_span(RustTracingLevel.Info, 3) - # Ignored - rust_tracing.event(RustTracingLevel.Trace, 3) + # Ignored + rust_tracing.event(RustTracingLevel.Trace, 3) - rust_tracing.close_span(3) + rust_tracing.close_span(3) - assert len(events) == 1 - (tx,) = events - assert tx["type"] == "transaction" - assert "message" not in tx + sentry_sdk.flush() + spans = [item.payload for item in items] + assert spans[1]["is_segment"] is True -@pytest.mark.parametrize("span_streaming", [True, False]) def test_span_filter( sentry_init, - capture_events, capture_items, - span_streaming, ): def span_filter(metadata: Dict[str, object]) -> bool: return RustTracingLevel(metadata.get("level")) in ( @@ -574,61 +378,36 @@ def span_filter(metadata: Dict[str, object]) -> bool: sentry_init( integrations=[integration], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="custom parent"): - original_sentry_span = sentry_sdk.traces.get_current_span() - - # Span is not ignored - rust_tracing.new_span(RustTracingLevel.Info, 3, index_arg=10) - info_span = sentry_sdk.traces.get_current_span() - - # Span is ignored, current span should remain the same - rust_tracing.new_span(RustTracingLevel.Trace, 5, index_arg=9) - assert sentry_sdk.traces.get_current_span() == info_span - - # Closing the filtered span should leave the current span alone - rust_tracing.close_span(5) - assert sentry_sdk.traces.get_current_span() == info_span - - rust_tracing.close_span(3) - assert sentry_sdk.traces.get_current_span() == original_sentry_span - - sentry_sdk.flush() - spans = [item.payload for item in items] - assert len(spans) == 2 - # The ignored span has index == 9 - assert spans[0]["attributes"]["index"] == 10 - else: - events = capture_events() - with start_transaction(): - original_sentry_span = sentry_sdk.get_current_span() + items = capture_items("span") + with sentry_sdk.start_span(name="custom parent"): + original_sentry_span = sentry_sdk.get_current_span() - # Span is not ignored - rust_tracing.new_span(RustTracingLevel.Info, 3, index_arg=10) - info_span = sentry_sdk.get_current_span() + # Span is not ignored + rust_tracing.new_span(RustTracingLevel.Info, 3, index_arg=10) + info_span = sentry_sdk.get_current_span() - # Span is ignored, current span should remain the same - rust_tracing.new_span(RustTracingLevel.Trace, 5, index_arg=9) - assert sentry_sdk.get_current_span() == info_span + # Span is ignored, current span should remain the same + rust_tracing.new_span(RustTracingLevel.Trace, 5, index_arg=9) + assert sentry_sdk.get_current_span() == info_span - # Closing the filtered span should leave the current span alone - rust_tracing.close_span(5) - assert sentry_sdk.get_current_span() == info_span + # Closing the filtered span should leave the current span alone + rust_tracing.close_span(5) + assert sentry_sdk.get_current_span() == info_span - rust_tracing.close_span(3) - assert sentry_sdk.get_current_span() == original_sentry_span + rust_tracing.close_span(3) + assert sentry_sdk.get_current_span() == original_sentry_span - (event,) = events - assert len(event["spans"]) == 1 - # The ignored span has index == 9 - assert event["spans"][0]["data"]["index"] == 10 + sentry_sdk.flush() + spans = [item.payload for item in items] + assert len(spans) == 2 + # The ignored span has index == 9 + assert spans[0]["attributes"]["index"] == 10 -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_record(sentry_init, span_streaming): +def test_record( + sentry_init, +): rust_tracing = FakeRustTracing() integration = RustTracingIntegration( "test_record", @@ -638,35 +417,22 @@ def test_record(sentry_init, span_streaming): sentry_init( integrations=[integration], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) + with sentry_sdk.start_span(name="custom parent"): + rust_tracing.new_span(RustTracingLevel.Info, 3) - if span_streaming: - with sentry_sdk.traces.start_span(name="custom parent"): - rust_tracing.new_span(RustTracingLevel.Info, 3) - - span_before_record = sentry_sdk.traces.get_current_span()._to_json() - assert span_before_record["attributes"]["version"] == "None" - - rust_tracing.record(3) - - span_after_record = sentry_sdk.traces.get_current_span()._to_json() - assert span_after_record["attributes"]["version"] == "memoized" - else: - with start_transaction(): - rust_tracing.new_span(RustTracingLevel.Info, 3) - - span_before_record = sentry_sdk.get_current_span().to_json() - assert span_before_record["data"]["version"] is None + span_before_record = sentry_sdk.get_current_span()._to_json() + assert span_before_record["attributes"]["version"] == "None" - rust_tracing.record(3) + rust_tracing.record(3) - span_after_record = sentry_sdk.get_current_span().to_json() - assert span_after_record["data"]["version"] == "memoized" + span_after_record = sentry_sdk.get_current_span()._to_json() + assert span_after_record["attributes"]["version"] == "memoized" -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_record_in_ignored_span(sentry_init, span_streaming): +def test_record_in_ignored_span( + sentry_init, +): def span_filter(metadata: Dict[str, object]) -> bool: # Just ignore Trace return RustTracingLevel(metadata.get("level")) != RustTracingLevel.Trace @@ -681,35 +447,19 @@ def span_filter(metadata: Dict[str, object]) -> bool: sentry_init( integrations=[integration], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) + with sentry_sdk.start_span(name="custom parent"): + rust_tracing.new_span(RustTracingLevel.Info, 3) - if span_streaming: - with sentry_sdk.traces.start_span(name="custom parent"): - rust_tracing.new_span(RustTracingLevel.Info, 3) - - span_before_record = sentry_sdk.traces.get_current_span()._to_json() - assert span_before_record["attributes"]["version"] == "None" - - rust_tracing.new_span(RustTracingLevel.Trace, 5) - rust_tracing.record(5) - - # `on_record()` should not do anything to the current Sentry span if the associated Rust span was ignored - span_after_record = sentry_sdk.traces.get_current_span()._to_json() - assert span_after_record["attributes"]["version"] == "None" - else: - with start_transaction(): - rust_tracing.new_span(RustTracingLevel.Info, 3) - - span_before_record = sentry_sdk.get_current_span().to_json() - assert span_before_record["data"]["version"] is None + span_before_record = sentry_sdk.get_current_span()._to_json() + assert span_before_record["attributes"]["version"] == "None" - rust_tracing.new_span(RustTracingLevel.Trace, 5) - rust_tracing.record(5) + rust_tracing.new_span(RustTracingLevel.Trace, 5) + rust_tracing.record(5) - # `on_record()` should not do anything to the current Sentry span if the associated Rust span was ignored - span_after_record = sentry_sdk.get_current_span().to_json() - assert span_after_record["data"]["version"] is None + # `on_record()` should not do anything to the current Sentry span if the associated Rust span was ignored + span_after_record = sentry_sdk.get_current_span()._to_json() + assert span_after_record["attributes"]["version"] == "None" @pytest.mark.parametrize( @@ -723,13 +473,11 @@ def span_filter(metadata: Dict[str, object]) -> bool: (False, None, False), ], ) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_include_tracing_fields( sentry_init, send_default_pii, include_tracing_fields, tracing_fields_expected, - span_streaming, ): rust_tracing = FakeRustTracing() integration = RustTracingIntegration( @@ -742,62 +490,36 @@ def test_include_tracing_fields( integrations=[integration], traces_sample_rate=1.0, send_default_pii=send_default_pii, - trace_lifecycle="stream" if span_streaming else "static", ) + with sentry_sdk.start_span(name="custom parent"): + rust_tracing.new_span(RustTracingLevel.Info, 3) - if span_streaming: - with sentry_sdk.traces.start_span(name="custom parent"): - rust_tracing.new_span(RustTracingLevel.Info, 3) - - span_before_record = sentry_sdk.traces.get_current_span()._to_json() - if tracing_fields_expected: - assert span_before_record["attributes"]["version"] == "None" - else: - assert span_before_record["attributes"]["version"] == "[Filtered]" - - rust_tracing.record(3) - - span_after_record = sentry_sdk.traces.get_current_span()._to_json() - - if tracing_fields_expected: - assert span_after_record["attributes"]["sentry.op"] == "function" - assert ( - span_after_record["attributes"]["sentry.origin"] - == "auto.function.rust_tracing.test_record" - ) - assert span_after_record["attributes"]["use_memoized"] is True - assert span_after_record["attributes"]["version"] == "memoized" - assert span_after_record["attributes"]["index"] == 10 - - else: - assert span_after_record["attributes"]["sentry.op"] == "function" - assert ( - span_after_record["attributes"]["sentry.origin"] - == "auto.function.rust_tracing.test_record" - ) - assert span_after_record["attributes"]["use_memoized"] == "[Filtered]" - assert span_after_record["attributes"]["version"] == "[Filtered]" - assert span_after_record["attributes"]["index"] == "[Filtered]" - else: - with start_transaction(): - rust_tracing.new_span(RustTracingLevel.Info, 3) - - span_before_record = sentry_sdk.get_current_span().to_json() - if tracing_fields_expected: - assert span_before_record["data"]["version"] is None - else: - assert span_before_record["data"]["version"] == "[Filtered]" - - rust_tracing.record(3) + span_before_record = sentry_sdk.get_current_span()._to_json() + if tracing_fields_expected: + assert span_before_record["attributes"]["version"] == "None" + else: + assert span_before_record["attributes"]["version"] == "[Filtered]" - span_after_record = sentry_sdk.get_current_span().to_json() + rust_tracing.record(3) - if tracing_fields_expected: - assert span_after_record["data"]["use_memoized"] is True - assert span_after_record["data"]["version"] == "memoized" - assert span_after_record["data"]["index"] == 10 + span_after_record = sentry_sdk.get_current_span()._to_json() - else: - assert span_after_record["data"]["use_memoized"] == "[Filtered]" - assert span_after_record["data"]["version"] == "[Filtered]" - assert span_after_record["data"]["index"] == "[Filtered]" + if tracing_fields_expected: + assert span_after_record["attributes"]["sentry.op"] == "function" + assert ( + span_after_record["attributes"]["sentry.origin"] + == "auto.function.rust_tracing.test_record" + ) + assert span_after_record["attributes"]["use_memoized"] is True + assert span_after_record["attributes"]["version"] == "memoized" + assert span_after_record["attributes"]["index"] == 10 + + else: + assert span_after_record["attributes"]["sentry.op"] == "function" + assert ( + span_after_record["attributes"]["sentry.origin"] + == "auto.function.rust_tracing.test_record" + ) + assert span_after_record["attributes"]["use_memoized"] == "[Filtered]" + assert span_after_record["attributes"]["version"] == "[Filtered]" + assert span_after_record["attributes"]["index"] == "[Filtered]" diff --git a/tests/integrations/sanic/test_sanic.py b/tests/integrations/sanic/test_sanic.py index 2d97a0ea12..6ca80edd4b 100644 --- a/tests/integrations/sanic/test_sanic.py +++ b/tests/integrations/sanic/test_sanic.py @@ -14,7 +14,7 @@ import sentry_sdk from sentry_sdk import capture_message from sentry_sdk.integrations.sanic import SanicIntegration -from sentry_sdk.tracing import TransactionSource +from sentry_sdk.traces import SegmentNameSource from tests.conftest import get_free_port from tests.integrations.utils import ( DATA_COLLECTION_REMOTE_ADDR_CASES, @@ -34,11 +34,9 @@ from typing import TYPE_CHECKING if TYPE_CHECKING: - from collections.abc import Container, Iterable from typing import Any, Optional SANIC_VERSION = tuple(map(int, SANIC_VERSION_RAW.split("."))) -PERFORMANCE_SUPPORTED = SANIC_VERSION >= (21, 9) @pytest.fixture @@ -90,7 +88,17 @@ def simple_client(app): yield app.test_client if ReusableClient is not None: - return ReusableClient(app, port=get_free_port()) + + @contextlib.contextmanager + def reusable_client(app): + client = ReusableClient(app, port=get_free_port()) + client.__enter__() + try: + yield client + finally: + client.__exit__(None, None, None) + + return reusable_client(app) else: return simple_client(app) @@ -259,7 +267,7 @@ async def task(i): "headers": {}, "version": "1.1", "method": "GET", - "transport": None, + "transport": Mock(spec=["get_extra_info"]), } if SANIC_VERSION >= (19,): @@ -346,79 +354,51 @@ class TransactionTestConfig: def __init__( self, - integration_args: "Iterable[Optional[Container[int]]]", url: str, expected_status: int, expected_transaction_name: "Optional[str]", expected_source: "Optional[str]" = None, - streaming_compatible: bool = True, ) -> None: """ expected_transaction_name of None indicates we expect to not receive a transaction """ - self.integration_args = integration_args self.url = url self.expected_status = expected_status self.expected_transaction_name = expected_transaction_name self.expected_source = expected_source - self.streaming_compatible = streaming_compatible -@pytest.mark.skipif( - not PERFORMANCE_SUPPORTED, reason="Performance not supported on this Sanic version" -) @pytest.mark.parametrize("send_pii", [True, False]) -@pytest.mark.parametrize("span_streaming", [True, False]) @pytest.mark.parametrize( "test_config", [ TransactionTestConfig( # Transaction for successful page load - integration_args=(), url="/message", expected_status=200, expected_transaction_name="hi", - expected_source=TransactionSource.COMPONENT, + expected_source=SegmentNameSource.COMPONENT, ), TransactionTestConfig( # Transaction for successful page load with query string - integration_args=(), url="/message?foo=bar", expected_status=200, expected_transaction_name="hi", - expected_source=TransactionSource.COMPONENT, + expected_source=SegmentNameSource.COMPONENT, ), TransactionTestConfig( # Transaction still recorded when we have an internal server error - integration_args=(), url="/500", expected_status=500, expected_transaction_name="fivehundred", - expected_source=TransactionSource.COMPONENT, - ), - TransactionTestConfig( - # By default, no transaction when we have a 404 error - integration_args=(), - url="/404", - expected_status=404, - expected_transaction_name=None, - streaming_compatible=False, + expected_source=SegmentNameSource.COMPONENT, ), TransactionTestConfig( - # With no ignored HTTP statuses, we should get transactions for 404 errors - integration_args=(None,), + # We should get transactions for 404 errors url="/404", expected_status=404, expected_transaction_name="/404", - expected_source=TransactionSource.URL, - ), - TransactionTestConfig( - # Transaction can be suppressed for other HTTP statuses, too, by passing config to the integration - integration_args=({200},), - url="/message", - expected_status=200, - expected_transaction_name=None, - streaming_compatible=False, + expected_source=SegmentNameSource.URL, ), ], ) @@ -426,26 +406,17 @@ def test_transactions( test_config: "TransactionTestConfig", sentry_init: "Any", app: "Any", - capture_events: "Any", capture_items: "Any", - span_streaming: bool, send_pii: bool, ) -> None: - if span_streaming and not test_config.streaming_compatible: - pytest.skip("unsampled_statuses is not supported in span streaming mode") - # Init the SanicIntegration with the desired arguments sentry_init( - integrations=[SanicIntegration(*test_config.integration_args)], + integrations=[SanicIntegration()], traces_sample_rate=1.0, send_default_pii=send_pii, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") - else: - events = capture_events() + items = capture_items("span") # Make request to the desired URL c = get_client(app) @@ -455,92 +426,57 @@ def test_transactions( sentry_sdk.flush() - if span_streaming: - segments = [ - i.payload - for i in items - if i.payload["attributes"].get("sentry.origin") == "auto.http.sanic" - and i.payload["is_segment"] - ] - assert len(segments) <= 1 - (segment, *_) = [*segments, None] - - assert (segment is None) == (test_config.expected_transaction_name is None) - - if segment is not None: - assert segment["name"] == test_config.expected_transaction_name - assert ( - segment["attributes"]["sentry.segment.name.source"] - == test_config.expected_source - ) - - attrs = segment["attributes"] - assert attrs["http.request.method"] == "GET" - assert attrs["network.protocol.name"] == "http" - header_keys = { - key[len("http.request.header.") :] - for key in attrs - if key.startswith("http.request.header.") - } - assert header_keys >= {"accept", "accept-encoding", "host", "user-agent"} - assert attrs["http.response.status_code"] == test_config.expected_status - assert segment["status"] == ( - "error" if test_config.expected_status >= 400 else "ok" - ) - - if send_pii: - assert attrs["url.full"].endswith(test_config.url) - assert attrs["url.path"] == test_config.url.split("?")[0] - if "?" in test_config.url: - assert attrs["http.query"] == test_config.url.split("?", 1)[1] - - else: - assert "url.full" not in attrs - assert "url.path" not in attrs - assert "http.query" not in attrs + segments = [ + i.payload + for i in items + if i.payload["attributes"].get("sentry.origin") == "auto.http.sanic" + and i.payload["is_segment"] + ] + assert len(segments) <= 1 + (segment, *_) = [*segments, None] - else: - # Extract the transaction events by inspecting the event types. We should at most have 1 transaction event. - transaction_events = [ - e for e in events if "type" in e and e["type"] == "transaction" - ] - assert len(transaction_events) <= 1 - - # Get the only transaction event, or set to None if there are no transaction events. - (transaction_event, *_) = [*transaction_events, None] - - # We should have no transaction event if and only if we expect no transactions - assert (transaction_event is None) == ( - test_config.expected_transaction_name is None - ) + assert (segment is None) == (test_config.expected_transaction_name is None) - # If a transaction was expected, ensure it is correct - assert ( - transaction_event is None - or transaction_event["transaction"] == test_config.expected_transaction_name - ) + if segment is not None: + assert segment["name"] == test_config.expected_transaction_name assert ( - transaction_event is None - or transaction_event["transaction_info"]["source"] + segment["attributes"]["sentry.segment.name.source"] == test_config.expected_source ) + attrs = segment["attributes"] + assert attrs["http.request.method"] == "GET" + assert attrs["network.protocol.name"] == "http" + header_keys = { + key[len("http.request.header.") :] + for key in attrs + if key.startswith("http.request.header.") + } + assert header_keys >= {"accept", "accept-encoding", "host", "user-agent"} + assert attrs["http.response.status_code"] == test_config.expected_status + assert segment["status"] == ( + "error" if test_config.expected_status >= 400 else "ok" + ) + + if send_pii: + assert attrs["url.full"].endswith(test_config.url) + assert attrs["url.path"] == test_config.url.split("?")[0] + if "?" in test_config.url: + assert attrs["http.query"] == test_config.url.split("?", 1)[1] -@pytest.mark.skipif( - not PERFORMANCE_SUPPORTED, reason="Performance not supported on this Sanic version" -) -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_span_origin(sentry_init, app, capture_events, capture_items, span_streaming): + else: + assert "url.full" not in attrs + assert "url.path" not in attrs + assert "http.query" not in attrs + + +def test_span_origin(sentry_init, app, capture_items): sentry_init( integrations=[SanicIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") - else: - events = capture_events() + items = capture_items("span") c = get_client(app) with c as client: @@ -548,21 +484,14 @@ def test_span_origin(sentry_init, app, capture_events, capture_items, span_strea sentry_sdk.flush() - if span_streaming: - (segment,) = [ - i.payload - for i in items - if i.payload["attributes"].get("sentry.origin") == "auto.http.sanic" - ] - assert segment["attributes"]["sentry.origin"] == "auto.http.sanic" - else: - (_, event) = events - assert event["contexts"]["trace"]["origin"] == "auto.http.sanic" + (segment,) = [ + i.payload + for i in items + if i.payload["attributes"].get("sentry.origin") == "auto.http.sanic" + ] + assert segment["attributes"]["sentry.origin"] == "auto.http.sanic" -@pytest.mark.skipif( - not PERFORMANCE_SUPPORTED, reason="Performance not supported on this Sanic version" -) @pytest.mark.parametrize("init_kwargs, expect_ip", DATA_COLLECTION_USER_INFO_CASES) def test_user_ip_address_on_all_spans( sentry_init, app, capture_items, init_kwargs, expect_ip @@ -571,7 +500,7 @@ def test_user_ip_address_on_all_spans( @app.route("/child-span") def child_span_handler(request): - with sentry_sdk.traces.start_span(name="child-span"): + with sentry_sdk.start_span(name="child-span"): pass return response.text("ok") @@ -579,7 +508,6 @@ def child_span_handler(request): integrations=[SanicIntegration()], default_integrations=False, traces_sample_rate=1.0, - trace_lifecycle="stream", **init_kwargs, ) @@ -604,9 +532,6 @@ def child_span_handler(request): assert "user.ip_address" not in child_span["attributes"] -@pytest.mark.skipif( - not PERFORMANCE_SUPPORTED, reason="Performance not supported on this Sanic version" -) @pytest.mark.parametrize("init_kwargs, expect_ip", DATA_COLLECTION_USER_INFO_CASES) def test_client_address_span_attribute_data_collection( sentry_init, app, capture_items, init_kwargs, expect_ip @@ -617,7 +542,6 @@ def test_client_address_span_attribute_data_collection( integrations=[SanicIntegration()], default_integrations=False, traces_sample_rate=1.0, - trace_lifecycle="stream", **init_kwargs, ) @@ -708,19 +632,15 @@ def test_client_address_span_attribute_data_collection( ] -@pytest.mark.skipif( - not PERFORMANCE_SUPPORTED, reason="Performance not supported on this Sanic version" -) @pytest.mark.parametrize( "init_kwargs, expected_query", _QUERY_PARAM_DATA_COLLECTION_CASES ) -def test_url_query_data_collection_span_streaming( +def test_url_query_data_collection( sentry_init, app, capture_items, init_kwargs, expected_query ): sentry_init( integrations=[SanicIntegration()], traces_sample_rate=1.0, - _experiments={"trace_lifecycle": "stream"}, **init_kwargs, ) diff --git a/tests/integrations/socket/test_socket.py b/tests/integrations/socket/test_socket.py index 7578d954e6..fe18355847 100644 --- a/tests/integrations/socket/test_socket.py +++ b/tests/integrations/socket/test_socket.py @@ -1,152 +1,84 @@ import socket -import pytest - import sentry_sdk -from sentry_sdk import start_transaction from sentry_sdk.integrations.socket import SocketIntegration -from tests.conftest import ApproxDict, create_mock_http_server +from tests.conftest import create_mock_http_server PORT = create_mock_http_server() -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_getaddrinfo_trace(sentry_init, capture_events, capture_items, span_streaming): +def test_getaddrinfo_trace(sentry_init, capture_items): sentry_init( integrations=[SocketIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="root"): - socket.getaddrinfo("localhost", PORT) - sentry_sdk.flush() - - spans = [item.payload for item in items] - dns_span, _root = spans - - assert dns_span["attributes"]["sentry.op"] == "socket.dns" - assert dns_span["attributes"]["sentry.origin"] == "auto.socket.socket" - assert dns_span["name"] == f"localhost:{PORT}" # noqa: E231 - assert dns_span["attributes"]["server.address"] == "localhost" - assert dns_span["attributes"]["server.port"] == PORT - else: - events = capture_events() - - with start_transaction(): - socket.getaddrinfo("localhost", PORT) - - (event,) = events - (span,) = event["spans"] - - assert span["op"] == "socket.dns" - assert span["description"] == f"localhost:{PORT}" # noqa: E231 - assert span["data"] == ApproxDict( - { - "host": "localhost", - "port": PORT, - } - ) - - -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_create_connection_trace( - sentry_init, capture_events, capture_items, span_streaming -): + items = capture_items("span") + + with sentry_sdk.start_span(name="root"): + socket.getaddrinfo("localhost", PORT) + + sentry_sdk.flush() + + spans = [item.payload for item in items] + dns_span, _root = spans + + assert dns_span["attributes"]["sentry.op"] == "socket.dns" + assert dns_span["attributes"]["sentry.origin"] == "auto.socket.socket" + assert dns_span["name"] == f"localhost:{PORT}" # noqa: E231 + assert dns_span["attributes"]["server.address"] == "localhost" + assert dns_span["attributes"]["server.port"] == PORT + + +def test_create_connection_trace(sentry_init, capture_items): timeout = 10 sentry_init( integrations=[SocketIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="root"): - socket.create_connection(("localhost", PORT), timeout, None) - sentry_sdk.flush() - - spans = [item.payload for item in items] - # as getaddrinfo gets called in create_connection it should also contain a dns span - # spans finish in order: dns (inner) ends first, connect ends, then root - dns_span, connect_span, _root = spans - - assert connect_span["attributes"]["sentry.op"] == "socket.connection" - assert connect_span["name"] == f"localhost:{PORT}" # noqa: E231 - assert connect_span["attributes"]["server.address"] == "localhost" - assert connect_span["attributes"]["server.port"] == PORT - - assert dns_span["attributes"]["sentry.op"] == "socket.dns" - assert dns_span["name"] == f"localhost:{PORT}" # noqa: E231 - assert dns_span["attributes"]["server.address"] == "localhost" - assert dns_span["attributes"]["server.port"] == PORT - else: - events = capture_events() - - with start_transaction(): - socket.create_connection(("localhost", PORT), timeout, None) - - (event,) = events - (connect_span, dns_span) = event["spans"] - # as getaddrinfo gets called in create_connection it should also contain a dns span - - assert connect_span["op"] == "socket.connection" - assert connect_span["description"] == f"localhost:{PORT}" # noqa: E231 - assert connect_span["data"] == ApproxDict( - { - "address": ["localhost", PORT], - "timeout": timeout, - "source_address": None, - } - ) - - assert dns_span["op"] == "socket.dns" - assert dns_span["description"] == f"localhost:{PORT}" # noqa: E231 - assert dns_span["data"] == ApproxDict( - { - "host": "localhost", - "port": PORT, - } - ) - - -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_span_origin(sentry_init, capture_events, capture_items, span_streaming): + items = capture_items("span") + + with sentry_sdk.start_span(name="root"): + socket.create_connection(("localhost", PORT), timeout, None) + + sentry_sdk.flush() + + spans = [item.payload for item in items] + # as getaddrinfo gets called in create_connection it should also contain a dns span + # spans finish in order: dns (inner) ends first, connect ends, then root + dns_span, connect_span, _root = spans + + assert connect_span["attributes"]["sentry.op"] == "socket.connection" + assert connect_span["name"] == f"localhost:{PORT}" # noqa: E231 + assert connect_span["attributes"]["server.address"] == "localhost" + assert connect_span["attributes"]["server.port"] == PORT + + assert dns_span["attributes"]["sentry.op"] == "socket.dns" + assert dns_span["name"] == f"localhost:{PORT}" # noqa: E231 + assert dns_span["attributes"]["server.address"] == "localhost" + assert dns_span["attributes"]["server.port"] == PORT + + +def test_span_origin(sentry_init, capture_items): sentry_init( integrations=[SocketIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="foo"): - socket.create_connection(("localhost", PORT), 1, None) - sentry_sdk.flush() - - spans = [item.payload for item in items] - dns_span, connect_span, _root = spans - - assert connect_span["attributes"]["sentry.op"] == "socket.connection" - assert connect_span["attributes"]["sentry.origin"] == "auto.socket.socket" - - assert dns_span["attributes"]["sentry.op"] == "socket.dns" - assert dns_span["attributes"]["sentry.origin"] == "auto.socket.socket" - else: - events = capture_events() + items = capture_items("span") - with start_transaction(name="foo"): - socket.create_connection(("localhost", PORT), 1, None) + with sentry_sdk.start_span(name="foo"): + socket.create_connection(("localhost", PORT), 1, None) - (event,) = events + sentry_sdk.flush() - assert event["contexts"]["trace"]["origin"] == "manual" + spans = [item.payload for item in items] + dns_span, connect_span, _root = spans - assert event["spans"][0]["op"] == "socket.connection" - assert event["spans"][0]["origin"] == "auto.socket.socket" + assert connect_span["attributes"]["sentry.op"] == "socket.connection" + assert connect_span["attributes"]["sentry.origin"] == "auto.socket.socket" - assert event["spans"][1]["op"] == "socket.dns" - assert event["spans"][1]["origin"] == "auto.socket.socket" + assert dns_span["attributes"]["sentry.op"] == "socket.dns" + assert dns_span["attributes"]["sentry.origin"] == "auto.socket.socket" diff --git a/tests/integrations/sqlalchemy/test_sqlalchemy.py b/tests/integrations/sqlalchemy/test_sqlalchemy.py index e08bb0a423..d4f0dca3aa 100644 --- a/tests/integrations/sqlalchemy/test_sqlalchemy.py +++ b/tests/integrations/sqlalchemy/test_sqlalchemy.py @@ -9,24 +9,18 @@ from sqlalchemy.orm import relationship, sessionmaker import sentry_sdk -from sentry_sdk import capture_message, start_transaction +from sentry_sdk import capture_message from sentry_sdk.consts import SPANDATA from sentry_sdk.integrations.sqlalchemy import SqlalchemyIntegration -from sentry_sdk.serializer import MAX_EVENT_BYTES from sentry_sdk.tracing_utils import record_sql_queries -from sentry_sdk.utils import json_dumps -@pytest.mark.parametrize("span_streaming", [True, False]) def test_orm_queries( sentry_init, - capture_events, capture_items, - span_streaming, ): sentry_init( integrations=[SqlalchemyIntegration()], - trace_lifecycle="stream" if span_streaming else "static", _experiments={ "record_sql_params": True, }, @@ -61,14 +55,9 @@ class Address(Base): assert session.query(Person).first() == bob - if span_streaming: - items = capture_items("event") - capture_message("hi") - (event,) = (item.payload for item in items) - else: - events = capture_events() - capture_message("hi") - (event,) = events + items = capture_items("event") + capture_message("hi") + (event,) = (item.payload for item in items) for crumb in event["breadcrumbs"]["values"]: del crumb["timestamp"] @@ -91,17 +80,13 @@ class Address(Base): ] -@pytest.mark.parametrize("span_streaming", [True, False]) def test_transactions( sentry_init, - capture_events, capture_items, render_span_tree, - span_streaming, ): sentry_init( integrations=[SqlalchemyIntegration()], - trace_lifecycle="stream" if span_streaming else "static", _experiments={ "record_sql_params": True, }, @@ -132,37 +117,36 @@ class Address(Base): Session = sessionmaker(bind=engine) # noqa: N806 session = Session() - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="custom parent"): - with session.begin_nested(): - session.query(Person).first() - - for _ in range(2): - with pytest.raises(IntegrityError): - with session.begin_nested(): - session.add(Person(id=1, name="bob")) - session.add(Person(id=1, name="bob")) - - with session.begin_nested(): - session.query(Person).first() - - sentry_sdk.flush() - spans = [item.payload for item in items] - sqlalchemy_spans = [ - span - for span in spans - if span["attributes"]["sentry.origin"] == "auto.db.sqlalchemy" - ] - for span in sqlalchemy_spans: - assert span["attributes"][SPANDATA.DB_SYSTEM_NAME] == "sqlite" - assert span["attributes"][SPANDATA.DB_DRIVER_NAME] == "pysqlite" - assert span["attributes"][SPANDATA.DB_NAMESPACE] == ":memory:" - assert SPANDATA.SERVER_PORT not in span["attributes"] - - assert ( - render_span_tree(spans) - == """\ + items = capture_items("span") + with sentry_sdk.start_span(name="custom parent"): + with session.begin_nested(): + session.query(Person).first() + + for _ in range(2): + with pytest.raises(IntegrityError): + with session.begin_nested(): + session.add(Person(id=1, name="bob")) + session.add(Person(id=1, name="bob")) + + with session.begin_nested(): + session.query(Person).first() + + sentry_sdk.flush() + spans = [item.payload for item in items] + sqlalchemy_spans = [ + span + for span in spans + if span["attributes"]["sentry.origin"] == "auto.db.sqlalchemy" + ] + for span in sqlalchemy_spans: + assert span["attributes"][SPANDATA.DB_SYSTEM_NAME] == "sqlite" + assert span["attributes"][SPANDATA.DB_DRIVER_NAME] == "pysqlite" + assert span["attributes"][SPANDATA.DB_NAMESPACE] == ":memory:" + assert SPANDATA.SERVER_PORT not in span["attributes"] + + assert ( + render_span_tree(spans) + == """\ - sentry.op=null: name="custom parent" - sentry.op="db": name="SAVEPOINT sa_savepoint_1" - sentry.op="db": name="SELECT person.id AS person_id, person.name AS person_name \\nFROM person\\n LIMIT ? OFFSET ?" @@ -177,61 +161,15 @@ class Address(Base): - sentry.op="db": name="SELECT person.id AS person_id, person.name AS person_name \\nFROM person\\n LIMIT ? OFFSET ?" - sentry.op="db": name="RELEASE SAVEPOINT sa_savepoint_4"\ """ - ) - else: - events = capture_events() - with start_transaction(name="test_transaction", sampled=True): - with session.begin_nested(): - session.query(Person).first() - - for _ in range(2): - with pytest.raises(IntegrityError): - with session.begin_nested(): - session.add(Person(id=1, name="bob")) - session.add(Person(id=1, name="bob")) - - with session.begin_nested(): - session.query(Person).first() - - (event,) = events - - for span in event["spans"]: - assert span["data"][SPANDATA.DB_SYSTEM] == "sqlite" - assert span["data"][SPANDATA.DB_DRIVER_NAME] == "pysqlite" - assert span["data"][SPANDATA.DB_NAME] == ":memory:" - assert SPANDATA.SERVER_ADDRESS not in span["data"] - assert SPANDATA.SERVER_PORT not in span["data"] - - assert ( - render_span_tree(event["spans"], event["contexts"]["trace"]) - == """\ -- op=null: description=null - - op="db": description="SAVEPOINT sa_savepoint_1" - - op="db": description="SELECT person.id AS person_id, person.name AS person_name \\nFROM person\\n LIMIT ? OFFSET ?" - - op="db": description="RELEASE SAVEPOINT sa_savepoint_1" - - op="db": description="SAVEPOINT sa_savepoint_2" - - op="db": description="INSERT INTO person (id, name) VALUES (?, ?)" - - op="db": description="ROLLBACK TO SAVEPOINT sa_savepoint_2" - - op="db": description="SAVEPOINT sa_savepoint_3" - - op="db": description="INSERT INTO person (id, name) VALUES (?, ?)" - - op="db": description="ROLLBACK TO SAVEPOINT sa_savepoint_3" - - op="db": description="SAVEPOINT sa_savepoint_4" - - op="db": description="SELECT person.id AS person_id, person.name AS person_name \\nFROM person\\n LIMIT ? OFFSET ?" - - op="db": description="RELEASE SAVEPOINT sa_savepoint_4"\ -""" - ) + ) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_transactions_no_engine_url( sentry_init, - capture_events, capture_items, - span_streaming, ): sentry_init( integrations=[SqlalchemyIntegration()], - trace_lifecycle="stream" if span_streaming else "static", _experiments={ "record_sql_params": True, }, @@ -263,169 +201,63 @@ class Address(Base): Session = sessionmaker(bind=engine) # noqa: N806 session = Session() - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="custom parent"): - with session.begin_nested(): - session.query(Person).first() - - for _ in range(2): - with pytest.raises(IntegrityError): - with session.begin_nested(): - session.add(Person(id=1, name="bob")) - session.add(Person(id=1, name="bob")) - - with session.begin_nested(): - session.query(Person).first() - - sentry_sdk.flush() - spans = [item.payload for item in items] - sqlalchemy_spans = [ - span - for span in spans - if span["attributes"]["sentry.origin"] == "auto.db.sqlalchemy" - ] - for span in sqlalchemy_spans: - assert span["attributes"][SPANDATA.DB_SYSTEM_NAME] == "sqlite" - assert span["attributes"][SPANDATA.DB_DRIVER_NAME] == "pysqlite" - assert SPANDATA.DB_NAME not in span["attributes"] - assert SPANDATA.SERVER_PORT not in span["attributes"] - else: - events = capture_events() - with start_transaction(name="test_transaction", sampled=True): - with session.begin_nested(): - session.query(Person).first() - - for _ in range(2): - with pytest.raises(IntegrityError): - with session.begin_nested(): - session.add(Person(id=1, name="bob")) - session.add(Person(id=1, name="bob")) - - with session.begin_nested(): - session.query(Person).first() - - (event,) = events - for span in event["spans"]: - assert span["data"][SPANDATA.DB_SYSTEM] == "sqlite" - assert span["data"][SPANDATA.DB_DRIVER_NAME] == "pysqlite" - assert SPANDATA.DB_NAME not in span["data"] - assert SPANDATA.SERVER_ADDRESS not in span["data"] - assert SPANDATA.SERVER_PORT not in span["data"] - - -@pytest.mark.parametrize("span_streaming", [True, False]) + items = capture_items("span") + with sentry_sdk.start_span(name="custom parent"): + with session.begin_nested(): + session.query(Person).first() + + for _ in range(2): + with pytest.raises(IntegrityError): + with session.begin_nested(): + session.add(Person(id=1, name="bob")) + session.add(Person(id=1, name="bob")) + + with session.begin_nested(): + session.query(Person).first() + + sentry_sdk.flush() + spans = [item.payload for item in items] + sqlalchemy_spans = [ + span + for span in spans + if span["attributes"]["sentry.origin"] == "auto.db.sqlalchemy" + ] + for span in sqlalchemy_spans: + assert span["attributes"][SPANDATA.DB_SYSTEM_NAME] == "sqlite" + assert span["attributes"][SPANDATA.DB_DRIVER_NAME] == "pysqlite" + assert SPANDATA.DB_NAME not in span["attributes"] + assert SPANDATA.SERVER_PORT not in span["attributes"] + + def test_long_sql_query_preserved( sentry_init, - capture_events, capture_items, - span_streaming, ): sentry_init( traces_sample_rate=1, integrations=[SqlalchemyIntegration()], - trace_lifecycle="stream" if span_streaming else "static", - ) - - engine = create_engine( - "sqlite:///:memory:", connect_args={"check_same_thread": False} - ) - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="custom parent"): - with engine.connect() as con: - con.execute( - text(" UNION ".join("SELECT {}".format(i) for i in range(100))) - ) - - sentry_sdk.flush() - spans = [item.payload for item in items] - name = spans[0]["name"] - assert name.startswith("SELECT 0 UNION SELECT 1") - assert name.endswith("SELECT 98 UNION SELECT 99") - else: - events = capture_events() - with start_transaction(name="test"): - with engine.connect() as con: - con.execute( - text(" UNION ".join("SELECT {}".format(i) for i in range(100))) - ) - - (event,) = events - description = event["spans"][0]["description"] - assert description.startswith("SELECT 0 UNION SELECT 1") - assert description.endswith("SELECT 98 UNION SELECT 99") - - -@pytest.mark.parametrize("max_value_length", [1024, None]) -def test_large_event_not_truncated(sentry_init, capture_events, max_value_length): - sentry_init( - traces_sample_rate=1, - integrations=[SqlalchemyIntegration()], - max_value_length=max_value_length, ) - events = capture_events() - - long_str = "x" * (1034) - - scope = sentry_sdk.get_isolation_scope() - - @scope.add_event_processor - def processor(event, hint): - event["message"] = long_str - return event engine = create_engine( "sqlite:///:memory:", connect_args={"check_same_thread": False} ) - with start_transaction(name="test"): + items = capture_items("span") + with sentry_sdk.start_span(name="custom parent"): with engine.connect() as con: - for _ in range(1500): - con.execute( - text(" UNION ".join("SELECT {}".format(i) for i in range(100))) - ) - - (event,) = events - - assert len(json_dumps(event)) > MAX_EVENT_BYTES - - # Some spans are discarded. - assert len(event["spans"]) == 1000 - - # Span descriptions are not truncated. - description = event["spans"][0]["description"] - assert len(description) == 1583 - assert description.startswith("SELECT 0") - assert description.endswith("SELECT 98 UNION SELECT 99") - - description = event["spans"][999]["description"] - assert len(description) == 1583 - assert description.startswith("SELECT 0") - assert description.endswith("SELECT 98 UNION SELECT 99") - - if max_value_length: - # Smoke check that truncation of other fields has not changed. - assert len(event["message"]) == 1024 - - # The _meta for other truncated fields should be there as well. - assert event["_meta"]["message"] == { - "": { - "len": 1034, - "rem": [["!limit", "x", 1021, 1024]], - } - } - else: - assert len(event["message"]) == 1034 + con.execute(text(" UNION ".join("SELECT {}".format(i) for i in range(100)))) + + sentry_sdk.flush() + spans = [item.payload for item in items] + name = spans[0]["name"] + assert name.startswith("SELECT 0 UNION SELECT 1") + assert name.endswith("SELECT 98 UNION SELECT 99") -@pytest.mark.parametrize("span_streaming", [True, False]) def test_engine_name_not_string( sentry_init, - span_streaming, ): sentry_init( integrations=[SqlalchemyIntegration()], - trace_lifecycle="stream" if span_streaming else "static", ) engine = create_engine( @@ -437,118 +269,69 @@ def test_engine_name_not_string( con.execute(text("SELECT 0")) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_query_source_disabled( sentry_init, - capture_events, capture_items, - span_streaming, ): sentry_options = { "integrations": [SqlalchemyIntegration()], "traces_sample_rate": 1.0, "enable_db_query_source": False, "db_query_source_threshold_ms": 0, - "trace_lifecycle": "stream" if span_streaming else "static", } sentry_init(**sentry_options) - if span_streaming: - items = capture_items("span") + items = capture_items("span") - with sentry_sdk.traces.start_span(name="custom parent"): - Base = declarative_base() # noqa: N806 + with sentry_sdk.start_span(name="custom parent"): + Base = declarative_base() # noqa: N806 - class Person(Base): - __tablename__ = "person" - id = Column(Integer, primary_key=True) - name = Column(String(250), nullable=False) + class Person(Base): + __tablename__ = "person" + id = Column(Integer, primary_key=True) + name = Column(String(250), nullable=False) - engine = create_engine( - "sqlite:///:memory:", connect_args={"check_same_thread": False} - ) - Base.metadata.create_all(engine) + engine = create_engine( + "sqlite:///:memory:", connect_args={"check_same_thread": False} + ) + Base.metadata.create_all(engine) - Session = sessionmaker(bind=engine) # noqa: N806 - session = Session() + Session = sessionmaker(bind=engine) # noqa: N806 + session = Session() - bob = Person(name="Bob") - session.add(bob) + bob = Person(name="Bob") + session.add(bob) - assert session.query(Person).first() == bob + assert session.query(Person).first() == bob - sentry_sdk.flush() - spans = [item.payload for item in items] - for span in spans: - if span["attributes"].get("sentry.op") == "db" and span["name"].startswith( - "SELECT person" - ): - attributes = span["attributes"] - - assert SPANDATA.CODE_LINE_NUMBER not in attributes - assert SPANDATA.CODE_NAMESPACE not in attributes - assert SPANDATA.CODE_FILE_PATH not in attributes - assert SPANDATA.CODE_FUNCTION not in attributes - break - else: - raise AssertionError("No db span found") + sentry_sdk.flush() + spans = [item.payload for item in items] + for span in spans: + if span["attributes"].get("sentry.op") == "db" and span["name"].startswith( + "SELECT person" + ): + attributes = span["attributes"] + assert SPANDATA.CODE_LINE_NUMBER not in attributes + assert SPANDATA.CODE_NAMESPACE not in attributes + assert SPANDATA.CODE_FILE_PATH not in attributes + assert SPANDATA.CODE_FUNCTION not in attributes + break else: - events = capture_events() - - with start_transaction(name="test_transaction", sampled=True): - Base = declarative_base() # noqa: N806 - - class Person(Base): - __tablename__ = "person" - id = Column(Integer, primary_key=True) - name = Column(String(250), nullable=False) - - engine = create_engine( - "sqlite:///:memory:", connect_args={"check_same_thread": False} - ) - Base.metadata.create_all(engine) - - Session = sessionmaker(bind=engine) # noqa: N806 - session = Session() - - bob = Person(name="Bob") - session.add(bob) - - assert session.query(Person).first() == bob - - (event,) = events - - for span in event["spans"]: - if span.get("op") == "db" and span.get("description").startswith( - "SELECT person" - ): - data = span.get("data", {}) - - assert SPANDATA.CODE_LINENO not in data - assert SPANDATA.CODE_NAMESPACE not in data - assert SPANDATA.CODE_FILEPATH not in data - assert SPANDATA.CODE_FUNCTION not in data - break - else: - raise AssertionError("No db span found") + raise AssertionError("No db span found") @pytest.mark.parametrize("enable_db_query_source", [None, True]) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_query_source_enabled( sentry_init, - capture_events, capture_items, enable_db_query_source, - span_streaming, ): sentry_options = { "integrations": [SqlalchemyIntegration()], "traces_sample_rate": 1.0, "db_query_source_threshold_ms": 0, - "trace_lifecycle": "stream" if span_streaming else "static", } if enable_db_query_source is not None: @@ -556,216 +339,114 @@ def test_query_source_enabled( sentry_init(**sentry_options) - if span_streaming: - items = capture_items("span") + items = capture_items("span") - with sentry_sdk.traces.start_span(name="custom parent"): - Base = declarative_base() # noqa: N806 - - class Person(Base): - __tablename__ = "person" - id = Column(Integer, primary_key=True) - name = Column(String(250), nullable=False) - - engine = create_engine( - "sqlite:///:memory:", connect_args={"check_same_thread": False} - ) - Base.metadata.create_all(engine) + with sentry_sdk.start_span(name="custom parent"): + Base = declarative_base() # noqa: N806 - Session = sessionmaker(bind=engine) # noqa: N806 - session = Session() + class Person(Base): + __tablename__ = "person" + id = Column(Integer, primary_key=True) + name = Column(String(250), nullable=False) - bob = Person(name="Bob") - session.add(bob) - - assert session.query(Person).first() == bob - - sentry_sdk.flush() - spans = [item.payload for item in items] - for span in spans: - if span["attributes"].get("sentry.op") == "db" and span["name"].startswith( - "SELECT person" - ): - attributes = span["attributes"] - - assert SPANDATA.CODE_LINE_NUMBER in attributes - assert SPANDATA.CODE_NAMESPACE in attributes - assert SPANDATA.CODE_FILE_PATH in attributes - assert SPANDATA.CODE_FUNCTION in attributes - break - else: - raise AssertionError("No db span found") - else: - events = capture_events() - - with start_transaction(name="test_transaction", sampled=True): - Base = declarative_base() # noqa: N806 - - class Person(Base): - __tablename__ = "person" - id = Column(Integer, primary_key=True) - name = Column(String(250), nullable=False) - - engine = create_engine( - "sqlite:///:memory:", connect_args={"check_same_thread": False} - ) - Base.metadata.create_all(engine) - - Session = sessionmaker(bind=engine) # noqa: N806 - session = Session() + engine = create_engine( + "sqlite:///:memory:", connect_args={"check_same_thread": False} + ) + Base.metadata.create_all(engine) - bob = Person(name="Bob") - session.add(bob) + Session = sessionmaker(bind=engine) # noqa: N806 + session = Session() - assert session.query(Person).first() == bob + bob = Person(name="Bob") + session.add(bob) - (event,) = events + assert session.query(Person).first() == bob - for span in event["spans"]: - if span.get("op") == "db" and span.get("description").startswith( - "SELECT person" - ): - data = span.get("data", {}) + sentry_sdk.flush() + spans = [item.payload for item in items] + for span in spans: + if span["attributes"].get("sentry.op") == "db" and span["name"].startswith( + "SELECT person" + ): + attributes = span["attributes"] - assert SPANDATA.CODE_LINENO in data - assert SPANDATA.CODE_NAMESPACE in data - assert SPANDATA.CODE_FILEPATH in data - assert SPANDATA.CODE_FUNCTION in data - break - else: - raise AssertionError("No db span found") + assert SPANDATA.CODE_LINE_NUMBER in attributes + assert SPANDATA.CODE_NAMESPACE in attributes + assert SPANDATA.CODE_FILE_PATH in attributes + assert SPANDATA.CODE_FUNCTION in attributes + break + else: + raise AssertionError("No db span found") -@pytest.mark.parametrize("span_streaming", [True, False]) def test_query_source( sentry_init, - capture_events, capture_items, - span_streaming, ): sentry_init( integrations=[SqlalchemyIntegration()], traces_sample_rate=1.0, enable_db_query_source=True, db_query_source_threshold_ms=0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") + items = capture_items("span") - with sentry_sdk.traces.start_span(name="custom parent"): - Base = declarative_base() # noqa: N806 + with sentry_sdk.start_span(name="custom parent"): + Base = declarative_base() # noqa: N806 - class Person(Base): - __tablename__ = "person" - id = Column(Integer, primary_key=True) - name = Column(String(250), nullable=False) + class Person(Base): + __tablename__ = "person" + id = Column(Integer, primary_key=True) + name = Column(String(250), nullable=False) - engine = create_engine( - "sqlite:///:memory:", connect_args={"check_same_thread": False} + engine = create_engine( + "sqlite:///:memory:", connect_args={"check_same_thread": False} + ) + Base.metadata.create_all(engine) + + Session = sessionmaker(bind=engine) # noqa: N806 + session = Session() + + bob = Person(name="Bob") + session.add(bob) + + assert session.query(Person).first() == bob + + sentry_sdk.flush() + spans = [item.payload for item in items] + for span in spans: + if span["attributes"].get("sentry.op") == "db" and span["name"].startswith( + "SELECT person" + ): + attributes = span["attributes"] + + assert SPANDATA.CODE_LINE_NUMBER in attributes + assert SPANDATA.CODE_NAMESPACE in attributes + assert SPANDATA.CODE_FILE_PATH in attributes + assert SPANDATA.CODE_FUNCTION in attributes + + assert type(attributes.get(SPANDATA.CODE_LINE_NUMBER)) == int + assert attributes.get(SPANDATA.CODE_LINE_NUMBER) > 0 + assert ( + attributes.get(SPANDATA.CODE_NAMESPACE) + == "tests.integrations.sqlalchemy.test_sqlalchemy" ) - Base.metadata.create_all(engine) - - Session = sessionmaker(bind=engine) # noqa: N806 - session = Session() - - bob = Person(name="Bob") - session.add(bob) - - assert session.query(Person).first() == bob - - sentry_sdk.flush() - spans = [item.payload for item in items] - for span in spans: - if span["attributes"].get("sentry.op") == "db" and span["name"].startswith( - "SELECT person" - ): - attributes = span["attributes"] - - assert SPANDATA.CODE_LINE_NUMBER in attributes - assert SPANDATA.CODE_NAMESPACE in attributes - assert SPANDATA.CODE_FILE_PATH in attributes - assert SPANDATA.CODE_FUNCTION in attributes - - assert type(attributes.get(SPANDATA.CODE_LINE_NUMBER)) == int - assert attributes.get(SPANDATA.CODE_LINE_NUMBER) > 0 - assert ( - attributes.get(SPANDATA.CODE_NAMESPACE) - == "tests.integrations.sqlalchemy.test_sqlalchemy" - ) - assert attributes.get(SPANDATA.CODE_FILE_PATH).endswith( - "tests/integrations/sqlalchemy/test_sqlalchemy.py" - ) - - is_relative_path = attributes.get(SPANDATA.CODE_FILE_PATH)[0] != os.sep - assert is_relative_path - - assert attributes.get(SPANDATA.CODE_FUNCTION) == "test_query_source" - break - else: - raise AssertionError("No db span found") - else: - events = capture_events() - - with start_transaction(name="test_transaction", sampled=True): - Base = declarative_base() # noqa: N806 - - class Person(Base): - __tablename__ = "person" - id = Column(Integer, primary_key=True) - name = Column(String(250), nullable=False) - - engine = create_engine( - "sqlite:///:memory:", connect_args={"check_same_thread": False} + assert attributes.get(SPANDATA.CODE_FILE_PATH).endswith( + "tests/integrations/sqlalchemy/test_sqlalchemy.py" ) - Base.metadata.create_all(engine) - - Session = sessionmaker(bind=engine) # noqa: N806 - session = Session() - - bob = Person(name="Bob") - session.add(bob) - - assert session.query(Person).first() == bob - - (event,) = events - - for span in event["spans"]: - if span.get("op") == "db" and span.get("description").startswith( - "SELECT person" - ): - data = span.get("data", {}) - - assert SPANDATA.CODE_LINENO in data - assert SPANDATA.CODE_NAMESPACE in data - assert SPANDATA.CODE_FILEPATH in data - assert SPANDATA.CODE_FUNCTION in data - assert type(data.get(SPANDATA.CODE_LINENO)) == int - assert data.get(SPANDATA.CODE_LINENO) > 0 - assert ( - data.get(SPANDATA.CODE_NAMESPACE) - == "tests.integrations.sqlalchemy.test_sqlalchemy" - ) - assert data.get(SPANDATA.CODE_FILEPATH).endswith( - "tests/integrations/sqlalchemy/test_sqlalchemy.py" - ) + is_relative_path = attributes.get(SPANDATA.CODE_FILE_PATH)[0] != os.sep + assert is_relative_path - is_relative_path = data.get(SPANDATA.CODE_FILEPATH)[0] != os.sep - assert is_relative_path - - assert data.get(SPANDATA.CODE_FUNCTION) == "test_query_source" - break - else: - raise AssertionError("No db span found") + assert attributes.get(SPANDATA.CODE_FUNCTION) == "test_query_source" + break + else: + raise AssertionError("No db span found") -@pytest.mark.parametrize("span_streaming", [True, False]) def test_query_source_with_module_in_search_path( sentry_init, - capture_events, capture_items, - span_streaming, ): """ Test that query source is relative to the path of the module it ran in @@ -775,7 +456,6 @@ def test_query_source_with_module_in_search_path( traces_sample_rate=1.0, enable_db_query_source=True, db_query_source_threshold_ms=0, - trace_lifecycle="stream" if span_streaming else "static", ) from sqlalchemy_helpers.helpers import ( @@ -783,449 +463,238 @@ def test_query_source_with_module_in_search_path( query_first_model_from_session, ) - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="custom parent"): - Base = declarative_base() # noqa: N806 - - class Person(Base): - __tablename__ = "person" - id = Column(Integer, primary_key=True) - name = Column(String(250), nullable=False) - - engine = create_engine( - "sqlite:///:memory:", connect_args={"check_same_thread": False} - ) - Base.metadata.create_all(engine) - - Session = sessionmaker(bind=engine) # noqa: N806 - session = Session() - - bob = Person(name="Bob") - - add_model_to_session(bob, session) - - assert query_first_model_from_session(Person, session) == bob - - sentry_sdk.flush() - spans = [item.payload for item in items] - for span in spans: - if span["attributes"].get("sentry.op") == "db" and span["name"].startswith( - "SELECT person" - ): - attributes = span["attributes"] - - assert SPANDATA.CODE_LINE_NUMBER in attributes - assert SPANDATA.CODE_NAMESPACE in attributes - assert SPANDATA.CODE_FILE_PATH in attributes - assert SPANDATA.CODE_FUNCTION in attributes - - assert type(attributes.get(SPANDATA.CODE_LINE_NUMBER)) == int - assert attributes.get(SPANDATA.CODE_LINE_NUMBER) > 0 - assert ( - attributes.get(SPANDATA.CODE_NAMESPACE) - == "sqlalchemy_helpers.helpers" - ) - assert ( - attributes.get(SPANDATA.CODE_FILE_PATH) - == "sqlalchemy_helpers/helpers.py" - ) - - is_relative_path = attributes.get(SPANDATA.CODE_FILE_PATH)[0] != os.sep - assert is_relative_path - - assert ( - attributes.get(SPANDATA.CODE_FUNCTION) - == "query_first_model_from_session" - ) - break - else: - raise AssertionError("No db span found") - else: - events = capture_events() - with start_transaction(name="test_transaction", sampled=True): - Base = declarative_base() # noqa: N806 + items = capture_items("span") + with sentry_sdk.start_span(name="custom parent"): + Base = declarative_base() # noqa: N806 - class Person(Base): - __tablename__ = "person" - id = Column(Integer, primary_key=True) - name = Column(String(250), nullable=False) - - engine = create_engine( - "sqlite:///:memory:", connect_args={"check_same_thread": False} - ) - Base.metadata.create_all(engine) + class Person(Base): + __tablename__ = "person" + id = Column(Integer, primary_key=True) + name = Column(String(250), nullable=False) - Session = sessionmaker(bind=engine) # noqa: N806 - session = Session() + engine = create_engine( + "sqlite:///:memory:", connect_args={"check_same_thread": False} + ) + Base.metadata.create_all(engine) - bob = Person(name="Bob") + Session = sessionmaker(bind=engine) # noqa: N806 + session = Session() - add_model_to_session(bob, session) + bob = Person(name="Bob") - assert query_first_model_from_session(Person, session) == bob + add_model_to_session(bob, session) - (event,) = events + assert query_first_model_from_session(Person, session) == bob - for span in event["spans"]: - if span.get("op") == "db" and span.get("description").startswith( - "SELECT person" - ): - data = span.get("data", {}) + sentry_sdk.flush() + spans = [item.payload for item in items] + for span in spans: + if span["attributes"].get("sentry.op") == "db" and span["name"].startswith( + "SELECT person" + ): + attributes = span["attributes"] - assert SPANDATA.CODE_LINENO in data - assert SPANDATA.CODE_NAMESPACE in data - assert SPANDATA.CODE_FILEPATH in data - assert SPANDATA.CODE_FUNCTION in data + assert SPANDATA.CODE_LINE_NUMBER in attributes + assert SPANDATA.CODE_NAMESPACE in attributes + assert SPANDATA.CODE_FILE_PATH in attributes + assert SPANDATA.CODE_FUNCTION in attributes - assert type(data.get(SPANDATA.CODE_LINENO)) == int - assert data.get(SPANDATA.CODE_LINENO) > 0 - assert data.get(SPANDATA.CODE_NAMESPACE) == "sqlalchemy_helpers.helpers" - assert ( - data.get(SPANDATA.CODE_FILEPATH) == "sqlalchemy_helpers/helpers.py" - ) + assert type(attributes.get(SPANDATA.CODE_LINE_NUMBER)) == int + assert attributes.get(SPANDATA.CODE_LINE_NUMBER) > 0 + assert ( + attributes.get(SPANDATA.CODE_NAMESPACE) == "sqlalchemy_helpers.helpers" + ) + assert ( + attributes.get(SPANDATA.CODE_FILE_PATH) + == "sqlalchemy_helpers/helpers.py" + ) - is_relative_path = data.get(SPANDATA.CODE_FILEPATH)[0] != os.sep - assert is_relative_path + is_relative_path = attributes.get(SPANDATA.CODE_FILE_PATH)[0] != os.sep + assert is_relative_path - assert ( - data.get(SPANDATA.CODE_FUNCTION) == "query_first_model_from_session" - ) - break - else: - raise AssertionError("No db span found") + assert ( + attributes.get(SPANDATA.CODE_FUNCTION) + == "query_first_model_from_session" + ) + break + else: + raise AssertionError("No db span found") -@pytest.mark.parametrize("span_streaming", [True, False]) def test_no_query_source_if_duration_too_short( sentry_init, - capture_events, capture_items, - span_streaming, ): sentry_init( integrations=[SqlalchemyIntegration()], traces_sample_rate=1.0, enable_db_query_source=True, db_query_source_threshold_ms=100, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") - - with sentry_sdk.traces.start_span(name="custom parent"): - Base = declarative_base() # noqa: N806 + items = capture_items("span") - class Person(Base): - __tablename__ = "person" - id = Column(Integer, primary_key=True) - name = Column(String(250), nullable=False) + with sentry_sdk.start_span(name="custom parent"): + Base = declarative_base() # noqa: N806 - engine = create_engine( - "sqlite:///:memory:", connect_args={"check_same_thread": False} - ) - Base.metadata.create_all(engine) - - Session = sessionmaker(bind=engine) # noqa: N806 - session = Session() - - bob = Person(name="Bob") - session.add(bob) - - class fake_record_sql_queries: # noqa: N801 - def __init__(self, *args, **kwargs): - self._ctx_mgr = record_sql_queries(*args, **kwargs) - - def __enter__(self): - self.span = self._ctx_mgr.__enter__() - self.span._start_timestamp = datetime(2024, 1, 1, microsecond=0) - self.span._end_timestamp = datetime(2024, 1, 1, microsecond=99999) - return self.span - - def __exit__(self, type, value, traceback): - self.span._end_timestamp = None - self._ctx_mgr.__exit__(type, value, traceback) - - with mock.patch( - "sentry_sdk.integrations.sqlalchemy.record_sql_queries", - fake_record_sql_queries, - ): - assert session.query(Person).first() == bob - - sentry_sdk.flush() - spans = [item.payload for item in items] - for span in spans: - if span["attributes"].get("sentry.op") == "db" and span["name"].startswith( - "SELECT person" - ): - attributes = span["attributes"] - - assert SPANDATA.CODE_LINE_NUMBER not in attributes - assert SPANDATA.CODE_NAMESPACE not in attributes - assert SPANDATA.CODE_FILE_PATH not in attributes - assert SPANDATA.CODE_FUNCTION not in attributes - break - else: - raise AssertionError("No db span found") + class Person(Base): + __tablename__ = "person" + id = Column(Integer, primary_key=True) + name = Column(String(250), nullable=False) - else: - events = capture_events() - - with start_transaction(name="test_transaction", sampled=True): - Base = declarative_base() # noqa: N806 - - class Person(Base): - __tablename__ = "person" - id = Column(Integer, primary_key=True) - name = Column(String(250), nullable=False) - - engine = create_engine( - "sqlite:///:memory:", connect_args={"check_same_thread": False} - ) - Base.metadata.create_all(engine) - - Session = sessionmaker(bind=engine) # noqa: N806 - session = Session() - - bob = Person(name="Bob") - session.add(bob) + engine = create_engine( + "sqlite:///:memory:", connect_args={"check_same_thread": False} + ) + Base.metadata.create_all(engine) - class fake_record_sql_queries: # noqa: N801 - def __init__(self, *args, **kwargs): - self._ctx_mgr = record_sql_queries(*args, **kwargs) + Session = sessionmaker(bind=engine) # noqa: N806 + session = Session() - def __enter__(self): - self.span = self._ctx_mgr.__enter__() - self.span.start_timestamp = datetime(2024, 1, 1, microsecond=0) - return self.span + bob = Person(name="Bob") + session.add(bob) - def __exit__(self, type, value, traceback): - self._ctx_mgr.__exit__(type, value, traceback) - self.span.timestamp = datetime(2024, 1, 1, microsecond=99999) + class fake_record_sql_queries: # noqa: N801 + def __init__(self, *args, **kwargs): + self._ctx_mgr = record_sql_queries(*args, **kwargs) - with mock.patch( - "sentry_sdk.integrations.sqlalchemy.record_sql_queries", - fake_record_sql_queries, - ): - assert session.query(Person).first() == bob + def __enter__(self): + self.span = self._ctx_mgr.__enter__() + self.span._start_timestamp = datetime(2024, 1, 1, microsecond=0) + self.span._end_timestamp = datetime(2024, 1, 1, microsecond=99999) + return self.span - (event,) = events + def __exit__(self, type, value, traceback): + self.span._end_timestamp = None + self._ctx_mgr.__exit__(type, value, traceback) - for span in event["spans"]: - if span.get("op") == "db" and span.get("description").startswith( - "SELECT person" - ): - data = span.get("data", {}) + with mock.patch( + "sentry_sdk.integrations.sqlalchemy.record_sql_queries", + fake_record_sql_queries, + ): + assert session.query(Person).first() == bob - assert SPANDATA.CODE_LINENO not in data - assert SPANDATA.CODE_NAMESPACE not in data - assert SPANDATA.CODE_FILEPATH not in data - assert SPANDATA.CODE_FUNCTION not in data - break - else: - raise AssertionError("No db span found") + sentry_sdk.flush() + spans = [item.payload for item in items] + for span in spans: + if span["attributes"].get("sentry.op") == "db" and span["name"].startswith( + "SELECT person" + ): + attributes = span["attributes"] + + assert SPANDATA.CODE_LINE_NUMBER not in attributes + assert SPANDATA.CODE_NAMESPACE not in attributes + assert SPANDATA.CODE_FILE_PATH not in attributes + assert SPANDATA.CODE_FUNCTION not in attributes + break + else: + raise AssertionError("No db span found") -@pytest.mark.parametrize("span_streaming", [True, False]) def test_query_source_if_duration_over_threshold( sentry_init, - capture_events, capture_items, - span_streaming, ): sentry_init( integrations=[SqlalchemyIntegration()], traces_sample_rate=1.0, enable_db_query_source=True, db_query_source_threshold_ms=100, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") + items = capture_items("span") - with sentry_sdk.traces.start_span(name="custom parent"): - Base = declarative_base() # noqa: N806 + with sentry_sdk.start_span(name="custom parent"): + Base = declarative_base() # noqa: N806 - class Person(Base): - __tablename__ = "person" - id = Column(Integer, primary_key=True) - name = Column(String(250), nullable=False) + class Person(Base): + __tablename__ = "person" + id = Column(Integer, primary_key=True) + name = Column(String(250), nullable=False) - engine = create_engine( - "sqlite:///:memory:", connect_args={"check_same_thread": False} - ) - Base.metadata.create_all(engine) - - Session = sessionmaker(bind=engine) # noqa: N806 - session = Session() - - bob = Person(name="Bob") - session.add(bob) - - class fake_record_sql_queries: # noqa: N801 - def __init__(self, *args, **kwargs): - self._ctx_mgr = record_sql_queries(*args, **kwargs) - - def __enter__(self): - self.span = self._ctx_mgr.__enter__() - self.span._start_timestamp = datetime(2024, 1, 1, microsecond=0) - self.span._end_timestamp = datetime(2024, 1, 1, microsecond=101000) - return self.span - - def __exit__(self, type, value, traceback): - self.span._end_timestamp = None - self._ctx_mgr.__exit__(type, value, traceback) - - with mock.patch( - "sentry_sdk.integrations.sqlalchemy.record_sql_queries", - fake_record_sql_queries, - ): - assert session.query(Person).first() == bob - - sentry_sdk.flush() - spans = [item.payload for item in items] - for span in spans: - if span["attributes"].get("sentry.op") == "db" and span["name"].startswith( - "SELECT person" - ): - attributes = span["attributes"] - - assert SPANDATA.CODE_LINE_NUMBER in attributes - assert SPANDATA.CODE_NAMESPACE in attributes - assert SPANDATA.CODE_FILE_PATH in attributes - assert SPANDATA.CODE_FUNCTION in attributes - - assert type(attributes.get(SPANDATA.CODE_LINE_NUMBER)) == int - assert attributes.get(SPANDATA.CODE_LINE_NUMBER) > 0 - assert ( - attributes.get(SPANDATA.CODE_NAMESPACE) - == "tests.integrations.sqlalchemy.test_sqlalchemy" - ) - assert attributes.get(SPANDATA.CODE_FILE_PATH).endswith( - "tests/integrations/sqlalchemy/test_sqlalchemy.py" - ) - - is_relative_path = attributes.get(SPANDATA.CODE_FILE_PATH)[0] != os.sep - assert is_relative_path - - assert ( - attributes.get(SPANDATA.CODE_FUNCTION) - == "test_query_source_if_duration_over_threshold" - ) - break - else: - raise AssertionError("No db span found") - else: - events = capture_events() + engine = create_engine( + "sqlite:///:memory:", connect_args={"check_same_thread": False} + ) + Base.metadata.create_all(engine) + + Session = sessionmaker(bind=engine) # noqa: N806 + session = Session() + + bob = Person(name="Bob") + session.add(bob) - with start_transaction(name="test_transaction", sampled=True): - Base = declarative_base() # noqa: N806 + class fake_record_sql_queries: # noqa: N801 + def __init__(self, *args, **kwargs): + self._ctx_mgr = record_sql_queries(*args, **kwargs) - class Person(Base): - __tablename__ = "person" - id = Column(Integer, primary_key=True) - name = Column(String(250), nullable=False) + def __enter__(self): + self.span = self._ctx_mgr.__enter__() + self.span._start_timestamp = datetime(2024, 1, 1, microsecond=0) + self.span._end_timestamp = datetime(2024, 1, 1, microsecond=101000) + return self.span - engine = create_engine( - "sqlite:///:memory:", connect_args={"check_same_thread": False} + def __exit__(self, type, value, traceback): + self.span._end_timestamp = None + self._ctx_mgr.__exit__(type, value, traceback) + + with mock.patch( + "sentry_sdk.integrations.sqlalchemy.record_sql_queries", + fake_record_sql_queries, + ): + assert session.query(Person).first() == bob + + sentry_sdk.flush() + spans = [item.payload for item in items] + for span in spans: + if span["attributes"].get("sentry.op") == "db" and span["name"].startswith( + "SELECT person" + ): + attributes = span["attributes"] + + assert SPANDATA.CODE_LINE_NUMBER in attributes + assert SPANDATA.CODE_NAMESPACE in attributes + assert SPANDATA.CODE_FILE_PATH in attributes + assert SPANDATA.CODE_FUNCTION in attributes + + assert type(attributes.get(SPANDATA.CODE_LINE_NUMBER)) == int + assert attributes.get(SPANDATA.CODE_LINE_NUMBER) > 0 + assert ( + attributes.get(SPANDATA.CODE_NAMESPACE) + == "tests.integrations.sqlalchemy.test_sqlalchemy" + ) + assert attributes.get(SPANDATA.CODE_FILE_PATH).endswith( + "tests/integrations/sqlalchemy/test_sqlalchemy.py" + ) + + is_relative_path = attributes.get(SPANDATA.CODE_FILE_PATH)[0] != os.sep + assert is_relative_path + + assert ( + attributes.get(SPANDATA.CODE_FUNCTION) + == "test_query_source_if_duration_over_threshold" ) - Base.metadata.create_all(engine) - - Session = sessionmaker(bind=engine) # noqa: N806 - session = Session() - - bob = Person(name="Bob") - session.add(bob) - - class fake_record_sql_queries: # noqa: N801 - def __init__(self, *args, **kwargs): - self._ctx_mgr = record_sql_queries(*args, **kwargs) - - def __enter__(self): - self.span = self._ctx_mgr.__enter__() - self.span.start_timestamp = datetime(2024, 1, 1, microsecond=0) - return self.span - - def __exit__(self, type, value, traceback): - self._ctx_mgr.__exit__(type, value, traceback) - self.span.timestamp = datetime(2024, 1, 1, microsecond=101000) - - with mock.patch( - "sentry_sdk.integrations.sqlalchemy.record_sql_queries", - fake_record_sql_queries, - ): - assert session.query(Person).first() == bob - - (event,) = events - - for span in event["spans"]: - if span.get("op") == "db" and span.get("description").startswith( - "SELECT person" - ): - data = span.get("data", {}) - - assert SPANDATA.CODE_LINENO in data - assert SPANDATA.CODE_NAMESPACE in data - assert SPANDATA.CODE_FILEPATH in data - assert SPANDATA.CODE_FUNCTION in data - - assert type(data.get(SPANDATA.CODE_LINENO)) == int - assert data.get(SPANDATA.CODE_LINENO) > 0 - assert ( - data.get(SPANDATA.CODE_NAMESPACE) - == "tests.integrations.sqlalchemy.test_sqlalchemy" - ) - assert data.get(SPANDATA.CODE_FILEPATH).endswith( - "tests/integrations/sqlalchemy/test_sqlalchemy.py" - ) - - is_relative_path = data.get(SPANDATA.CODE_FILEPATH)[0] != os.sep - assert is_relative_path - - assert ( - data.get(SPANDATA.CODE_FUNCTION) - == "test_query_source_if_duration_over_threshold" - ) - break - else: - raise AssertionError("No db span found") - - -@pytest.mark.parametrize("span_streaming", [True, False]) + break + else: + raise AssertionError("No db span found") + + def test_span_origin( sentry_init, - capture_events, capture_items, - span_streaming, ): sentry_init( integrations=[SqlalchemyIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) engine = create_engine( "sqlite:///:memory:", connect_args={"check_same_thread": False} ) - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="custom parent"): - with engine.connect() as con: - con.execute(text("SELECT 0")) - - sentry_sdk.flush() - spans = [item.payload for item in items] - - assert spans[0]["attributes"]["sentry.origin"] == "auto.db.sqlalchemy" - assert spans[1]["attributes"]["sentry.origin"] == "manual" - else: - events = capture_events() - with start_transaction(name="foo"): - with engine.connect() as con: - con.execute(text("SELECT 0")) + items = capture_items("span") + with sentry_sdk.start_span(name="custom parent"): + with engine.connect() as con: + con.execute(text("SELECT 0")) - (event,) = events + sentry_sdk.flush() + spans = [item.payload for item in items] - assert event["contexts"]["trace"]["origin"] == "manual" - assert event["spans"][0]["origin"] == "auto.db.sqlalchemy" + assert spans[0]["attributes"]["sentry.origin"] == "auto.db.sqlalchemy" + assert spans[1]["attributes"]["sentry.origin"] == "manual" diff --git a/tests/integrations/starlette/test_starlette.py b/tests/integrations/starlette/test_starlette.py index 585cf4d541..aeae723eec 100644 --- a/tests/integrations/starlette/test_starlette.py +++ b/tests/integrations/starlette/test_starlette.py @@ -7,7 +7,6 @@ import re import threading import warnings -from unittest import mock import pytest import starlette @@ -28,6 +27,7 @@ from sentry_sdk._types import SENSITIVE_DATA_SUBSTITUTE from sentry_sdk.consts import SPANDATA from sentry_sdk.integrations.asgi import SentryAsgiMiddleware +from sentry_sdk.integrations.logging import LoggingIntegration from sentry_sdk.integrations.starlette import ( StarletteIntegration, ) @@ -288,238 +288,142 @@ async def my_send(*args, **kwargs): @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) -async def test_request_info_json_body( - sentry_init, capture_events, capture_items, span_streaming -): +async def test_request_info_json_body(sentry_init, capture_items): sentry_init( traces_sample_rate=1.0, send_default_pii=True, integrations=[StarletteIntegration()], - trace_lifecycle="stream" if span_streaming else "static", ) starlette_app = starlette_app_factory() client = TestClient(starlette_app) - if span_streaming: - items = capture_items("event", "span") - - client.post( - "/body/json", - json=BODY_JSON, - headers={ - "cookie": "yummy_cookie=choco; tasty_cookie=strawberry", - }, - ) - - (event,) = (item.payload for item in items if item.type == "event") - assert event["request"]["cookies"] == { - "tasty_cookie": "strawberry", - "yummy_cookie": "choco", - } - assert event["request"]["data"] == BODY_JSON - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - server_span = next( - span for span in spans if span["attributes"]["sentry.op"] == "http.server" - ) - - assert json.loads( - server_span["attributes"][SPANDATA.HTTP_REQUEST_BODY_DATA] - ) == {"some": "json", "for": "testing", "nested": {"numbers": 123}} - else: - events = capture_events() + items = capture_items("event", "span") - client.post( - "/body/json", - json=BODY_JSON, - headers={ - "cookie": "yummy_cookie=choco; tasty_cookie=strawberry", - }, - ) + client.post( + "/body/json", + json=BODY_JSON, + headers={ + "cookie": "yummy_cookie=choco; tasty_cookie=strawberry", + }, + ) - (event, transaction_event) = events + (event,) = (item.payload for item in items if item.type == "event") + assert event["request"]["cookies"] == { + "tasty_cookie": "strawberry", + "yummy_cookie": "choco", + } + assert event["request"]["data"] == BODY_JSON - assert event["request"]["cookies"] == { - "tasty_cookie": "strawberry", - "yummy_cookie": "choco", - } - assert event["request"]["data"] == BODY_JSON + sentry_sdk.flush() + spans = [item.payload for item in items if item.type == "span"] + server_span = next( + span for span in spans if span["attributes"]["sentry.op"] == "http.server" + ) - assert transaction_event["request"]["cookies"] == { - "tasty_cookie": "strawberry", - "yummy_cookie": "choco", - } - assert transaction_event["request"]["data"] == BODY_JSON + assert json.loads(server_span["attributes"][SPANDATA.HTTP_REQUEST_BODY_DATA]) == { + "some": "json", + "for": "testing", + "nested": {"numbers": 123}, + } @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) -async def test_formdata_request_body( - sentry_init, capture_events, capture_items, span_streaming -): +async def test_formdata_request_body(sentry_init, capture_items): sentry_init( traces_sample_rate=1.0, send_default_pii=True, max_request_body_size="always", integrations=[StarletteIntegration()], - trace_lifecycle="stream" if span_streaming else "static", ) starlette_app = starlette_app_factory() client = TestClient(starlette_app) - if span_streaming: - items = capture_items("event", "span") - - client.post( - "/body/form", - data=BODY_FORM.encode("utf-8"), - headers={ - "content-type": "multipart/form-data; boundary=fd721ef49ea403a6", - }, - ) - - (event,) = (item.payload for item in items if item.type == "event") - assert event["request"]["data"].keys() == PARSED_FORM.keys() - assert event["request"]["data"]["username"] == PARSED_FORM["username"] - assert event["request"]["data"]["password"] == "[Filtered]" - assert event["request"]["data"]["photo"] == "" + items = capture_items("event", "span") - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - server_span = next( - span for span in spans if span["attributes"]["sentry.op"] == "http.server" - ) - - # Going forward, the sanitization of data will need to happen within the `before_send_span` hooks - # See https://sentry.slack.com/archives/C09RR0KD2N7/p1776951331206129?thread_ts=1776951227.440659&cid=C09RR0KD2N7 - parsed_form_attribute = json.loads( - server_span["attributes"][SPANDATA.HTTP_REQUEST_BODY_DATA] - ) - assert parsed_form_attribute.keys() == PARSED_FORM.keys() - assert parsed_form_attribute["username"] == PARSED_FORM["username"] - assert parsed_form_attribute["password"] == "hello123" - assert parsed_form_attribute["photo"] == "[Unparsable]" - else: - events = capture_events() + client.post( + "/body/form", + data=BODY_FORM.encode("utf-8"), + headers={ + "content-type": "multipart/form-data; boundary=fd721ef49ea403a6", + }, + ) - client.post( - "/body/form", - data=BODY_FORM.encode("utf-8"), - headers={ - "content-type": "multipart/form-data; boundary=fd721ef49ea403a6", - }, - ) + (event,) = (item.payload for item in items if item.type == "event") + assert event["request"]["data"].keys() == PARSED_FORM.keys() + assert event["request"]["data"]["username"] == PARSED_FORM["username"] + assert event["request"]["data"]["password"] == "[Filtered]" + assert event["request"]["data"]["photo"] == "" - (event, transaction_event) = events - assert event["request"]["data"].keys() == PARSED_FORM.keys() - assert event["request"]["data"]["username"] == PARSED_FORM["username"] - assert event["request"]["data"]["password"] == "[Filtered]" - assert event["request"]["data"]["photo"] == "" - assert event["_meta"]["request"]["data"]["photo"] == { - "": {"rem": [["!raw", "x"]]} - } + sentry_sdk.flush() + spans = [item.payload for item in items if item.type == "span"] + server_span = next( + span for span in spans if span["attributes"]["sentry.op"] == "http.server" + ) - assert transaction_event["request"]["data"].keys() == PARSED_FORM.keys() - assert ( - transaction_event["request"]["data"]["username"] == PARSED_FORM["username"] - ) - assert transaction_event["request"]["data"]["password"] == "[Filtered]" - assert transaction_event["request"]["data"]["photo"] == "" - assert transaction_event["_meta"]["request"]["data"]["photo"] == { - "": {"rem": [["!raw", "x"]]} - } + # Going forward, the sanitization of data will need to happen within the `before_send_span` hooks + # See https://sentry.slack.com/archives/C09RR0KD2N7/p1776951331206129?thread_ts=1776951227.440659&cid=C09RR0KD2N7 + parsed_form_attribute = json.loads( + server_span["attributes"][SPANDATA.HTTP_REQUEST_BODY_DATA] + ) + assert parsed_form_attribute.keys() == PARSED_FORM.keys() + assert parsed_form_attribute["username"] == PARSED_FORM["username"] + assert parsed_form_attribute["password"] == "hello123" + assert parsed_form_attribute["photo"] == "[Unparsable]" @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) -async def test_request_body_too_big( - sentry_init, capture_events, capture_items, span_streaming -): +async def test_request_body_too_big(sentry_init, capture_items): sentry_init( traces_sample_rate=1.0, send_default_pii=True, integrations=[StarletteIntegration()], - trace_lifecycle="stream" if span_streaming else "static", ) starlette_app = starlette_app_factory() client = TestClient(starlette_app) - if span_streaming: - items = capture_items("event", "span") - - client.post( - "/body/form", - data=BODY_FORM.encode("utf-8"), - headers={ - "content-type": "multipart/form-data; boundary=fd721ef49ea403a6", - "cookie": "yummy_cookie=choco; tasty_cookie=strawberry", - }, - ) - - (event,) = (item.payload for item in items if item.type == "event") - assert event["request"]["cookies"] == { - "tasty_cookie": "strawberry", - "yummy_cookie": "choco", - } - # Because request is too big only the AnnotatedValue is extracted. - assert event["_meta"]["request"]["data"] == {"": {"rem": [["!config", "x"]]}} + items = capture_items("event", "span") - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - server_span = next( - span for span in spans if span["attributes"]["sentry.op"] == "http.server" - ) + client.post( + "/body/form", + data=BODY_FORM.encode("utf-8"), + headers={ + "content-type": "multipart/form-data; boundary=fd721ef49ea403a6", + "cookie": "yummy_cookie=choco; tasty_cookie=strawberry", + }, + ) - # Because request is too big only the AnnotatedValue is extracted. - assert ( - server_span["attributes"][SPANDATA.HTTP_REQUEST_BODY_DATA] - == "[Exceeds maximum size]" - ) - else: - events = capture_events() - - client.post( - "/body/form", - data=BODY_FORM.encode("utf-8"), - headers={ - "content-type": "multipart/form-data; boundary=fd721ef49ea403a6", - "cookie": "yummy_cookie=choco; tasty_cookie=strawberry", - }, - ) + (event,) = (item.payload for item in items if item.type == "event") + assert event["request"]["cookies"] == { + "tasty_cookie": "strawberry", + "yummy_cookie": "choco", + } + # Because request is too big only the AnnotatedValue is extracted. + assert event["_meta"]["request"]["data"] == {"": {"rem": [["!config", "x"]]}} - (event, transaction_event) = events - assert event["request"]["cookies"] == { - "tasty_cookie": "strawberry", - "yummy_cookie": "choco", - } - # Because request is too big only the AnnotatedValue is extracted. - assert event["_meta"]["request"]["data"] == {"": {"rem": [["!config", "x"]]}} + sentry_sdk.flush() + spans = [item.payload for item in items if item.type == "span"] + server_span = next( + span for span in spans if span["attributes"]["sentry.op"] == "http.server" + ) - assert transaction_event["request"]["cookies"] == { - "tasty_cookie": "strawberry", - "yummy_cookie": "choco", - } - # Because request is too big only the AnnotatedValue is extracted. - assert transaction_event["_meta"]["request"]["data"] == { - "": {"rem": [["!config", "x"]]} - } + # Because request is too big only the AnnotatedValue is extracted. + assert ( + server_span["attributes"][SPANDATA.HTTP_REQUEST_BODY_DATA] + == "[Exceeds maximum size]" + ) @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) async def test_formdata_request_body_data_collection_http_bodies_empty( - sentry_init, capture_events, capture_items, span_streaming + sentry_init, capture_items ): sentry_init( traces_sample_rate=1.0, max_request_body_size="always", integrations=[StarletteIntegration()], - trace_lifecycle="stream" if span_streaming else "static", data_collection={"http_bodies": []}, ) @@ -528,31 +432,22 @@ async def test_formdata_request_body_data_collection_http_bodies_empty( headers = {"content-type": "multipart/form-data; boundary=fd721ef49ea403a6"} - if span_streaming: - items = capture_items("event", "span") - - client.post("/body/form", data=BODY_FORM.encode("utf-8"), headers=headers) + items = capture_items("event", "span") - (event,) = (item.payload for item in items if item.type == "event") - assert "data" not in event["request"] - - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - server_span = next( - span for span in spans if span["attributes"]["sentry.op"] == "http.server" - ) - assert SPANDATA.HTTP_REQUEST_BODY_DATA not in server_span["attributes"] - else: - events = capture_events() + client.post("/body/form", data=BODY_FORM.encode("utf-8"), headers=headers) - client.post("/body/form", data=BODY_FORM.encode("utf-8"), headers=headers) + (event,) = (item.payload for item in items if item.type == "event") + assert "data" not in event["request"] - (event, _) = events - assert "data" not in event["request"] + sentry_sdk.flush() + spans = [item.payload for item in items if item.type == "span"] + server_span = next( + span for span in spans if span["attributes"]["sentry.op"] == "http.server" + ) + assert SPANDATA.HTTP_REQUEST_BODY_DATA not in server_span["attributes"] @pytest.mark.asyncio -@pytest.mark.parametrize("span_streaming", [True, False]) @pytest.mark.parametrize( "data_collection, expect_body", [ @@ -570,59 +465,44 @@ async def test_formdata_request_body_data_collection_http_bodies_empty( ) async def test_request_body_data_collection( sentry_init, - capture_events, capture_items, - span_streaming, data_collection, expect_body, ): sentry_init( traces_sample_rate=1.0, integrations=[StarletteIntegration()], - trace_lifecycle="stream" if span_streaming else "static", data_collection=data_collection, ) starlette_app = starlette_app_factory() client = TestClient(starlette_app) - if span_streaming: - items = capture_items("event", "span") + items = capture_items("event", "span") - client.post("/body/json", json=BODY_JSON) + client.post("/body/json", json=BODY_JSON) - (event,) = (item.payload for item in items if item.type == "event") + (event,) = (item.payload for item in items if item.type == "event") - sentry_sdk.flush() - spans = [item.payload for item in items if item.type == "span"] - server_span = next( - span for span in spans if span["attributes"]["sentry.op"] == "http.server" - ) + sentry_sdk.flush() + spans = [item.payload for item in items if item.type == "span"] + server_span = next( + span for span in spans if span["attributes"]["sentry.op"] == "http.server" + ) - if expect_body: - assert event["request"]["data"] == BODY_JSON - assert ( - json.loads(server_span["attributes"][SPANDATA.HTTP_REQUEST_BODY_DATA]) - == BODY_JSON - ) - else: - assert "data" not in event["request"] - assert SPANDATA.HTTP_REQUEST_BODY_DATA not in server_span["attributes"] + if expect_body: + assert event["request"]["data"] == BODY_JSON + assert ( + json.loads(server_span["attributes"][SPANDATA.HTTP_REQUEST_BODY_DATA]) + == BODY_JSON + ) else: - events = capture_events() - - client.post("/body/json", json=BODY_JSON) - - (event, _) = events - - if expect_body: - assert event["request"]["data"] == BODY_JSON - else: - assert "data" not in event["request"] + assert "data" not in event["request"] + assert SPANDATA.HTTP_REQUEST_BODY_DATA not in server_span["attributes"] @pytest.mark.asyncio -async def test_request_info_no_pii(sentry_init, capture_events): +async def test_request_info_no_pii(sentry_init, capture_items): sentry_init( traces_sample_rate=1.0, send_default_pii=False, @@ -630,7 +510,8 @@ async def test_request_info_no_pii(sentry_init, capture_events): ) starlette_app = starlette_app_factory() - events = capture_events() + + items = capture_items("event", "span") client = TestClient(starlette_app) client.post( @@ -641,12 +522,19 @@ async def test_request_info_no_pii(sentry_init, capture_events): }, ) - (event, transaction_event) = events + (event,) = (item.payload for item in items if item.type == "event") assert "cookies" not in event["request"] assert event["request"]["data"] == BODY_JSON - assert "cookies" not in transaction_event["request"] - assert transaction_event["request"]["data"] == BODY_JSON + sentry_sdk.flush() + spans = [item.payload for item in items if item.type == "span"] + server_span = next( + span for span in spans if span["attributes"]["sentry.op"] == "http.server" + ) + assert ( + json.loads(server_span["attributes"][SPANDATA.HTTP_REQUEST_BODY_DATA]) + == BODY_JSON + ) @pytest.mark.asyncio @@ -752,14 +640,12 @@ async def test_cookie_data_collection( client = TestClient(starlette_app) client.get("/message", headers={"cookie": COOKIE_HEADER}) - (event, transaction_event) = events + (event,) = events if expected_cookies is None: assert "cookies" not in event["request"] - assert "cookies" not in transaction_event["request"] else: assert event["request"]["cookies"] == expected_cookies - assert transaction_event["request"]["cookies"] == expected_cookies @pytest.mark.parametrize( @@ -792,7 +678,7 @@ async def test_cookie_data_collection( ], ) def test_query_string_data_collection( - sentry_init, capture_events, init_kwargs, expected_query_string + sentry_init, capture_items, init_kwargs, expected_query_string ): sentry_init( traces_sample_rate=1.0, @@ -801,19 +687,29 @@ def test_query_string_data_collection( ) starlette_app = starlette_app_factory() - events = capture_events() + items = capture_items("event", "span") client = TestClient(starlette_app) client.get("/message?" + QUERY_STRING) - (event, transaction_event) = events + sentry_sdk.flush() + + events = [item.payload for item in items if item.type == "event"] + (event,) = events + + segments = [ + item.payload + for item in items + if item.type == "span" and item.payload.get("is_segment") + ] + assert len(segments) == 1 if expected_query_string is None: assert "query_string" not in event["request"] - assert "query_string" not in transaction_event["request"] + assert SPANDATA.HTTP_QUERY not in segments[0]["attributes"] else: assert event["request"]["query_string"] == expected_query_string - assert transaction_event["request"]["query_string"] == expected_query_string + assert segments[0]["attributes"][SPANDATA.HTTP_QUERY] == expected_query_string @pytest.mark.parametrize( @@ -846,7 +742,6 @@ def test_span_http_query_data_collection( auto_enabling_integrations=False, integrations=[StarletteIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", **init_kwargs, ) @@ -919,32 +814,6 @@ def test_span_http_query_data_collection( @pytest.mark.parametrize("init_kwargs, expected_ip", USER_INFO_CASES) def test_user_info_data_collection( - sentry_init, capture_events, init_kwargs, expected_ip -): - sentry_init( - traces_sample_rate=1.0, - integrations=[StarletteIntegration()], - **init_kwargs, - ) - - starlette_app = starlette_app_factory() - events = capture_events() - - client = TestClient(starlette_app) - client.get("/message") - - (event, transaction_event) = events - - if expected_ip is NO_USER_INFO: - assert "env" not in event["request"] - assert "env" not in transaction_event["request"] - else: - assert event["request"]["env"] == {"REMOTE_ADDR": expected_ip} - assert transaction_event["request"]["env"] == {"REMOTE_ADDR": expected_ip} - - -@pytest.mark.parametrize("init_kwargs, expected_ip", USER_INFO_CASES) -def test_user_info_data_collection_with_streamed_spans( sentry_init, capture_items, init_kwargs, expected_ip ): kwargs = dict(init_kwargs) @@ -952,7 +821,6 @@ def test_user_info_data_collection_with_streamed_spans( auto_enabling_integrations=False, integrations=[StarletteIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", **kwargs, ) @@ -1025,13 +893,14 @@ def test_transaction_style( assert event["transaction_info"] == {"source": expected_source} -def test_host_route_path_has_url_source(sentry_init, capture_events): +def test_host_route_path_has_url_source(sentry_init, capture_items): sentry_init( integrations=[StarletteIntegration(transaction_style="url")], traces_sample_rate=1.0, ) async def hosted_endpoint(request): + sentry_sdk.capture_message("hi") return starlette.responses.JSONResponse({"status": "ok"}) subapp = starlette.applications.Starlette( @@ -1041,13 +910,24 @@ async def hosted_endpoint(request): routes=[starlette.routing.Host("subapp", subapp)] ) - events = capture_events() + items = capture_items("event", "span") client = TestClient(app) client.get("/users/123456", headers={"Host": "subapp"}) - (event,) = events - assert event["transaction"].endswith("/users/123456") - assert event["transaction_info"] == {"source": "url"} + sentry_sdk.flush() + + events = [item.payload for item in items if item.type == "event"] + assert len(events) == 1 + assert events[0]["transaction"].endswith("/users/123456") + + segments = [ + item.payload + for item in items + if item.type == "span" and item.payload.get("is_segment") + ] + assert len(segments) == 1 + assert segments[0]["name"].endswith("/users/123456") + assert segments[0]["attributes"]["sentry.segment.name.source"] == "url" @pytest.mark.parametrize( @@ -1141,9 +1021,7 @@ def test_user_information_error(sentry_init, capture_events, init_kwargs, expect @pytest.mark.parametrize("init_kwargs, expect_user", USER_AUTH_CASES) -def test_user_information_transaction( - sentry_init, capture_events, init_kwargs, expect_user -): +def test_user_information(sentry_init, capture_events, init_kwargs, expect_user): sentry_init( traces_sample_rate=1.0, integrations=[StarletteIntegration()], @@ -1157,14 +1035,14 @@ def test_user_information_transaction( client = TestClient(starlette_app, raise_server_exceptions=False) client.get("/message", auth=("Gabriela", "hello123")) - (_, transaction_event) = events + (event,) = events if expect_user: - user = transaction_event.get("user", None) + user = event.get("user", None) assert user assert "username" in user assert user["username"] == "Gabriela" else: - assert "user" not in transaction_event + assert "user" not in event def test_user_information_does_not_clobber_app_set_user(sentry_init, capture_events): @@ -1189,6 +1067,7 @@ async def _set_user(request): "username": "Ada", } ) + capture_message("hi") return starlette.responses.JSONResponse({"status": "ok"}) app = starlette.applications.Starlette( @@ -1201,30 +1080,25 @@ async def _set_user(request): client = TestClient(app, raise_server_exceptions=False) client.get("/set_user", auth=("Ada", "hello123")) - (transaction_event,) = events - user = transaction_event.get("user", None) + (event,) = events + user = event.get("user", None) assert user assert user["username"] == "Ada" assert user["id"] == "user_42" assert user["email"] == "ada@beans.com" -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_middleware_spans(sentry_init, capture_events, capture_items, span_streaming): +def test_middleware_spans(sentry_init, capture_items): sentry_init( traces_sample_rate=1.0, integrations=[StarletteIntegration(middleware_spans=True)], auto_enabling_integrations=False, # disable because httpx will enable otherwise, leading to the segment span being an `http.client` sentry.op (the TestClient initiating the request), rather than the more realistic `http.server`. - trace_lifecycle="stream" if span_streaming else "static", ) starlette_app = starlette_app_factory( middleware=[Middleware(AuthenticationMiddleware, backend=BasicAuthBackend())] ) - if span_streaming: - items = capture_items("span") - else: - events = capture_events() + items = capture_items("span") client = TestClient(starlette_app, raise_server_exceptions=False) try: @@ -1242,59 +1116,36 @@ def test_middleware_spans(sentry_init, capture_events, capture_items, span_strea "ServerErrorMiddleware", # 'op': 'middleware.starlette.send' ] - if span_streaming: - sentry_sdk.flush() - - segment = items.pop().payload - middleware_spans = [item.payload for item in items] + sentry_sdk.flush() - # In span-first, the `middleware.starlette.send` ops appear first, - # so the list needs to be reversed for the assertions below - middleware_spans.reverse() + segment = items.pop().payload + middleware_spans = [item.payload for item in items] - assert len(middleware_spans) == len(expected_middleware_spans) + # In span-first, the `middleware.starlette.send` ops appear first, + # so the list needs to be reversed for the assertions below + middleware_spans.reverse() - assert segment["is_segment"] is True - assert segment["attributes"]["sentry.op"] == "http.server" + assert len(middleware_spans) == len(expected_middleware_spans) - idx = 0 - for idx, span in enumerate(middleware_spans): - assert ( - span["attributes"]["middleware.name"] == expected_middleware_spans[idx] - ) - else: - (_, transaction_event) = events + assert segment["is_segment"] is True + assert segment["attributes"]["sentry.op"] == "http.server" - assert len(transaction_event["spans"]) == len(expected_middleware_spans) - - idx = 0 - for span in transaction_event["spans"]: - if span["op"].startswith("middleware.starlette"): - assert ( - span["tags"]["starlette.middleware_name"] - == expected_middleware_spans[idx] - ) - idx += 1 + idx = 0 + for idx, span in enumerate(middleware_spans): + assert span["attributes"]["middleware.name"] == expected_middleware_spans[idx] -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_middleware_spans_disabled( - sentry_init, capture_events, capture_items, span_streaming -): +def test_middleware_spans_disabled(sentry_init, capture_items): sentry_init( traces_sample_rate=1.0, integrations=[StarletteIntegration(middleware_spans=False)], auto_enabling_integrations=False, # disable because httpx will enable otherwise, leading to the segment span being an `http.client` sentry.op (the TestClient initiating the request), rather than the more realistic `http.server`. - trace_lifecycle="stream" if span_streaming else "static", ) starlette_app = starlette_app_factory( middleware=[Middleware(AuthenticationMiddleware, backend=BasicAuthBackend())] ) - if span_streaming: - items = capture_items("span") - else: - events = capture_events() + items = capture_items("span") client = TestClient(starlette_app, raise_server_exceptions=False) try: @@ -1302,37 +1153,26 @@ def test_middleware_spans_disabled( except Exception: pass - if span_streaming: - sentry_sdk.flush() + sentry_sdk.flush() - segment = items.pop().payload - middleware_spans = [item.payload for item in items] + segment = items.pop().payload + middleware_spans = [item.payload for item in items] - assert len(middleware_spans) == 0 + assert len(middleware_spans) == 0 - assert segment["is_segment"] is True - assert segment["attributes"]["sentry.op"] == "http.server" - else: - (_, transaction_event) = events - assert len(transaction_event["spans"]) == 0 + assert segment["is_segment"] is True + assert segment["attributes"]["sentry.op"] == "http.server" -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_middleware_callback_spans( - sentry_init, capture_events, capture_items, span_streaming -): +def test_middleware_callback_spans(sentry_init, capture_items): sentry_init( traces_sample_rate=1.0, integrations=[StarletteIntegration(middleware_spans=True)], auto_enabling_integrations=False, # disable because httpx will enable otherwise, leading to the segment span being an `http.client` sentry.op (the TestClient initiating the request), rather than the more realistic `http.server`. - trace_lifecycle="stream" if span_streaming else "static", ) starlette_app = starlette_app_factory(middleware=[Middleware(SampleMiddleware)]) - if span_streaming: - items = capture_items("span") - else: - events = capture_events() + items = capture_items("span") client = TestClient(starlette_app, raise_server_exceptions=False) try: @@ -1344,81 +1184,68 @@ def test_middleware_callback_spans( { "op": "middleware.starlette", "description": "ServerErrorMiddleware", - "tags": {"starlette.middleware_name": "ServerErrorMiddleware"}, + "middleware_name": "ServerErrorMiddleware", }, { "op": "middleware.starlette", "description": "SampleMiddleware", - "tags": {"starlette.middleware_name": "SampleMiddleware"}, + "middleware_name": "SampleMiddleware", }, { "op": "middleware.starlette", "description": "ExceptionMiddleware", - "tags": {"starlette.middleware_name": "ExceptionMiddleware"}, + "middleware_name": "ExceptionMiddleware", }, { "op": "middleware.starlette.send", "description": "SampleMiddleware.__call__..do_stuff", - "tags": {"starlette.middleware_name": "ExceptionMiddleware"}, + "middleware_name": "ExceptionMiddleware", }, { "op": "middleware.starlette.send", "description": "ServerErrorMiddleware.__call__.._send", - "tags": {"starlette.middleware_name": "SampleMiddleware"}, + "middleware_name": "SampleMiddleware", }, { "op": "middleware.starlette.send", "description": "SentryAsgiMiddleware._run_app.._sentry_wrapped_send", - "tags": {"starlette.middleware_name": "ServerErrorMiddleware"}, + "middleware_name": "ServerErrorMiddleware", }, { "op": "middleware.starlette.send", "description": "SampleMiddleware.__call__..do_stuff", - "tags": {"starlette.middleware_name": "ExceptionMiddleware"}, + "middleware_name": "ExceptionMiddleware", }, { "op": "middleware.starlette.send", "description": "ServerErrorMiddleware.__call__.._send", - "tags": {"starlette.middleware_name": "SampleMiddleware"}, + "middleware_name": "SampleMiddleware", }, { "op": "middleware.starlette.send", "description": "SentryAsgiMiddleware._run_app.._sentry_wrapped_send", - "tags": {"starlette.middleware_name": "ServerErrorMiddleware"}, + "middleware_name": "ServerErrorMiddleware", }, ] - if span_streaming: - sentry_sdk.flush() + sentry_sdk.flush() - segment = items.pop().payload - middleware_spans = [item.payload for item in items] + segment = items.pop().payload + middleware_spans = [item.payload for item in items] - # In span-first, the `middleware.starlette.send` ops appear first, - # so the list needs to be reversed for the assertions below - middleware_spans.reverse() + # In span-first, the `middleware.starlette.send` ops appear first, + # so the list needs to be reversed for the assertions below + middleware_spans.reverse() - assert len(middleware_spans) == len(expected) + assert len(middleware_spans) == len(expected) - assert segment["is_segment"] is True - assert segment["attributes"]["sentry.op"] == "http.server" + assert segment["is_segment"] is True + assert segment["attributes"]["sentry.op"] == "http.server" - for span, exp in zip(middleware_spans, expected): - assert span["attributes"]["sentry.op"] == exp["op"] - assert span["name"] == exp["description"] - assert ( - span["attributes"]["middleware.name"] - == exp["tags"]["starlette.middleware_name"] - ) - else: - (_, transaction_event) = events - - idx = 0 - for span in transaction_event["spans"]: - assert span["op"] == expected[idx]["op"] - assert span["description"] == expected[idx]["description"] - assert span["tags"] == expected[idx]["tags"] - idx += 1 + for span, exp in zip(middleware_spans, expected): + assert span["attributes"]["sentry.op"] == exp["op"] + assert span["name"] == exp["description"] + assert span["attributes"]["middleware.name"] == exp["middleware_name"] def test_middleware_receive_send(sentry_init, capture_events): @@ -1439,7 +1266,7 @@ def test_middleware_receive_send(sentry_init, capture_events): pass -def test_middleware_partial_receive_send(sentry_init, capture_events): +def test_middleware_partial_receive_send(sentry_init, capture_items): sentry_init( traces_sample_rate=1.0, integrations=[StarletteIntegration()], @@ -1447,7 +1274,7 @@ def test_middleware_partial_receive_send(sentry_init, capture_events): starlette_app = starlette_app_factory( middleware=[Middleware(SamplePartialReceiveSendMiddleware)] ) - events = capture_events() + items = capture_items("span") client = TestClient(starlette_app, raise_server_exceptions=False) try: @@ -1455,61 +1282,56 @@ def test_middleware_partial_receive_send(sentry_init, capture_events): except Exception: pass - (_, transaction_event) = events + sentry_sdk.flush() + + segment = items.pop().payload + middleware_spans = [item.payload for item in items] expected = [ { - "op": "middleware.starlette", - "description": "ServerErrorMiddleware", - "tags": {"starlette.middleware_name": "ServerErrorMiddleware"}, + "op": "middleware.starlette.send", + "description": "functools.partial(.my_send at ", }, { - "op": "middleware.starlette", - "description": "SamplePartialReceiveSendMiddleware", - "tags": {"starlette.middleware_name": "SamplePartialReceiveSendMiddleware"}, + "op": "middleware.starlette.send", + "description": "functools.partial(.my_send at ", }, { - "op": "middleware.starlette.receive", - "description": ( - "_ASGIAdapter.send..receive" - if STARLETTE_VERSION < (0, 21) - else "_TestClientTransport.handle_request..receive" - ), - "tags": {"starlette.middleware_name": "ServerErrorMiddleware"}, + "op": "middleware.starlette", + "description": "ExceptionMiddleware", }, { "op": "middleware.starlette.send", - "description": "ServerErrorMiddleware.__call__.._send", - "tags": {"starlette.middleware_name": "SamplePartialReceiveSendMiddleware"}, + "description": "SentryAsgiMiddleware._run_app.._sentry_wrapped_send", }, { "op": "middleware.starlette.send", - "description": "SentryAsgiMiddleware._run_app.._sentry_wrapped_send", - "tags": {"starlette.middleware_name": "ServerErrorMiddleware"}, + "description": "ServerErrorMiddleware.__call__.._send", }, { - "op": "middleware.starlette", - "description": "ExceptionMiddleware", - "tags": {"starlette.middleware_name": "ExceptionMiddleware"}, + "op": "middleware.starlette.receive", + "description": ( + "_ASGIAdapter.send..receive" + if STARLETTE_VERSION < (0, 21) + else "_TestClientTransport.handle_request..receive" + ), }, { - "op": "middleware.starlette.send", - "description": "functools.partial(.my_send at ", - "tags": {"starlette.middleware_name": "ExceptionMiddleware"}, + "op": "middleware.starlette", + "description": "SamplePartialReceiveSendMiddleware", }, { - "op": "middleware.starlette.send", - "description": "functools.partial(.my_send at ", - "tags": {"starlette.middleware_name": "ExceptionMiddleware"}, + "op": "middleware.starlette", + "description": "ServerErrorMiddleware", }, ] - idx = 0 - for span in transaction_event["spans"]: - assert span["op"] == expected[idx]["op"] - assert span["description"].startswith(expected[idx]["description"]) - assert span["tags"] == expected[idx]["tags"] - idx += 1 + assert segment["is_segment"] is True + assert segment["attributes"]["sentry.op"] == "http.server" + + for span, exp in zip(middleware_spans, expected): + assert span["attributes"]["sentry.op"] == exp["op"] + assert span["name"].startswith(exp["description"]) @pytest.mark.skipif( @@ -1549,50 +1371,11 @@ def test_legacy_setup( @pytest.mark.parametrize("endpoint", ["/sync/thread_ids", "/async/thread_ids"]) -@mock.patch("sentry_sdk.profiler.transaction_profiler.PROFILE_MINIMUM_SAMPLES", 0) -def test_active_thread_id(sentry_init, capture_envelopes, teardown_profiling, endpoint): - sentry_init( - traces_sample_rate=1.0, - profiles_sample_rate=1.0, - ) - app = starlette_app_factory() - asgi_app = SentryAsgiMiddleware(app) - - envelopes = capture_envelopes() - - client = TestClient(asgi_app) - response = client.get(endpoint) - assert response.status_code == 200 - - data = json.loads(response.content) - - envelopes = [envelope for envelope in envelopes] - assert len(envelopes) == 1 - - profiles = [item for item in envelopes[0].items if item.type == "profile"] - assert len(profiles) == 1 - - for item in profiles: - transactions = item.payload.json["transactions"] - assert len(transactions) == 1 - assert str(data["active"]) == transactions[0]["active_thread_id"] - - transactions = [item for item in envelopes[0].items if item.type == "transaction"] - assert len(transactions) == 1 - - for item in transactions: - transaction = item.payload.json - trace_context = transaction["contexts"]["trace"] - assert str(data["active"]) == trace_context["data"]["thread.id"] - - -@pytest.mark.parametrize("endpoint", ["/sync/thread_ids", "/async/thread_ids"]) -def test_active_thread_id_span_streaming(sentry_init, capture_items, endpoint): +def test_active_thread_id(sentry_init, capture_items, endpoint): sentry_init( auto_enabling_integrations=False, # avoid legacy spans from auto-enabled integrations leaking into streaming mode integrations=[StarletteIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", ) app = starlette_app_factory() @@ -1612,12 +1395,11 @@ def test_active_thread_id_span_streaming(sentry_init, capture_items, endpoint): @pytest.mark.parametrize("endpoint", ["/sync/thread_ids", "/async/thread_ids"]) -def test_http_route_span_streaming(sentry_init, capture_items, endpoint): +def test_http_route(sentry_init, capture_items, endpoint): sentry_init( auto_enabling_integrations=False, integrations=[StarletteIntegration(transaction_style="url")], traces_sample_rate=1.0, - trace_lifecycle="stream", ) app = starlette_app_factory() @@ -1637,30 +1419,40 @@ def test_http_route_span_streaming(sentry_init, capture_items, endpoint): @pytest.mark.parametrize("endpoint", ["/sync/thread_ids", "/async/thread_ids"]) -def test_transaction_name_is_route_resolved_name_static( - sentry_init, capture_events, endpoint +def test_segment_name_is_route_resolved_name_static( + sentry_init, capture_items, endpoint ): sentry_init( + auto_enabling_integrations=False, integrations=[StarletteIntegration(transaction_style="url")], traces_sample_rate=1.0, ) - events = capture_events() + items = capture_items("span") client = TestClient(starlette_app_factory()) response = client.get(endpoint) assert response.status_code == 200 - (transaction,) = [e for e in events if e.get("type") == "transaction"] - assert transaction["transaction"] == endpoint - assert transaction["transaction_info"] == {"source": "route"} + sentry_sdk.flush() + + segments = [item.payload for item in items if item.payload.get("is_segment")] + assert len(segments) == 1 + assert segments[0]["name"] == endpoint + assert segments[0]["attributes"]["sentry.segment.name.source"] == "route" def test_original_request_not_scrubbed(sentry_init, capture_events): - sentry_init(integrations=[StarletteIntegration()]) + sentry_init( + integrations=[ + StarletteIntegration(), + LoggingIntegration(event_level=logging.ERROR), + ] + ) events = capture_events() async def _error(request): + await request.json() logging.critical("Oh no!") assert request.headers["Authorization"] == "Bearer ohno" assert request.headers["Proxy-Authorization"] == "Basic ohno" @@ -1742,7 +1534,7 @@ def test_transaction_name( transaction_style, expected_transaction_name, expected_transaction_source, - capture_envelopes, + capture_items, ): """ Tests that the transaction name is something meaningful. @@ -1753,18 +1545,20 @@ def test_transaction_name( traces_sample_rate=1.0, ) - envelopes = capture_envelopes() + items = capture_items("span") app = starlette_app_factory() client = TestClient(app) client.get(request_url) - (_, transaction_envelope) = envelopes - transaction_event = transaction_envelope.get_transaction_event() + sentry_sdk.flush() - assert transaction_event["transaction"] == expected_transaction_name + segments = [item.payload for item in items if item.payload.get("is_segment")] + assert len(segments) == 1 + assert segments[0]["name"] == expected_transaction_name assert ( - transaction_event["transaction_info"]["source"] == expected_transaction_source + segments[0]["attributes"]["sentry.segment.name.source"] + == expected_transaction_source ) @@ -1843,7 +1637,7 @@ def test_transaction_name_in_middleware( transaction_style, expected_transaction_name, expected_transaction_source, - capture_envelopes, + capture_items, ): """ Tests that the transaction name is something meaningful. @@ -1858,7 +1652,7 @@ def test_transaction_name_in_middleware( traces_sample_rate=1.0, ) - envelopes = capture_envelopes() + items = capture_items("span") middleware = [ Middleware( @@ -1871,32 +1665,28 @@ def test_transaction_name_in_middleware( client = TestClient(app) client.get(request_url) - (transaction_envelope,) = envelopes - transaction_event = transaction_envelope.get_transaction_event() + sentry_sdk.flush() - assert transaction_event["contexts"]["response"]["status_code"] == 400 - assert transaction_event["transaction"] == expected_transaction_name + segments = [item.payload for item in items if item.payload.get("is_segment")] + assert len(segments) == 1 + assert segments[0]["name"] == expected_transaction_name assert ( - transaction_event["transaction_info"]["source"] == expected_transaction_source + segments[0]["attributes"]["sentry.segment.name.source"] + == expected_transaction_source ) -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_span_origin(sentry_init, capture_events, capture_items, span_streaming): +def test_span_origin(sentry_init, capture_items): sentry_init( auto_enabling_integrations=False, # avoid httpx auto-instrumentation leaking spans integrations=[StarletteIntegration(middleware_spans=True)], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) starlette_app = starlette_app_factory( middleware=[Middleware(AuthenticationMiddleware, backend=BasicAuthBackend())] ) - if span_streaming: - items = capture_items("span") - else: - events = capture_events() + items = capture_items("span") client = TestClient(starlette_app, raise_server_exceptions=False) try: @@ -1904,111 +1694,29 @@ def test_span_origin(sentry_init, capture_events, capture_items, span_streaming) except Exception: pass - if span_streaming: - sentry_sdk.flush() - - assert len(items) > 0 - for item in items: - assert item.payload["attributes"]["sentry.origin"] == "auto.http.starlette" - else: - (_, event) = events - - assert event["contexts"]["trace"]["origin"] == "auto.http.starlette" - for span in event["spans"]: - assert span["origin"] == "auto.http.starlette" - - -class NonIterableContainer: - """Wraps any container and makes it non-iterable. - - Used to test backwards compatibility with our old way of defining failed_request_status_codes, which allowed - passing in a list of (possibly non-iterable) containers. The Python standard library does not provide any built-in - non-iterable containers, so we have to define our own. - """ - - def __init__(self, inner): - self.inner = inner - - def __contains__(self, item): - return item in self.inner - - -parametrize_test_configurable_status_codes_deprecated = pytest.mark.parametrize( - "failed_request_status_codes,status_code,expected_error", - [ - (None, 500, True), - (None, 400, False), - ([500, 501], 500, True), - ([500, 501], 401, False), - ([range(400, 499)], 401, True), - ([range(400, 499)], 500, False), - ([range(400, 499), range(500, 599)], 300, False), - ([range(400, 499), range(500, 599)], 403, True), - ([range(400, 499), range(500, 599)], 503, True), - ([range(400, 403), 500, 501], 401, True), - ([range(400, 403), 500, 501], 405, False), - ([range(400, 403), 500, 501], 501, True), - ([range(400, 403), 500, 501], 503, False), - ([], 500, False), - ([NonIterableContainer(range(500, 600))], 500, True), - ([NonIterableContainer(range(500, 600))], 404, False), - ], -) -"""Test cases for configurable status codes (deprecated API). -Also used by the FastAPI tests. -""" - - -@parametrize_test_configurable_status_codes_deprecated -def test_configurable_status_codes_deprecated( - sentry_init, - capture_events, - failed_request_status_codes, - status_code, - expected_error, -): - with pytest.warns(DeprecationWarning): - starlette_integration = StarletteIntegration( - failed_request_status_codes=failed_request_status_codes - ) - - sentry_init(integrations=[starlette_integration]) - - events = capture_events() - - async def _error(request): - raise HTTPException(status_code) - - app = starlette.applications.Starlette( - routes=[ - starlette.routing.Route("/error", _error, methods=["GET"]), - ], - ) - - client = TestClient(app) - client.get("/error") + sentry_sdk.flush() - if expected_error: - assert len(events) == 1 - else: - assert not events + assert len(items) > 0 + for item in items: + assert item.payload["attributes"]["sentry.origin"] == "auto.http.starlette" @pytest.mark.skipif( STARLETTE_VERSION < (0, 21), reason="Requires Starlette >= 0.21, because earlier versions do not support HTTP 'HEAD' requests", ) -def test_transaction_http_method_default(sentry_init, capture_events): +def test_segment_http_method_default(sentry_init, capture_items): """ - By default OPTIONS and HEAD requests do not create a transaction. + By default OPTIONS and HEAD requests do not create a segment span. """ sentry_init( + auto_enabling_integrations=False, traces_sample_rate=1.0, integrations=[ StarletteIntegration(), ], ) - events = capture_events() + items = capture_items("span") starlette_app = starlette_app_factory() @@ -2017,59 +1725,48 @@ def test_transaction_http_method_default(sentry_init, capture_events): client.options("/nomessage") client.head("/nomessage") - assert len(events) == 1 - - (event,) = events + sentry_sdk.flush() - assert event["request"]["method"] == "GET" + segments = [item.payload for item in items if item.payload.get("is_segment")] + assert len(segments) == 1 + assert segments[0]["attributes"]["http.request.method"] == "GET" -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_request_url(sentry_init, capture_events, capture_items, span_streaming): +def test_request_url(sentry_init, capture_items): sentry_init( traces_sample_rate=1.0, send_default_pii=True, integrations=[ StarletteIntegration(), ], - trace_lifecycle="stream" if span_streaming else "static", ) starlette_app = starlette_app_factory() client = TestClient(starlette_app) - if span_streaming: - items = capture_items("span") - - client.get("/root/nomessage") - sentry_sdk.flush() - spans = [item.payload for item in items] - - (server_span,) = ( - span - for span in spans - if span["attributes"].get("sentry.op") == "http.server" - ) - assert server_span["attributes"][SPANDATA.URL_FULL] == ( - "http://testserver/root/nomessage" - ) - assert server_span["attributes"][SPANDATA.URL_PATH] == "/root/nomessage" - else: - events = capture_events() + items = capture_items("span") - client.get("/root/nomessage") + client.get("/root/nomessage") + sentry_sdk.flush() + spans = [item.payload for item in items] - (event,) = events - assert event["request"]["url"] == "http://testserver/root/nomessage" + (server_span,) = ( + span for span in spans if span["attributes"].get("sentry.op") == "http.server" + ) + assert server_span["attributes"][SPANDATA.URL_FULL] == ( + "http://testserver/root/nomessage" + ) + assert server_span["attributes"][SPANDATA.URL_PATH] == "/root/nomessage" @pytest.mark.skipif( STARLETTE_VERSION < (0, 21), reason="Requires Starlette >= 0.21, because earlier versions do not support HTTP 'HEAD' requests", ) -def test_transaction_http_method_custom(sentry_init, capture_events): +def test_segment_http_method_custom(sentry_init, capture_items): sentry_init( + auto_enabling_integrations=False, traces_sample_rate=1.0, integrations=[ StarletteIntegration( @@ -2079,9 +1776,8 @@ def test_transaction_http_method_custom(sentry_init, capture_events): ), # capitalization does not matter ), ], - debug=True, ) - events = capture_events() + items = capture_items("span") starlette_app = starlette_app_factory() @@ -2090,12 +1786,13 @@ def test_transaction_http_method_custom(sentry_init, capture_events): client.options("/nomessage") client.head("/nomessage") - assert len(events) == 2 + sentry_sdk.flush() - (event1, event2) = events + segments = [item.payload for item in items if item.payload.get("is_segment")] + assert len(segments) == 2 - assert event1["request"]["method"] == "OPTIONS" - assert event2["request"]["method"] == "HEAD" + assert segments[0]["attributes"]["http.request.method"] == "OPTIONS" + assert segments[1]["attributes"]["http.request.method"] == "HEAD" @parametrize_test_configurable_status_codes @@ -2151,6 +1848,5 @@ async def test_malformed_json_request_body(sentry_init, capture_events): headers={"content-type": "application/json"}, ) - (event, transaction_event) = events + (event,) = events assert event["request"]["data"] == "" - assert transaction_event["request"]["data"] == "" diff --git a/tests/integrations/starlite/test_starlite.py b/tests/integrations/starlite/test_starlite.py index cb659faf15..6693b6a40f 100644 --- a/tests/integrations/starlite/test_starlite.py +++ b/tests/integrations/starlite/test_starlite.py @@ -137,55 +137,37 @@ def test_catch_exceptions( ), ], ) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_transaction_name_and_source( sentry_init, - capture_events, test_url, expected_tx_name, capture_items, - span_streaming, ): sentry_init( traces_sample_rate=1.0, integrations=[StarliteIntegration()], - trace_lifecycle="stream" if span_streaming else "static", ) starlite_app = starlite_app_factory() client = TestClient(starlite_app) - if span_streaming: - items = capture_items("span") - - try: - client.get(test_url) - except Exception: - pass + items = capture_items("span") - sentry_sdk.flush() - spans = [item.payload for item in items] - spans = [span for span in spans if expected_tx_name in span["name"]] - assert len(spans) == 1 - assert spans[0]["attributes"]["sentry.segment.name.source"] == "component" - else: - events = capture_events() - - try: - client.get(test_url) - except Exception: - pass + try: + client.get(test_url) + except Exception: + pass - (_, transaction) = events - assert expected_tx_name in transaction["transaction"] - assert transaction["transaction_info"] == {"source": "component"} + sentry_sdk.flush() + spans = [item.payload for item in items] + spans = [span for span in spans if expected_tx_name in span["name"]] + assert len(spans) == 1 + assert spans[0]["attributes"]["sentry.segment.name.source"] == "component" -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_middleware_spans(sentry_init, capture_events, capture_items, span_streaming): +def test_middleware_spans(sentry_init, capture_items): sentry_init( traces_sample_rate=1.0, integrations=[StarliteIntegration()], - trace_lifecycle="stream" if span_streaming else "static", ) logging_config = LoggingMiddlewareConfig() @@ -200,10 +182,7 @@ def test_middleware_spans(sentry_init, capture_events, capture_items, span_strea ] ) - if span_streaming: - items = capture_items("span") - else: - events = capture_events() + items = capture_items("span") client = TestClient( starlite_app, raise_server_exceptions=False, base_url="http://testserver.local" @@ -212,45 +191,24 @@ def test_middleware_spans(sentry_init, capture_events, capture_items, span_strea expected = {"SessionMiddleware", "LoggingMiddleware", "RateLimitMiddleware"} - if span_streaming: - sentry_sdk.flush() + sentry_sdk.flush() - middleware_spans = [ - item.payload - for item in items - if item.payload.get("attributes", {}).get("sentry.op") - == "middleware.starlite" - ] - assert len(middleware_spans) == 3 - - found = set() - for span in middleware_spans: - assert span["name"] in expected - assert span["name"] not in found - found.add(span["name"]) - assert span["name"] == span["attributes"]["middleware.name"] - else: - (_, transaction_event) = events - - found = set() - middleware_spans = [ - span - for span in transaction_event["spans"] - if span["op"] == "middleware.starlite" - ] - assert len(middleware_spans) == 3 + middleware_spans = [ + item.payload + for item in items + if item.payload.get("attributes", {}).get("sentry.op") == "middleware.starlite" + ] + assert len(middleware_spans) == 3 - for span in middleware_spans: - assert span["description"] in expected - assert span["description"] not in found - found.add(span["description"]) - assert span["description"] == span["tags"]["starlite.middleware_name"] + found = set() + for span in middleware_spans: + assert span["name"] in expected + assert span["name"] not in found + found.add(span["name"]) + assert span["name"] == span["attributes"]["middleware.name"] -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_middleware_callback_spans( - sentry_init, capture_events, capture_items, span_streaming -): +def test_middleware_callback_spans(sentry_init, capture_items): class SampleMiddleware(AbstractMiddleware): async def __call__(self, scope, receive, send) -> None: async def do_stuff(message): @@ -264,14 +222,10 @@ async def do_stuff(message): sentry_init( traces_sample_rate=1.0, integrations=[StarliteIntegration()], - trace_lifecycle="stream" if span_streaming else "static", ) starlite_app = starlite_app_factory(middleware=[SampleMiddleware]) - if span_streaming: - items = capture_items("span") - else: - events = capture_events() + items = capture_items("span") client = TestClient(starlite_app, raise_server_exceptions=False) client.get("/message") @@ -280,66 +234,38 @@ async def do_stuff(message): { "op": "middleware.starlite", "description": "SampleMiddleware", - "tags": {"starlite.middleware_name": "SampleMiddleware"}, }, { "op": "middleware.starlite.send", "description": "SentryAsgiMiddleware._run_app.._sentry_wrapped_send", - "tags": {"starlite.middleware_name": "SampleMiddleware"}, }, { "op": "middleware.starlite.send", "description": "SentryAsgiMiddleware._run_app.._sentry_wrapped_send", - "tags": {"starlite.middleware_name": "SampleMiddleware"}, }, ] - if span_streaming: - sentry_sdk.flush() + sentry_sdk.flush() - actual_starlite_spans = [ - item.payload - for item in items - if "middleware.starlite" - in item.payload.get("attributes", {}).get("sentry.op", "") - ] - assert len(actual_starlite_spans) == 3 - - def is_matching_span_streaming(expected_span, actual_span): - return ( - expected_span["op"] == actual_span["attributes"]["sentry.op"] - and expected_span["description"] == actual_span["name"] - and expected_span["tags"]["starlite.middleware_name"] - == actual_span["attributes"]["middleware.name"] - ) - - for expected_span in expected_starlite_spans: - assert any( - is_matching_span_streaming(expected_span, actual_span) - for actual_span in actual_starlite_spans - ) - else: - (_, transaction_events) = events - - def is_matching_span(expected_span, actual_span): - return ( - expected_span["op"] == actual_span["op"] - and expected_span["description"] == actual_span["description"] - and expected_span["tags"] == actual_span["tags"] - ) - - actual_starlite_spans = list( - span - for span in transaction_events["spans"] - if "middleware.starlite" in span["op"] + actual_starlite_spans = [ + item.payload + for item in items + if "middleware.starlite" + in item.payload.get("attributes", {}).get("sentry.op", "") + ] + assert len(actual_starlite_spans) == 3 + + def is_matching_span(expected_span, actual_span): + return ( + expected_span["op"] == actual_span["attributes"]["sentry.op"] + and expected_span["description"] == actual_span["name"] ) - assert len(actual_starlite_spans) == 3 - for expected_span in expected_starlite_spans: - assert any( - is_matching_span(expected_span, actual_span) - for actual_span in actual_starlite_spans - ) + for expected_span in expected_starlite_spans: + assert any( + is_matching_span(expected_span, actual_span) + for actual_span in actual_starlite_spans + ) def test_middleware_receive_send(sentry_init, capture_events): @@ -365,10 +291,7 @@ async def __call__(self, scope, receive, send): client.get("/message") -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_middleware_partial_receive_send( - sentry_init, capture_events, capture_items, span_streaming -): +def test_middleware_partial_receive_send(sentry_init, capture_items): class SamplePartialReceiveSendMiddleware(AbstractMiddleware): async def __call__(self, scope, receive, send): message = await receive() @@ -392,14 +315,10 @@ async def my_send(*args, **kwargs): sentry_init( traces_sample_rate=1.0, integrations=[StarliteIntegration()], - trace_lifecycle="stream" if span_streaming else "static", ) starlite_app = starlite_app_factory(middleware=[SamplePartialReceiveSendMiddleware]) - if span_streaming: - items = capture_items("span") - else: - events = capture_events() + items = capture_items("span") client = TestClient(starlite_app, raise_server_exceptions=False) # See SamplePartialReceiveSendMiddleware.__call__ above for assertions of correct behavior @@ -409,74 +328,43 @@ async def my_send(*args, **kwargs): { "op": "middleware.starlite", "description": "SamplePartialReceiveSendMiddleware", - "tags": {"starlite.middleware_name": "SamplePartialReceiveSendMiddleware"}, }, { "op": "middleware.starlite.receive", "description": "TestClientTransport.create_receive..receive", - "tags": {"starlite.middleware_name": "SamplePartialReceiveSendMiddleware"}, }, { "op": "middleware.starlite.send", "description": "SentryAsgiMiddleware._run_app.._sentry_wrapped_send", - "tags": {"starlite.middleware_name": "SamplePartialReceiveSendMiddleware"}, }, ] - if span_streaming: - sentry_sdk.flush() + sentry_sdk.flush() - actual_starlite_spans = [ - item.payload - for item in items - if "middleware.starlite" - in item.payload.get("attributes", {}).get("sentry.op", "") - ] - assert len(actual_starlite_spans) == 3 - - def is_matching_span_streaming(expected_span, actual_span): - return ( - expected_span["op"] == actual_span["attributes"]["sentry.op"] - and actual_span["name"].startswith(expected_span["description"]) - and expected_span["tags"]["starlite.middleware_name"] - == actual_span["attributes"]["middleware.name"] - ) - - for expected_span in expected_starlite_spans: - assert any( - is_matching_span_streaming(expected_span, actual_span) - for actual_span in actual_starlite_spans - ) - else: - (_, transaction_events) = events - - def is_matching_span(expected_span, actual_span): - return ( - expected_span["op"] == actual_span["op"] - and actual_span["description"].startswith(expected_span["description"]) - and expected_span["tags"] == actual_span["tags"] - ) - - actual_starlite_spans = list( - span - for span in transaction_events["spans"] - if "middleware.starlite" in span["op"] - ) - assert len(actual_starlite_spans) == 3 + actual_starlite_spans = [ + item.payload + for item in items + if "middleware.starlite" + in item.payload.get("attributes", {}).get("sentry.op", "") + ] + assert len(actual_starlite_spans) == 3 + + def is_matching_span(expected_span, actual_span): + return expected_span["op"] == actual_span["attributes"][ + "sentry.op" + ] and actual_span["name"].startswith(expected_span["description"]) - for expected_span in expected_starlite_spans: - assert any( - is_matching_span(expected_span, actual_span) - for actual_span in actual_starlite_spans - ) + for expected_span in expected_starlite_spans: + assert any( + is_matching_span(expected_span, actual_span) + for actual_span in actual_starlite_spans + ) -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_span_origin(sentry_init, capture_events, capture_items, span_streaming): +def test_span_origin(sentry_init, capture_items): sentry_init( integrations=[StarliteIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) logging_config = LoggingMiddlewareConfig() @@ -491,35 +379,23 @@ def test_span_origin(sentry_init, capture_events, capture_items, span_streaming) ] ) - if span_streaming: - items = capture_items("span") - else: - events = capture_events() + items = capture_items("span") client = TestClient( starlite_app, raise_server_exceptions=False, base_url="http://testserver.local" ) client.get("/message") - if span_streaming: - sentry_sdk.flush() - - starlite_items = [ - item - for item in items - if "starlite" in item.payload.get("attributes", {}).get("sentry.op", "") - ] - assert len(starlite_items) > 0 - for item in starlite_items: - assert item.payload["attributes"]["sentry.origin"] == "auto.http.starlite" - else: - (_, event) = events + sentry_sdk.flush() - assert event["contexts"]["trace"]["origin"] == "auto.http.starlite" - starlite_spans = [span for span in event["spans"] if "starlite" in span["op"]] - assert len(starlite_spans) > 0 - for span in starlite_spans: - assert span["origin"] == "auto.http.starlite" + starlite_items = [ + item + for item in items + if "starlite" in item.payload.get("attributes", {}).get("sentry.op", "") + ] + assert len(starlite_items) > 0 + for item in starlite_items: + assert item.payload["attributes"]["sentry.origin"] == "auto.http.starlite" @pytest.mark.parametrize("init_kwargs, expect_user", DATA_COLLECTION_USER_INFO_CASES) @@ -597,14 +473,12 @@ def test_request_body_data_collection( client = TestClient(starlite_app) client.post("/body/json", json=body) - (event, transaction_event) = events + (event,) = events if expect_body: assert event["request"]["data"] == body - assert transaction_event["request"]["data"] == body else: assert "data" not in event["request"] - assert "data" not in transaction_event["request"] def test_request_body_data_collection_wins_over_send_default_pii( @@ -623,10 +497,9 @@ def test_request_body_data_collection_wins_over_send_default_pii( client = TestClient(starlite_app) client.post("/body/json", json={"foo": {"bar": "baz", "qux": ["1", "2", "3"]}}) - (event, transaction_event) = events + (event,) = events assert "data" not in event["request"] - assert "data" not in transaction_event["request"] @pytest.mark.parametrize( @@ -731,11 +604,9 @@ def test_cookie_data_collection( client = TestClient(starlite_app) client.get("/message", headers={"cookie": COOKIE_HEADER}) - (event, transaction_event) = events + (event,) = events if expected_cookies is None: assert "cookies" not in event["request"] - assert "cookies" not in transaction_event["request"] else: assert event["request"]["cookies"] == expected_cookies - assert transaction_event["request"]["cookies"] == expected_cookies diff --git a/tests/integrations/statsig/test_statsig.py b/tests/integrations/statsig/test_statsig.py index 037006ab6b..7446f321b3 100644 --- a/tests/integrations/statsig/test_statsig.py +++ b/tests/integrations/statsig/test_statsig.py @@ -1,5 +1,4 @@ import concurrent.futures as cf -import sys from contextlib import contextmanager from random import random from unittest.mock import Mock @@ -9,9 +8,7 @@ from statsig.statsig_user import StatsigUser import sentry_sdk -from sentry_sdk import start_span, start_transaction from sentry_sdk.integrations.statsig import StatsigIntegration -from tests.conftest import ApproxDict @contextmanager @@ -101,7 +98,6 @@ def task(flag_key): } -@pytest.mark.skipif(sys.version_info < (3, 7), reason="requires python3.7 or higher") def test_check_gate_asyncio(sentry_init, capture_events, uninstall_integration): asyncio = pytest.importorskip("asyncio") uninstall_integration(StatsigIntegration.identifier) @@ -185,12 +181,11 @@ def test_wrapper_attributes(sentry_init, uninstall_integration): statsig.check_gate = original_check_gate -@pytest.mark.parametrize( - "span_streaming", - [True, False], -) def test_statsig_span_integration( - sentry_init, capture_events, capture_items, uninstall_integration, span_streaming + sentry_init, + capture_events, + capture_items, + uninstall_integration, ): uninstall_integration(StatsigIntegration.identifier) @@ -198,31 +193,17 @@ def test_statsig_span_integration( sentry_init( traces_sample_rate=1.0, integrations=[StatsigIntegration()], - trace_lifecycle="stream" if span_streaming else "static", ) user = StatsigUser(user_id="user-id") - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="hi"): - statsig.check_gate(user, "hello") - statsig.check_gate(user, "world") - - sentry_sdk.flush() - - assert len(items) == 1 - span = items[0].payload - assert span["attributes"]["flag.evaluation.hello"] is True - assert span["attributes"]["flag.evaluation.world"] is False - - else: - events = capture_events() - with start_transaction(name="hi"): - with start_span(op="foo", name="bar"): - statsig.check_gate(user, "hello") - statsig.check_gate(user, "world") - - (event,) = events - assert event["spans"][0]["data"] == ApproxDict( - {"flag.evaluation.hello": True, "flag.evaluation.world": False} - ) + items = capture_items("span") + with sentry_sdk.start_span(name="hi"): + statsig.check_gate(user, "hello") + statsig.check_gate(user, "world") + + sentry_sdk.flush() + + assert len(items) == 1 + span = items[0].payload + assert span["attributes"]["flag.evaluation.hello"] is True + assert span["attributes"]["flag.evaluation.world"] is False diff --git a/tests/integrations/stdlib/test_httplib.py b/tests/integrations/stdlib/test_httplib.py index db9c94bc51..1951d429c7 100644 --- a/tests/integrations/stdlib/test_httplib.py +++ b/tests/integrations/stdlib/test_httplib.py @@ -13,7 +13,7 @@ import pytest import sentry_sdk -from sentry_sdk import capture_message, continue_trace, start_transaction +from sentry_sdk import capture_message from sentry_sdk.consts import MATCH_ALL, SPANDATA from sentry_sdk.integrations.stdlib import StdlibIntegration from tests.conftest import ApproxDict, create_mock_http_server, get_free_port @@ -76,37 +76,10 @@ def create_chunked_server(): CHUNKED_PORT = create_chunked_server() -def test_crumb_capture(sentry_init, capture_events): - sentry_init(integrations=[StdlibIntegration()], send_default_pii=True) - events = capture_events() - - url = "http://localhost:{}/some/random/url".format(PORT) - urlopen(url) - - capture_message("Testing!") - - (event,) = events - (crumb,) = event["breadcrumbs"]["values"] - - assert crumb["type"] == "http" - assert crumb["category"] == "httplib" - assert crumb["data"] == ApproxDict( - { - "url": url, - SPANDATA.HTTP_METHOD: "GET", - SPANDATA.HTTP_STATUS_CODE: 200, - "reason": "OK", - SPANDATA.HTTP_FRAGMENT: "", - SPANDATA.HTTP_QUERY: "", - } - ) - - @pytest.mark.parametrize("send_default_pii", [True, False]) -def test_crumb_capture_span_streaming(sentry_init, capture_events, send_default_pii): +def test_crumb_capture(sentry_init, capture_events, send_default_pii): sentry_init( integrations=[StdlibIntegration()], - trace_lifecycle="stream", send_default_pii=send_default_pii, ) events = capture_events() @@ -139,50 +112,6 @@ def test_crumb_capture_span_streaming(sentry_init, capture_events, send_default_ ) -@pytest.mark.parametrize( - "status_code,level", - [ - (200, None), - (301, None), - (403, "warning"), - (405, "warning"), - (500, "error"), - ], -) -def test_crumb_capture_client_error(sentry_init, capture_events, status_code, level): - sentry_init(integrations=[StdlibIntegration()], send_default_pii=True) - events = capture_events() - - url = f"http://localhost:{PORT}/status/{status_code}" # noqa:E231 - try: - urlopen(url) - except HTTPError: - pass - - capture_message("Testing!") - - (event,) = events - (crumb,) = event["breadcrumbs"]["values"] - - assert crumb["type"] == "http" - assert crumb["category"] == "httplib" - - if level is None: - assert "level" not in crumb - else: - assert crumb["level"] == level - - assert crumb["data"] == ApproxDict( - { - "url": url, - SPANDATA.HTTP_METHOD: "GET", - SPANDATA.HTTP_STATUS_CODE: status_code, - SPANDATA.HTTP_FRAGMENT: "", - SPANDATA.HTTP_QUERY: "", - } - ) - - @pytest.mark.parametrize( "status_code,level", [ @@ -194,12 +123,11 @@ def test_crumb_capture_client_error(sentry_init, capture_events, status_code, le ], ) @pytest.mark.parametrize("send_default_pii", [True, False]) -def test_crumb_capture_client_error_span_streaming( +def test_crumb_capture_client_error( sentry_init, capture_events, status_code, level, send_default_pii ): sentry_init( integrations=[StdlibIntegration()], - trace_lifecycle="stream", send_default_pii=send_default_pii, ) events = capture_events() @@ -240,44 +168,8 @@ def test_crumb_capture_client_error_span_streaming( ) -def test_crumb_capture_hint(sentry_init, capture_events): - def before_breadcrumb(crumb, hint): - crumb["data"]["extra"] = "foo" - return crumb - - sentry_init( - integrations=[StdlibIntegration()], - before_breadcrumb=before_breadcrumb, - send_default_pii=True, - ) - events = capture_events() - - url = "http://localhost:{}/some/random/url".format(PORT) - urlopen(url) - - capture_message("Testing!") - - (event,) = events - (crumb,) = event["breadcrumbs"]["values"] - assert crumb["type"] == "http" - assert crumb["category"] == "httplib" - assert crumb["data"] == ApproxDict( - { - "url": url, - SPANDATA.HTTP_METHOD: "GET", - SPANDATA.HTTP_STATUS_CODE: 200, - "reason": "OK", - "extra": "foo", - SPANDATA.HTTP_FRAGMENT: "", - SPANDATA.HTTP_QUERY: "", - } - ) - - @pytest.mark.parametrize("send_default_pii", [True, False]) -def test_crumb_capture_hint_span_streaming( - sentry_init, capture_events, send_default_pii -): +def test_crumb_capture_hint(sentry_init, capture_events, send_default_pii): def before_breadcrumb(crumb, hint): crumb["data"]["extra"] = "foo" return crumb @@ -286,7 +178,6 @@ def before_breadcrumb(crumb, hint): integrations=[StdlibIntegration()], before_breadcrumb=before_breadcrumb, send_default_pii=send_default_pii, - trace_lifecycle="stream", ) events = capture_events() @@ -319,10 +210,8 @@ def before_breadcrumb(crumb, hint): ) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_empty_realurl( sentry_init, - span_streaming, ): """ Ensure that after using sentry_sdk.init you can putrequest a @@ -331,7 +220,6 @@ def test_empty_realurl( sentry_init( dsn="", - trace_lifecycle="stream" if span_streaming else "static", ) HTTPConnection("localhost", port=PORT).putrequest("POST", None) @@ -375,26 +263,19 @@ def test_httplib_misuse(sentry_init, capture_events, request): assert crumb["category"] == "httplib" assert crumb["data"] == ApproxDict( { - "url": "http://localhost:{}/200".format(PORT), - SPANDATA.HTTP_METHOD: "GET", + SPANDATA.URL_FULL: "http://localhost:{}/200".format(PORT), + SPANDATA.HTTP_REQUEST_METHOD: "GET", SPANDATA.HTTP_STATUS_CODE: 200, - "reason": "OK", - SPANDATA.HTTP_FRAGMENT: "", - SPANDATA.HTTP_QUERY: "", } ) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_outgoing_trace_headers( sentry_init, - capture_events, capture_items, - span_streaming, ): sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) already_patched_getresponse = HTTPSConnection.getresponse @@ -416,8 +297,6 @@ def send(self, *args, **kwargs) -> None: def getresponse(self, *args, **kwargs): return already_patched_getresponse(self, *args, **kwargs) - events = capture_events() - headers = { "sentry-trace": "771a43a4192642f0b136d5159a501700-1234567890abcdef-1", "baggage": ( @@ -431,83 +310,47 @@ def getresponse(self, *args, **kwargs): "other-vendor-value-2=foo;bar;" ), } + items = capture_items("span") + sentry_sdk.continue_trace(headers) + + with sentry_sdk.start_span( + name="/interactions/other-dogs/new-dog", + attributes={ + "sentry.op": "greeting.sniff", + }, + ): + connection = HTTPSConnectionRecordingRequestHeaders("localhost", port=PORT) + connection.request("GET", "/top-chasers") + connection.getresponse() - if span_streaming: - items = capture_items("span") - sentry_sdk.traces.continue_trace(headers) - - with sentry_sdk.traces.start_span( - name="/interactions/other-dogs/new-dog", - attributes={ - "sentry.op": "greeting.sniff", - }, - ): - connection = HTTPSConnectionRecordingRequestHeaders("localhost", port=PORT) - connection.request("GET", "/top-chasers") - connection.getresponse() - - sentry_sdk.flush() - request_span = next(item.payload for item in items) - expected_sentry_trace = "{trace_id}-{parent_span_id}-{sampled}".format( - trace_id=request_span["trace_id"], - parent_span_id=request_span["span_id"], - sampled=1, - ) - - expected_outgoing_baggage = ( - "sentry-trace_id=771a43a4192642f0b136d5159a501700," - "sentry-public_key=49d0f7386ad645858ae85020e393bef3," - "sentry-sample_rate=1.0," - "sentry-user_id=Am%C3%A9lie," - "sentry-sample_rand=0.000005," - "sentry-sampled=true" - ) - else: - events = capture_events() - transaction = continue_trace(headers) - - with start_transaction( - transaction=transaction, - name="/interactions/other-dogs/new-dog", - op="greeting.sniff", - trace_id="12312012123120121231201212312012", - ) as transaction: - connection = HTTPSConnectionRecordingRequestHeaders("localhost", port=PORT) - connection.request("GET", "/top-chasers") - connection.getresponse() - - (event,) = events - request_span = event["spans"][-1] - expected_sentry_trace = "{trace_id}-{parent_span_id}-{sampled}".format( - trace_id=event["contexts"]["trace"]["trace_id"], - parent_span_id=request_span["span_id"], - sampled=1, - ) + sentry_sdk.flush() + request_span = next(item.payload for item in items) + expected_sentry_trace = "{trace_id}-{parent_span_id}-{sampled}".format( + trace_id=request_span["trace_id"], + parent_span_id=request_span["span_id"], + sampled=1, + ) - expected_outgoing_baggage = ( - "sentry-trace_id=771a43a4192642f0b136d5159a501700," - "sentry-public_key=49d0f7386ad645858ae85020e393bef3," - "sentry-sample_rate=1.0," - "sentry-user_id=Am%C3%A9lie," - "sentry-sample_rand=0.000005," - "sentry-sampled=true" - ) + expected_outgoing_baggage = ( + "sentry-trace_id=771a43a4192642f0b136d5159a501700," + "sentry-public_key=49d0f7386ad645858ae85020e393bef3," + "sentry-sample_rate=1.0," + "sentry-user_id=Am%C3%A9lie," + "sentry-sample_rand=0.000005," + "sentry-sampled=true" + ) assert request_headers["sentry-trace"] == expected_sentry_trace assert request_headers["baggage"] == expected_outgoing_baggage -@pytest.mark.parametrize("span_streaming", [True, False]) def test_outgoing_trace_headers_head_sdk( sentry_init, - capture_events, capture_items, - span_streaming, ): sentry_init( traces_sample_rate=0.5, release="foo", - trace_lifecycle="stream" if span_streaming else "static", ) already_patched_getresponse = HTTPSConnection.getresponse @@ -529,75 +372,39 @@ def send(self, *args, **kwargs) -> None: def getresponse(self, *args, **kwargs): return already_patched_getresponse(self, *args, **kwargs) - if span_streaming: - items = capture_items("span") - - sentry_sdk.traces.continue_trace({}) - - with mock.patch( - "sentry_sdk.tracing_utils.Random.randrange", return_value=250000 - ): - with sentry_sdk.traces.start_span(name="Head SDK tx"): - connection = HTTPSConnectionRecordingRequestHeaders( - "localhost", port=PORT - ) - connection.request("GET", "/top-chasers") - connection.getresponse() - - sentry_sdk.flush() - request_span = next(item.payload for item in items) - expected_sentry_trace = "{trace_id}-{parent_span_id}-{sampled}".format( - trace_id=request_span["trace_id"], - parent_span_id=request_span["span_id"], - sampled=1, - ) - - expected_outgoing_baggage = ( - "sentry-trace_id=%s," - "sentry-sample_rand=0.250000," - "sentry-environment=production," - "sentry-release=foo," - "sentry-transaction=Head%%20SDK%%20tx," - "sentry-sample_rate=0.5," - "sentry-sampled=true" - ) % request_span["trace_id"] - else: - events = capture_events() + items = capture_items("span") - with mock.patch( - "sentry_sdk.tracing_utils.Random.randrange", return_value=250000 - ): - transaction = continue_trace({}) + sentry_sdk.continue_trace({}) - with start_transaction( - transaction=transaction, name="Head SDK tx" - ) as transaction: + with mock.patch("sentry_sdk.tracing_utils.Random.randrange", return_value=250000): + with sentry_sdk.start_span(name="Head SDK tx"): connection = HTTPSConnectionRecordingRequestHeaders("localhost", port=PORT) connection.request("GET", "/top-chasers") connection.getresponse() - (event,) = events - request_span = event["spans"][-1] - expected_sentry_trace = "{trace_id}-{parent_span_id}-{sampled}".format( - trace_id=event["contexts"]["trace"]["trace_id"], - parent_span_id=request_span["span_id"], - sampled=1, - ) + sentry_sdk.flush() + request_span = next(item.payload for item in items) + expected_sentry_trace = "{trace_id}-{parent_span_id}-{sampled}".format( + trace_id=request_span["trace_id"], + parent_span_id=request_span["span_id"], + sampled=1, + ) - expected_outgoing_baggage = ( - "sentry-trace_id=%s," - "sentry-sample_rand=0.250000," - "sentry-environment=production," - "sentry-release=foo," - "sentry-sample_rate=0.5," - "sentry-sampled=%s" - ) % (transaction.trace_id, "true" if transaction.sampled else "false") + expected_outgoing_baggage = ( + "sentry-trace_id=%s," + "sentry-sample_rand=0.250000," + "sentry-environment=production," + "sentry-release=foo," + "sentry-transaction=Head%%20SDK%%20tx," + "sentry-sample_rate=0.5," + "sentry-sampled=true" + ) % request_span["trace_id"] assert request_headers["sentry-trace"] == expected_sentry_trace assert request_headers["baggage"] == expected_outgoing_baggage -def test_outgoing_trace_headers_span_streaming_no_current_span(sentry_init): +def test_outgoing_trace_headers_no_current_span(sentry_init): """ With span streaming enabled and no active span, trace propagation headers should still be attached to outgoing requests, propagated from the scope's @@ -605,7 +412,6 @@ def test_outgoing_trace_headers_span_streaming_no_current_span(sentry_init): """ sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream", ) already_patched_getresponse = HTTPSConnection.getresponse @@ -639,8 +445,8 @@ def getresponse(self, *args, **kwargs): } # Seed the scope's propagation context, but do NOT start a span. - sentry_sdk.traces.continue_trace(headers) - assert sentry_sdk.traces.get_current_span() is None + sentry_sdk.continue_trace(headers) + assert sentry_sdk.get_current_span() is None connection = HTTPSConnectionRecordingRequestHeaders("localhost", port=PORT) connection.request("GET", "/top-chasers") @@ -724,19 +530,16 @@ def getresponse(self, *args, **kwargs): ], ], ) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_option_trace_propagation_targets( sentry_init, trace_propagation_targets, host, path, trace_propagated, - span_streaming, ): sentry_init( trace_propagation_targets=trace_propagation_targets, traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) already_patched_getresponse = HTTPSConnection.getresponse @@ -765,31 +568,17 @@ def getresponse(self, *args, **kwargs): "sentry-public_key=49d0f7386ad645858ae85020e393bef3, sentry-sample_rate=0.01337, " ) } - - if span_streaming: - sentry_sdk.traces.continue_trace(headers) - - with sentry_sdk.traces.start_span( - name="/interactions/other-dogs/new-dog", - attributes={ - "sentry.op": "greeting.sniff", - }, - ): - connection = HTTPSConnectionRecordingRequestHeaders(host) - connection.request("GET", path) - connection.getresponse() - else: - transaction = continue_trace(headers) - - with start_transaction( - transaction=transaction, - name="/interactions/other-dogs/new-dog", - op="greeting.sniff", - trace_id="12312012123120121231201212312012", - ) as transaction: - connection = HTTPSConnectionRecordingRequestHeaders(host) - connection.request("GET", path) - connection.getresponse() + sentry_sdk.continue_trace(headers) + + with sentry_sdk.start_span( + name="/interactions/other-dogs/new-dog", + attributes={ + "sentry.op": "greeting.sniff", + }, + ): + connection = HTTPSConnectionRecordingRequestHeaders(host) + connection.request("GET", path) + connection.getresponse() if trace_propagated: assert "sentry-trace" in request_headers @@ -799,12 +588,9 @@ def getresponse(self, *args, **kwargs): assert "baggage" not in request_headers -@pytest.mark.parametrize("span_streaming", [True, False]) def test_request_source_disabled( sentry_init, - capture_events, capture_items, - span_streaming, ): sentry_options = { "traces_sample_rate": 1.0, @@ -814,199 +600,108 @@ def test_request_source_disabled( sentry_init( **sentry_options, - trace_lifecycle="stream" if span_streaming else "static", ) + items = capture_items("span") - if span_streaming: - items = capture_items("span") - - with sentry_sdk.traces.start_span(name="custom parent"): - conn = HTTPConnection("localhost", port=PORT) - conn.request("GET", "/foo") - conn.getresponse() - - sentry_sdk.flush() - span = next(item.payload for item in items) - assert span["name"].startswith("GET") - - attributes = span["attributes"] - - assert SPANDATA.CODE_LINE_NUMBER not in attributes - assert SPANDATA.CODE_NAMESPACE not in attributes - assert SPANDATA.CODE_FILE_PATH not in attributes - assert SPANDATA.CODE_FUNCTION not in attributes - else: - events = capture_events() - - with start_transaction(name="foo"): - conn = HTTPConnection("localhost", port=PORT) - conn.request("GET", "/foo") - conn.getresponse() - - (event,) = events + with sentry_sdk.start_span(name="custom parent"): + conn = HTTPConnection("localhost", port=PORT) + conn.request("GET", "/foo") + conn.getresponse() - span = event["spans"][-1] - assert span["description"].startswith("GET") + sentry_sdk.flush() + span = next(item.payload for item in items) + assert span["name"].startswith("GET") - data = span.get("data", {}) + attributes = span["attributes"] - assert SPANDATA.CODE_LINENO not in data - assert SPANDATA.CODE_NAMESPACE not in data - assert SPANDATA.CODE_FILEPATH not in data - assert SPANDATA.CODE_FUNCTION not in data + assert SPANDATA.CODE_LINE_NUMBER not in attributes + assert SPANDATA.CODE_NAMESPACE not in attributes + assert SPANDATA.CODE_FILE_PATH not in attributes + assert SPANDATA.CODE_FUNCTION not in attributes @pytest.mark.parametrize("enable_http_request_source", [None, True]) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_request_source_enabled( sentry_init, - capture_events, capture_items, enable_http_request_source, - span_streaming, ): sentry_options = { "traces_sample_rate": 1.0, "http_request_source_threshold_ms": 0, - "trace_lifecycle": "stream" if span_streaming else "static", } if enable_http_request_source is not None: sentry_options["enable_http_request_source"] = enable_http_request_source + sentry_init( + **sentry_options, + ) - if span_streaming: - sentry_init( - **sentry_options, - ) - - items = capture_items("span") - - with sentry_sdk.traces.start_span(name="custom parent"): - conn = HTTPConnection("localhost", port=PORT) - conn.request("GET", "/foo") - conn.getresponse() - - sentry_sdk.flush() - span = next(item.payload for item in items) - assert span["name"].startswith("GET") - - attributes = span["attributes"] - - assert SPANDATA.CODE_LINE_NUMBER in attributes - assert SPANDATA.CODE_NAMESPACE in attributes - assert SPANDATA.CODE_FILE_PATH in attributes - assert SPANDATA.CODE_FUNCTION in attributes - else: - sentry_init(**sentry_options) - - events = capture_events() - - with start_transaction(name="foo"): - conn = HTTPConnection("localhost", port=PORT) - conn.request("GET", "/foo") - conn.getresponse() + items = capture_items("span") - (event,) = events + with sentry_sdk.start_span(name="custom parent"): + conn = HTTPConnection("localhost", port=PORT) + conn.request("GET", "/foo") + conn.getresponse() - span = event["spans"][-1] - assert span["description"].startswith("GET") + sentry_sdk.flush() + span = next(item.payload for item in items) + assert span["name"].startswith("GET") - data = span.get("data", {}) + attributes = span["attributes"] - assert SPANDATA.CODE_LINENO in data - assert SPANDATA.CODE_NAMESPACE in data - assert SPANDATA.CODE_FILEPATH in data - assert SPANDATA.CODE_FUNCTION in data + assert SPANDATA.CODE_LINE_NUMBER in attributes + assert SPANDATA.CODE_NAMESPACE in attributes + assert SPANDATA.CODE_FILE_PATH in attributes + assert SPANDATA.CODE_FUNCTION in attributes -@pytest.mark.parametrize("span_streaming", [True, False]) def test_request_source( sentry_init, - capture_events, capture_items, - span_streaming, ): sentry_init( traces_sample_rate=1.0, enable_http_request_source=True, http_request_source_threshold_ms=0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") - - with sentry_sdk.traces.start_span(name="custom parent"): - conn = HTTPConnection("localhost", port=PORT) - conn.request("GET", "/foo") - conn.getresponse() - - sentry_sdk.flush() - span = next(item.payload for item in items) - assert span["name"].startswith("GET") - - attributes = span["attributes"] - - assert SPANDATA.CODE_LINE_NUMBER in attributes - assert SPANDATA.CODE_NAMESPACE in attributes - assert SPANDATA.CODE_FILE_PATH in attributes - assert SPANDATA.CODE_FUNCTION in attributes - - assert type(attributes.get(SPANDATA.CODE_LINE_NUMBER)) == int - assert attributes.get(SPANDATA.CODE_LINE_NUMBER) > 0 - assert ( - attributes.get(SPANDATA.CODE_NAMESPACE) - == "tests.integrations.stdlib.test_httplib" - ) - assert attributes.get(SPANDATA.CODE_FILE_PATH).endswith( - "tests/integrations/stdlib/test_httplib.py" - ) - - is_relative_path = attributes.get(SPANDATA.CODE_FILE_PATH)[0] != os.sep - assert is_relative_path - - assert attributes.get(SPANDATA.CODE_FUNCTION) == "test_request_source" - else: - events = capture_events() - - with start_transaction(name="foo"): - conn = HTTPConnection("localhost", port=PORT) - conn.request("GET", "/foo") - conn.getresponse() + items = capture_items("span") - (event,) = events + with sentry_sdk.start_span(name="custom parent"): + conn = HTTPConnection("localhost", port=PORT) + conn.request("GET", "/foo") + conn.getresponse() - span = event["spans"][-1] - assert span["description"].startswith("GET") + sentry_sdk.flush() + span = next(item.payload for item in items) + assert span["name"].startswith("GET") - data = span.get("data", {}) + attributes = span["attributes"] - assert SPANDATA.CODE_LINENO in data - assert SPANDATA.CODE_NAMESPACE in data - assert SPANDATA.CODE_FILEPATH in data - assert SPANDATA.CODE_FUNCTION in data + assert SPANDATA.CODE_LINE_NUMBER in attributes + assert SPANDATA.CODE_NAMESPACE in attributes + assert SPANDATA.CODE_FILE_PATH in attributes + assert SPANDATA.CODE_FUNCTION in attributes - assert type(data.get(SPANDATA.CODE_LINENO)) == int - assert data.get(SPANDATA.CODE_LINENO) > 0 - assert ( - data.get(SPANDATA.CODE_NAMESPACE) - == "tests.integrations.stdlib.test_httplib" - ) - assert data.get(SPANDATA.CODE_FILEPATH).endswith( - "tests/integrations/stdlib/test_httplib.py" - ) + assert type(attributes.get(SPANDATA.CODE_LINE_NUMBER)) == int + assert attributes.get(SPANDATA.CODE_LINE_NUMBER) > 0 + assert ( + attributes.get(SPANDATA.CODE_NAMESPACE) + == "tests.integrations.stdlib.test_httplib" + ) + assert attributes.get(SPANDATA.CODE_FILE_PATH).endswith( + "tests/integrations/stdlib/test_httplib.py" + ) - is_relative_path = data.get(SPANDATA.CODE_FILEPATH)[0] != os.sep - assert is_relative_path + is_relative_path = attributes.get(SPANDATA.CODE_FILE_PATH)[0] != os.sep + assert is_relative_path - assert data.get(SPANDATA.CODE_FUNCTION) == "test_request_source" + assert attributes.get(SPANDATA.CODE_FUNCTION) == "test_request_source" -@pytest.mark.parametrize("span_streaming", [True, False]) def test_request_source_with_module_in_search_path( sentry_init, - capture_events, capture_items, - span_streaming, ): """ Test that request source is relative to the path of the module it ran in @@ -1015,465 +710,261 @@ def test_request_source_with_module_in_search_path( traces_sample_rate=1.0, enable_http_request_source=True, http_request_source_threshold_ms=0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") - - with sentry_sdk.traces.start_span(name="custom parent"): - from httplib_helpers.helpers import get_request_with_connection - - conn = HTTPConnection("localhost", port=PORT) - get_request_with_connection(conn, "/foo") - - sentry_sdk.flush() - span = next(item.payload for item in items) - assert span["name"].startswith("GET") - - attributes = span["attributes"] - - assert SPANDATA.CODE_LINE_NUMBER in attributes - assert SPANDATA.CODE_NAMESPACE in attributes - assert SPANDATA.CODE_FILE_PATH in attributes - assert SPANDATA.CODE_FUNCTION in attributes - - assert type(attributes.get(SPANDATA.CODE_LINE_NUMBER)) == int - assert attributes.get(SPANDATA.CODE_LINE_NUMBER) > 0 - assert attributes.get(SPANDATA.CODE_NAMESPACE) == "httplib_helpers.helpers" - assert attributes.get(SPANDATA.CODE_FILE_PATH) == "httplib_helpers/helpers.py" - - is_relative_path = attributes.get(SPANDATA.CODE_FILE_PATH)[0] != os.sep - assert is_relative_path - - assert attributes.get(SPANDATA.CODE_FUNCTION) == "get_request_with_connection" - else: - events = capture_events() - - with start_transaction(name="foo"): - from httplib_helpers.helpers import get_request_with_connection + items = capture_items("span") - conn = HTTPConnection("localhost", port=PORT) - get_request_with_connection(conn, "/foo") + with sentry_sdk.start_span(name="custom parent"): + from httplib_helpers.helpers import get_request_with_connection - (event,) = events + conn = HTTPConnection("localhost", port=PORT) + get_request_with_connection(conn, "/foo") - span = event["spans"][-1] - assert span["description"].startswith("GET") + sentry_sdk.flush() + span = next(item.payload for item in items) + assert span["name"].startswith("GET") - data = span.get("data", {}) + attributes = span["attributes"] - assert SPANDATA.CODE_LINENO in data - assert SPANDATA.CODE_NAMESPACE in data - assert SPANDATA.CODE_FILEPATH in data - assert SPANDATA.CODE_FUNCTION in data + assert SPANDATA.CODE_LINE_NUMBER in attributes + assert SPANDATA.CODE_NAMESPACE in attributes + assert SPANDATA.CODE_FILE_PATH in attributes + assert SPANDATA.CODE_FUNCTION in attributes - assert type(data.get(SPANDATA.CODE_LINENO)) == int - assert data.get(SPANDATA.CODE_LINENO) > 0 - assert data.get(SPANDATA.CODE_NAMESPACE) == "httplib_helpers.helpers" - assert data.get(SPANDATA.CODE_FILEPATH) == "httplib_helpers/helpers.py" + assert type(attributes.get(SPANDATA.CODE_LINE_NUMBER)) == int + assert attributes.get(SPANDATA.CODE_LINE_NUMBER) > 0 + assert attributes.get(SPANDATA.CODE_NAMESPACE) == "httplib_helpers.helpers" + assert attributes.get(SPANDATA.CODE_FILE_PATH) == "httplib_helpers/helpers.py" - is_relative_path = data.get(SPANDATA.CODE_FILEPATH)[0] != os.sep - assert is_relative_path + is_relative_path = attributes.get(SPANDATA.CODE_FILE_PATH)[0] != os.sep + assert is_relative_path - assert data.get(SPANDATA.CODE_FUNCTION) == "get_request_with_connection" + assert attributes.get(SPANDATA.CODE_FUNCTION) == "get_request_with_connection" -@pytest.mark.parametrize("span_streaming", [True, False]) def test_no_request_source_if_duration_too_short( sentry_init, - capture_events, capture_items, - span_streaming, ): sentry_init( traces_sample_rate=1.0, enable_http_request_source=True, http_request_source_threshold_ms=100, - trace_lifecycle="stream" if span_streaming else "static", ) add_http_request_source = sentry_sdk.tracing_utils.add_http_request_source def add_http_request_source_with_pinned_timestamps(span): - if span_streaming: - span._start_timestamp = datetime.datetime(2024, 1, 1, microsecond=0) - span._end_timestamp = datetime.datetime(2024, 1, 1, microsecond=99999) - result = add_http_request_source(span) - span._end_timestamp = None - return result - else: - span.start_timestamp = datetime.datetime(2024, 1, 1, microsecond=0) - span.timestamp = datetime.datetime(2024, 1, 1, microsecond=99999) - return add_http_request_source(span) - - if span_streaming: - items = capture_items("span") - with mock.patch( - "sentry_sdk.integrations.stdlib.add_http_request_source", - add_http_request_source_with_pinned_timestamps, - ): - with sentry_sdk.traces.start_span(name="foo"): - conn = HTTPConnection("localhost", port=PORT) - conn.request("GET", "/foo") - conn.getresponse() + span._start_timestamp = datetime.datetime(2024, 1, 1, microsecond=0) + span._end_timestamp = datetime.datetime(2024, 1, 1, microsecond=99999) + result = add_http_request_source(span) + span._end_timestamp = None + return result - sentry_sdk.flush() - span = next(item.payload for item in items) - assert span["name"].startswith("GET") - - attributes = span["attributes"] - - assert SPANDATA.CODE_LINE_NUMBER not in attributes - assert SPANDATA.CODE_NAMESPACE not in attributes - assert SPANDATA.CODE_FILE_PATH not in attributes - assert SPANDATA.CODE_FUNCTION not in attributes - else: - events = capture_events() - - with mock.patch( - "sentry_sdk.integrations.stdlib.add_http_request_source", - add_http_request_source_with_pinned_timestamps, - ): - with start_transaction(name="foo"): - conn = HTTPConnection("localhost", port=PORT) - conn.request("GET", "/foo") - conn.getresponse() - - (event,) = events + items = capture_items("span") + with mock.patch( + "sentry_sdk.integrations.stdlib.add_http_request_source", + add_http_request_source_with_pinned_timestamps, + ): + with sentry_sdk.start_span(name="foo"): + conn = HTTPConnection("localhost", port=PORT) + conn.request("GET", "/foo") + conn.getresponse() - span = event["spans"][-1] - assert span["description"].startswith("GET") + sentry_sdk.flush() + span = next(item.payload for item in items) + assert span["name"].startswith("GET") - data = span.get("data", {}) + attributes = span["attributes"] - assert SPANDATA.CODE_LINENO not in data - assert SPANDATA.CODE_NAMESPACE not in data - assert SPANDATA.CODE_FILEPATH not in data - assert SPANDATA.CODE_FUNCTION not in data + assert SPANDATA.CODE_LINE_NUMBER not in attributes + assert SPANDATA.CODE_NAMESPACE not in attributes + assert SPANDATA.CODE_FILE_PATH not in attributes + assert SPANDATA.CODE_FUNCTION not in attributes -@pytest.mark.parametrize("span_streaming", [True, False]) def test_request_source_if_duration_over_threshold( sentry_init, - capture_events, capture_items, - span_streaming, ): sentry_init( traces_sample_rate=1.0, enable_http_request_source=True, http_request_source_threshold_ms=100, - trace_lifecycle="stream" if span_streaming else "static", ) add_http_request_source = sentry_sdk.tracing_utils.add_http_request_source def add_http_request_source_with_pinned_timestamps(span): - if span_streaming: - span._start_timestamp = datetime.datetime(2024, 1, 1, microsecond=0) - span._end_timestamp = datetime.datetime(2024, 1, 1, microsecond=100001) - result = add_http_request_source(span) - span._end_timestamp = None - return result - else: - span.start_timestamp = datetime.datetime(2024, 1, 1, microsecond=0) - span.timestamp = datetime.datetime(2024, 1, 1, microsecond=100001) - return add_http_request_source(span) - - if span_streaming: - items = capture_items("span") - - with mock.patch( - "sentry_sdk.integrations.stdlib.add_http_request_source", - add_http_request_source_with_pinned_timestamps, - ): - with sentry_sdk.traces.start_span(name="foo"): - conn = HTTPConnection("localhost", port=PORT) - conn.request("GET", "/foo") - conn.getresponse() - - sentry_sdk.flush() - span = next(item.payload for item in items) - assert span["name"].startswith("GET") - - attributes = span["attributes"] - - assert SPANDATA.CODE_LINE_NUMBER in attributes - assert SPANDATA.CODE_NAMESPACE in attributes - assert SPANDATA.CODE_FILE_PATH in attributes - assert SPANDATA.CODE_FUNCTION in attributes - - assert type(attributes.get(SPANDATA.CODE_LINE_NUMBER)) == int - assert attributes.get(SPANDATA.CODE_LINE_NUMBER) > 0 - assert ( - attributes.get(SPANDATA.CODE_NAMESPACE) - == "tests.integrations.stdlib.test_httplib" - ) - assert attributes.get(SPANDATA.CODE_FILE_PATH).endswith( - "tests/integrations/stdlib/test_httplib.py" - ) + span._start_timestamp = datetime.datetime(2024, 1, 1, microsecond=0) + span._end_timestamp = datetime.datetime(2024, 1, 1, microsecond=100001) + result = add_http_request_source(span) + span._end_timestamp = None + return result - is_relative_path = attributes.get(SPANDATA.CODE_FILE_PATH)[0] != os.sep - assert is_relative_path - - assert ( - attributes.get(SPANDATA.CODE_FUNCTION) - == "add_http_request_source_with_pinned_timestamps" - ) - else: - events = capture_events() - - with mock.patch( - "sentry_sdk.integrations.stdlib.add_http_request_source", - add_http_request_source_with_pinned_timestamps, - ): - with start_transaction(name="foo"): - conn = HTTPConnection("localhost", port=PORT) - conn.request("GET", "/foo") - conn.getresponse() + items = capture_items("span") - (event,) = events + with mock.patch( + "sentry_sdk.integrations.stdlib.add_http_request_source", + add_http_request_source_with_pinned_timestamps, + ): + with sentry_sdk.start_span(name="foo"): + conn = HTTPConnection("localhost", port=PORT) + conn.request("GET", "/foo") + conn.getresponse() - span = event["spans"][-1] - assert span["description"].startswith("GET") + sentry_sdk.flush() + span = next(item.payload for item in items) + assert span["name"].startswith("GET") - data = span.get("data", {}) + attributes = span["attributes"] - assert SPANDATA.CODE_LINENO in data - assert SPANDATA.CODE_NAMESPACE in data - assert SPANDATA.CODE_FILEPATH in data - assert SPANDATA.CODE_FUNCTION in data + assert SPANDATA.CODE_LINE_NUMBER in attributes + assert SPANDATA.CODE_NAMESPACE in attributes + assert SPANDATA.CODE_FILE_PATH in attributes + assert SPANDATA.CODE_FUNCTION in attributes - assert type(data.get(SPANDATA.CODE_LINENO)) == int - assert data.get(SPANDATA.CODE_LINENO) > 0 - assert ( - data.get(SPANDATA.CODE_NAMESPACE) - == "tests.integrations.stdlib.test_httplib" - ) - assert data.get(SPANDATA.CODE_FILEPATH).endswith( - "tests/integrations/stdlib/test_httplib.py" - ) + assert type(attributes.get(SPANDATA.CODE_LINE_NUMBER)) == int + assert attributes.get(SPANDATA.CODE_LINE_NUMBER) > 0 + assert ( + attributes.get(SPANDATA.CODE_NAMESPACE) + == "tests.integrations.stdlib.test_httplib" + ) + assert attributes.get(SPANDATA.CODE_FILE_PATH).endswith( + "tests/integrations/stdlib/test_httplib.py" + ) - is_relative_path = data.get(SPANDATA.CODE_FILEPATH)[0] != os.sep - assert is_relative_path + is_relative_path = attributes.get(SPANDATA.CODE_FILE_PATH)[0] != os.sep + assert is_relative_path - assert ( - data.get(SPANDATA.CODE_FUNCTION) - == "add_http_request_source_with_pinned_timestamps" - ) + assert ( + attributes.get(SPANDATA.CODE_FUNCTION) + == "add_http_request_source_with_pinned_timestamps" + ) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_span_origin( sentry_init, - capture_events, capture_items, - span_streaming, ): sentry_init( traces_sample_rate=1.0, debug=True, - trace_lifecycle="stream" if span_streaming else "static", ) + items = capture_items("span") - if span_streaming: - items = capture_items("span") - - with sentry_sdk.traces.start_span(name="custom parent"): - conn = HTTPConnection("localhost", port=PORT) - conn.request("GET", "/foo") - conn.getresponse() - - sentry_sdk.flush() - spans = [item.payload for item in items] - assert spans[1]["attributes"]["sentry.origin"] == "manual" - - assert spans[0]["attributes"]["sentry.op"] == "http.client" - assert spans[0]["attributes"]["sentry.origin"] == "auto.http.stdlib.httplib" - else: - events = capture_events() - - with start_transaction(name="foo"): - conn = HTTPConnection("localhost", port=PORT) - conn.request("GET", "/foo") - conn.getresponse() + with sentry_sdk.start_span(name="custom parent"): + conn = HTTPConnection("localhost", port=PORT) + conn.request("GET", "/foo") + conn.getresponse() - (event,) = events - assert event["contexts"]["trace"]["origin"] == "manual" + sentry_sdk.flush() + spans = [item.payload for item in items] + assert spans[1]["attributes"]["sentry.origin"] == "manual" - assert event["spans"][0]["op"] == "http.client" - assert event["spans"][0]["origin"] == "auto.http.stdlib.httplib" + assert spans[0]["attributes"]["sentry.op"] == "http.client" + assert spans[0]["attributes"]["sentry.origin"] == "auto.http.stdlib.httplib" -@pytest.mark.parametrize("span_streaming", [True, False]) def test_http_timeout( monkeypatch, sentry_init, capture_envelopes, capture_items, - span_streaming, ): mock_readinto = mock.Mock(side_effect=TimeoutError) monkeypatch.setattr(SocketIO, "readinto", mock_readinto) sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) + items = capture_items("span") - if span_streaming: - items = capture_items("span") - - with pytest.raises(TimeoutError): - with sentry_sdk.traces.start_span( - name="name", - attributes={ - "sentry.op": "op", - }, - ): - conn = HTTPConnection("localhost", port=PORT) - conn.request("GET", "/bla") - conn.getresponse() - - sentry_sdk.flush() - spans = [item.payload for item in items] - assert len(spans) == 2 - span = spans[0] - assert span["attributes"]["sentry.op"] == "http.client" - assert span["name"] == f"GET http://localhost:{PORT}/bla" # noqa: E231 - else: - envelopes = capture_envelopes() - - with pytest.raises(TimeoutError): - with start_transaction(op="op", name="name"): - conn = HTTPConnection("localhost", port=PORT) - conn.request("GET", "/bla") - conn.getresponse() - - (transaction_envelope,) = envelopes - transaction = transaction_envelope.get_transaction_event() - assert len(transaction["spans"]) == 1 + with pytest.raises(TimeoutError): + with sentry_sdk.start_span( + name="name", + attributes={ + "sentry.op": "op", + }, + ): + conn = HTTPConnection("localhost", port=PORT) + conn.request("GET", "/bla") + conn.getresponse() - span = transaction["spans"][0] - assert span["op"] == "http.client" - assert span["description"] == f"GET http://localhost:{PORT}/bla" # noqa: E231 + sentry_sdk.flush() + spans = [item.payload for item in items] + assert len(spans) == 2 + span = spans[0] + assert span["attributes"]["sentry.op"] == "http.client" + assert span["name"] == f"GET http://localhost:{PORT}/bla" # noqa: E231 @pytest.mark.parametrize("tunnel_port", [8080, None]) -@pytest.mark.parametrize("span_streaming", [True, False]) @pytest.mark.parametrize("send_default_pii", [True, False]) def test_proxy_http_tunnel( sentry_init, - capture_events, capture_items, tunnel_port, - span_streaming, send_default_pii, ): sentry_init( traces_sample_rate=1.0, send_default_pii=send_default_pii, - trace_lifecycle="stream" if span_streaming else "static", ) + items = capture_items("span") - if span_streaming: - items = capture_items("span") + with sentry_sdk.start_span(name="custom parent"): + conn = HTTPConnection("localhost", PROXY_PORT) + conn.set_tunnel("api.example.com", tunnel_port) + conn.request("GET", "/foo?bar=1") + conn.getresponse() - with sentry_sdk.traces.start_span(name="custom parent"): - conn = HTTPConnection("localhost", PROXY_PORT) - conn.set_tunnel("api.example.com", tunnel_port) - conn.request("GET", "/foo?bar=1") - conn.getresponse() + sentry_sdk.flush() + spans = [item.payload for item in items] + (span,) = ( + span + for span in spans + if span["attributes"].get("sentry.origin") == "auto.http.stdlib.httplib" + ) - sentry_sdk.flush() - spans = [item.payload for item in items] - (span,) = ( - span - for span in spans - if span["attributes"].get("sentry.origin") == "auto.http.stdlib.httplib" - ) + port_modifier = f":{tunnel_port}" if tunnel_port else "" + assert span["name"] == f"GET http://api.example.com{port_modifier}/foo" + assert span["attributes"][SPANDATA.HTTP_REQUEST_METHOD] == "GET" + assert span["attributes"][SPANDATA.NETWORK_PEER_ADDRESS] == "localhost" + assert span["attributes"][SPANDATA.NETWORK_PEER_PORT] == PROXY_PORT - port_modifier = f":{tunnel_port}" if tunnel_port else "" - assert span["name"] == f"GET http://api.example.com{port_modifier}/foo" - assert span["attributes"][SPANDATA.HTTP_REQUEST_METHOD] == "GET" - assert span["attributes"][SPANDATA.NETWORK_PEER_ADDRESS] == "localhost" - assert span["attributes"][SPANDATA.NETWORK_PEER_PORT] == PROXY_PORT - - if send_default_pii: - assert ( - span["attributes"][SPANDATA.URL_FULL] - == f"http://api.example.com{port_modifier}/foo?bar=1" - ) - assert span["attributes"][SPANDATA.URL_QUERY] == "bar=1" - else: - assert SPANDATA.URL_FULL not in span["attributes"] - assert SPANDATA.URL_QUERY not in span["attributes"] + if send_default_pii: + assert ( + span["attributes"][SPANDATA.URL_FULL] + == f"http://api.example.com{port_modifier}/foo?bar=1" + ) + assert span["attributes"][SPANDATA.URL_QUERY] == "bar=1" else: - events = capture_events() - - with start_transaction(name="test_transaction"): - conn = HTTPConnection("localhost", PROXY_PORT) - conn.set_tunnel("api.example.com", tunnel_port) - conn.request("GET", "/foo?bar=1") - conn.getresponse() - - (event,) = events - (span,) = event["spans"] - - port_modifier = f":{tunnel_port}" if tunnel_port else "" - assert span["description"] == f"GET http://api.example.com{port_modifier}/foo" - assert span["data"][SPANDATA.HTTP_METHOD] == "GET" - assert span["data"][SPANDATA.NETWORK_PEER_ADDRESS] == "localhost" - assert span["data"][SPANDATA.NETWORK_PEER_PORT] == PROXY_PORT - assert span["data"]["url"] == f"http://api.example.com{port_modifier}/foo" - assert span["data"][SPANDATA.HTTP_QUERY] == "bar=1" + assert SPANDATA.URL_FULL not in span["attributes"] + assert SPANDATA.URL_QUERY not in span["attributes"] -@pytest.mark.parametrize("span_streaming", [True, False]) def test_chunked_response_span_covers_body_read( sentry_init, - capture_events, capture_items, - span_streaming, ): sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) min_expected_duration = CHUNK_DELAY * NUM_CHUNKS + items = capture_items("span") - if span_streaming: - items = capture_items("span") - - with sentry_sdk.traces.start_span(name="custom parent"): - conn = HTTPConnection("localhost", CHUNKED_PORT) - conn.request("GET", "/chunked") - response = conn.getresponse() - response.read() - - sentry_sdk.flush() - http_span, parent_span = [item.payload for item in items] - - duration = http_span["end_timestamp"] - http_span["start_timestamp"] - assert duration >= min_expected_duration - else: - events = capture_events() - - with start_transaction(name="test_chunked"): - conn = HTTPConnection("localhost", CHUNKED_PORT) - conn.request("GET", "/chunked") - response = conn.getresponse() - response.read() + with sentry_sdk.start_span(name="custom parent"): + conn = HTTPConnection("localhost", CHUNKED_PORT) + conn.request("GET", "/chunked") + response = conn.getresponse() + response.read() - (event,) = events - (span,) = event["spans"] + sentry_sdk.flush() + http_span, parent_span = [item.payload for item in items] - fmt = "%Y-%m-%dT%H:%M:%S.%fZ" - start = datetime.datetime.strptime(span["start_timestamp"], fmt) - end = datetime.datetime.strptime(span["timestamp"], fmt) - duration = (end - start).total_seconds() - assert duration >= min_expected_duration + duration = http_span["end_timestamp"] - http_span["start_timestamp"] + assert duration >= min_expected_duration @pytest.mark.parametrize( @@ -1541,19 +1032,18 @@ def test_chunked_response_span_covers_body_read( ), ], ) -def test_url_query_data_collection_span_streaming( +def test_url_query_data_collection( sentry_init, capture_items, init_kwargs, expected_query ): sentry_init( integrations=[StdlibIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", **init_kwargs, ) items = capture_items("span") - with sentry_sdk.traces.start_span(name="custom parent"): + with sentry_sdk.start_span(name="custom parent"): conn = HTTPConnection("localhost", PORT) conn.request( "GET", "/some/random/url?toy=tennisball&color=red&auth=secret#frag" @@ -1598,19 +1088,16 @@ def test_url_query_data_collection_span_streaming( ), ], ) -def test_url_full_reassembly_span_streaming( - sentry_init, capture_items, init_kwargs, expected_suffix -): +def test_url_full_reassembly(sentry_init, capture_items, init_kwargs, expected_suffix): sentry_init( integrations=[StdlibIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", **init_kwargs, ) items = capture_items("span") - with sentry_sdk.traces.start_span(name="custom parent"): + with sentry_sdk.start_span(name="custom parent"): conn = HTTPConnection("localhost", PORT) conn.request( "GET", "/some/random/url?toy=tennisball&color=red&auth=secret#frag" @@ -1658,12 +1145,11 @@ def test_url_full_reassembly_span_streaming( ), ], ) -def test_crumb_url_query_data_collection_span_streaming( +def test_crumb_url_query_data_collection( sentry_init, capture_events, init_kwargs, expected_query, expects_url ): sentry_init( integrations=[StdlibIntegration()], - trace_lifecycle="stream", **init_kwargs, ) events = capture_events() diff --git a/tests/integrations/stdlib/test_subprocess.py b/tests/integrations/stdlib/test_subprocess.py index e67ef22e2b..4969f7db7b 100644 --- a/tests/integrations/stdlib/test_subprocess.py +++ b/tests/integrations/stdlib/test_subprocess.py @@ -7,7 +7,7 @@ import pytest import sentry_sdk -from sentry_sdk import capture_message, start_transaction +from sentry_sdk import capture_message from sentry_sdk.consts import SPANDATA from sentry_sdk.integrations.stdlib import StdlibIntegration from tests.conftest import ApproxDict @@ -44,17 +44,14 @@ def __len__(self): ) @pytest.mark.parametrize("env_mapping", [None, os.environ, ImmutableDict(os.environ)]) @pytest.mark.parametrize("with_cwd", [True, False]) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_subprocess_basic( sentry_init, - capture_events, capture_items, monkeypatch, positional_args, iterator, env_mapping, with_cwd, - span_streaming, ): monkeypatch.setenv("FOO", "bar") @@ -63,271 +60,134 @@ def test_subprocess_basic( sentry_init( integrations=[StdlibIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) + items = capture_items("event", "span") + + with sentry_sdk.start_span(name="custom parent") as span: + args = [ + sys.executable, + "-c", + "import os; " + "import sentry_sdk; " + "from sentry_sdk.integrations.stdlib import get_subprocess_traceparent_headers; " + "sentry_sdk.init(); " + "assert os.environ['FOO'] == 'bar'; " + "print(dict(get_subprocess_traceparent_headers()))", + ] - if span_streaming: - items = capture_items("event", "span") - - with sentry_sdk.traces.start_span(name="custom parent") as span: - args = [ - sys.executable, - "-c", - "import os; " - "import sentry_sdk; " - "from sentry_sdk.integrations.stdlib import get_subprocess_traceparent_headers; " - "sentry_sdk.init(); " - "assert os.environ['FOO'] == 'bar'; " - "print(dict(get_subprocess_traceparent_headers()))", - ] - - if iterator: - args = iter(args) - - if positional_args: - a = ( - args, - 0, # bufsize - None, # executable - None, # stdin - subprocess.PIPE, # stdout - None, # stderr - None, # preexec_fn - False, # close_fds - False, # shell - os.getcwd() if with_cwd else None, # cwd - ) - - if env_mapping is not None: - a += (env_mapping,) - - popen = subprocess.Popen(*a) - - else: - kw = {"args": args, "stdout": subprocess.PIPE} - - if with_cwd: - kw["cwd"] = os.getcwd() - - if env_mapping is not None: - kw["env"] = env_mapping - - popen = subprocess.Popen(**kw) - - output, unused_err = popen.communicate() - retcode = popen.poll() - assert not retcode - - assert os.environ == old_environ - - assert span.trace_id in str(output) - - capture_message("hi") - - (message_event,) = (item.payload for item in items if item.type == "event") - assert message_event["message"] == "hi" - - data = ApproxDict({}) - - sentry_sdk.flush() - ( - subprocess_init_span, - subprocess_wait_span, - subprocess_communicate_span, - parent_span, - ) = (item.payload for item in items if item.type == "span") - - assert ( - subprocess_init_span["attributes"]["sentry.op"], - subprocess_wait_span["attributes"]["sentry.op"], - subprocess_communicate_span["attributes"]["sentry.op"], - ) == ("subprocess", "subprocess.wait", "subprocess.communicate") - - # span hierarchy - assert ( - subprocess_wait_span["parent_span_id"] - == subprocess_communicate_span["span_id"] - ) - - assert ( - subprocess_communicate_span["parent_span_id"] - == subprocess_init_span["parent_span_id"] - == parent_span["span_id"] - ) - - assert ( - subprocess_init_span["attributes"][SPANDATA.PROCESS_PID] - == subprocess_wait_span["attributes"][SPANDATA.PROCESS_PID] - == subprocess_communicate_span["attributes"][SPANDATA.PROCESS_PID] - ) - - # data of init span - assert subprocess_init_span.get("attributes", {}) == data if iterator: - assert "iterator" in subprocess_init_span["name"] - assert subprocess_init_span["name"].startswith("<") + args = iter(args) + + if positional_args: + a = ( + args, + 0, # bufsize + None, # executable + None, # stdin + subprocess.PIPE, # stdout + None, # stderr + None, # preexec_fn + False, # close_fds + False, # shell + os.getcwd() if with_cwd else None, # cwd + ) + + if env_mapping is not None: + a += (env_mapping,) + + popen = subprocess.Popen(*a) + else: - assert sys.executable + " -c" in subprocess_init_span["name"] + kw = {"args": args, "stdout": subprocess.PIPE} + + if with_cwd: + kw["cwd"] = os.getcwd() + + if env_mapping is not None: + kw["env"] = env_mapping + + popen = subprocess.Popen(**kw) + + output, unused_err = popen.communicate() + retcode = popen.poll() + assert not retcode + + assert os.environ == old_environ + + assert span.trace_id in str(output) + capture_message("hi") + + (message_event,) = (item.payload for item in items if item.type == "event") + assert message_event["message"] == "hi" + + data = ApproxDict({}) + + sentry_sdk.flush() + ( + subprocess_init_span, + subprocess_wait_span, + subprocess_communicate_span, + parent_span, + ) = (item.payload for item in items if item.type == "span") + + assert ( + subprocess_init_span["attributes"]["sentry.op"], + subprocess_wait_span["attributes"]["sentry.op"], + subprocess_communicate_span["attributes"]["sentry.op"], + ) == ("subprocess", "subprocess.wait", "subprocess.communicate") + + # span hierarchy + assert ( + subprocess_wait_span["parent_span_id"] == subprocess_communicate_span["span_id"] + ) + + assert ( + subprocess_communicate_span["parent_span_id"] + == subprocess_init_span["parent_span_id"] + == parent_span["span_id"] + ) + + assert ( + subprocess_init_span["attributes"][SPANDATA.PROCESS_PID] + == subprocess_wait_span["attributes"][SPANDATA.PROCESS_PID] + == subprocess_communicate_span["attributes"][SPANDATA.PROCESS_PID] + ) + + # data of init span + assert subprocess_init_span.get("attributes", {}) == data + if iterator: + assert "iterator" in subprocess_init_span["name"] + assert subprocess_init_span["name"].startswith("<") else: - events = capture_events() - - with start_transaction(name="foo") as transaction: - args = [ - sys.executable, - "-c", - "import os; " - "import sentry_sdk; " - "from sentry_sdk.integrations.stdlib import get_subprocess_traceparent_headers; " - "sentry_sdk.init(); " - "assert os.environ['FOO'] == 'bar'; " - "print(dict(get_subprocess_traceparent_headers()))", - ] - - if iterator: - args = iter(args) - - if positional_args: - a = ( - args, - 0, # bufsize - None, # executable - None, # stdin - subprocess.PIPE, # stdout - None, # stderr - None, # preexec_fn - False, # close_fds - False, # shell - os.getcwd() if with_cwd else None, # cwd - ) - - if env_mapping is not None: - a += (env_mapping,) - - popen = subprocess.Popen(*a) - - else: - kw = {"args": args, "stdout": subprocess.PIPE} - - if with_cwd: - kw["cwd"] = os.getcwd() - - if env_mapping is not None: - kw["env"] = env_mapping - - popen = subprocess.Popen(**kw) - - output, unused_err = popen.communicate() - retcode = popen.poll() - assert not retcode - - assert os.environ == old_environ - - assert transaction.trace_id in str(output) - - capture_message("hi") - - ( - transaction_event, - message_event, - ) = events - - assert message_event["message"] == "hi" - - data = ApproxDict({"subprocess.cwd": os.getcwd()} if with_cwd else {}) - - (crumb,) = message_event["breadcrumbs"]["values"] - assert crumb == { - "category": "subprocess", - "data": data, - "message": crumb["message"], - "timestamp": crumb["timestamp"], - "type": "subprocess", - } - - if not iterator: - assert crumb["message"].startswith(sys.executable + " ") - - assert transaction_event["type"] == "transaction" - - ( - subprocess_init_span, - subprocess_communicate_span, - subprocess_wait_span, - ) = transaction_event["spans"] - - assert ( - subprocess_init_span["op"], - subprocess_communicate_span["op"], - subprocess_wait_span["op"], - ) == ("subprocess", "subprocess.communicate", "subprocess.wait") - - assert ( - subprocess_wait_span["parent_span_id"] - == subprocess_communicate_span["span_id"] - ) - - assert ( - subprocess_communicate_span["parent_span_id"] - == subprocess_init_span["parent_span_id"] - == transaction_event["contexts"]["trace"]["span_id"] - ) - - assert ( - subprocess_init_span["tags"]["subprocess.pid"] - == subprocess_wait_span["tags"]["subprocess.pid"] - == subprocess_communicate_span["tags"]["subprocess.pid"] - ) - - # data of init span - assert subprocess_init_span.get("data", {}) == data - if iterator: - assert "iterator" in subprocess_init_span["description"] - assert subprocess_init_span["description"].startswith("<") - else: - assert sys.executable + " -c" in subprocess_init_span["description"] + assert sys.executable + " -c" in subprocess_init_span["name"] -@pytest.mark.parametrize("span_streaming", [True, False]) def test_subprocess_empty_env( sentry_init, monkeypatch, - span_streaming, ): monkeypatch.setenv("TEST_MARKER", "should_not_be_seen") sentry_init( integrations=[StdlibIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - with sentry_sdk.traces.start_span(name="custom parent"): - args = [ - sys.executable, - "-c", - "import os; print(os.environ.get('TEST_MARKER', None))", - ] - output = subprocess.check_output(args, env={}, universal_newlines=True) - else: - with start_transaction(name="foo"): - args = [ - sys.executable, - "-c", - "import os; print(os.environ.get('TEST_MARKER', None))", - ] - output = subprocess.check_output(args, env={}, universal_newlines=True) + with sentry_sdk.start_span(name="custom parent"): + args = [ + sys.executable, + "-c", + "import os; print(os.environ.get('TEST_MARKER', None))", + ] + output = subprocess.check_output(args, env={}, universal_newlines=True) assert "should_not_be_seen" not in output -@pytest.mark.parametrize("span_streaming", [True, False]) def test_subprocess_invalid_args( sentry_init, - span_streaming, ): sentry_init( integrations=[StdlibIntegration()], - trace_lifecycle="stream" if span_streaming else "static", ) with pytest.raises(TypeError) as excinfo: @@ -336,80 +196,44 @@ def test_subprocess_invalid_args( assert "'int' object is not iterable" in str(excinfo.value) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_subprocess_span_origin( sentry_init, - capture_events, capture_items, - span_streaming, ): sentry_init( integrations=[StdlibIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) + items = capture_items("span") - if span_streaming: - items = capture_items("span") - - with sentry_sdk.traces.start_span(name="custom parent"): - args = [ - sys.executable, - "-c", - "print('hello world')", - ] - kw = {"args": args, "stdout": subprocess.PIPE} - - popen = subprocess.Popen(**kw) - popen.communicate() - popen.poll() - - sentry_sdk.flush() - spans = [item.payload for item in items] - - assert spans[3]["attributes"]["sentry.origin"] == "manual" - - assert spans[0]["attributes"]["sentry.op"] == "subprocess" - assert ( - spans[0]["attributes"]["sentry.origin"] - == "auto.subprocess.stdlib.subprocess" - ) - - assert spans[1]["attributes"]["sentry.op"] == "subprocess.wait" - assert ( - spans[1]["attributes"]["sentry.origin"] - == "auto.subprocess.stdlib.subprocess" - ) - - assert spans[2]["attributes"]["sentry.op"] == "subprocess.communicate" - assert ( - spans[2]["attributes"]["sentry.origin"] - == "auto.subprocess.stdlib.subprocess" - ) - else: - events = capture_events() - - with start_transaction(name="foo"): - args = [ - sys.executable, - "-c", - "print('hello world')", - ] - kw = {"args": args, "stdout": subprocess.PIPE} + with sentry_sdk.start_span(name="custom parent"): + args = [ + sys.executable, + "-c", + "print('hello world')", + ] + kw = {"args": args, "stdout": subprocess.PIPE} - popen = subprocess.Popen(**kw) - popen.communicate() - popen.poll() + popen = subprocess.Popen(**kw) + popen.communicate() + popen.poll() - (event,) = events + sentry_sdk.flush() + spans = [item.payload for item in items] - assert event["contexts"]["trace"]["origin"] == "manual" + assert spans[3]["attributes"]["sentry.origin"] == "manual" - assert event["spans"][0]["op"] == "subprocess" - assert event["spans"][0]["origin"] == "auto.subprocess.stdlib.subprocess" + assert spans[0]["attributes"]["sentry.op"] == "subprocess" + assert ( + spans[0]["attributes"]["sentry.origin"] == "auto.subprocess.stdlib.subprocess" + ) - assert event["spans"][1]["op"] == "subprocess.communicate" - assert event["spans"][1]["origin"] == "auto.subprocess.stdlib.subprocess" + assert spans[1]["attributes"]["sentry.op"] == "subprocess.wait" + assert ( + spans[1]["attributes"]["sentry.origin"] == "auto.subprocess.stdlib.subprocess" + ) - assert event["spans"][2]["op"] == "subprocess.wait" - assert event["spans"][2]["origin"] == "auto.subprocess.stdlib.subprocess" + assert spans[2]["attributes"]["sentry.op"] == "subprocess.communicate" + assert ( + spans[2]["attributes"]["sentry.origin"] == "auto.subprocess.stdlib.subprocess" + ) diff --git a/tests/integrations/strawberry/test_strawberry.py b/tests/integrations/strawberry/test_strawberry.py index f9f652fd15..9177709ca1 100644 --- a/tests/integrations/strawberry/test_strawberry.py +++ b/tests/integrations/strawberry/test_strawberry.py @@ -340,11 +340,12 @@ def test_event_processor_data_collection( # request.data comes from the framework integration and must not be # overwritten by the strawberry integration - assert error_event["request"]["data"] == { - "query": query, - "operationName": "ErrorQuery", - "variables": {"value": "boom"}, - } + assert error_event["request"]["data"] == ApproxDict( + { + "operationName": "ErrorQuery", + "variables": {"value": "boom"}, + } + ) if expect_api_target: assert error_event["request"]["api_target"] == "graphql" @@ -541,8 +542,7 @@ def test_breadcrumb_no_operation_name( "send_default_pii", [True, False], ) -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_capture_transaction_on_error( +def test_capture_segment_on_error( request, sentry_init, capture_events, @@ -551,7 +551,6 @@ def test_capture_transaction_on_error( async_execution, framework_integrations, send_default_pii, - span_streaming, ): sentry_init( send_default_pii=send_default_pii, @@ -560,13 +559,9 @@ def test_capture_transaction_on_error( ] + framework_integrations, traces_sample_rate=1, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("event", "span") - else: - events = capture_events() + items = capture_items("event", "span") schema = strawberry.Schema(Query) @@ -576,103 +571,40 @@ def test_capture_transaction_on_error( query = "query ErrorQuery { error }" client.post("/graphql", json={"query": query, "operationName": "ErrorQuery"}) - if span_streaming: - sentry_sdk.flush() - error_events = [i.payload for i in items if i.type == "event"] - spans = [i.payload for i in items if i.type == "span"] - - assert len(error_events) == 1 - - assert len(spans) == 5 - parse_span, validate_span, resolve_span, query_span, segment = spans - - assert segment["is_segment"] is True - assert segment["name"] == "ErrorQuery" - assert segment["attributes"]["sentry.op"] == OP.GRAPHQL_QUERY + sentry_sdk.flush() + error_events = [i.payload for i in items if i.type == "event"] + spans = [i.payload for i in items if i.type == "span"] - assert query_span["attributes"]["sentry.op"] == OP.GRAPHQL_QUERY - assert query_span["name"] == "query ErrorQuery" - assert query_span["attributes"]["graphql.operation.type"] == "query" - assert query_span["attributes"]["graphql.operation.name"] == "ErrorQuery" + assert len(error_events) == 1 - if send_default_pii is True: - assert query_span["attributes"]["graphql.document"] == query - else: - assert "graphql.document" not in query_span["attributes"] + assert len(spans) == 5 + parse_span, validate_span, resolve_span, query_span, segment = spans - assert parse_span["attributes"]["sentry.op"] == OP.GRAPHQL_PARSE - assert parse_span["name"] == "parsing" - assert parse_span["parent_span_id"] == query_span["span_id"] + assert segment["is_segment"] is True + assert segment["name"] == "ErrorQuery" + assert segment["attributes"]["sentry.op"] == OP.GRAPHQL_QUERY - assert validate_span["attributes"]["sentry.op"] == OP.GRAPHQL_VALIDATE - assert validate_span["name"] == "validation" - assert validate_span["parent_span_id"] == query_span["span_id"] + assert query_span["attributes"]["sentry.op"] == OP.GRAPHQL_QUERY + assert query_span["name"] == "query ErrorQuery" + assert query_span["attributes"]["graphql.operation.type"] == "query" + assert query_span["attributes"]["graphql.operation.name"] == "ErrorQuery" - assert resolve_span["attributes"]["sentry.op"] == OP.GRAPHQL_RESOLVE - assert resolve_span["name"] == "resolving Query.error" - assert resolve_span["parent_span_id"] == query_span["span_id"] + if send_default_pii is True: + assert query_span["attributes"]["graphql.document"] == query else: - assert len(events) == 2 - (_, transaction_event) = events + assert "graphql.document" not in query_span["attributes"] - assert transaction_event["transaction"] == "ErrorQuery" - assert transaction_event["contexts"]["trace"]["op"] == OP.GRAPHQL_QUERY - assert transaction_event["spans"] + assert parse_span["attributes"]["sentry.op"] == OP.GRAPHQL_PARSE + assert parse_span["name"] == "parsing" + assert parse_span["parent_span_id"] == query_span["span_id"] - query_spans = [ - span - for span in transaction_event["spans"] - if span["op"] == OP.GRAPHQL_QUERY - ] - assert len(query_spans) == 1, "exactly one query span expected" - query_span = query_spans[0] - assert query_span["description"] == "query ErrorQuery" - assert query_span["data"]["graphql.operation.type"] == "query" - assert query_span["data"]["graphql.operation.name"] == "ErrorQuery" - assert query_span["data"]["graphql.resource_name"] - - if send_default_pii is True: - assert query_span["data"]["graphql.document"] == query - else: - assert "graphql.document" not in query_span["data"] - - parse_spans = [ - span - for span in transaction_event["spans"] - if span["op"] == OP.GRAPHQL_PARSE - ] - assert len(parse_spans) == 1, "exactly one parse span expected" - parse_span = parse_spans[0] - assert parse_span["parent_span_id"] == query_span["span_id"] - assert parse_span["description"] == "parsing" - - validate_spans = [ - span - for span in transaction_event["spans"] - if span["op"] == OP.GRAPHQL_VALIDATE - ] - assert len(validate_spans) == 1, "exactly one validate span expected" - validate_span = validate_spans[0] - assert validate_span["parent_span_id"] == query_span["span_id"] - assert validate_span["description"] == "validation" - - resolve_spans = [ - span - for span in transaction_event["spans"] - if span["op"] == OP.GRAPHQL_RESOLVE - ] - assert len(resolve_spans) == 1, "exactly one resolve span expected" - resolve_span = resolve_spans[0] - assert resolve_span["parent_span_id"] == query_span["span_id"] - assert resolve_span["description"] == "resolving Query.error" - assert resolve_span["data"] == ApproxDict( - { - "graphql.field_name": "error", - "graphql.parent_type": "Query", - "graphql.field_path": "Query.error", - "graphql.path": "error", - } - ) + assert validate_span["attributes"]["sentry.op"] == OP.GRAPHQL_VALIDATE + assert validate_span["name"] == "validation" + assert validate_span["parent_span_id"] == query_span["span_id"] + + assert resolve_span["attributes"]["sentry.op"] == OP.GRAPHQL_RESOLVE + assert resolve_span["name"] == "resolving Query.error" + assert resolve_span["parent_span_id"] == query_span["span_id"] @parameterize_strawberry_test @@ -680,8 +612,7 @@ def test_capture_transaction_on_error( "send_default_pii", [True, False], ) -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_capture_transaction_on_success( +def test_capture_segment_on_success( request, sentry_init, capture_events, @@ -690,7 +621,6 @@ def test_capture_transaction_on_success( async_execution, framework_integrations, send_default_pii, - span_streaming, ): sentry_init( integrations=[ @@ -699,13 +629,9 @@ def test_capture_transaction_on_success( + framework_integrations, traces_sample_rate=1, send_default_pii=send_default_pii, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") - else: - events = capture_events() + items = capture_items("span") schema = strawberry.Schema(Query) @@ -715,100 +641,37 @@ def test_capture_transaction_on_success( query = "query GreetingQuery { hello }" client.post("/graphql", json={"query": query, "operationName": "GreetingQuery"}) - if span_streaming: - sentry_sdk.flush() - spans = [i.payload for i in items] - - assert len(spans) == 5 - parse_span, validate_span, resolve_span, query_span, segment = spans + sentry_sdk.flush() + spans = [i.payload for i in items] - assert segment["is_segment"] is True - assert segment["name"] == "GreetingQuery" - assert segment["attributes"]["sentry.op"] == OP.GRAPHQL_QUERY + assert len(spans) == 5 + parse_span, validate_span, resolve_span, query_span, segment = spans - assert query_span["attributes"]["sentry.op"] == OP.GRAPHQL_QUERY - assert query_span["name"] == "query GreetingQuery" - assert query_span["attributes"]["graphql.operation.type"] == "query" - assert query_span["attributes"]["graphql.operation.name"] == "GreetingQuery" + assert segment["is_segment"] is True + assert segment["name"] == "GreetingQuery" + assert segment["attributes"]["sentry.op"] == OP.GRAPHQL_QUERY - if send_default_pii is True: - assert query_span["attributes"]["graphql.document"] == query - else: - assert "graphql.document" not in query_span["attributes"] + assert query_span["attributes"]["sentry.op"] == OP.GRAPHQL_QUERY + assert query_span["name"] == "query GreetingQuery" + assert query_span["attributes"]["graphql.operation.type"] == "query" + assert query_span["attributes"]["graphql.operation.name"] == "GreetingQuery" - assert parse_span["attributes"]["sentry.op"] == OP.GRAPHQL_PARSE - assert parse_span["name"] == "parsing" - assert parse_span["parent_span_id"] == query_span["span_id"] - - assert validate_span["attributes"]["sentry.op"] == OP.GRAPHQL_VALIDATE - assert validate_span["name"] == "validation" - assert validate_span["parent_span_id"] == query_span["span_id"] - - assert resolve_span["attributes"]["sentry.op"] == OP.GRAPHQL_RESOLVE - assert resolve_span["name"] == "resolving Query.hello" - assert resolve_span["parent_span_id"] == query_span["span_id"] + if send_default_pii is True: + assert query_span["attributes"]["graphql.document"] == query else: - assert len(events) == 1 - (transaction_event,) = events + assert "graphql.document" not in query_span["attributes"] - assert transaction_event["transaction"] == "GreetingQuery" - assert transaction_event["contexts"]["trace"]["op"] == OP.GRAPHQL_QUERY - assert transaction_event["spans"] + assert parse_span["attributes"]["sentry.op"] == OP.GRAPHQL_PARSE + assert parse_span["name"] == "parsing" + assert parse_span["parent_span_id"] == query_span["span_id"] - query_spans = [ - span - for span in transaction_event["spans"] - if span["op"] == OP.GRAPHQL_QUERY - ] - assert len(query_spans) == 1, "exactly one query span expected" - query_span = query_spans[0] - assert query_span["description"] == "query GreetingQuery" - assert query_span["data"]["graphql.operation.type"] == "query" - assert query_span["data"]["graphql.operation.name"] == "GreetingQuery" - assert query_span["data"]["graphql.resource_name"] - - if send_default_pii is True: - assert query_span["data"]["graphql.document"] == query - else: - assert "graphql.document" not in query_span["data"] - - parse_spans = [ - span - for span in transaction_event["spans"] - if span["op"] == OP.GRAPHQL_PARSE - ] - assert len(parse_spans) == 1, "exactly one parse span expected" - parse_span = parse_spans[0] - assert parse_span["parent_span_id"] == query_span["span_id"] - assert parse_span["description"] == "parsing" - - validate_spans = [ - span - for span in transaction_event["spans"] - if span["op"] == OP.GRAPHQL_VALIDATE - ] - assert len(validate_spans) == 1, "exactly one validate span expected" - validate_span = validate_spans[0] - assert validate_span["parent_span_id"] == query_span["span_id"] - assert validate_span["description"] == "validation" - - resolve_spans = [ - span - for span in transaction_event["spans"] - if span["op"] == OP.GRAPHQL_RESOLVE - ] - assert len(resolve_spans) == 1, "exactly one resolve span expected" - resolve_span = resolve_spans[0] - assert resolve_span["parent_span_id"] == query_span["span_id"] - assert resolve_span["description"] == "resolving Query.hello" - assert resolve_span["data"] == ApproxDict( - { - "graphql.field_name": "hello", - "graphql.parent_type": "Query", - "graphql.field_path": "Query.hello", - "graphql.path": "hello", - } - ) + assert validate_span["attributes"]["sentry.op"] == OP.GRAPHQL_VALIDATE + assert validate_span["name"] == "validation" + assert validate_span["parent_span_id"] == query_span["span_id"] + + assert resolve_span["attributes"]["sentry.op"] == OP.GRAPHQL_RESOLVE + assert resolve_span["name"] == "resolving Query.hello" + assert resolve_span["parent_span_id"] == query_span["span_id"] @parameterize_strawberry_test @@ -816,8 +679,7 @@ def test_capture_transaction_on_success( "send_default_pii", [True, False], ) -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_transaction_no_operation_name( +def test_segment_no_operation_name( request, sentry_init, capture_events, @@ -826,7 +688,6 @@ def test_transaction_no_operation_name( async_execution, framework_integrations, send_default_pii, - span_streaming, ): sentry_init( integrations=[ @@ -835,13 +696,9 @@ def test_transaction_no_operation_name( + framework_integrations, traces_sample_rate=1, send_default_pii=send_default_pii, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") - else: - events = capture_events() + items = capture_items("span") schema = strawberry.Schema(Query) @@ -851,105 +708,39 @@ def test_transaction_no_operation_name( query = "{ hello }" client.post("/graphql", json={"query": query}) - if span_streaming: - sentry_sdk.flush() - spans = [i.payload for i in items] - - assert len(spans) == 5 - parse_span, validate_span, resolve_span, query_span, segment = spans - - assert segment["is_segment"] is True - if async_execution: - assert segment["name"] == "/graphql" - else: - assert segment["name"] == "graphql_view" + sentry_sdk.flush() + spans = [i.payload for i in items] - assert query_span["attributes"]["sentry.op"] == OP.GRAPHQL_QUERY - assert query_span["name"] == "query" - assert query_span["attributes"]["graphql.operation.type"] == "query" - assert "graphql.operation.name" not in query_span["attributes"] + assert len(spans) == 5 + parse_span, validate_span, resolve_span, query_span, segment = spans - if send_default_pii is True: - assert query_span["attributes"]["graphql.document"] == query - else: - assert "graphql.document" not in query_span["attributes"] - - assert parse_span["attributes"]["sentry.op"] == OP.GRAPHQL_PARSE - assert parse_span["name"] == "parsing" - assert parse_span["parent_span_id"] == query_span["span_id"] + assert segment["is_segment"] is True + if async_execution: + assert segment["name"] == "/graphql" + else: + assert segment["name"] == "graphql_view" - assert validate_span["attributes"]["sentry.op"] == OP.GRAPHQL_VALIDATE - assert validate_span["name"] == "validation" - assert validate_span["parent_span_id"] == query_span["span_id"] + assert query_span["attributes"]["sentry.op"] == OP.GRAPHQL_QUERY + assert query_span["name"] == "query" + assert query_span["attributes"]["graphql.operation.type"] == "query" + assert "graphql.operation.name" not in query_span["attributes"] - assert resolve_span["attributes"]["sentry.op"] == OP.GRAPHQL_RESOLVE - assert resolve_span["name"] == "resolving Query.hello" - assert resolve_span["parent_span_id"] == query_span["span_id"] + if send_default_pii is True: + assert query_span["attributes"]["graphql.document"] == query else: - assert len(events) == 1 - (transaction_event,) = events + assert "graphql.document" not in query_span["attributes"] - if async_execution: - assert transaction_event["transaction"] == "/graphql" - else: - assert transaction_event["transaction"] == "graphql_view" + assert parse_span["attributes"]["sentry.op"] == OP.GRAPHQL_PARSE + assert parse_span["name"] == "parsing" + assert parse_span["parent_span_id"] == query_span["span_id"] - assert transaction_event["spans"] + assert validate_span["attributes"]["sentry.op"] == OP.GRAPHQL_VALIDATE + assert validate_span["name"] == "validation" + assert validate_span["parent_span_id"] == query_span["span_id"] - query_spans = [ - span - for span in transaction_event["spans"] - if span["op"] == OP.GRAPHQL_QUERY - ] - assert len(query_spans) == 1, "exactly one query span expected" - query_span = query_spans[0] - assert query_span["description"] == "query" - assert query_span["data"]["graphql.operation.type"] == "query" - assert query_span["data"]["graphql.operation.name"] is None - assert query_span["data"]["graphql.resource_name"] - - if send_default_pii is True: - assert query_span["data"]["graphql.document"] == query - else: - assert "graphql.document" not in query_span["data"] - - parse_spans = [ - span - for span in transaction_event["spans"] - if span["op"] == OP.GRAPHQL_PARSE - ] - assert len(parse_spans) == 1, "exactly one parse span expected" - parse_span = parse_spans[0] - assert parse_span["parent_span_id"] == query_span["span_id"] - assert parse_span["description"] == "parsing" - - validate_spans = [ - span - for span in transaction_event["spans"] - if span["op"] == OP.GRAPHQL_VALIDATE - ] - assert len(validate_spans) == 1, "exactly one validate span expected" - validate_span = validate_spans[0] - assert validate_span["parent_span_id"] == query_span["span_id"] - assert validate_span["description"] == "validation" - - resolve_spans = [ - span - for span in transaction_event["spans"] - if span["op"] == OP.GRAPHQL_RESOLVE - ] - assert len(resolve_spans) == 1, "exactly one resolve span expected" - resolve_span = resolve_spans[0] - assert resolve_span["parent_span_id"] == query_span["span_id"] - assert resolve_span["description"] == "resolving Query.hello" - assert resolve_span["data"] == ApproxDict( - { - "graphql.field_name": "hello", - "graphql.parent_type": "Query", - "graphql.field_path": "Query.hello", - "graphql.path": "hello", - } - ) + assert resolve_span["attributes"]["sentry.op"] == OP.GRAPHQL_RESOLVE + assert resolve_span["name"] == "resolving Query.hello" + assert resolve_span["parent_span_id"] == query_span["span_id"] @parameterize_strawberry_test @@ -957,8 +748,7 @@ def test_transaction_no_operation_name( "send_default_pii", [True, False], ) -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_transaction_mutation( +def test_segment_mutation( request, sentry_init, capture_events, @@ -967,7 +757,6 @@ def test_transaction_mutation( async_execution, framework_integrations, send_default_pii, - span_streaming, ): sentry_init( integrations=[ @@ -976,13 +765,9 @@ def test_transaction_mutation( + framework_integrations, traces_sample_rate=1, send_default_pii=send_default_pii, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") - else: - events = capture_events() + items = capture_items("span") schema = strawberry.Schema(Query, mutation=Mutation) @@ -992,100 +777,37 @@ def test_transaction_mutation( query = 'mutation Change { change(attribute: "something") }' client.post("/graphql", json={"query": query}) - if span_streaming: - sentry_sdk.flush() - spans = [i.payload for i in items] + sentry_sdk.flush() + spans = [i.payload for i in items] - assert len(spans) == 5 - parse_span, validate_span, resolve_span, mutation_span, segment = spans + assert len(spans) == 5 + parse_span, validate_span, resolve_span, mutation_span, segment = spans - assert segment["is_segment"] is True - assert segment["name"] == "Change" - assert segment["attributes"]["sentry.op"] == OP.GRAPHQL_MUTATION + assert segment["is_segment"] is True + assert segment["name"] == "Change" + assert segment["attributes"]["sentry.op"] == OP.GRAPHQL_MUTATION - assert mutation_span["attributes"]["sentry.op"] == OP.GRAPHQL_MUTATION - assert mutation_span["name"] == "mutation" - assert mutation_span["attributes"]["graphql.operation.type"] == "mutation" - assert "graphql.operation.name" not in mutation_span["attributes"] + assert mutation_span["attributes"]["sentry.op"] == OP.GRAPHQL_MUTATION + assert mutation_span["name"] == "mutation" + assert mutation_span["attributes"]["graphql.operation.type"] == "mutation" + assert "graphql.operation.name" not in mutation_span["attributes"] - if send_default_pii is True: - assert mutation_span["attributes"]["graphql.document"] == query - else: - assert "graphql.document" not in mutation_span["attributes"] - - assert parse_span["attributes"]["sentry.op"] == OP.GRAPHQL_PARSE - assert parse_span["name"] == "parsing" - assert parse_span["parent_span_id"] == mutation_span["span_id"] - - assert validate_span["attributes"]["sentry.op"] == OP.GRAPHQL_VALIDATE - assert validate_span["name"] == "validation" - assert validate_span["parent_span_id"] == mutation_span["span_id"] - - assert resolve_span["attributes"]["sentry.op"] == OP.GRAPHQL_RESOLVE - assert resolve_span["name"] == "resolving Mutation.change" - assert resolve_span["parent_span_id"] == mutation_span["span_id"] + if send_default_pii is True: + assert mutation_span["attributes"]["graphql.document"] == query else: - assert len(events) == 1 - (transaction_event,) = events + assert "graphql.document" not in mutation_span["attributes"] - assert transaction_event["transaction"] == "Change" - assert transaction_event["contexts"]["trace"]["op"] == OP.GRAPHQL_MUTATION - assert transaction_event["spans"] + assert parse_span["attributes"]["sentry.op"] == OP.GRAPHQL_PARSE + assert parse_span["name"] == "parsing" + assert parse_span["parent_span_id"] == mutation_span["span_id"] - query_spans = [ - span - for span in transaction_event["spans"] - if span["op"] == OP.GRAPHQL_MUTATION - ] - assert len(query_spans) == 1, "exactly one mutation span expected" - query_span = query_spans[0] - assert query_span["description"] == "mutation" - assert query_span["data"]["graphql.operation.type"] == "mutation" - assert query_span["data"]["graphql.operation.name"] is None - assert query_span["data"]["graphql.resource_name"] - - if send_default_pii is True: - assert query_span["data"]["graphql.document"] == query - else: - assert "graphql.document" not in query_span["data"] - - parse_spans = [ - span - for span in transaction_event["spans"] - if span["op"] == OP.GRAPHQL_PARSE - ] - assert len(parse_spans) == 1, "exactly one parse span expected" - parse_span = parse_spans[0] - assert parse_span["parent_span_id"] == query_span["span_id"] - assert parse_span["description"] == "parsing" - - validate_spans = [ - span - for span in transaction_event["spans"] - if span["op"] == OP.GRAPHQL_VALIDATE - ] - assert len(validate_spans) == 1, "exactly one validate span expected" - validate_span = validate_spans[0] - assert validate_span["parent_span_id"] == query_span["span_id"] - assert validate_span["description"] == "validation" - - resolve_spans = [ - span - for span in transaction_event["spans"] - if span["op"] == OP.GRAPHQL_RESOLVE - ] - assert len(resolve_spans) == 1, "exactly one resolve span expected" - resolve_span = resolve_spans[0] - assert resolve_span["parent_span_id"] == query_span["span_id"] - assert resolve_span["description"] == "resolving Mutation.change" - assert resolve_span["data"] == ApproxDict( - { - "graphql.field_name": "change", - "graphql.parent_type": "Mutation", - "graphql.field_path": "Mutation.change", - "graphql.path": "change", - } - ) + assert validate_span["attributes"]["sentry.op"] == OP.GRAPHQL_VALIDATE + assert validate_span["name"] == "validation" + assert validate_span["parent_span_id"] == mutation_span["span_id"] + + assert resolve_span["attributes"]["sentry.op"] == OP.GRAPHQL_RESOLVE + assert resolve_span["name"] == "resolving Mutation.change" + assert resolve_span["parent_span_id"] == mutation_span["span_id"] @parameterize_strawberry_test @@ -1118,7 +840,6 @@ def test_transaction_mutation( ), ], ) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_graphql_span_data_collection( request, sentry_init, @@ -1130,23 +851,19 @@ def test_graphql_span_data_collection( data_collection, send_default_pii, expect_document, - span_streaming, ): init_kwargs = { "integrations": [StrawberryIntegration(async_execution=async_execution)] + framework_integrations, "traces_sample_rate": 1, - "trace_lifecycle": "stream" if span_streaming else "static", "data_collection": data_collection, } if send_default_pii is not None: init_kwargs["send_default_pii"] = send_default_pii + sentry_init(**init_kwargs) - if span_streaming: - items = capture_items("span") - else: - events = capture_events() + items = capture_items("span") schema = strawberry.Schema(Query) @@ -1156,39 +873,20 @@ def test_graphql_span_data_collection( query = "query GreetingQuery { hello }" client.post("/graphql", json={"query": query, "operationName": "GreetingQuery"}) - if span_streaming: - sentry_sdk.flush() - spans = [i.payload for i in items] - assert len(spans) == 5 - query_span = spans[3] - - assert query_span["attributes"]["sentry.op"] == OP.GRAPHQL_QUERY - assert query_span["attributes"]["graphql.operation.type"] == "query" - # operation.name is always set when an operation name is present - assert query_span["attributes"]["graphql.operation.name"] == "GreetingQuery" - - if expect_document: - assert query_span["attributes"]["graphql.document"] == query - else: - assert "graphql.document" not in query_span["attributes"] - else: - assert len(events) == 1 - (transaction_event,) = events + sentry_sdk.flush() + spans = [i.payload for i in items] + assert len(spans) == 5 + query_span = spans[3] - query_spans = [ - span - for span in transaction_event["spans"] - if span["op"] == OP.GRAPHQL_QUERY - ] - assert len(query_spans) == 1, "exactly one query span expected" - query_span = query_spans[0] - assert query_span["data"]["graphql.operation.type"] == "query" - assert query_span["data"]["graphql.operation.name"] == "GreetingQuery" + assert query_span["attributes"]["sentry.op"] == OP.GRAPHQL_QUERY + assert query_span["attributes"]["graphql.operation.type"] == "query" + # operation.name is always set when an operation name is present + assert query_span["attributes"]["graphql.operation.name"] == "GreetingQuery" - if expect_document: - assert query_span["data"]["graphql.document"] == query - else: - assert "graphql.document" not in query_span["data"] + if expect_document: + assert query_span["attributes"]["graphql.document"] == query + else: + assert "graphql.document" not in query_span["attributes"] @parameterize_strawberry_test @@ -1247,7 +945,6 @@ def test_handle_none_query_gracefully_with_data_collection( @parameterize_strawberry_test -@pytest.mark.parametrize("span_streaming", [True, False]) def test_span_origin( request, sentry_init, @@ -1256,7 +953,6 @@ def test_span_origin( client_factory, async_execution, framework_integrations, - span_streaming, ): """ Tests for OP.GRAPHQL_MUTATION, OP.GRAPHQL_PARSE, OP.GRAPHQL_VALIDATE, OP.GRAPHQL_RESOLVE, @@ -1267,13 +963,9 @@ def test_span_origin( ] + framework_integrations, traces_sample_rate=1, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") - else: - events = capture_events() + items = capture_items("span") schema = strawberry.Schema(Query, mutation=Mutation) @@ -1285,36 +977,23 @@ def test_span_origin( is_flask = "Flask" in str(framework_integrations[0]) - if span_streaming: - sentry_sdk.flush() - spans = [i.payload for i in items] - - assert len(spans) == 5 - parse_span, validate_span, resolve_span, mutation_span, segment = spans + sentry_sdk.flush() + spans = [i.payload for i in items] - assert segment["is_segment"] is True - if is_flask: - assert segment["attributes"]["sentry.origin"] == "auto.http.flask" - else: - assert segment["attributes"]["sentry.origin"] == "auto.http.starlette" + assert len(spans) == 5 + parse_span, validate_span, resolve_span, mutation_span, segment = spans - for span in (parse_span, validate_span, resolve_span, mutation_span): - assert span["attributes"]["sentry.origin"] == "auto.graphql.strawberry" + assert segment["is_segment"] is True + if is_flask: + assert segment["attributes"]["sentry.origin"] == "auto.http.flask" else: - (event,) = events + assert segment["attributes"]["sentry.origin"] == "auto.http.starlette" - if is_flask: - assert event["contexts"]["trace"]["origin"] == "auto.http.flask" - else: - assert event["contexts"]["trace"]["origin"] == "auto.http.starlette" - - for span in event["spans"]: - if span["op"].startswith("graphql."): - assert span["origin"] == "auto.graphql.strawberry" + for span in (parse_span, validate_span, resolve_span, mutation_span): + assert span["attributes"]["sentry.origin"] == "auto.graphql.strawberry" @parameterize_strawberry_test -@pytest.mark.parametrize("span_streaming", [True, False]) def test_span_origin2( request, sentry_init, @@ -1323,7 +1002,6 @@ def test_span_origin2( client_factory, async_execution, framework_integrations, - span_streaming, ): """ Tests for OP.GRAPHQL_QUERY @@ -1334,13 +1012,9 @@ def test_span_origin2( ] + framework_integrations, traces_sample_rate=1, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") - else: - events = capture_events() + items = capture_items("span") schema = strawberry.Schema(Query, mutation=Mutation) @@ -1352,36 +1026,23 @@ def test_span_origin2( is_flask = "Flask" in str(framework_integrations[0]) - if span_streaming: - sentry_sdk.flush() - spans = [i.payload for i in items] + sentry_sdk.flush() + spans = [i.payload for i in items] - assert len(spans) == 5 - parse_span, validate_span, resolve_span, query_span, segment = spans + assert len(spans) == 5 + parse_span, validate_span, resolve_span, query_span, segment = spans - assert segment["is_segment"] is True - if is_flask: - assert segment["attributes"]["sentry.origin"] == "auto.http.flask" - else: - assert segment["attributes"]["sentry.origin"] == "auto.http.starlette" - - for span in (parse_span, validate_span, resolve_span, query_span): - assert span["attributes"]["sentry.origin"] == "auto.graphql.strawberry" + assert segment["is_segment"] is True + if is_flask: + assert segment["attributes"]["sentry.origin"] == "auto.http.flask" else: - (event,) = events - - if is_flask: - assert event["contexts"]["trace"]["origin"] == "auto.http.flask" - else: - assert event["contexts"]["trace"]["origin"] == "auto.http.starlette" + assert segment["attributes"]["sentry.origin"] == "auto.http.starlette" - for span in event["spans"]: - if span["op"].startswith("graphql."): - assert span["origin"] == "auto.graphql.strawberry" + for span in (parse_span, validate_span, resolve_span, query_span): + assert span["attributes"]["sentry.origin"] == "auto.graphql.strawberry" @parameterize_strawberry_test -@pytest.mark.parametrize("span_streaming", [True, False]) def test_span_origin3( request, sentry_init, @@ -1390,7 +1051,6 @@ def test_span_origin3( client_factory, async_execution, framework_integrations, - span_streaming, ): """ Tests for OP.GRAPHQL_SUBSCRIPTION @@ -1401,13 +1061,9 @@ def test_span_origin3( ] + framework_integrations, traces_sample_rate=1, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") - else: - events = capture_events() + items = capture_items("span") schema = strawberry.Schema(Query, subscription=Subscription) @@ -1419,29 +1075,17 @@ def test_span_origin3( is_flask = "Flask" in str(framework_integrations[0]) - if span_streaming: - sentry_sdk.flush() - spans = [i.payload for i in items] - - assert len(spans) == 5 - parse_span, validate_span, resolve_span, subscription_span, segment = spans + sentry_sdk.flush() + spans = [i.payload for i in items] - assert segment["is_segment"] is True - if is_flask: - assert segment["attributes"]["sentry.origin"] == "auto.http.flask" - else: - assert segment["attributes"]["sentry.origin"] == "auto.http.starlette" + assert len(spans) == 5 + parse_span, validate_span, resolve_span, subscription_span, segment = spans - for span in (parse_span, validate_span, resolve_span, subscription_span): - assert span["attributes"]["sentry.origin"] == "auto.graphql.strawberry" + assert segment["is_segment"] is True + if is_flask: + assert segment["attributes"]["sentry.origin"] == "auto.http.flask" else: - (event,) = events - - if is_flask: - assert event["contexts"]["trace"]["origin"] == "auto.http.flask" - else: - assert event["contexts"]["trace"]["origin"] == "auto.http.starlette" + assert segment["attributes"]["sentry.origin"] == "auto.http.starlette" - for span in event["spans"]: - if span["op"].startswith("graphql."): - assert span["origin"] == "auto.graphql.strawberry" + for span in (parse_span, validate_span, resolve_span, subscription_span): + assert span["attributes"]["sentry.origin"] == "auto.graphql.strawberry" diff --git a/tests/integrations/threading/test_threading.py b/tests/integrations/threading/test_threading.py index 9c06ce24a7..87c8569a99 100644 --- a/tests/integrations/threading/test_threading.py +++ b/tests/integrations/threading/test_threading.py @@ -1,7 +1,5 @@ -import gc import sys from concurrent import futures -from textwrap import dedent from threading import Thread import pytest @@ -38,98 +36,6 @@ def crash(): assert not events -@pytest.mark.filterwarnings("ignore:.*:pytest.PytestUnhandledThreadExceptionWarning") -@pytest.mark.parametrize("propagate_hub", (True, False)) -def test_propagates_hub(sentry_init, capture_events, propagate_hub): - sentry_init( - default_integrations=False, - integrations=[ThreadingIntegration(propagate_hub=propagate_hub)], - ) - events = capture_events() - - def stage1(): - sentry_sdk.get_isolation_scope().set_tag("stage1", "true") - - t = Thread(target=stage2) - t.start() - t.join() - - def stage2(): - 1 / 0 - - t = Thread(target=stage1) - t.start() - t.join() - - (event,) = events - - (exception,) = event["exception"]["values"] - - assert exception["type"] == "ZeroDivisionError" - assert exception["mechanism"]["type"] == "threading" - assert not exception["mechanism"]["handled"] - - # Free-threaded builds set thread_inherit_context to True, otherwise thread_inherit_context is False - if propagate_hub or getattr(sys.flags, "thread_inherit_context", None): - assert event["tags"]["stage1"] == "true" - else: - assert "stage1" not in event.get("tags", {}) - - -@pytest.mark.parametrize("propagate_hub", (True, False)) -def test_propagates_threadpool_hub(sentry_init, capture_events, propagate_hub): - sentry_init( - traces_sample_rate=1.0, - integrations=[ThreadingIntegration(propagate_hub=propagate_hub)], - ) - events = capture_events() - - def double(number): - with sentry_sdk.start_span(op="task", name=str(number)): - return number * 2 - - with sentry_sdk.start_transaction(name="test_handles_threadpool"): - with futures.ThreadPoolExecutor(max_workers=1) as executor: - tasks = [executor.submit(double, number) for number in [1, 2, 3, 4]] - for future in futures.as_completed(tasks): - print("Getting future value!", future.result()) - - sentry_sdk.flush() - - # Free-threaded builds set thread_inherit_context to True, otherwise thread_inherit_context is False - if propagate_hub or getattr(sys.flags, "thread_inherit_context", None): - assert len(events) == 1 - (event,) = events - assert event["spans"][0]["trace_id"] == event["spans"][1]["trace_id"] - assert event["spans"][1]["trace_id"] == event["spans"][2]["trace_id"] - assert event["spans"][2]["trace_id"] == event["spans"][3]["trace_id"] - assert event["spans"][3]["trace_id"] == event["spans"][0]["trace_id"] - else: - (event,) = events - assert len(event["spans"]) == 0 - - -@pytest.mark.skip(reason="Temporarily disable to release SDK 2.0a1.") -def test_circular_references(sentry_init, request): - sentry_init(default_integrations=False, integrations=[ThreadingIntegration()]) - - gc.collect() - gc.disable() - request.addfinalizer(gc.enable) - - class MyThread(Thread): - def run(self): - pass - - t = MyThread() - t.start() - t.join() - del t - - unreachable_objects = gc.collect() - assert unreachable_objects == 0 - - @pytest.mark.filterwarnings("ignore:.*:pytest.PytestUnhandledThreadExceptionWarning") def test_double_patching(sentry_init, capture_events): sentry_init(default_integrations=False, integrations=[ThreadingIntegration()]) @@ -222,67 +128,61 @@ def do_some_work(): ids=["propagate_scope=True", "propagate_scope=False"], ) def test_spans_from_multiple_threads( - sentry_init, capture_events, render_span_tree, propagate_scope + sentry_init, capture_items, render_span_tree, propagate_scope ): sentry_init( traces_sample_rate=1.0, integrations=[ThreadingIntegration(propagate_scope=propagate_scope)], ) - events = capture_events() + items = capture_items("span") def do_some_work(number): - with sentry_sdk.start_span( - op=f"inner-run-{number}", name=f"Thread: child-{number}" - ): - pass + with sentry_sdk.start_span(name=f"inner-run-{number}") as span: + inner_run_spans[number] = span threads = [] + outer_submit_spans = {} + inner_run_spans = {} - with sentry_sdk.start_transaction(op="outer-trx"): + with sentry_sdk.start_span(name="outer-seg", parent_span=None) as outer: for number in range(5): - with sentry_sdk.start_span( - op=f"outer-submit-{number}", name="Thread: main" - ): + with sentry_sdk.start_span(name=f"outer-submit-{number}") as span: t = Thread(target=do_some_work, args=(number,)) t.start() threads.append(t) + outer_submit_spans[number] = span for t in threads: t.join() - (event,) = events + sentry_sdk.flush() + + spans = [item.payload for item in items] + assert len(spans) == 11 + + for span in spans: + if span["name"] == "outer-seg": + assert span["is_segment"] is True + assert "parent_span_id" not in span + + if span["name"].startswith("outer-submit-"): + assert span["is_segment"] is False + assert span["parent_span_id"] == outer.span_id # Free-threaded builds set thread_inherit_context to True, otherwise thread_inherit_context is False if propagate_scope or getattr(sys.flags, "thread_inherit_context", None): - assert event["type"] == "transaction" - assert render_span_tree(event["spans"], event["contexts"]["trace"]) == dedent( - """\ - - op="outer-trx": description=null - - op="outer-submit-0": description="Thread: main" - - op="inner-run-0": description="Thread: child-0" - - op="outer-submit-1": description="Thread: main" - - op="inner-run-1": description="Thread: child-1" - - op="outer-submit-2": description="Thread: main" - - op="inner-run-2": description="Thread: child-2" - - op="outer-submit-3": description="Thread: main" - - op="inner-run-3": description="Thread: child-3" - - op="outer-submit-4": description="Thread: main" - - op="inner-run-4": description="Thread: child-4"\ -""" - ) + for span in spans: + if span["name"].startswith("inner-run-"): + num = int(span["name"][-1]) + assert span["is_segment"] is False + assert span["parent_span_id"] == outer_submit_spans[num].span_id elif not propagate_scope: - assert event["type"] == "transaction" - assert render_span_tree(event["spans"], event["contexts"]["trace"]) == dedent( - """\ - - op="outer-trx": description=null - - op="outer-submit-0": description="Thread: main" - - op="outer-submit-1": description="Thread: main" - - op="outer-submit-2": description="Thread: main" - - op="outer-submit-3": description="Thread: main" - - op="outer-submit-4": description="Thread: main"\ -""" - ) + for span in spans: + if span["name"].startswith("inner-run-"): + num = int(span["name"][-1]) + assert span["is_segment"] is True + assert "parent_span_id" not in span @pytest.mark.parametrize( @@ -291,59 +191,55 @@ def do_some_work(number): ids=["propagate_scope=True", "propagate_scope=False"], ) def test_spans_from_threadpool( - sentry_init, capture_events, render_span_tree, propagate_scope + sentry_init, capture_items, render_span_tree, propagate_scope ): sentry_init( traces_sample_rate=1.0, integrations=[ThreadingIntegration(propagate_scope=propagate_scope)], ) - events = capture_events() + items = capture_items() def do_some_work(number): - with sentry_sdk.start_span( - op=f"inner-run-{number}", name=f"Thread: child-{number}" - ): - pass + with sentry_sdk.start_span(name=f"inner-run-{number}") as span: + inner_run_spans[number] = span + + outer_submit_spans = {} + inner_run_spans = {} - with sentry_sdk.start_transaction(op="outer-trx"): + with sentry_sdk.start_span(name="outer-seg") as outer: with futures.ThreadPoolExecutor(max_workers=1) as executor: for number in range(5): - with sentry_sdk.start_span( - op=f"outer-submit-{number}", name="Thread: main" - ): + with sentry_sdk.start_span(name=f"outer-submit-{number}") as span: + outer_submit_spans[number] = span future = executor.submit(do_some_work, number) future.result() - (event,) = events + sentry_sdk.flush() + + spans = [item.payload for item in items] + assert len(spans) == 11 + + # Free-threaded builds set thread_inherit_context to True, otherwise thread_inherit_context is False + for span in spans: + if span["name"] == "outer-seg": + assert span["is_segment"] is True + assert "parent_span_id" not in span + + if span["name"].startswith("outer-submit-"): + assert span["is_segment"] is False + assert span["parent_span_id"] == outer.span_id # Free-threaded builds set thread_inherit_context to True, otherwise thread_inherit_context is False if propagate_scope or getattr(sys.flags, "thread_inherit_context", None): - assert event["type"] == "transaction" - assert render_span_tree(event["spans"], event["contexts"]["trace"]) == dedent( - """\ - - op="outer-trx": description=null - - op="outer-submit-0": description="Thread: main" - - op="inner-run-0": description="Thread: child-0" - - op="outer-submit-1": description="Thread: main" - - op="inner-run-1": description="Thread: child-1" - - op="outer-submit-2": description="Thread: main" - - op="inner-run-2": description="Thread: child-2" - - op="outer-submit-3": description="Thread: main" - - op="inner-run-3": description="Thread: child-3" - - op="outer-submit-4": description="Thread: main" - - op="inner-run-4": description="Thread: child-4"\ -""" - ) + for span in spans: + if span["name"].startswith("inner-run-"): + num = int(span["name"][-1]) + assert span["is_segment"] is False + assert span["parent_span_id"] == outer_submit_spans[num].span_id elif not propagate_scope: - assert event["type"] == "transaction" - assert render_span_tree(event["spans"], event["contexts"]["trace"]) == dedent( - """\ - - op="outer-trx": description=null - - op="outer-submit-0": description="Thread: main" - - op="outer-submit-1": description="Thread: main" - - op="outer-submit-2": description="Thread: main" - - op="outer-submit-3": description="Thread: main" - - op="outer-submit-4": description="Thread: main"\ -""" - ) + for span in spans: + if span["name"].startswith("inner-run-"): + num = int(span["name"][-1]) + assert span["is_segment"] is True + assert "parent_span_id" not in span diff --git a/tests/integrations/tornado/test_tornado.py b/tests/integrations/tornado/test_tornado.py index e995e3e2be..0750d49747 100644 --- a/tests/integrations/tornado/test_tornado.py +++ b/tests/integrations/tornado/test_tornado.py @@ -5,7 +5,7 @@ from tornado.web import Application, HTTPError, RequestHandler import sentry_sdk -from sentry_sdk import capture_message, start_transaction +from sentry_sdk import capture_message from sentry_sdk._types import SENSITIVE_DATA_SUBSTITUTE from sentry_sdk.integrations.tornado import TornadoIntegration from tests.integrations.utils import ( @@ -69,52 +69,11 @@ async def post(self): class ChildSpanHandler(RequestHandler): def get(self): - with sentry_sdk.traces.start_span(name="child-span"): + with sentry_sdk.start_span(name="child-span"): pass self.write("ok") -def test_basic(tornado_testcase, sentry_init, capture_events): - sentry_init(integrations=[TornadoIntegration()], send_default_pii=True) - events = capture_events() - client = tornado_testcase(Application([(r"/hi", CrashingHandler)])) - - response = client.fetch( - "/hi?foo=bar", headers={"Cookie": "name=value; name2=value2; name3=value3"} - ) - assert response.code == 500 - - (event,) = events - (exception,) = event["exception"]["values"] - assert exception["type"] == "ZeroDivisionError" - assert exception["mechanism"]["type"] == "tornado" - - request = event["request"] - host = request["headers"]["Host"] - assert event["request"] == { - "env": {"REMOTE_ADDR": "127.0.0.1"}, - "headers": { - "Accept-Encoding": "gzip", - "Connection": "close", - "Cookie": "name=value; name2=value2; name3=value3", - **request["headers"], - }, - "cookies": {"name": "value", "name2": "value2", "name3": "value3"}, - "method": "GET", - "query_string": "foo=bar", - "url": "http://{host}/hi".format(host=host), - } - - assert event["tags"] == {"foo": "42"} - assert ( - event["transaction"] - == "tests.integrations.tornado.test_tornado.CrashingHandler.get" - ) - assert event["transaction_info"] == {"source": "component"} - - assert not sentry_sdk.get_isolation_scope()._tags - - # Sent by every data-collection cookie test below. Mixes benign cookies # (``theme``, ``lang``) with ones whose names match the data-collection # sensitive denylist (``jwt``, ``identity``). Those two names are deliberately @@ -300,14 +259,13 @@ async def get(self): @pytest.mark.parametrize( "init_kwargs, expected_query", _QUERY_PARAM_DATA_COLLECTION_CASES ) -def test_url_query_data_collection_span_streaming( +def test_url_query_data_collection( tornado_testcase, sentry_init, capture_items, init_kwargs, expected_query ): init_kwargs = dict(init_kwargs) sentry_init( integrations=[TornadoIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", **init_kwargs, ) @@ -341,48 +299,12 @@ def test_url_query_data_collection_span_streaming( assert server_span["attributes"]["url.path"] == "/hi" -@pytest.mark.parametrize( - "init_kwargs, expected_query", _QUERY_PARAM_DATA_COLLECTION_CASES -) -def test_url_query_data_collection_event_processor( - tornado_testcase, sentry_init, capture_events, init_kwargs, expected_query -): - sentry_init( - integrations=[TornadoIntegration()], - traces_sample_rate=1.0, - trace_lifecycle="static", - **init_kwargs, - ) - - events = capture_events() - - client = tornado_testcase(Application([(r"/hi", QueryHandler)])) - response = client.fetch("/hi?toy=tennisball&color=red&auth=secret") - assert response.code == 200 - - sentry_sdk.flush() - - (event,) = events - - assert event["request"]["url"].endswith("/hi") - assert event["request"]["method"] == "GET" - if "data_collection" not in init_kwargs: - assert ( - event["request"]["query_string"] == "toy=tennisball&color=red&auth=secret" - ) - elif expected_query is None: - assert "query_string" not in event["request"] - else: - assert event["request"]["query_string"] == expected_query - - def test_url_query_data_collection_no_query_string( tornado_testcase, sentry_init, capture_items ): sentry_init( integrations=[TornadoIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", data_collection={}, ) @@ -407,7 +329,6 @@ def test_url_query_data_collection_repeated_and_blank_params( sentry_init( integrations=[TornadoIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", data_collection={}, ) @@ -424,54 +345,6 @@ def test_url_query_data_collection_repeated_and_blank_params( assert server_span["attributes"]["url.query"] == "a=1&a=2&b=" -def test_url_query_data_collection__event_processor_no_query_string( - tornado_testcase, sentry_init, capture_events -): - sentry_init( - integrations=[TornadoIntegration()], - traces_sample_rate=1.0, - trace_lifecycle="static", - data_collection={}, - ) - - events = capture_events() - - client = tornado_testcase(Application([(r"/hi", QueryHandler)])) - response = client.fetch("/hi") - assert response.code == 200 - - sentry_sdk.flush() - - (event,) = events - - assert "query_string" not in event["request"] - assert event["request"]["url"].endswith("/hi") - assert event["request"]["method"] == "GET" - - -def test_url_query_data_collection_event_processor_repeated_and_blank_params( - tornado_testcase, sentry_init, capture_events -): - sentry_init( - integrations=[TornadoIntegration()], - traces_sample_rate=1.0, - trace_lifecycle="static", - data_collection={}, - ) - - events = capture_events() - - client = tornado_testcase(Application([(r"/hi", QueryHandler)])) - response = client.fetch("/hi?a=1&a=2&b=") - assert response.code == 200 - - sentry_sdk.flush() - - (event,) = events - - assert event["request"]["query_string"] == "a=1&a=2&b=" - - @pytest.mark.parametrize( "data_collection, expect_body", [ @@ -491,13 +364,12 @@ def test_url_query_data_collection_event_processor_repeated_and_blank_params( ), ], ) -def test_request_body_data_collection_span_streaming( +def test_request_body_data_collection( tornado_testcase, sentry_init, capture_items, data_collection, expect_body ): sentry_init( integrations=[TornadoIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", data_collection=data_collection, ) @@ -517,6 +389,33 @@ def test_request_body_data_collection_span_streaming( assert "http.request.body.data" not in server_span["attributes"] +def test_oversized_request_body_not_annotated_data_collection( + tornado_testcase, sentry_init, capture_items +): + """ + The gating happens before the size check, so an oversized body is dropped + outright instead of being reported as removed because of the size limit. + """ + sentry_init( + integrations=[TornadoIntegration()], + traces_sample_rate=1.0, + max_request_body_size="small", + data_collection={"http_bodies": []}, + ) + + items = capture_items("span") + + client = tornado_testcase(Application([(r"/hi", HelloHandler)])) + response = client.fetch("/hi", method="POST", body=b"a" * 2000) + assert response.code == 200 + + sentry_sdk.flush() + + (server_span,) = [item.payload for item in items] + + assert "http.request.body.data" not in server_span["attributes"] + + @pytest.mark.parametrize( "data_collection, expect_body", [ @@ -541,7 +440,6 @@ def test_request_body_data_collection_event_processor( ): sentry_init( integrations=[TornadoIntegration()], - trace_lifecycle="static", data_collection=data_collection, ) @@ -567,36 +465,7 @@ def test_request_body_data_collection_event_processor( assert "data" not in event["request"] -def test_oversized_request_body_not_annotated_data_collection_span_streaming( - tornado_testcase, sentry_init, capture_items -): - """ - The gating happens before the size check, so an oversized body is dropped - outright instead of being reported as removed because of the size limit. - """ - sentry_init( - integrations=[TornadoIntegration()], - traces_sample_rate=1.0, - trace_lifecycle="stream", - max_request_body_size="small", - data_collection={"http_bodies": []}, - ) - - items = capture_items("span") - - client = tornado_testcase(Application([(r"/hi", HelloHandler)])) - response = client.fetch("/hi", method="POST", body=b"a" * 2000) - assert response.code == 200 - - sentry_sdk.flush() - - (server_span,) = [item.payload for item in items] - - assert "http.request.body.data" not in server_span["attributes"] - - @pytest.mark.parametrize("send_pii", [True, False]) -@pytest.mark.parametrize("span_streaming", [True, False]) @pytest.mark.parametrize( "handler,code", [ @@ -611,30 +480,20 @@ def test_transactions( capture_items, handler, code, - span_streaming, send_pii, ): sentry_init( integrations=[TornadoIntegration()], traces_sample_rate=1.0, send_default_pii=send_pii, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("event", "span") - else: - events = capture_events() + items = capture_items("event", "span") client = tornado_testcase(Application([(r"/hi", handler)])) - if span_streaming: - with sentry_sdk.traces.start_span(name="client") as span: - request_headers = dict(span._iter_headers()) - else: - with start_transaction(name="client") as span: - pass - request_headers = dict(span.iter_headers()) + with sentry_sdk.start_span(name="client") as span: + request_headers = dict(span._iter_headers()) response = client.fetch( "/hi?foo=bar", method="POST", body=b"heyoo", headers=request_headers @@ -643,111 +502,46 @@ def test_transactions( sentry_sdk.flush() - if span_streaming: - spans = [i.payload for i in items if i.type == "span"] - errors = [i.payload for i in items if i.type == "event"] - - client_segment, server_segment = spans - - if code == 500: - assert len(errors) == 1 - server_error = errors[0] - assert server_error["exception"]["values"][0]["type"] == "ZeroDivisionError" - assert ( - server_error["transaction"] - == "tests.integrations.tornado.test_tornado.CrashingHandler.post" - ) - assert server_error["transaction_info"] == {"source": "component"} - assert ( - server_error["contexts"]["trace"]["trace_id"] - == server_segment["trace_id"] - ) - - expected_handler = ( - "tests.integrations.tornado.test_tornado.HelloHandler.post" - if code == 200 - else "tests.integrations.tornado.test_tornado.CrashingHandler.post" - ) - assert server_segment["name"] == expected_handler - assert server_segment["attributes"]["sentry.segment.name.source"] == "component" - assert server_segment["attributes"]["http.request.method"] == "POST" - assert server_segment["attributes"]["http.request.body.data"] == "heyoo" - assert server_segment["attributes"]["http.response.status_code"] == code - assert server_segment["status"] == ("ok" if code == 200 else "error") - assert client_segment["trace_id"] == server_segment["trace_id"] - - if send_pii: - assert server_segment["attributes"]["url.query"] == "foo=bar" - assert server_segment["attributes"]["url.full"].endswith("/hi?foo=bar") - assert server_segment["attributes"]["url.full"].startswith("http://") - assert server_segment["attributes"]["url.path"] == "/hi" - else: - assert "url.query" not in server_segment["attributes"] - assert "url.full" not in server_segment["attributes"] - assert "url.path" not in server_segment["attributes"] - else: - if code == 200: - client_tx, server_tx = events - server_error = None - else: - client_tx, server_error, server_tx = events - - assert client_tx["type"] == "transaction" - assert client_tx["transaction"] == "client" - assert client_tx["transaction_info"] == { - "source": "custom" - } # because this is just the start_transaction() above. - - if server_error is not None: - assert server_error["exception"]["values"][0]["type"] == "ZeroDivisionError" - assert ( - server_error["transaction"] - == "tests.integrations.tornado.test_tornado.CrashingHandler.post" - ) - assert server_error["transaction_info"] == {"source": "component"} - - if code == 200: - assert ( - server_tx["transaction"] - == "tests.integrations.tornado.test_tornado.HelloHandler.post" - ) - else: - assert ( - server_tx["transaction"] - == "tests.integrations.tornado.test_tornado.CrashingHandler.post" - ) - - assert server_tx["transaction_info"] == {"source": "component"} - assert server_tx["type"] == "transaction" - - request = server_tx["request"] - host = request["headers"]["Host"] - expected_request = { - "env": {"REMOTE_ADDR": "127.0.0.1"}, - "headers": { - "Accept-Encoding": "gzip", - "Connection": "close", - **request["headers"], - }, - "method": "POST", - "query_string": "foo=bar", - "data": {"heyoo": [""]}, - "url": "http://{host}/hi".format(host=host), - } - if send_pii: - expected_request["cookies"] = {} - assert server_tx["request"] == expected_request + spans = [i.payload for i in items if i.type == "span"] + errors = [i.payload for i in items if i.type == "event"] + + client_segment, server_segment = spans + if code == 500: + assert len(errors) == 1 + server_error = errors[0] + assert server_error["exception"]["values"][0]["type"] == "ZeroDivisionError" + assert ( + server_error["transaction"] + == "tests.integrations.tornado.test_tornado.CrashingHandler.post" + ) + assert server_error["transaction_info"] == {"source": "component"} assert ( - client_tx["contexts"]["trace"]["trace_id"] - == server_tx["contexts"]["trace"]["trace_id"] + server_error["contexts"]["trace"]["trace_id"] == server_segment["trace_id"] ) - if server_error is not None: - assert ( - server_error["contexts"]["trace"]["trace_id"] - == server_tx["contexts"]["trace"]["trace_id"] - ) + expected_handler = ( + "tests.integrations.tornado.test_tornado.HelloHandler.post" + if code == 200 + else "tests.integrations.tornado.test_tornado.CrashingHandler.post" + ) + assert server_segment["name"] == expected_handler + assert server_segment["attributes"]["sentry.segment.name.source"] == "component" + assert server_segment["attributes"]["http.request.method"] == "POST" + assert server_segment["attributes"]["http.request.body.data"] == "heyoo" + assert server_segment["attributes"]["http.response.status_code"] == code + assert server_segment["status"] == ("ok" if code == 200 else "error") + assert client_segment["trace_id"] == server_segment["trace_id"] + + if send_pii: + assert server_segment["attributes"]["url.query"] == "foo=bar" + assert server_segment["attributes"]["url.full"].endswith("/hi?foo=bar") + assert server_segment["attributes"]["url.full"].startswith("http://") + assert server_segment["attributes"]["url.path"] == "/hi" + else: + assert "url.query" not in server_segment["attributes"] + assert "url.full" not in server_segment["attributes"] + assert "url.path" not in server_segment["attributes"] def test_400_not_logged(tornado_testcase, sentry_init, capture_events): @@ -888,43 +682,42 @@ def post(self): def test_error_has_new_trace_context_performance_enabled( - tornado_testcase, sentry_init, capture_events + tornado_testcase, sentry_init, capture_items ): """ - Check if an 'trace' context is added to errros and transactions when performance monitoring is enabled. + Check if a 'trace' context is added to events when performance monitoring is enabled. """ sentry_init( integrations=[TornadoIntegration()], traces_sample_rate=1.0, ) - events = capture_events() + items = capture_items() client = tornado_testcase(Application([(r"/hi", CrashingWithMessageHandler)])) client.fetch("/hi") - (msg_event, error_event, transaction_event) = events + sentry_sdk.flush() - assert "trace" in msg_event["contexts"] - assert "trace_id" in msg_event["contexts"]["trace"] + (message, error, span) = [item.payload for item in items] - assert "trace" in error_event["contexts"] - assert "trace_id" in error_event["contexts"]["trace"] + assert "trace" in message["contexts"] + assert "trace_id" in message["contexts"]["trace"] - assert "trace" in transaction_event["contexts"] - assert "trace_id" in transaction_event["contexts"]["trace"] + assert "trace" in error["contexts"] + assert "trace_id" in error["contexts"]["trace"] assert ( - msg_event["contexts"]["trace"]["trace_id"] - == error_event["contexts"]["trace"]["trace_id"] - == transaction_event["contexts"]["trace"]["trace_id"] + message["contexts"]["trace"]["trace_id"] + == error["contexts"]["trace"]["trace_id"] ) + assert message["contexts"]["trace"]["trace_id"] == span["trace_id"] def test_error_has_new_trace_context_performance_disabled( tornado_testcase, sentry_init, capture_events ): """ - Check if an 'trace' context is added to errros and transactions when performance monitoring is disabled. + Check if a 'trace' context is added to events when performance monitoring is disabled. """ sentry_init( integrations=[TornadoIntegration()], @@ -950,17 +743,17 @@ def test_error_has_new_trace_context_performance_disabled( def test_error_has_existing_trace_context_performance_enabled( - tornado_testcase, sentry_init, capture_events + tornado_testcase, sentry_init, capture_items ): """ - Check if an 'trace' context is added to errros and transactions + Check if an 'trace' context is added to events from the incoming 'sentry-trace' header when performance monitoring is enabled. """ sentry_init( integrations=[TornadoIntegration()], traces_sample_rate=1.0, ) - events = capture_events() + items = capture_items() trace_id = "471a43a4192642f0b136d5159a501701" parent_span_id = "6e8f22c393e68f19" @@ -972,21 +765,19 @@ def test_error_has_existing_trace_context_performance_enabled( client = tornado_testcase(Application([(r"/hi", CrashingWithMessageHandler)])) client.fetch("/hi", headers=headers) - (msg_event, error_event, transaction_event) = events + sentry_sdk.flush() - assert "trace" in msg_event["contexts"] - assert "trace_id" in msg_event["contexts"]["trace"] + (message, error, span) = [item.payload for item in items] - assert "trace" in error_event["contexts"] - assert "trace_id" in error_event["contexts"]["trace"] + assert "trace" in message["contexts"] + assert "trace_id" in message["contexts"]["trace"] - assert "trace" in transaction_event["contexts"] - assert "trace_id" in transaction_event["contexts"]["trace"] + assert "trace" in error["contexts"] + assert "trace_id" in error["contexts"]["trace"] assert ( - msg_event["contexts"]["trace"]["trace_id"] - == error_event["contexts"]["trace"]["trace_id"] - == transaction_event["contexts"]["trace"]["trace_id"] + message["contexts"]["trace"]["trace_id"] + == error["contexts"]["trace"]["trace_id"] == "471a43a4192642f0b136d5159a501701" ) @@ -995,7 +786,7 @@ def test_error_has_existing_trace_context_performance_disabled( tornado_testcase, sentry_init, capture_events ): """ - Check if an 'trace' context is added to errros and transactions + Check if an 'trace' context is added to events from the incoming 'sentry-trace' header when performance monitoring is disabled. """ sentry_init( @@ -1029,20 +820,18 @@ def test_error_has_existing_trace_context_performance_disabled( ) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_span_origin( - tornado_testcase, sentry_init, capture_events, capture_items, span_streaming + tornado_testcase, + sentry_init, + capture_events, + capture_items, ): sentry_init( integrations=[TornadoIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") - else: - events = capture_events() + items = capture_items("span") client = tornado_testcase(Application([(r"/hi", CrashingHandler)])) @@ -1052,12 +841,8 @@ def test_span_origin( sentry_sdk.flush() - if span_streaming: - (segment,) = [i.payload for i in items] - assert segment["attributes"]["sentry.origin"] == "auto.http.tornado" - else: - (_, event) = events - assert event["contexts"]["trace"]["origin"] == "auto.http.tornado" + (segment,) = [i.payload for i in items] + assert segment["attributes"]["sentry.origin"] == "auto.http.tornado" @pytest.mark.parametrize("init_kwargs, expect_ip", DATA_COLLECTION_USER_INFO_CASES) @@ -1067,7 +852,6 @@ def test_user_ip_address_on_all_spans( sentry_init( integrations=[TornadoIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", **init_kwargs, ) @@ -1095,7 +879,6 @@ def test_client_address_span_attribute_data_collection( sentry_init( integrations=[TornadoIntegration()], traces_sample_rate=1.0, - trace_lifecycle="stream", **init_kwargs, ) diff --git a/tests/integrations/trytond/__init__.py b/tests/integrations/trytond_wsgi/__init__.py similarity index 100% rename from tests/integrations/trytond/__init__.py rename to tests/integrations/trytond_wsgi/__init__.py diff --git a/tests/integrations/trytond/test_trytond.py b/tests/integrations/trytond_wsgi/test_trytond.py similarity index 91% rename from tests/integrations/trytond/test_trytond.py rename to tests/integrations/trytond_wsgi/test_trytond.py index face56ce1b..619cd40eed 100644 --- a/tests/integrations/trytond/test_trytond.py +++ b/tests/integrations/trytond_wsgi/test_trytond.py @@ -2,7 +2,6 @@ import unittest.mock import pytest -import trytond from trytond.exceptions import LoginException from trytond.exceptions import TrytonException as TrytondBaseException from trytond.exceptions import UserError as TrytondUserError @@ -10,6 +9,7 @@ from trytond.wsgi import app as trytond_app from werkzeug.test import Client +import sentry_sdk from sentry_sdk.integrations.trytond import TrytondWSGIIntegration from tests.conftest import unpack_werkzeug_response @@ -75,9 +75,6 @@ def _(request): assert not exceptions -@pytest.mark.skipif( - trytond.__version__.split(".") < ["5", "4"], reason="At least Trytond-5.4 required" -) def test_rpc_error_page(sentry_init, app, get_client): """Test that, after initializing the Trytond-SentrySDK integration a custom error handler can be registered to the Trytond WSGI app so as to @@ -125,12 +122,12 @@ def _(app, request, e): assert data == dict(id=42, error=["UserError", ["Sentry error.", "foo", None]]) -def test_span_origin(sentry_init, app, capture_events, get_client): +def test_span_origin(sentry_init, app, capture_items, get_client): sentry_init( integrations=[TrytondWSGIIntegration()], traces_sample_rate=1.0, ) - events = capture_events() + items = capture_items("span") @app.route("/something") def _(request): @@ -139,6 +136,9 @@ def _(request): client = get_client() client.get("/something") - (event,) = events + sentry_sdk.flush() + + (item,) = items + span = item.payload - assert event["contexts"]["trace"]["origin"] == "auto.http.trytond_wsgi" + assert span["attributes"]["sentry.origin"] == "auto.http.trytond_wsgi" diff --git a/tests/integrations/unleash/test_unleash.py b/tests/integrations/unleash/test_unleash.py index 00616f11c5..9287fe51c4 100644 --- a/tests/integrations/unleash/test_unleash.py +++ b/tests/integrations/unleash/test_unleash.py @@ -1,5 +1,4 @@ import concurrent.futures as cf -import sys from random import random from unittest import mock @@ -7,9 +6,7 @@ from UnleashClient import UnleashClient import sentry_sdk -from sentry_sdk import start_span, start_transaction from sentry_sdk.integrations.unleash import UnleashIntegration -from tests.conftest import ApproxDict from tests.integrations.unleash.testutils import mock_unleash_client @@ -85,7 +82,6 @@ def task(flag_key): } -@pytest.mark.skipif(sys.version_info < (3, 7), reason="requires python3.7 or higher") def test_is_enabled_asyncio(sentry_init, capture_events, uninstall_integration): asyncio = pytest.importorskip("asyncio") uninstall_integration(UnleashIntegration.identifier) @@ -168,12 +164,11 @@ def test_wrapper_attributes(sentry_init, uninstall_integration): assert client.is_enabled.__qualname__ == original_is_enabled.__qualname__ -@pytest.mark.parametrize( - "span_streaming", - [True, False], -) def test_unleash_span_integration( - sentry_init, capture_events, capture_items, uninstall_integration, span_streaming + sentry_init, + capture_events, + capture_items, + uninstall_integration, ): uninstall_integration(UnleashIntegration.identifier) @@ -181,32 +176,18 @@ def test_unleash_span_integration( sentry_init( traces_sample_rate=1.0, integrations=[UnleashIntegration()], - trace_lifecycle="stream" if span_streaming else "static", ) client = UnleashClient() # type: ignore[arg-type] - if span_streaming: - items = capture_items("span") - with sentry_sdk.traces.start_span(name="bar"): - client.is_enabled("hello") - client.is_enabled("other") - - sentry_sdk.flush() - - assert len(items) == 1 - span = items[0].payload - assert span["attributes"]["flag.evaluation.hello"] is True - assert span["attributes"]["flag.evaluation.other"] is False - - else: - events = capture_events() - with start_transaction(name="hi"): - with start_span(op="foo", name="bar"): - client.is_enabled("hello") - client.is_enabled("other") - - (event,) = events - assert event["spans"][0]["data"] == ApproxDict( - {"flag.evaluation.hello": True, "flag.evaluation.other": False} - ) + items = capture_items("span") + with sentry_sdk.start_span(name="bar"): + client.is_enabled("hello") + client.is_enabled("other") + + sentry_sdk.flush() + + assert len(items) == 1 + span = items[0].payload + assert span["attributes"]["flag.evaluation.hello"] is True + assert span["attributes"]["flag.evaluation.other"] is False diff --git a/tests/integrations/utils.py b/tests/integrations/utils.py index 2f0cbbaff7..4fd0cf413f 100644 --- a/tests/integrations/utils.py +++ b/tests/integrations/utils.py @@ -1,7 +1,5 @@ import pytest -from sentry_sdk.utils import SENSITIVE_DATA_SUBSTITUTE - # Shared parametrization test matrix exercising the precedence between the legacy # ``send_default_pii`` boolean and the ``data_collection.user_info`` setting. # Each case is ``(init_kwargs, expect_user_info)`` where the second element indicates @@ -39,15 +37,9 @@ ), ] -# Shared parametrization test matrix for ``REMOTE_ADDR`` on events in -# integrations that set it unconditionally pre-data collection (tornado, sanic, -# aiohttp). Each case is ``(init_kwargs, expect_remote_addr)``: the address is -# only gated once ``data_collection`` is enabled, so the legacy -# ``send_default_pii`` cases still expect it to be collected. +# Shared parametrization test matrix for ``REMOTE_ADDR`` on events. +# Each case is ``(init_kwargs, expect_remote_addr)``. DATA_COLLECTION_REMOTE_ADDR_CASES = [ - pytest.param({}, True, id="defaults"), - pytest.param({"send_default_pii": True}, True, id="send_default_pii_true"), - pytest.param({"send_default_pii": False}, True, id="send_default_pii_false"), pytest.param({"data_collection": {}}, True, id="data_collection_default"), pytest.param( {"data_collection": {"user_info": True}}, @@ -59,14 +51,6 @@ False, id="data_collection_user_info_false", ), - pytest.param( - { - "send_default_pii": True, - "data_collection": {"user_info": False}, - }, - False, - id="data_collection_wins_over_send_default_pii", - ), ] # Shared parametrization test matrix exercising the interaction between the @@ -93,28 +77,4 @@ None, id="data_collection_queues_off", ), - pytest.param( - {"send_default_pii": False}, - SENSITIVE_DATA_SUBSTITUTE, - SENSITIVE_DATA_SUBSTITUTE, - id="no_pii", - ), - pytest.param( - { - "data_collection": {"queues": False}, - "send_default_pii": False, - }, - None, - None, - id="data_collection_queues_off_with_no_pii", - ), - pytest.param( - { - "data_collection": {"queues": True}, - "send_default_pii": False, - }, - [1], - {"b": 0}, - id="data_collection_queues_on_with_no_pii", - ), ] diff --git a/tests/integrations/wsgi/test_wsgi.py b/tests/integrations/wsgi/test_wsgi.py index 6fbd0a8d7f..12fed06ff8 100644 --- a/tests/integrations/wsgi/test_wsgi.py +++ b/tests/integrations/wsgi/test_wsgi.py @@ -56,7 +56,6 @@ def test_basic(sentry_init, crashing_app, capture_events): (event,) = events assert event["transaction"] == "generic WSGI request" - assert event["request"] == { "env": {"SERVER_NAME": "localhost", "SERVER_PORT": "80"}, "headers": {"Host": "localhost"}, @@ -140,14 +139,12 @@ def test_keyboard_interrupt_is_captured(sentry_init, capture_events): assert event["level"] == "error" -@pytest.mark.parametrize("span_streaming", [True, False]) def test_transaction_with_error( sentry_init, crashing_app, capture_events, capture_items, DictionaryContaining, # noqa:N803 - span_streaming, ): def dogpark(environ, start_response): raise ValueError("Fetch aborted. The ball was not returned.") @@ -155,32 +152,23 @@ def dogpark(environ, start_response): sentry_init( send_default_pii=True, traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) app = SentryWsgiMiddleware(dogpark) client = Client(app) - if span_streaming: - items = capture_items("event", "span") - else: - events = capture_events() + items = capture_items("event", "span") with pytest.raises(ValueError): client.get("http://dogs.are.great/sit/stay/rollover/") sentry_sdk.flush() - if span_streaming: - assert len(items) == 2 - assert items[0].type == "event" - assert items[1].type == "span" - - error_event = items[0].payload - span_item = items[1].payload - else: - error_event, envelope = events + assert len(items) == 2 + assert items[0].type == "event" + assert items[1].type == "span" - assert error_event["transaction"] == "generic WSGI request" + error_event = items[0].payload + span_item = items[1].payload assert error_event["contexts"]["trace"]["op"] == "http.server" assert error_event["exception"]["values"][0]["type"] == "ValueError" @@ -191,30 +179,17 @@ def dogpark(environ, start_response): == "Fetch aborted. The ball was not returned." ) - if span_streaming: - assert span_item["trace_id"] == error_event["contexts"]["trace"]["trace_id"] - assert span_item["span_id"] == error_event["contexts"]["trace"]["span_id"] - assert span_item["status"] == "error" - else: - assert envelope["type"] == "transaction" - - # event trace context is a subset of envelope trace context - assert envelope["contexts"]["trace"] == DictionaryContaining( - error_event["contexts"]["trace"] - ) - assert envelope["contexts"]["trace"]["status"] == "internal_error" - assert envelope["transaction"] == error_event["transaction"] - assert envelope["request"] == error_event["request"] + assert span_item["trace_id"] == error_event["contexts"]["trace"]["trace_id"] + assert span_item["span_id"] == error_event["contexts"]["trace"]["span_id"] + assert span_item["status"] == "error" @pytest.mark.parametrize("send_pii", [True, False]) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_transaction_no_error( sentry_init, capture_events, capture_items, DictionaryContaining, # noqa:N803 - span_streaming, send_pii, ): def dogpark(environ, start_response): @@ -224,65 +199,44 @@ def dogpark(environ, start_response): sentry_init( send_default_pii=send_pii, traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) app = SentryWsgiMiddleware(dogpark) client = Client(app) - if span_streaming: - items = capture_items("span") - else: - events = capture_events() + items = capture_items("span") client.get("/dogs/are/great?toy=tennisball") sentry_sdk.flush() - if span_streaming: - assert len(items) == 1 - span = items[0].payload - - assert span["is_segment"] is True - assert span["name"] == "generic WSGI request" - assert span["attributes"]["sentry.op"] == "http.server" - assert span["attributes"]["sentry.segment.name.source"] == "route" - assert span["attributes"]["http.request.method"] == "GET" - assert span["attributes"]["http.response.status_code"] == 200 - assert span["status"] == "ok" - - if send_pii: - assert ( - span["attributes"]["url.full"] - == "http://localhost/dogs/are/great?toy=tennisball" - ) - assert span["attributes"]["url.path"] == "/dogs/are/great" - assert span["attributes"]["http.query"] == "toy=tennisball" - else: - assert "url.path" not in span["attributes"] - assert "url.full" not in span["attributes"] - assert "http.query" not in span["attributes"] + assert len(items) == 1 + span = items[0].payload - else: - envelope = events[0] + assert span["is_segment"] is True + assert span["name"] == "generic WSGI request" + assert span["attributes"]["sentry.op"] == "http.server" + assert span["attributes"]["sentry.segment.name.source"] == "route" + assert span["attributes"]["http.request.method"] == "GET" + assert span["attributes"]["http.response.status_code"] == 200 + assert span["status"] == "ok" - assert envelope["type"] == "transaction" - assert envelope["transaction"] == "generic WSGI request" - assert envelope["contexts"]["trace"]["op"] == "http.server" - assert envelope["request"] == DictionaryContaining( - { - "method": "GET", - "url": "http://localhost/dogs/are/great", - "query_string": "toy=tennisball", - } + if send_pii: + assert ( + span["attributes"]["url.full"] + == "http://localhost/dogs/are/great?toy=tennisball" ) + assert span["attributes"]["url.path"] == "/dogs/are/great" + assert span["attributes"]["http.query"] == "toy=tennisball" + else: + assert "url.path" not in span["attributes"] + assert "url.full" not in span["attributes"] + assert "http.query" not in span["attributes"] -@pytest.mark.parametrize("span_streaming", [True, False]) def test_has_trace_if_performance_enabled( sentry_init, capture_events, capture_items, - span_streaming, ): def dogpark(environ, start_response): capture_message("Attempting to fetch the ball") @@ -290,60 +244,38 @@ def dogpark(environ, start_response): sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) app = SentryWsgiMiddleware(dogpark) client = Client(app) - if span_streaming: - items = capture_items("event", "span") - else: - events = capture_events() + items = capture_items("event", "span") with pytest.raises(ValueError): client.get("http://dogs.are.great/sit/stay/rollover/") sentry_sdk.flush() - if span_streaming: - msg_event, error_event, span_item = items + msg_event, error_event, span_item = items - assert msg_event.type == "event" - msg_event = msg_event.payload - assert msg_event["contexts"]["trace"] - assert "trace_id" in msg_event["contexts"]["trace"] - - assert error_event.type == "event" - error_event = error_event.payload - assert error_event["contexts"]["trace"] - assert "trace_id" in error_event["contexts"]["trace"] - - assert span_item.type == "span" - span_item = span_item.payload - assert span_item["trace_id"] is not None - - assert ( - msg_event["contexts"]["trace"]["trace_id"] - == error_event["contexts"]["trace"]["trace_id"] - == span_item["trace_id"] - ) - else: - msg_event, error_event, transaction_event = events - - assert msg_event["contexts"]["trace"] - assert "trace_id" in msg_event["contexts"]["trace"] + assert msg_event.type == "event" + msg_event = msg_event.payload + assert msg_event["contexts"]["trace"] + assert "trace_id" in msg_event["contexts"]["trace"] - assert error_event["contexts"]["trace"] - assert "trace_id" in error_event["contexts"]["trace"] + assert error_event.type == "event" + error_event = error_event.payload + assert error_event["contexts"]["trace"] + assert "trace_id" in error_event["contexts"]["trace"] - assert transaction_event["contexts"]["trace"] - assert "trace_id" in transaction_event["contexts"]["trace"] + assert span_item.type == "span" + span_item = span_item.payload + assert span_item["trace_id"] is not None - assert ( - msg_event["contexts"]["trace"]["trace_id"] - == error_event["contexts"]["trace"]["trace_id"] - == transaction_event["contexts"]["trace"]["trace_id"] - ) + assert ( + msg_event["contexts"]["trace"]["trace_id"] + == error_event["contexts"]["trace"]["trace_id"] + == span_item["trace_id"] + ) def test_has_trace_if_performance_disabled( @@ -371,12 +303,10 @@ def dogpark(environ, start_response): assert "trace_id" in error_event["contexts"]["trace"] -@pytest.mark.parametrize("span_streaming", [True, False]) def test_trace_from_headers_if_performance_enabled( sentry_init, capture_events, capture_items, - span_streaming, ): def dogpark(environ, start_response): capture_message("Attempting to fetch the ball") @@ -384,15 +314,11 @@ def dogpark(environ, start_response): sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) app = SentryWsgiMiddleware(dogpark) client = Client(app) - if span_streaming: - items = capture_items("event", "span") - else: - events = capture_events() + items = capture_items("event", "span") trace_id = "582b43a4192642f0b136d5159a501701" sentry_trace_header = "{}-{}-{}".format(trace_id, "6e8f22c393e68f19", 1) @@ -405,27 +331,11 @@ def dogpark(environ, start_response): sentry_sdk.flush() - if span_streaming: - msg_event, error_event, span_item = items + msg_event, error_event, span_item = items - assert msg_event.payload["contexts"]["trace"]["trace_id"] == trace_id - assert error_event.payload["contexts"]["trace"]["trace_id"] == trace_id - assert span_item.payload["trace_id"] == trace_id - else: - msg_event, error_event, transaction_event = events - - assert msg_event["contexts"]["trace"] - assert "trace_id" in msg_event["contexts"]["trace"] - - assert error_event["contexts"]["trace"] - assert "trace_id" in error_event["contexts"]["trace"] - - assert transaction_event["contexts"]["trace"] - assert "trace_id" in transaction_event["contexts"]["trace"] - - assert msg_event["contexts"]["trace"]["trace_id"] == trace_id - assert error_event["contexts"]["trace"]["trace_id"] == trace_id - assert transaction_event["contexts"]["trace"]["trace_id"] == trace_id + assert msg_event.payload["contexts"]["trace"]["trace_id"] == trace_id + assert error_event.payload["contexts"]["trace"]["trace_id"] == trace_id + assert span_item.payload["trace_id"] == trace_id def test_trace_from_headers_if_performance_disabled( @@ -461,11 +371,9 @@ def dogpark(environ, start_response): assert error_event["contexts"]["trace"]["trace_id"] == trace_id -@pytest.mark.parametrize("span_streaming", [True, False]) def test_traces_sampler_gets_correct_values_in_sampling_context( sentry_init, DictionaryContaining, # noqa:N803 - span_streaming, ): def app(environ, start_response): start_response("200 OK", []) @@ -475,7 +383,6 @@ def app(environ, start_response): sentry_init( send_default_pii=True, traces_sampler=traces_sampler, - trace_lifecycle="stream" if span_streaming else "static", ) app = SentryWsgiMiddleware(app) client = Client(app) @@ -501,9 +408,9 @@ def app(environ, start_response): ) -@pytest.mark.parametrize("span_streaming", [True, False]) def test_session_mode_defaults_to_request_mode_in_wsgi_handler( - capture_envelopes, sentry_init, span_streaming + capture_envelopes, + sentry_init, ): """ Test that ensures that even though the default `session_mode` for @@ -519,7 +426,6 @@ def app(environ, start_response): sentry_init( send_default_pii=True, traces_sampler=traces_sampler, - trace_lifecycle="stream" if span_streaming else "static", ) app = SentryWsgiMiddleware(app) envelopes = capture_envelopes() @@ -543,9 +449,9 @@ def app(environ, start_response): assert aggregates[0]["exited"] == 1 -@pytest.mark.parametrize("span_streaming", [True, False]) def test_auto_session_tracking_with_aggregates( - sentry_init, capture_envelopes, span_streaming + sentry_init, + capture_envelopes, ): """ Test for correct session aggregates in auto session tracking. @@ -562,7 +468,6 @@ def sample_app(environ, start_response): sentry_init( send_default_pii=True, traces_sampler=traces_sampler, - trace_lifecycle="stream" if span_streaming else "static", ) app = SentryWsgiMiddleware(sample_app) envelopes = capture_envelopes() @@ -583,10 +488,7 @@ def sample_app(environ, start_response): for item in envelope.items: count_item_types[item.type] += 1 - if span_streaming: - assert count_item_types["span"] == 3 - else: - assert count_item_types["transaction"] == 3 + assert count_item_types["span"] == 3 assert count_item_types["event"] == 1 assert count_item_types["sessions"] == 1 @@ -600,35 +502,7 @@ def sample_app(environ, start_response): assert sum(agg.get("crashed", 0) for agg in session_aggregates) == 1 -@mock.patch("sentry_sdk.profiler.transaction_profiler.PROFILE_MINIMUM_SAMPLES", 0) -def test_profile_sent( - sentry_init, - capture_envelopes, - teardown_profiling, -): - def test_app(environ, start_response): - start_response("200 OK", []) - return ["Go get the ball! Good dog!"] - - sentry_init( - traces_sample_rate=1.0, - _experiments={"profiles_sample_rate": 1.0}, - ) - app = SentryWsgiMiddleware(test_app) - envelopes = capture_envelopes() - - client = Client(app) - client.get("/") - - envelopes = [envelope for envelope in envelopes] - assert len(envelopes) == 1 - - profiles = [item for item in envelopes[0].items if item.type == "profile"] - assert len(profiles) == 1 - - -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_span_origin_manual(sentry_init, capture_events, capture_items, span_streaming): +def test_span_origin_manual(sentry_init, capture_events, capture_items): def dogpark(environ, start_response): start_response("200 OK", []) return ["Go get the ball! Good dog!"] @@ -636,30 +510,21 @@ def dogpark(environ, start_response): sentry_init( send_default_pii=True, traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) app = SentryWsgiMiddleware(dogpark) - if span_streaming: - items = capture_items("span") - else: - events = capture_events() + items = capture_items("span") client = Client(app) client.get("/dogs/are/great/") sentry_sdk.flush() - if span_streaming: - assert len(items) == 1 - assert items[0].payload["attributes"]["sentry.origin"] == "manual" - else: - (event,) = events - assert event["contexts"]["trace"]["origin"] == "manual" + assert len(items) == 1 + assert items[0].payload["attributes"]["sentry.origin"] == "manual" -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_span_origin_custom(sentry_init, capture_events, capture_items, span_streaming): +def test_span_origin_custom(sentry_init, capture_events, capture_items): def dogpark(environ, start_response): start_response("200 OK", []) return ["Go get the ball! Good dog!"] @@ -667,29 +532,21 @@ def dogpark(environ, start_response): sentry_init( send_default_pii=True, traces_sample_rate=1.0, - trace_lifecycle="stream" if span_streaming else "static", ) app = SentryWsgiMiddleware( dogpark, span_origin="auto.dogpark.deluxe", ) - if span_streaming: - items = capture_items("span") - else: - events = capture_events() + items = capture_items("span") client = Client(app) client.get("/dogs/are/great/") sentry_sdk.flush() - if span_streaming: - assert len(items) == 1 - assert items[0].payload["attributes"]["sentry.origin"] == "auto.dogpark.deluxe" - else: - (event,) = events - assert event["contexts"]["trace"]["origin"] == "auto.dogpark.deluxe" + assert len(items) == 1 + assert items[0].payload["attributes"]["sentry.origin"] == "auto.dogpark.deluxe" @pytest.mark.parametrize( @@ -1207,7 +1064,6 @@ def dogpark(environ, start_response): sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream", **init_kwargs, ) app = SentryWsgiMiddleware(dogpark) @@ -1230,7 +1086,7 @@ def dogpark(environ, start_response): @pytest.mark.parametrize("send_default_pii", [True, False]) def test_user_ip_address_on_all_spans(sentry_init, capture_items, send_default_pii): def dogpark(environ, start_response): - with sentry_sdk.traces.start_span(name="child-span"): + with sentry_sdk.start_span(name="child-span"): pass start_response("200 OK", []) return ["Go get the ball! Good dog!"] @@ -1238,7 +1094,6 @@ def dogpark(environ, start_response): sentry_init( send_default_pii=send_default_pii, traces_sample_rate=1.0, - trace_lifecycle="stream", ) app = SentryWsgiMiddleware(dogpark) client = Client(app) @@ -1264,7 +1119,7 @@ def test_user_info_span_attributes_data_collection( sentry_init, capture_items, init_kwargs, expect_ip ): def dogpark(environ, start_response): - with sentry_sdk.traces.start_span(name="child-span"): + with sentry_sdk.start_span(name="child-span"): pass start_response("200 OK", []) return ["Go get the ball! Good dog!"] @@ -1273,7 +1128,6 @@ def dogpark(environ, start_response): sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream", **init_kwargs, ) app = SentryWsgiMiddleware(dogpark) diff --git a/tests/new_scopes_compat/__init__.py b/tests/new_scopes_compat/__init__.py deleted file mode 100644 index 45391bd9ad..0000000000 --- a/tests/new_scopes_compat/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -Separate module for tests that check backwards compatibility of the Hub API with 1.x. -These tests should be removed once we remove the Hub API, likely in the next major. - -All tests in this module are run with hub isolation, provided by `isolate_hub` autouse -fixture, defined in `conftest.py`. -""" diff --git a/tests/new_scopes_compat/conftest.py b/tests/new_scopes_compat/conftest.py deleted file mode 100644 index 7023b9a63f..0000000000 --- a/tests/new_scopes_compat/conftest.py +++ /dev/null @@ -1,9 +0,0 @@ -import pytest - -import sentry_sdk - - -@pytest.fixture(autouse=True) -def isolate_hub(suppress_deprecation_warnings): - with sentry_sdk.Hub(None): - yield diff --git a/tests/new_scopes_compat/test_new_scopes_compat.py b/tests/new_scopes_compat/test_new_scopes_compat.py deleted file mode 100644 index 21e2ac27d3..0000000000 --- a/tests/new_scopes_compat/test_new_scopes_compat.py +++ /dev/null @@ -1,275 +0,0 @@ -import sentry_sdk -from sentry_sdk.hub import Hub - -""" -Those tests are meant to check the compatibility of the new scopes in SDK 2.0 with the old Hub/Scope system in SDK 1.x. - -Those tests have been run with the latest SDK 1.x versiona and the data used in the `assert` statements represents -the behvaior of the SDK 1.x. - -This makes sure that we are backwards compatible. (on a best effort basis, there will probably be some edge cases that are not covered here) -""" - - -def test_configure_scope_sdk1(sentry_init, capture_events): - """ - Mutate data in a `with configure_scope` block. - - Checks the results of SDK 2.x against the results the same code returned in SDK 1.x. - """ - sentry_init() - - events = capture_events() - - sentry_sdk.set_tag("A", 1) - sentry_sdk.capture_message("Event A") - - with sentry_sdk.configure_scope() as scope: # configure scope - sentry_sdk.set_tag("B1", 1) - scope.set_tag("B2", 1) - sentry_sdk.capture_message("Event B") - - sentry_sdk.set_tag("Z", 1) - sentry_sdk.capture_message("Event Z") - - (event_a, event_b, event_z) = events - - # Check against the results the same code returned in SDK 1.x - assert event_a["tags"] == {"A": 1} - assert event_b["tags"] == {"A": 1, "B1": 1, "B2": 1} - assert event_z["tags"] == {"A": 1, "B1": 1, "B2": 1, "Z": 1} - - -def test_push_scope_sdk1(sentry_init, capture_events): - """ - Mutate data in a `with push_scope` block - - Checks the results of SDK 2.x against the results the same code returned in SDK 1.x. - """ - sentry_init() - - events = capture_events() - - sentry_sdk.set_tag("A", 1) - sentry_sdk.capture_message("Event A") - - with sentry_sdk.push_scope() as scope: # push scope - sentry_sdk.set_tag("B1", 1) - scope.set_tag("B2", 1) - sentry_sdk.capture_message("Event B") - - sentry_sdk.set_tag("Z", 1) - sentry_sdk.capture_message("Event Z") - - (event_a, event_b, event_z) = events - - # Check against the results the same code returned in SDK 1.x - assert event_a["tags"] == {"A": 1} - assert event_b["tags"] == {"A": 1, "B1": 1, "B2": 1} - assert event_z["tags"] == {"A": 1, "Z": 1} - - -def test_with_hub_sdk1(sentry_init, capture_events): - """ - Mutate data in a `with Hub:` block - - Checks the results of SDK 2.x against the results the same code returned in SDK 1.x. - """ - sentry_init() - - events = capture_events() - - sentry_sdk.set_tag("A", 1) - sentry_sdk.capture_message("Event A") - - with Hub.current as hub: # with hub - sentry_sdk.set_tag("B1", 1) - hub.scope.set_tag("B2", 1) - sentry_sdk.capture_message("Event B") - - sentry_sdk.set_tag("Z", 1) - sentry_sdk.capture_message("Event Z") - - (event_a, event_b, event_z) = events - - # Check against the results the same code returned in SDK 1.x - assert event_a["tags"] == {"A": 1} - assert event_b["tags"] == {"A": 1, "B1": 1, "B2": 1} - assert event_z["tags"] == {"A": 1, "B1": 1, "B2": 1, "Z": 1} - - -def test_with_hub_configure_scope_sdk1(sentry_init, capture_events): - """ - Mutate data in a `with Hub:` containing a `with configure_scope` block - - Checks the results of SDK 2.x against the results the same code returned in SDK 1.x. - """ - sentry_init() - - events = capture_events() - - sentry_sdk.set_tag("A", 1) - sentry_sdk.capture_message("Event A") - - with Hub.current as hub: # with hub - sentry_sdk.set_tag("B1", 1) - with hub.configure_scope() as scope: # configure scope - sentry_sdk.set_tag("B2", 1) - hub.scope.set_tag("B3", 1) - scope.set_tag("B4", 1) - sentry_sdk.capture_message("Event B") - sentry_sdk.set_tag("B5", 1) - sentry_sdk.capture_message("Event C") - - sentry_sdk.set_tag("Z", 1) - sentry_sdk.capture_message("Event Z") - - (event_a, event_b, event_c, event_z) = events - - # Check against the results the same code returned in SDK 1.x - assert event_a["tags"] == {"A": 1} - assert event_b["tags"] == {"A": 1, "B1": 1, "B2": 1, "B3": 1, "B4": 1} - assert event_c["tags"] == {"A": 1, "B1": 1, "B2": 1, "B3": 1, "B4": 1, "B5": 1} - assert event_z["tags"] == { - "A": 1, - "B1": 1, - "B2": 1, - "B3": 1, - "B4": 1, - "B5": 1, - "Z": 1, - } - - -def test_with_hub_push_scope_sdk1(sentry_init, capture_events): - """ - Mutate data in a `with Hub:` containing a `with push_scope` block - - Checks the results of SDK 2.x against the results the same code returned in SDK 1.x. - """ - sentry_init() - - events = capture_events() - - sentry_sdk.set_tag("A", 1) - sentry_sdk.capture_message("Event A") - - with Hub.current as hub: # with hub - sentry_sdk.set_tag("B1", 1) - with hub.push_scope() as scope: # push scope - sentry_sdk.set_tag("B2", 1) - hub.scope.set_tag("B3", 1) - scope.set_tag("B4", 1) - sentry_sdk.capture_message("Event B") - sentry_sdk.set_tag("B5", 1) - sentry_sdk.capture_message("Event C") - - sentry_sdk.set_tag("Z", 1) - sentry_sdk.capture_message("Event Z") - - (event_a, event_b, event_c, event_z) = events - - # Check against the results the same code returned in SDK 1.x - assert event_a["tags"] == {"A": 1} - assert event_b["tags"] == {"A": 1, "B1": 1, "B2": 1, "B3": 1, "B4": 1} - assert event_c["tags"] == {"A": 1, "B1": 1, "B5": 1} - assert event_z["tags"] == {"A": 1, "B1": 1, "B5": 1, "Z": 1} - - -def test_with_cloned_hub_sdk1(sentry_init, capture_events): - """ - Mutate data in a `with cloned Hub:` block - - Checks the results of SDK 2.x against the results the same code returned in SDK 1.x. - """ - sentry_init() - - events = capture_events() - - sentry_sdk.set_tag("A", 1) - sentry_sdk.capture_message("Event A") - - with Hub(Hub.current) as hub: # clone hub - sentry_sdk.set_tag("B1", 1) - hub.scope.set_tag("B2", 1) - sentry_sdk.capture_message("Event B") - - sentry_sdk.set_tag("Z", 1) - sentry_sdk.capture_message("Event Z") - - (event_a, event_b, event_z) = events - - # Check against the results the same code returned in SDK 1.x - assert event_a["tags"] == {"A": 1} - assert event_b["tags"] == {"A": 1, "B1": 1, "B2": 1} - assert event_z["tags"] == {"A": 1, "Z": 1} - - -def test_with_cloned_hub_configure_scope_sdk1(sentry_init, capture_events): - """ - Mutate data in a `with cloned Hub:` containing a `with configure_scope` block - - Checks the results of SDK 2.x against the results the same code returned in SDK 1.x. - """ - sentry_init() - - events = capture_events() - - sentry_sdk.set_tag("A", 1) - sentry_sdk.capture_message("Event A") - - with Hub(Hub.current) as hub: # clone hub - sentry_sdk.set_tag("B1", 1) - with hub.configure_scope() as scope: # configure scope - sentry_sdk.set_tag("B2", 1) - hub.scope.set_tag("B3", 1) - scope.set_tag("B4", 1) - sentry_sdk.capture_message("Event B") - sentry_sdk.set_tag("B5", 1) - sentry_sdk.capture_message("Event C") - - sentry_sdk.set_tag("Z", 1) - sentry_sdk.capture_message("Event Z") - - (event_a, event_b, event_c, event_z) = events - - # Check against the results the same code returned in SDK 1.x - assert event_a["tags"] == {"A": 1} - assert event_b["tags"] == {"A": 1, "B1": 1, "B2": 1, "B3": 1, "B4": 1} - assert event_c["tags"] == {"A": 1, "B1": 1, "B2": 1, "B3": 1, "B4": 1, "B5": 1} - assert event_z["tags"] == {"A": 1, "Z": 1} - - -def test_with_cloned_hub_push_scope_sdk1(sentry_init, capture_events): - """ - Mutate data in a `with cloned Hub:` containing a `with push_scope` block - - Checks the results of SDK 2.x against the results the same code returned in SDK 1.x. - """ - sentry_init() - - events = capture_events() - - sentry_sdk.set_tag("A", 1) - sentry_sdk.capture_message("Event A") - - with Hub(Hub.current) as hub: # clone hub - sentry_sdk.set_tag("B1", 1) - with hub.push_scope() as scope: # push scope - sentry_sdk.set_tag("B2", 1) - hub.scope.set_tag("B3", 1) - scope.set_tag("B4", 1) - sentry_sdk.capture_message("Event B") - sentry_sdk.set_tag("B5", 1) - sentry_sdk.capture_message("Event C") - - sentry_sdk.set_tag("Z", 1) - sentry_sdk.capture_message("Event Z") - - (event_a, event_b, event_c, event_z) = events - - # Check against the results the same code returned in SDK 1.x - assert event_a["tags"] == {"A": 1} - assert event_b["tags"] == {"A": 1, "B1": 1, "B2": 1, "B3": 1, "B4": 1} - assert event_c["tags"] == {"A": 1, "B1": 1, "B5": 1} - assert event_z["tags"] == {"A": 1, "Z": 1} diff --git a/tests/new_scopes_compat/test_new_scopes_compat_event.py b/tests/new_scopes_compat/test_new_scopes_compat_event.py deleted file mode 100644 index 0b8a4ecba9..0000000000 --- a/tests/new_scopes_compat/test_new_scopes_compat_event.py +++ /dev/null @@ -1,498 +0,0 @@ -from unittest import mock - -import pytest - -import sentry_sdk -from sentry_sdk.hub import Hub -from sentry_sdk.integrations import iter_default_integrations -from sentry_sdk.scrubber import DEFAULT_DENYLIST, EventScrubber - -""" -Those tests are meant to check the compatibility of the new scopes in SDK 2.0 with the old Hub/Scope system in SDK 1.x. - -Those tests have been run with the latest SDK 1.x version and the data used in the `assert` statements represents -the behvaior of the SDK 1.x. - -This makes sure that we are backwards compatible. (on a best effort basis, there will probably be some edge cases that are not covered here) -""" - - -@pytest.fixture -def integrations(): - return [ - integration.identifier - for integration in iter_default_integrations( - with_auto_enabling_integrations=False - ) - ] - - -@pytest.fixture -def expected_error(integrations): - def create_expected_error_event(trx, span): - return { - "level": "warning-X", - "exception": { - "values": [ - { - "mechanism": {"type": "generic", "handled": True}, - "module": None, - "type": "ValueError", - "value": "This is a test exception", - "stacktrace": { - "frames": [ - { - "filename": "tests/new_scopes_compat/test_new_scopes_compat_event.py", - "abs_path": mock.ANY, - "function": "_faulty_function", - "module": "tests.new_scopes_compat.test_new_scopes_compat_event", - "lineno": mock.ANY, - "pre_context": [ - " return create_expected_transaction_event", - "", - "", - "def _faulty_function():", - " try:", - ], - "context_line": ' raise ValueError("This is a test exception")', - "post_context": [ - " except ValueError as ex:", - " sentry_sdk.capture_exception(ex)", - "", - "", - "def _test_before_send(event, hint):", - ], - "vars": { - "ex": mock.ANY, - }, - "in_app": True, - } - ] - }, - } - ] - }, - "event_id": mock.ANY, - "timestamp": mock.ANY, - "contexts": { - "character": { - "name": "Mighty Fighter changed by before_send", - "age": 19, - "attack_type": "melee", - }, - "trace": { - "trace_id": trx.trace_id, - "span_id": span.span_id, - "parent_span_id": span.parent_span_id, - "op": "test_span", - "origin": "manual", - "description": None, - "data": { - "thread.id": mock.ANY, - "thread.name": "MainThread", - }, - }, - "runtime": { - "name": "CPython", - "version": mock.ANY, - "build": mock.ANY, - }, - }, - "user": { - "id": "123", - "email": "jane.doe@example.com", - }, - "transaction": "test_transaction", - "transaction_info": {"source": "custom"}, - "tags": {"tag1": "tag1_value", "tag2": "tag2_value"}, - "extra": { - "extra1": "extra1_value", - "extra2": "extra2_value", - "should_be_removed_by_event_scrubber": "[Filtered]", - "sys.argv": "[Filtered]", - }, - "breadcrumbs": { - "values": [ - { - "category": "error-level", - "message": "Authenticated user %s", - "level": "error", - "data": {"breadcrumb2": "somedata"}, - "timestamp": mock.ANY, - "type": "default", - } - ] - }, - "modules": mock.ANY, - "release": "0.1.2rc3", - "environment": "checking-compatibility-with-sdk1", - "server_name": mock.ANY, - "sdk": { - "name": "sentry.python", - "version": mock.ANY, - "packages": [{"name": "pypi:sentry-sdk", "version": mock.ANY}], - "integrations": integrations, - }, - "platform": "python", - "_meta": { - "extra": { - "should_be_removed_by_event_scrubber": { - "": {"rem": [["!config", "s"]]} - }, - "sys.argv": {"": {"rem": [["!config", "s"]]}}, - }, - }, - } - - return create_expected_error_event - - -@pytest.fixture -def expected_transaction(integrations): - def create_expected_transaction_event(trx, span): - return { - "type": "transaction", - "transaction": "test_transaction changed by before_send_transaction", - "transaction_info": {"source": "custom"}, - "contexts": { - "trace": { - "trace_id": trx.trace_id, - "span_id": trx.span_id, - "parent_span_id": None, - "op": "test_transaction_op", - "origin": "manual", - "description": None, - "data": { - "thread.id": mock.ANY, - "thread.name": "MainThread", - }, - }, - "character": { - "name": "Mighty Fighter changed by before_send_transaction", - "age": 19, - "attack_type": "melee", - }, - "runtime": { - "name": "CPython", - "version": mock.ANY, - "build": mock.ANY, - }, - }, - "tags": {"tag1": "tag1_value", "tag2": "tag2_value"}, - "timestamp": mock.ANY, - "start_timestamp": mock.ANY, - "spans": [ - { - "data": { - "thread.id": mock.ANY, - "thread.name": "MainThread", - }, - "trace_id": trx.trace_id, - "span_id": span.span_id, - "parent_span_id": span.parent_span_id, - "same_process_as_parent": True, - "op": "test_span", - "origin": "manual", - "description": None, - "start_timestamp": mock.ANY, - "timestamp": mock.ANY, - } - ], - "measurements": {"memory_used": {"value": 456, "unit": "byte"}}, - "event_id": mock.ANY, - "level": "warning-X", - "user": { - "id": "123", - "email": "jane.doe@example.com", - }, - "extra": { - "extra1": "extra1_value", - "extra2": "extra2_value", - "should_be_removed_by_event_scrubber": "[Filtered]", - "sys.argv": "[Filtered]", - }, - "release": "0.1.2rc3", - "environment": "checking-compatibility-with-sdk1", - "server_name": mock.ANY, - "sdk": { - "name": "sentry.python", - "version": mock.ANY, - "packages": [{"name": "pypi:sentry-sdk", "version": mock.ANY}], - "integrations": integrations, - }, - "platform": "python", - "_meta": { - "extra": { - "should_be_removed_by_event_scrubber": { - "": {"rem": [["!config", "s"]]} - }, - "sys.argv": {"": {"rem": [["!config", "s"]]}}, - }, - }, - } - - return create_expected_transaction_event - - -def _faulty_function(): - try: - raise ValueError("This is a test exception") - except ValueError as ex: - sentry_sdk.capture_exception(ex) - - -def _test_before_send(event, hint): - event["contexts"]["character"]["name"] += " changed by before_send" - return event - - -def _test_before_send_transaction(event, hint): - event["transaction"] += " changed by before_send_transaction" - event["contexts"]["character"]["name"] += " changed by before_send_transaction" - return event - - -def _test_before_breadcrumb(breadcrumb, hint): - if breadcrumb["category"] == "info-level": - return None - return breadcrumb - - -def _generate_event_data(scope=None): - """ - Generates some data to be used in the events sent by the tests. - """ - sentry_sdk.set_level("warning-X") - - sentry_sdk.add_breadcrumb( - category="info-level", - message="Authenticated user %s", - level="info", - data={"breadcrumb1": "somedata"}, - ) - sentry_sdk.add_breadcrumb( - category="error-level", - message="Authenticated user %s", - level="error", - data={"breadcrumb2": "somedata"}, - ) - - sentry_sdk.set_context( - "character", - { - "name": "Mighty Fighter", - "age": 19, - "attack_type": "melee", - }, - ) - - sentry_sdk.set_extra("extra1", "extra1_value") - sentry_sdk.set_extra("extra2", "extra2_value") - sentry_sdk.set_extra("should_be_removed_by_event_scrubber", "XXX") - - sentry_sdk.set_tag("tag1", "tag1_value") - sentry_sdk.set_tag("tag2", "tag2_value") - - sentry_sdk.set_user( - {"id": "123", "email": "jane.doe@example.com", "ip_address": "211.161.1.124"} - ) - - sentry_sdk.set_measurement("memory_used", 456, "byte") - - if scope is not None: - scope.add_attachment(bytes=b"Hello World", filename="hello.txt") - - -def _init_sentry_sdk(sentry_init): - sentry_init( - environment="checking-compatibility-with-sdk1", - release="0.1.2rc3", - before_send=_test_before_send, - before_send_transaction=_test_before_send_transaction, - before_breadcrumb=_test_before_breadcrumb, - event_scrubber=EventScrubber( - denylist=DEFAULT_DENYLIST - + ["should_be_removed_by_event_scrubber", "sys.argv"] - ), - send_default_pii=False, - traces_sample_rate=1.0, - auto_enabling_integrations=False, - ) - - -# -# The actual Tests start here! -# - - -def test_event(sentry_init, capture_envelopes, expected_error, expected_transaction): - _init_sentry_sdk(sentry_init) - - envelopes = capture_envelopes() - - with sentry_sdk.start_transaction( - name="test_transaction", op="test_transaction_op" - ) as trx: - with sentry_sdk.start_span(op="test_span") as span: - with sentry_sdk.configure_scope() as scope: # configure scope - _generate_event_data(scope) - _faulty_function() - - (error_envelope, transaction_envelope) = envelopes - - error = error_envelope.get_event() - transaction = transaction_envelope.get_transaction_event() - attachment = error_envelope.items[-1] - - assert error == expected_error(trx, span) - assert transaction == expected_transaction(trx, span) - assert attachment.headers == { - "filename": "hello.txt", - "type": "attachment", - "content_type": "text/plain", - } - assert attachment.payload.bytes == b"Hello World" - - -def test_event2(sentry_init, capture_envelopes, expected_error, expected_transaction): - _init_sentry_sdk(sentry_init) - - envelopes = capture_envelopes() - - with Hub(Hub.current): - sentry_sdk.set_tag("A", 1) # will not be added - - with Hub.current: # with hub - with sentry_sdk.push_scope() as scope: - scope.set_tag("B", 1) # will not be added - - with sentry_sdk.start_transaction( - name="test_transaction", op="test_transaction_op" - ) as trx: - with sentry_sdk.start_span(op="test_span") as span: - with sentry_sdk.configure_scope() as scope: # configure scope - _generate_event_data(scope) - _faulty_function() - - (error_envelope, transaction_envelope) = envelopes - - error = error_envelope.get_event() - transaction = transaction_envelope.get_transaction_event() - attachment = error_envelope.items[-1] - - assert error == expected_error(trx, span) - assert transaction == expected_transaction(trx, span) - assert attachment.headers == { - "filename": "hello.txt", - "type": "attachment", - "content_type": "text/plain", - } - assert attachment.payload.bytes == b"Hello World" - - -def test_event3(sentry_init, capture_envelopes, expected_error, expected_transaction): - _init_sentry_sdk(sentry_init) - - envelopes = capture_envelopes() - - with Hub(Hub.current): - sentry_sdk.set_tag("A", 1) # will not be added - - with Hub.current: # with hub - with sentry_sdk.push_scope() as scope: - scope.set_tag("B", 1) # will not be added - - with sentry_sdk.push_scope() as scope: # push scope - with sentry_sdk.start_transaction( - name="test_transaction", op="test_transaction_op" - ) as trx: - with sentry_sdk.start_span(op="test_span") as span: - _generate_event_data(scope) - _faulty_function() - - (error_envelope, transaction_envelope) = envelopes - - error = error_envelope.get_event() - transaction = transaction_envelope.get_transaction_event() - attachment = error_envelope.items[-1] - - assert error == expected_error(trx, span) - assert transaction == expected_transaction(trx, span) - assert attachment.headers == { - "filename": "hello.txt", - "type": "attachment", - "content_type": "text/plain", - } - assert attachment.payload.bytes == b"Hello World" - - -def test_event4(sentry_init, capture_envelopes, expected_error, expected_transaction): - _init_sentry_sdk(sentry_init) - - envelopes = capture_envelopes() - - with Hub(Hub.current): - sentry_sdk.set_tag("A", 1) # will not be added - - with Hub(Hub.current): # with hub clone - with sentry_sdk.push_scope() as scope: - scope.set_tag("B", 1) # will not be added - - with sentry_sdk.start_transaction( - name="test_transaction", op="test_transaction_op" - ) as trx: - with sentry_sdk.start_span(op="test_span") as span: - with sentry_sdk.configure_scope() as scope: # configure scope - _generate_event_data(scope) - _faulty_function() - - (error_envelope, transaction_envelope) = envelopes - - error = error_envelope.get_event() - transaction = transaction_envelope.get_transaction_event() - attachment = error_envelope.items[-1] - - assert error == expected_error(trx, span) - assert transaction == expected_transaction(trx, span) - assert attachment.headers == { - "filename": "hello.txt", - "type": "attachment", - "content_type": "text/plain", - } - assert attachment.payload.bytes == b"Hello World" - - -def test_event5(sentry_init, capture_envelopes, expected_error, expected_transaction): - _init_sentry_sdk(sentry_init) - - envelopes = capture_envelopes() - - with Hub(Hub.current): - sentry_sdk.set_tag("A", 1) # will not be added - - with Hub(Hub.current): # with hub clone - with sentry_sdk.push_scope() as scope: - scope.set_tag("B", 1) # will not be added - - with sentry_sdk.push_scope() as scope: # push scope - with sentry_sdk.start_transaction( - name="test_transaction", op="test_transaction_op" - ) as trx: - with sentry_sdk.start_span(op="test_span") as span: - _generate_event_data(scope) - _faulty_function() - - (error_envelope, transaction_envelope) = envelopes - - error = error_envelope.get_event() - transaction = transaction_envelope.get_transaction_event() - attachment = error_envelope.items[-1] - - assert error == expected_error(trx, span) - assert transaction == expected_transaction(trx, span) - assert attachment.headers == { - "filename": "hello.txt", - "type": "attachment", - "content_type": "text/plain", - } - assert attachment.payload.bytes == b"Hello World" diff --git a/tests/profiler/test_continuous_profiler.py b/tests/profiler/test_continuous_profiler.py index 93d8ddd3bb..e7a75a022d 100644 --- a/tests/profiler/test_continuous_profiler.py +++ b/tests/profiler/test_continuous_profiler.py @@ -11,9 +11,7 @@ get_profiler_id, is_profile_session_sampled, setup_continuous_profiler, - start_profile_session, start_profiler, - stop_profile_session, stop_profiler, ) from tests.conftest import ApproxDict @@ -27,6 +25,19 @@ requires_gevent = pytest.mark.skipif(gevent is None, reason="gevent not enabled") +def make_options( + mode=None, auto_start=None, profile_session_sample_rate=1.0, lifecycle="manual" +): + return { + "profile_lifecycle": lifecycle, + "profiler_mode": mode, + "profile_session_sample_rate": profile_session_sample_rate, + "_experiments": { + "continuous_profiling_auto_start": auto_start, + }, + } + + def wait_for_profiler_to_stop(envelopes, timeout=1.0): deadline = time.monotonic() + timeout while time.monotonic() < deadline: @@ -48,31 +59,6 @@ def wait_for_profiler_to_stop(envelopes, timeout=1.0): ), "profiler should have flushed a profile chunk" -def get_client_options(use_top_level_profiler_mode): - def client_options( - mode=None, auto_start=None, profile_session_sample_rate=1.0, lifecycle="manual" - ): - if use_top_level_profiler_mode: - return { - "profile_lifecycle": lifecycle, - "profiler_mode": mode, - "profile_session_sample_rate": profile_session_sample_rate, - "_experiments": { - "continuous_profiling_auto_start": auto_start, - }, - } - return { - "profile_lifecycle": lifecycle, - "profile_session_sample_rate": profile_session_sample_rate, - "_experiments": { - "continuous_profiling_auto_start": auto_start, - "continuous_profiling_mode": mode, - }, - } - - return client_options - - mock_sdk_info = { "name": "sentry.python", "version": VERSION, @@ -80,18 +66,10 @@ def client_options( } -@pytest.mark.parametrize("mode", [pytest.param("foo")]) -@pytest.mark.parametrize( - "make_options", - [ - pytest.param(get_client_options(True), id="non-experiment"), - pytest.param(get_client_options(False), id="experiment"), - ], -) -def test_continuous_profiler_invalid_mode(mode, make_options, teardown_profiling): +def test_continuous_profiler_invalid_mode(teardown_profiling): with pytest.raises(ValueError): setup_continuous_profiler( - make_options(mode=mode), + make_options(mode="foo"), mock_sdk_info, lambda envelope: None, ) @@ -104,17 +82,9 @@ def test_continuous_profiler_invalid_mode(mode, make_options, teardown_profiling pytest.param("gevent", marks=requires_gevent), ], ) -@pytest.mark.parametrize( - "make_options", - [ - pytest.param(get_client_options(True), id="non-experiment"), - pytest.param(get_client_options(False), id="experiment"), - ], -) -def test_continuous_profiler_valid_mode(mode, make_options, teardown_profiling): - options = make_options(mode=mode) +def test_continuous_profiler_valid_mode(mode, teardown_profiling): setup_continuous_profiler( - options, + make_options(mode=mode), mock_sdk_info, lambda envelope: None, ) @@ -127,14 +97,7 @@ def test_continuous_profiler_valid_mode(mode, make_options, teardown_profiling): pytest.param("gevent", marks=requires_gevent), ], ) -@pytest.mark.parametrize( - "make_options", - [ - pytest.param(get_client_options(True), id="non-experiment"), - pytest.param(get_client_options(False), id="experiment"), - ], -) -def test_continuous_profiler_setup_twice(mode, make_options, teardown_profiling): +def test_continuous_profiler_setup_twice(mode, teardown_profiling): assert not is_profile_session_sampled() # setting up the first time should return True to indicate success @@ -318,120 +281,15 @@ def assert_single_segment_without_profile_chunks(envelopes): pytest.param("gevent", marks=requires_gevent), ], ) -@pytest.mark.parametrize( - ["start_profiler_func", "stop_profiler_func"], - [ - pytest.param( - start_profile_session, - stop_profile_session, - id="start_profile_session/stop_profile_session (deprecated)", - ), - pytest.param( - start_profiler, - stop_profiler, - id="start_profiler/stop_profiler", - ), - ], -) -@pytest.mark.parametrize( - "make_options", - [ - pytest.param(get_client_options(True), id="non-experiment"), - pytest.param(get_client_options(False), id="experiment"), - ], -) def test_continuous_profiler_auto_start_and_manual_stop( sentry_init, capture_envelopes, mode, - start_profiler_func, - stop_profiler_func, - make_options, - teardown_profiling, -): - options = make_options(mode=mode, auto_start=True) - sentry_init( - traces_sample_rate=1.0, - **options, - ) - - envelopes = capture_envelopes() - - thread = threading.current_thread() - - with sentry_sdk.start_transaction(name="profiling"): - with sentry_sdk.start_span(op="op"): - pass - - for _ in range(3): - stop_profiler_func() - - assert_single_transaction_with_profile_chunks(envelopes, thread) - - envelopes.clear() - - with sentry_sdk.start_transaction(name="profiling"): - with sentry_sdk.start_span(op="op"): - time.sleep(0.05) - - assert_single_transaction_without_profile_chunks(envelopes) - - start_profiler_func() - - envelopes.clear() - - with sentry_sdk.start_transaction(name="profiling"): - with sentry_sdk.start_span(op="op"): - pass - - stop_profiler_func() - - assert_single_transaction_with_profile_chunks(envelopes, thread) - - -@pytest.mark.forked -@pytest.mark.parametrize( - "mode", - [ - pytest.param("thread"), - pytest.param("gevent", marks=requires_gevent), - ], -) -@pytest.mark.parametrize( - ["start_profiler_func", "stop_profiler_func"], - [ - pytest.param( - start_profile_session, - stop_profile_session, - id="start_profile_session/stop_profile_session (deprecated)", - ), - pytest.param( - start_profiler, - stop_profiler, - id="start_profiler/stop_profiler", - ), - ], -) -@pytest.mark.parametrize( - "make_options", - [ - pytest.param(get_client_options(True), id="non-experiment"), - pytest.param(get_client_options(False), id="experiment"), - ], -) -def test_continuous_profiler_auto_start_and_manual_stop_span_streaming( - sentry_init, - capture_envelopes, - mode, - start_profiler_func, - stop_profiler_func, - make_options, teardown_profiling, ): options = make_options(mode=mode, auto_start=True) sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream", **options, ) @@ -439,34 +297,34 @@ def test_continuous_profiler_auto_start_and_manual_stop_span_streaming( thread = threading.current_thread() - with sentry_sdk.traces.start_span(name="profiling"): - with sentry_sdk.traces.start_span(name="op"): + with sentry_sdk.start_span(name="profiling"): + with sentry_sdk.start_span(name="op"): pass for _ in range(3): - stop_profiler_func() + stop_profiler() sentry_sdk.flush() assert_single_segment_with_profile_chunks(envelopes, thread) envelopes.clear() - with sentry_sdk.traces.start_span(name="profiling"): - with sentry_sdk.traces.start_span(name="op"): + with sentry_sdk.start_span(name="profiling"): + with sentry_sdk.start_span(name="op"): time.sleep(0.05) sentry_sdk.flush() assert_single_segment_without_profile_chunks(envelopes) - start_profiler_func() + start_profiler() envelopes.clear() - with sentry_sdk.traces.start_span(name="profiling"): - with sentry_sdk.traces.start_span(name="op"): + with sentry_sdk.start_span(name="profiling"): + with sentry_sdk.start_span(name="op"): pass - stop_profiler_func() + stop_profiler() sentry_sdk.flush() assert_single_segment_with_profile_chunks(envelopes, thread) @@ -479,118 +337,11 @@ def test_continuous_profiler_auto_start_and_manual_stop_span_streaming( pytest.param("gevent", marks=requires_gevent), ], ) -@pytest.mark.parametrize( - ["start_profiler_func", "stop_profiler_func"], - [ - pytest.param( - start_profile_session, - stop_profile_session, - id="start_profile_session/stop_profile_session (deprecated)", - ), - pytest.param( - start_profiler, - stop_profiler, - id="start_profiler/stop_profiler", - ), - ], -) -@pytest.mark.parametrize( - "make_options", - [ - pytest.param(get_client_options(True), id="non-experiment"), - pytest.param(get_client_options(False), id="experiment"), - ], -) @mock.patch("sentry_sdk.profiler.continuous_profiler.PROFILE_BUFFER_SECONDS", 0.01) def test_continuous_profiler_manual_start_and_stop_sampled( sentry_init, capture_envelopes, mode, - start_profiler_func, - stop_profiler_func, - make_options, - teardown_profiling, -): - options = make_options( - mode=mode, profile_session_sample_rate=1.0, lifecycle="manual" - ) - sentry_init( - traces_sample_rate=1.0, - **options, - ) - - envelopes = capture_envelopes() - - thread = threading.current_thread() - - for _ in range(3): - start_profiler_func() - - envelopes.clear() - - with sentry_sdk.start_transaction(name="profiling"): - assert get_profiler_id() is not None, "profiler should be running" - with sentry_sdk.start_span(op="op"): - time.sleep(0.1) - assert get_profiler_id() is not None, "profiler should be running" - - assert get_profiler_id() is not None, "profiler should be running" - - stop_profiler_func() - - assert_single_transaction_with_profile_chunks(envelopes, thread) - - # the profiler stops immediately in manual mode - assert get_profiler_id() is None, "profiler should not be running" - - envelopes.clear() - - with sentry_sdk.start_transaction(name="profiling"): - assert get_profiler_id() is None, "profiler should not be running" - with sentry_sdk.start_span(op="op"): - time.sleep(0.1) - assert get_profiler_id() is None, "profiler should not be running" - - assert_single_transaction_without_profile_chunks(envelopes) - - -@pytest.mark.parametrize( - "mode", - [ - pytest.param("thread"), - pytest.param("gevent", marks=requires_gevent), - ], -) -@pytest.mark.parametrize( - ["start_profiler_func", "stop_profiler_func"], - [ - pytest.param( - start_profile_session, - stop_profile_session, - id="start_profile_session/stop_profile_session (deprecated)", - ), - pytest.param( - start_profiler, - stop_profiler, - id="start_profiler/stop_profiler", - ), - ], -) -@pytest.mark.parametrize( - "make_options", - [ - pytest.param(get_client_options(True), id="non-experiment"), - pytest.param(get_client_options(False), id="experiment"), - ], -) -@mock.patch("sentry_sdk.profiler.continuous_profiler.PROFILE_BUFFER_SECONDS", 0.01) -def test_continuous_profiler_manual_start_and_stop_sampled_span_streaming( - sentry_init, - capture_envelopes, - mode, - start_profiler_func, - stop_profiler_func, - make_options, teardown_profiling, ): options = make_options( @@ -598,7 +349,6 @@ def test_continuous_profiler_manual_start_and_stop_sampled_span_streaming( ) sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream", **options, ) @@ -607,19 +357,19 @@ def test_continuous_profiler_manual_start_and_stop_sampled_span_streaming( thread = threading.current_thread() for _ in range(3): - start_profiler_func() + start_profiler() envelopes.clear() - with sentry_sdk.traces.start_span(name="profiling"): + with sentry_sdk.start_span(name="profiling"): assert get_profiler_id() is not None, "profiler should be running" - with sentry_sdk.traces.start_span(name="op"): + with sentry_sdk.start_span(name="op"): time.sleep(0.1) assert get_profiler_id() is not None, "profiler should be running" assert get_profiler_id() is not None, "profiler should be running" - stop_profiler_func() + stop_profiler() sentry_sdk.flush() assert_single_segment_with_profile_chunks(envelopes, thread) @@ -629,9 +379,9 @@ def test_continuous_profiler_manual_start_and_stop_sampled_span_streaming( envelopes.clear() - with sentry_sdk.traces.start_span(name="profiling"): + with sentry_sdk.start_span(name="profiling"): assert get_profiler_id() is None, "profiler should not be running" - with sentry_sdk.traces.start_span(name="op"): + with sentry_sdk.start_span(name="op"): time.sleep(0.1) assert get_profiler_id() is None, "profiler should not be running" @@ -646,94 +396,10 @@ def test_continuous_profiler_manual_start_and_stop_sampled_span_streaming( pytest.param("gevent", marks=requires_gevent), ], ) -@pytest.mark.parametrize( - ["start_profiler_func", "stop_profiler_func"], - [ - pytest.param( - start_profile_session, - stop_profile_session, - id="start_profile_session/stop_profile_session (deprecated)", - ), - pytest.param( - start_profiler, - stop_profiler, - id="start_profiler/stop_profiler", - ), - ], -) -@pytest.mark.parametrize( - "make_options", - [ - pytest.param(get_client_options(True), id="non-experiment"), - pytest.param(get_client_options(False), id="experiment"), - ], -) def test_continuous_profiler_manual_start_and_stop_unsampled( sentry_init, capture_envelopes, mode, - start_profiler_func, - stop_profiler_func, - make_options, - teardown_profiling, -): - options = make_options( - mode=mode, profile_session_sample_rate=0.0, lifecycle="manual" - ) - sentry_init( - traces_sample_rate=1.0, - **options, - ) - - envelopes = capture_envelopes() - - start_profiler_func() - - with sentry_sdk.start_transaction(name="profiling"): - with sentry_sdk.start_span(op="op"): - pass - - stop_profiler_func() - - assert_single_transaction_without_profile_chunks(envelopes) - - -@pytest.mark.parametrize( - "mode", - [ - pytest.param("thread"), - pytest.param("gevent", marks=requires_gevent), - ], -) -@pytest.mark.parametrize( - ["start_profiler_func", "stop_profiler_func"], - [ - pytest.param( - start_profile_session, - stop_profile_session, - id="start_profile_session/stop_profile_session (deprecated)", - ), - pytest.param( - start_profiler, - stop_profiler, - id="start_profiler/stop_profiler", - ), - ], -) -@pytest.mark.parametrize( - "make_options", - [ - pytest.param(get_client_options(True), id="non-experiment"), - pytest.param(get_client_options(False), id="experiment"), - ], -) -def test_continuous_profiler_manual_start_and_stop_unsampled_span_streaming( - sentry_init, - capture_envelopes, - mode, - start_profiler_func, - stop_profiler_func, - make_options, teardown_profiling, ): options = make_options( @@ -741,19 +407,18 @@ def test_continuous_profiler_manual_start_and_stop_unsampled_span_streaming( ) sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream", **options, ) envelopes = capture_envelopes() - start_profiler_func() + start_profiler() - with sentry_sdk.traces.start_span(name="profiling"): - with sentry_sdk.traces.start_span(name="op"): + with sentry_sdk.start_span(name="profiling"): + with sentry_sdk.start_span(name="op"): pass - stop_profiler_func() + stop_profiler() sentry_sdk.flush() assert_single_segment_without_profile_chunks(envelopes) @@ -766,19 +431,11 @@ def test_continuous_profiler_manual_start_and_stop_unsampled_span_streaming( pytest.param("gevent", marks=requires_gevent), ], ) -@pytest.mark.parametrize( - "make_options", - [ - pytest.param(get_client_options(True), id="non-experiment"), - pytest.param(get_client_options(False), id="experiment"), - ], -) @mock.patch("sentry_sdk.profiler.continuous_profiler.DEFAULT_SAMPLING_FREQUENCY", 21) def test_continuous_profiler_auto_start_and_stop_sampled( sentry_init, capture_envelopes, mode, - make_options, teardown_profiling, ): options = make_options( @@ -800,11 +457,11 @@ def test_continuous_profiler_auto_start_and_stop_sampled( profiler_ids = set() - with sentry_sdk.start_transaction(name="profiling 1"): + with sentry_sdk.start_span(name="profiling 1"): profiler_id = get_profiler_id() assert profiler_id is not None, "profiler should be running" profiler_ids.add(profiler_id) - with sentry_sdk.start_span(op="op"): + with sentry_sdk.start_span(name="op"): time.sleep(0.1) profiler_id = get_profiler_id() assert profiler_id is not None, "profiler should be running" @@ -818,93 +475,11 @@ def test_continuous_profiler_auto_start_and_stop_sampled( assert profiler_id is not None, "profiler should be running" profiler_ids.add(profiler_id) - with sentry_sdk.start_transaction(name="profiling 2"): + with sentry_sdk.start_span(name="profiling 2"): profiler_id = get_profiler_id() assert profiler_id is not None, "profiler should be running" profiler_ids.add(profiler_id) - with sentry_sdk.start_span(op="op"): - time.sleep(0.1) - profiler_id = get_profiler_id() - assert profiler_id is not None, "profiler should be running" - profiler_ids.add(profiler_id) - - wait_for_profiler_to_stop(envelopes) - - assert len(profiler_ids) == 1 - all_profiler_ids.add(profiler_ids.pop()) - - assert_single_transaction_with_profile_chunks( - envelopes, thread, max_chunks=1, transactions=2 - ) - - assert len(all_profiler_ids) == 3 - - -@pytest.mark.parametrize( - "mode", - [ - pytest.param("thread"), - pytest.param("gevent", marks=requires_gevent), - ], -) -@pytest.mark.parametrize( - "make_options", - [ - pytest.param(get_client_options(True), id="non-experiment"), - pytest.param(get_client_options(False), id="experiment"), - ], -) -@mock.patch("sentry_sdk.profiler.continuous_profiler.DEFAULT_SAMPLING_FREQUENCY", 21) -def test_continuous_profiler_auto_start_and_stop_sampled_span_streaming( - sentry_init, - capture_envelopes, - mode, - make_options, - teardown_profiling, -): - options = make_options( - mode=mode, profile_session_sample_rate=1.0, lifecycle="trace" - ) - sentry_init( - traces_sample_rate=1.0, - trace_lifecycle="stream", - **options, - ) - - envelopes = capture_envelopes() - - thread = threading.current_thread() - - all_profiler_ids = set() - - for _ in range(3): - envelopes.clear() - - profiler_ids = set() - - with sentry_sdk.traces.start_span(name="profiling 1"): - profiler_id = get_profiler_id() - assert profiler_id is not None, "profiler should be running" - profiler_ids.add(profiler_id) - with sentry_sdk.traces.start_span(name="op"): - time.sleep(0.1) - profiler_id = get_profiler_id() - assert profiler_id is not None, "profiler should be running" - profiler_ids.add(profiler_id) - - time.sleep(0.03) - - # the profiler takes a while to stop in auto mode so if we start - # a transaction immediately, it'll be part of the same chunk - profiler_id = get_profiler_id() - assert profiler_id is not None, "profiler should be running" - profiler_ids.add(profiler_id) - - with sentry_sdk.traces.start_span(name="profiling 2"): - profiler_id = get_profiler_id() - assert profiler_id is not None, "profiler should be running" - profiler_ids.add(profiler_id) - with sentry_sdk.traces.start_span(name="op"): + with sentry_sdk.start_span(name="op"): time.sleep(0.1) profiler_id = get_profiler_id() assert profiler_id is not None, "profiler should be running" @@ -930,64 +505,11 @@ def test_continuous_profiler_auto_start_and_stop_sampled_span_streaming( pytest.param("gevent", marks=requires_gevent), ], ) -@pytest.mark.parametrize( - "make_options", - [ - pytest.param(get_client_options(True), id="non-experiment"), - pytest.param(get_client_options(False), id="experiment"), - ], -) @mock.patch("sentry_sdk.profiler.continuous_profiler.PROFILE_BUFFER_SECONDS", 0.01) def test_continuous_profiler_auto_start_and_stop_unsampled( sentry_init, capture_envelopes, mode, - make_options, - teardown_profiling, -): - options = make_options( - mode=mode, profile_session_sample_rate=0.0, lifecycle="trace" - ) - sentry_init( - traces_sample_rate=1.0, - **options, - ) - - envelopes = capture_envelopes() - - for _ in range(3): - envelopes.clear() - - with sentry_sdk.start_transaction(name="profiling"): - assert get_profiler_id() is None, "profiler should not be running" - with sentry_sdk.start_span(op="op"): - time.sleep(0.05) - assert get_profiler_id() is None, "profiler should not be running" - - assert get_profiler_id() is None, "profiler should not be running" - assert_single_transaction_without_profile_chunks(envelopes) - - -@pytest.mark.parametrize( - "mode", - [ - pytest.param("thread"), - pytest.param("gevent", marks=requires_gevent), - ], -) -@pytest.mark.parametrize( - "make_options", - [ - pytest.param(get_client_options(True), id="non-experiment"), - pytest.param(get_client_options(False), id="experiment"), - ], -) -@mock.patch("sentry_sdk.profiler.continuous_profiler.PROFILE_BUFFER_SECONDS", 0.01) -def test_continuous_profiler_auto_start_and_stop_unsampled_span_streaming( - sentry_init, - capture_envelopes, - mode, - make_options, teardown_profiling, ): options = make_options( @@ -995,7 +517,6 @@ def test_continuous_profiler_auto_start_and_stop_unsampled_span_streaming( ) sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream", **options, ) @@ -1004,9 +525,9 @@ def test_continuous_profiler_auto_start_and_stop_unsampled_span_streaming( for _ in range(3): envelopes.clear() - with sentry_sdk.traces.start_span(name="profiling"): + with sentry_sdk.start_span(name="profiling"): assert get_profiler_id() is None, "profiler should not be running" - with sentry_sdk.traces.start_span(name="op"): + with sentry_sdk.start_span(name="op"): time.sleep(0.05) assert get_profiler_id() is None, "profiler should not be running" @@ -1027,98 +548,10 @@ def test_continuous_profiler_auto_start_and_stop_unsampled_span_streaming( ), ], ) -@pytest.mark.parametrize( - ["start_profiler_func", "stop_profiler_func"], - [ - pytest.param( - start_profile_session, - stop_profile_session, - id="start_profile_session/stop_profile_session (deprecated)", - ), - pytest.param( - start_profiler, - stop_profiler, - id="start_profiler/stop_profiler", - ), - ], -) -@pytest.mark.parametrize( - "make_options", - [ - pytest.param(get_client_options(True), id="non-experiment"), - pytest.param(get_client_options(False), id="experiment"), - ], -) def test_continuous_profiler_manual_start_and_stop_noop_when_using_trace_lifecyle( sentry_init, mode, - start_profiler_func, - stop_profiler_func, - class_name, - make_options, - teardown_profiling, -): - options = make_options( - mode=mode, profile_session_sample_rate=0.0, lifecycle="trace" - ) - sentry_init( - traces_sample_rate=1.0, - **options, - ) - - with mock.patch( - f"sentry_sdk.profiler.continuous_profiler.{class_name}.ensure_running" - ) as mock_ensure_running: - start_profiler_func() - mock_ensure_running.assert_not_called() - - with mock.patch( - f"sentry_sdk.profiler.continuous_profiler.{class_name}.teardown" - ) as mock_teardown: - stop_profiler_func() - mock_teardown.assert_not_called() - - -@pytest.mark.parametrize( - ["mode", "class_name"], - [ - pytest.param("thread", "ThreadContinuousScheduler"), - pytest.param( - "gevent", - "GeventContinuousScheduler", - marks=requires_gevent, - ), - ], -) -@pytest.mark.parametrize( - ["start_profiler_func", "stop_profiler_func"], - [ - pytest.param( - start_profile_session, - stop_profile_session, - id="start_profile_session/stop_profile_session (deprecated)", - ), - pytest.param( - start_profiler, - stop_profiler, - id="start_profiler/stop_profiler", - ), - ], -) -@pytest.mark.parametrize( - "make_options", - [ - pytest.param(get_client_options(True), id="non-experiment"), - pytest.param(get_client_options(False), id="experiment"), - ], -) -def test_continuous_profiler_manual_start_and_stop_noop_when_using_trace_lifecyle_span_streaming( - sentry_init, - mode, - start_profiler_func, - stop_profiler_func, class_name, - make_options, teardown_profiling, ): options = make_options( @@ -1126,20 +559,19 @@ def test_continuous_profiler_manual_start_and_stop_noop_when_using_trace_lifecyl ) sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream", **options, ) with mock.patch( f"sentry_sdk.profiler.continuous_profiler.{class_name}.ensure_running" ) as mock_ensure_running: - start_profiler_func() + start_profiler() mock_ensure_running.assert_not_called() with mock.patch( f"sentry_sdk.profiler.continuous_profiler.{class_name}.teardown" ) as mock_teardown: - stop_profiler_func() + stop_profiler() mock_teardown.assert_not_called() @@ -1163,76 +595,11 @@ def test_continuous_profiler_run_does_not_null_buffer( """ from sentry_sdk.profiler import continuous_profiler as cp - options = get_client_options(True)( - mode="thread", profile_session_sample_rate=1.0, lifecycle="manual" - ) - sentry_init(traces_sample_rate=1.0, **options) - envelopes = capture_envelopes() - thread = threading.current_thread() - - # Start and verify profiler works - start_profiler() - envelopes.clear() - with sentry_sdk.start_transaction(name="profiling"): - with sentry_sdk.start_span(op="op"): - pass - - # Get the scheduler and create a sentinel buffer. - # We'll call run() directly to verify it doesn't null out self.buffer. - scheduler = cp._scheduler - assert scheduler is not None - - # Stop the profiler so the thread exits cleanly - stop_profiler() - - assert_single_transaction_with_profile_chunks(envelopes, thread) - - # Now set up a fresh buffer and mark the scheduler as not running - # (simulating the state right after ensure_running() created a new buffer - # but the old thread hasn't done cleanup yet). - scheduler.reset_buffer() - buffer_before = scheduler.buffer - assert buffer_before is not None - - # Simulate what happens when run() exits its while loop: - # self.running is already False, so the while loop exits immediately. - scheduler.running = False - scheduler.run() - - # After the fix, run() should NOT have set self.buffer = None. - # It should only flush using a local reference. - assert scheduler.buffer is not None, ( - "run() must not set self.buffer = None; " - "this would destroy buffers created by concurrent ensure_running() calls" - ) - - -def test_continuous_profiler_run_does_not_null_buffer_span_streaming( - sentry_init, - capture_envelopes, - teardown_profiling, -): - """ - Verifies that ContinuousScheduler.run() does not set self.buffer = None - after exiting its sampling loop. - - Previously, run() would execute `self.buffer = None` after the while - loop exited. During rapid stop/start cycles, this could race with - ensure_running() which creates a new buffer: the old thread's cleanup - would destroy the newly-created buffer, causing the new profiler thread - to silently drop all samples (self.buffer is None in the sampler). - - The fix uses a local buffer reference for flushing and never sets - self.buffer = None from run(). - """ - from sentry_sdk.profiler import continuous_profiler as cp - - options = get_client_options(True)( + options = make_options( mode="thread", profile_session_sample_rate=1.0, lifecycle="manual" ) sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream", **options, ) envelopes = capture_envelopes() @@ -1241,8 +608,8 @@ def test_continuous_profiler_run_does_not_null_buffer_span_streaming( # Start and verify profiler works start_profiler() envelopes.clear() - with sentry_sdk.traces.start_span(name="profiling"): - with sentry_sdk.traces.start_span(name="op"): + with sentry_sdk.start_span(name="profiling"): + with sentry_sdk.start_span(name="op"): pass # Get the scheduler and create a sentinel buffer. diff --git a/tests/profiler/test_transaction_profiler.py b/tests/profiler/test_transaction_profiler.py deleted file mode 100644 index 749e91add0..0000000000 --- a/tests/profiler/test_transaction_profiler.py +++ /dev/null @@ -1,838 +0,0 @@ -import inspect -import os -import sys -import threading -import time -import warnings -from collections import defaultdict -from unittest import mock - -import pytest - -import sentry_sdk -from sentry_sdk import start_transaction -from sentry_sdk._lru_cache import LRUCache -from sentry_sdk.profiler.transaction_profiler import ( - GeventScheduler, - Profile, - Scheduler, - ThreadScheduler, - setup_profiler, -) -from sentry_sdk.profiler.utils import ( - extract_frame, - extract_stack, - frame_id, - get_frame_name, -) - -try: - import gevent -except ImportError: - gevent = None - - -requires_gevent = pytest.mark.skipif(gevent is None, reason="gevent not enabled") - - -def process_test_sample(sample): - # insert a mock hashable for the stack - return [(tid, (stack, stack)) for tid, stack in sample] - - -def non_experimental_options(mode=None, sample_rate=None): - return {"profiler_mode": mode, "profiles_sample_rate": sample_rate} - - -def experimental_options(mode=None, sample_rate=None): - return { - "_experiments": {"profiler_mode": mode, "profiles_sample_rate": sample_rate} - } - - -@pytest.mark.parametrize( - "mode", - [pytest.param("foo")], -) -@pytest.mark.parametrize( - "make_options", - [ - pytest.param(experimental_options, id="experiment"), - pytest.param(non_experimental_options, id="non experimental"), - ], -) -def test_profiler_invalid_mode(mode, make_options, teardown_profiling): - with pytest.raises(ValueError): - setup_profiler(make_options(mode)) - - -@pytest.mark.parametrize( - "mode", - [ - pytest.param("thread"), - pytest.param("sleep"), - pytest.param("gevent", marks=requires_gevent), - ], -) -@pytest.mark.parametrize( - "make_options", - [ - pytest.param(experimental_options, id="experiment"), - pytest.param(non_experimental_options, id="non experimental"), - ], -) -def test_profiler_valid_mode(mode, make_options, teardown_profiling): - # should not raise any exceptions - setup_profiler(make_options(mode)) - - -@pytest.mark.parametrize( - "make_options", - [ - pytest.param(experimental_options, id="experiment"), - pytest.param(non_experimental_options, id="non experimental"), - ], -) -def test_profiler_setup_twice(make_options, teardown_profiling): - # setting up the first time should return True to indicate success - assert setup_profiler(make_options()) - # setting up the second time should return False to indicate no-op - assert not setup_profiler(make_options()) - - -@pytest.mark.parametrize( - "mode", - [ - pytest.param("thread"), - pytest.param("gevent", marks=requires_gevent), - ], -) -@pytest.mark.parametrize( - ("profiles_sample_rate", "profile_count"), - [ - pytest.param(1.00, 1, id="profiler sampled at 1.00"), - pytest.param(0.75, 1, id="profiler sampled at 0.75"), - pytest.param(0.25, 0, id="profiler sampled at 0.25"), - pytest.param(0.00, 0, id="profiler sampled at 0.00"), - pytest.param(None, 0, id="profiler not enabled"), - ], -) -@pytest.mark.parametrize( - "make_options", - [ - pytest.param(experimental_options, id="experiment"), - pytest.param(non_experimental_options, id="non experimental"), - ], -) -@mock.patch("sentry_sdk.profiler.transaction_profiler.PROFILE_MINIMUM_SAMPLES", 0) -def test_profiles_sample_rate( - sentry_init, - capture_envelopes, - capture_record_lost_event_calls, - teardown_profiling, - profiles_sample_rate, - profile_count, - make_options, - mode, -): - options = make_options(mode=mode, sample_rate=profiles_sample_rate) - sentry_init( - traces_sample_rate=1.0, - profiler_mode=options.get("profiler_mode"), - profiles_sample_rate=options.get("profiles_sample_rate"), - _experiments=options.get("_experiments", {}), - ) - - envelopes = capture_envelopes() - record_lost_event_calls = capture_record_lost_event_calls() - - with mock.patch( - "sentry_sdk.profiler.transaction_profiler.random.random", return_value=0.5 - ): - with start_transaction(name="profiling"): - pass - - items = defaultdict(list) - for envelope in envelopes: - for item in envelope.items: - items[item.type].append(item) - - assert len(items["transaction"]) == 1 - assert len(items["profile"]) == profile_count - if profiles_sample_rate is None or profiles_sample_rate == 0: - assert record_lost_event_calls == [] - elif profile_count: - assert record_lost_event_calls == [] - else: - assert record_lost_event_calls == [("sample_rate", "profile", None, 1)] - - -@pytest.mark.parametrize( - "mode", - [ - pytest.param("thread"), - pytest.param("gevent", marks=requires_gevent), - ], -) -@pytest.mark.parametrize( - ("profiles_sampler", "profile_count"), - [ - pytest.param(lambda _: 1.00, 1, id="profiler sampled at 1.00"), - pytest.param(lambda _: 0.75, 1, id="profiler sampled at 0.75"), - pytest.param(lambda _: 0.25, 0, id="profiler sampled at 0.25"), - pytest.param(lambda _: 0.00, 0, id="profiler sampled at 0.00"), - pytest.param(lambda _: None, 0, id="profiler not enabled"), - pytest.param( - lambda ctx: 1 if ctx["transaction_context"]["name"] == "profiling" else 0, - 1, - id="profiler sampled for transaction name", - ), - pytest.param( - lambda ctx: 0 if ctx["transaction_context"]["name"] == "profiling" else 1, - 0, - id="profiler not sampled for transaction name", - ), - pytest.param( - lambda _: "1", 0, id="profiler not sampled because string sample rate" - ), - pytest.param(lambda _: True, 1, id="profiler sampled at True"), - pytest.param(lambda _: False, 0, id="profiler sampled at False"), - ], -) -@mock.patch("sentry_sdk.profiler.transaction_profiler.PROFILE_MINIMUM_SAMPLES", 0) -def test_profiles_sampler( - sentry_init, - capture_envelopes, - capture_record_lost_event_calls, - teardown_profiling, - profiles_sampler, - profile_count, - mode, -): - sentry_init( - traces_sample_rate=1.0, - profiles_sampler=profiles_sampler, - ) - - envelopes = capture_envelopes() - record_lost_event_calls = capture_record_lost_event_calls() - - with mock.patch( - "sentry_sdk.profiler.transaction_profiler.random.random", return_value=0.5 - ): - with start_transaction(name="profiling"): - pass - - items = defaultdict(list) - for envelope in envelopes: - for item in envelope.items: - items[item.type].append(item) - - assert len(items["transaction"]) == 1 - assert len(items["profile"]) == profile_count - if profile_count: - assert record_lost_event_calls == [] - else: - assert record_lost_event_calls == [("sample_rate", "profile", None, 1)] - - -def test_minimum_unique_samples_required( - sentry_init, - capture_envelopes, - capture_record_lost_event_calls, - teardown_profiling, -): - sentry_init( - traces_sample_rate=1.0, - _experiments={"profiles_sample_rate": 1.0}, - ) - - envelopes = capture_envelopes() - record_lost_event_calls = capture_record_lost_event_calls() - - with start_transaction(name="profiling"): - pass - - items = defaultdict(list) - for envelope in envelopes: - for item in envelope.items: - items[item.type].append(item) - - assert len(items["transaction"]) == 1 - # because we dont leave any time for the profiler to - # take any samples, it should be not be sent - assert len(items["profile"]) == 0 - assert record_lost_event_calls == [("insufficient_data", "profile", None, 1)] - - -@pytest.mark.forked -def test_profile_captured( - sentry_init, - capture_envelopes, - teardown_profiling, -): - sentry_init( - traces_sample_rate=1.0, - _experiments={"profiles_sample_rate": 1.0}, - ) - - envelopes = capture_envelopes() - - with start_transaction(name="profiling"): - time.sleep(0.05) - - items = defaultdict(list) - for envelope in envelopes: - for item in envelope.items: - items[item.type].append(item) - - assert len(items["transaction"]) == 1 - assert len(items["profile"]) == 1 - - -def get_frame(depth=1): - """ - This function is not exactly true to its name. Depending on - how it is called, the true depth of the stack can be deeper - than the argument implies. - """ - if depth <= 0: - raise ValueError("only positive integers allowed") - if depth > 1: - return get_frame(depth=depth - 1) - return inspect.currentframe() - - -class GetFrameBase: - def inherited_instance_method(self): - return inspect.currentframe() - - def inherited_instance_method_wrapped(self): - def wrapped(): - return inspect.currentframe() - - return wrapped - - @classmethod - def inherited_class_method(cls): - return inspect.currentframe() - - @classmethod - def inherited_class_method_wrapped(cls): - def wrapped(): - return inspect.currentframe() - - return wrapped - - @staticmethod - def inherited_static_method(): - return inspect.currentframe() - - -class GetFrame(GetFrameBase): - def instance_method(self): - return inspect.currentframe() - - def instance_method_wrapped(self): - def wrapped(): - return inspect.currentframe() - - return wrapped - - @classmethod - def class_method(cls): - return inspect.currentframe() - - @classmethod - def class_method_wrapped(cls): - def wrapped(): - return inspect.currentframe() - - return wrapped - - @staticmethod - def static_method(): - return inspect.currentframe() - - -@pytest.mark.parametrize( - ("frame", "frame_name"), - [ - pytest.param( - get_frame(), - "get_frame", - id="function", - ), - pytest.param( - (lambda: inspect.currentframe())(), - "", - id="lambda", - ), - pytest.param( - GetFrame().instance_method(), - "GetFrame.instance_method", - id="instance_method", - ), - pytest.param( - GetFrame().instance_method_wrapped()(), - ( - "wrapped" - if sys.version_info < (3, 11) - else "GetFrame.instance_method_wrapped..wrapped" - ), - id="instance_method_wrapped", - ), - pytest.param( - GetFrame().class_method(), - "GetFrame.class_method", - id="class_method", - ), - pytest.param( - GetFrame().class_method_wrapped()(), - ( - "wrapped" - if sys.version_info < (3, 11) - else "GetFrame.class_method_wrapped..wrapped" - ), - id="class_method_wrapped", - ), - pytest.param( - GetFrame().static_method(), - "static_method" if sys.version_info < (3, 11) else "GetFrame.static_method", - id="static_method", - ), - pytest.param( - GetFrame().inherited_instance_method(), - "GetFrameBase.inherited_instance_method", - id="inherited_instance_method", - ), - pytest.param( - GetFrame().inherited_instance_method_wrapped()(), - ( - "wrapped" - if sys.version_info < (3, 11) - else "GetFrameBase.inherited_instance_method_wrapped..wrapped" - ), - id="instance_method_wrapped", - ), - pytest.param( - GetFrame().inherited_class_method(), - "GetFrameBase.inherited_class_method", - id="inherited_class_method", - ), - pytest.param( - GetFrame().inherited_class_method_wrapped()(), - ( - "wrapped" - if sys.version_info < (3, 11) - else "GetFrameBase.inherited_class_method_wrapped..wrapped" - ), - id="inherited_class_method_wrapped", - ), - pytest.param( - GetFrame().inherited_static_method(), - ( - "inherited_static_method" - if sys.version_info < (3, 11) - else "GetFrameBase.inherited_static_method" - ), - id="inherited_static_method", - ), - ], -) -def test_get_frame_name(frame, frame_name): - assert get_frame_name(frame) == frame_name - - -@pytest.mark.parametrize( - ("get_frame", "function"), - [ - pytest.param(lambda: get_frame(depth=1), "get_frame", id="simple"), - ], -) -def test_extract_frame(get_frame, function): - cwd = os.getcwd() - frame = get_frame() - extracted_frame = extract_frame(frame_id(frame), frame, cwd) - - # the abs_path should be equal toe the normalized path of the co_filename - assert extracted_frame["abs_path"] == os.path.normpath(frame.f_code.co_filename) - - # the module should be pull from this test module - assert extracted_frame["module"] == __name__ - - # the filename should be the file starting after the cwd - assert extracted_frame["filename"] == __file__[len(cwd) + 1 :] - - assert extracted_frame["function"] == function - - # the lineno will shift over time as this file is modified so just check - # that it is an int - assert isinstance(extracted_frame["lineno"], int) - - -@pytest.mark.parametrize( - ("depth", "max_stack_depth", "actual_depth"), - [ - pytest.param(1, 128, 1, id="less than"), - pytest.param(256, 128, 128, id="greater than"), - pytest.param(128, 128, 128, id="equals"), - ], -) -def test_extract_stack_with_max_depth(depth, max_stack_depth, actual_depth): - # introduce a lambda that we'll be looking for in the stack - frame = (lambda: get_frame(depth=depth))() - - # plus 1 because we introduced a lambda intentionally that we'll - # look for in the final stack to make sure its in the right position - base_stack_depth = len(inspect.stack()) + 1 - - # increase the max_depth by the `base_stack_depth` to account - # for the extra frames pytest will add - _, frame_ids, frames = extract_stack( - frame, - LRUCache(max_size=1), - max_stack_depth=max_stack_depth + base_stack_depth, - cwd=os.getcwd(), - ) - assert len(frame_ids) == base_stack_depth + actual_depth - assert len(frames) == base_stack_depth + actual_depth - - for i in range(actual_depth): - assert frames[i]["function"] == "get_frame", i - - # index 0 contains the inner most frame on the stack, so the lamdba - # should be at index `actual_depth` - if sys.version_info >= (3, 11): - assert ( - frames[actual_depth]["function"] - == "test_extract_stack_with_max_depth.." - ), actual_depth - else: - assert frames[actual_depth]["function"] == "", actual_depth - - -@pytest.mark.parametrize( - ("frame", "depth"), - [(get_frame(depth=1), len(inspect.stack()))], -) -def test_extract_stack_with_cache(frame, depth): - # make sure cache has enough room or this test will fail - cache = LRUCache(max_size=depth) - cwd = os.getcwd() - _, _, frames1 = extract_stack(frame, cache, cwd=cwd) - _, _, frames2 = extract_stack(frame, cache, cwd=cwd) - - assert len(frames1) > 0 - assert len(frames2) > 0 - assert len(frames1) == len(frames2) - for i, (frame1, frame2) in enumerate(zip(frames1, frames2)): - # DO NOT use `==` for the assertion here since we are - # testing for identity, and using `==` would test for - # equality which would always pass since we're extract - # the same stack. - assert frame1 is frame2, i - - -def get_scheduler_threads(scheduler): - return [thread for thread in threading.enumerate() if thread.name == scheduler.name] - - -@pytest.mark.parametrize( - ("scheduler_class",), - [ - pytest.param(ThreadScheduler, id="thread scheduler"), - pytest.param( - GeventScheduler, - marks=[ - requires_gevent, - pytest.mark.skip( - reason="cannot find this thread via threading.enumerate()" - ), - ], - id="gevent scheduler", - ), - ], -) -def test_thread_scheduler_single_background_thread(scheduler_class): - scheduler = scheduler_class(frequency=1000) - - # not yet setup, no scheduler threads yet - assert len(get_scheduler_threads(scheduler)) == 0 - - scheduler.setup() - - # setup but no profiles started so still no threads - assert len(get_scheduler_threads(scheduler)) == 0 - - scheduler.ensure_running() - - # the scheduler will start always 1 thread - assert len(get_scheduler_threads(scheduler)) == 1 - - scheduler.ensure_running() - - # the scheduler still only has 1 thread - assert len(get_scheduler_threads(scheduler)) == 1 - - scheduler.teardown() - - # once finished, the thread should stop - assert len(get_scheduler_threads(scheduler)) == 0 - - -@pytest.mark.parametrize( - ("scheduler_class",), - [ - pytest.param(ThreadScheduler, id="thread scheduler"), - pytest.param( - GeventScheduler, - marks=[ - requires_gevent, - pytest.mark.skip( - reason="cannot find this thread via threading.enumerate()" - ), - ], - id="gevent scheduler", - ), - ], -) -def test_thread_scheduler_no_thread_on_shutdown(scheduler_class): - scheduler = scheduler_class(frequency=1000) - - # not yet setup, no scheduler threads yet - assert len(get_scheduler_threads(scheduler)) == 0 - - scheduler.setup() - - # setup but no profiles started so still no threads - assert len(get_scheduler_threads(scheduler)) == 0 - - # mock RuntimeError as if the 3.12 interpreter was shutting down - with mock.patch( - "threading.Thread.start", - side_effect=RuntimeError("can't create new thread at interpreter shutdown"), - ): - scheduler.ensure_running() - - assert scheduler.running is False - - # still no thread - assert len(get_scheduler_threads(scheduler)) == 0 - - scheduler.teardown() - - assert len(get_scheduler_threads(scheduler)) == 0 - - -@pytest.mark.parametrize( - ("scheduler_class",), - [ - pytest.param(ThreadScheduler, id="thread scheduler"), - pytest.param(GeventScheduler, marks=requires_gevent, id="gevent scheduler"), - ], -) -@mock.patch("sentry_sdk.profiler.transaction_profiler.MAX_PROFILE_DURATION_NS", 1) -def test_max_profile_duration_reached(scheduler_class): - sample = [ - ( - "1", - extract_stack( - get_frame(), - LRUCache(max_size=1), - cwd=os.getcwd(), - ), - ), - ] - - with scheduler_class(frequency=1000) as scheduler: - with Profile(True, 0, scheduler=scheduler) as profile: - # profile just started, it's active - assert profile.active - - # write a sample at the start time, so still active - profile.write(profile.start_ns + 0, sample) - assert profile.active - - # write a sample at max time, so still active - profile.write(profile.start_ns + 1, sample) - assert profile.active - - # write a sample PAST the max time, so now inactive - profile.write(profile.start_ns + 2, sample) - assert not profile.active - - -class NoopScheduler(Scheduler): - def setup(self) -> None: - pass - - def teardown(self) -> None: - pass - - def ensure_running(self) -> None: - pass - - -current_thread = threading.current_thread() -thread_metadata = { - str(current_thread.ident): { - "name": str(current_thread.name), - }, -} - - -sample_stacks = [ - extract_stack( - get_frame(), - LRUCache(max_size=1), - max_stack_depth=1, - cwd=os.getcwd(), - ), - extract_stack( - get_frame(), - LRUCache(max_size=1), - max_stack_depth=2, - cwd=os.getcwd(), - ), -] - - -@pytest.mark.parametrize( - ("samples", "expected"), - [ - pytest.param( - [], - { - "frames": [], - "samples": [], - "stacks": [], - "thread_metadata": thread_metadata, - }, - id="empty", - ), - pytest.param( - [(6, [("1", sample_stacks[0])])], - { - "frames": [], - "samples": [], - "stacks": [], - "thread_metadata": thread_metadata, - }, - id="single sample out of range", - ), - pytest.param( - [(0, [("1", sample_stacks[0])])], - { - "frames": [sample_stacks[0][2][0]], - "samples": [ - { - "elapsed_since_start_ns": "0", - "thread_id": "1", - "stack_id": 0, - }, - ], - "stacks": [[0]], - "thread_metadata": thread_metadata, - }, - id="single sample in range", - ), - pytest.param( - [ - (0, [("1", sample_stacks[0])]), - (1, [("1", sample_stacks[0])]), - ], - { - "frames": [sample_stacks[0][2][0]], - "samples": [ - { - "elapsed_since_start_ns": "0", - "thread_id": "1", - "stack_id": 0, - }, - { - "elapsed_since_start_ns": "1", - "thread_id": "1", - "stack_id": 0, - }, - ], - "stacks": [[0]], - "thread_metadata": thread_metadata, - }, - id="two identical stacks", - ), - pytest.param( - [ - (0, [("1", sample_stacks[0])]), - (1, [("1", sample_stacks[1])]), - ], - { - "frames": [ - sample_stacks[0][2][0], - sample_stacks[1][2][0], - ], - "samples": [ - { - "elapsed_since_start_ns": "0", - "thread_id": "1", - "stack_id": 0, - }, - { - "elapsed_since_start_ns": "1", - "thread_id": "1", - "stack_id": 1, - }, - ], - "stacks": [[0], [1, 0]], - "thread_metadata": thread_metadata, - }, - id="two different stacks", - ), - ], -) -@mock.patch("sentry_sdk.profiler.transaction_profiler.MAX_PROFILE_DURATION_NS", 5) -def test_profile_processing( - DictionaryContaining, # noqa: N803 - samples, - expected, -): - with NoopScheduler(frequency=1000) as scheduler: - with Profile(True, 0, scheduler=scheduler) as profile: - for ts, sample in samples: - # force the sample to be written at a time relative to the - # start of the profile - now = profile.start_ns + ts - profile.write(now, sample) - - processed = profile.process() - - assert processed["thread_metadata"] == DictionaryContaining( - expected["thread_metadata"] - ) - assert processed["frames"] == expected["frames"] - assert processed["stacks"] == expected["stacks"] - assert processed["samples"] == expected["samples"] - - -def test_hub_backwards_compatibility(suppress_deprecation_warnings): - hub = sentry_sdk.Hub() - - with pytest.warns(DeprecationWarning): - profile = Profile(True, 0, hub=hub) - - with pytest.warns(DeprecationWarning): - assert profile.hub is hub - - new_hub = sentry_sdk.Hub() - - with pytest.warns(DeprecationWarning): - profile.hub = new_hub - - with pytest.warns(DeprecationWarning): - assert profile.hub is new_hub - - -def test_no_warning_without_hub(): - with warnings.catch_warnings(): - warnings.simplefilter("error") - Profile(True, 0) diff --git a/tests/test_ai_integration_deactivation.py b/tests/test_ai_integration_deactivation.py deleted file mode 100644 index 3c13ef7546..0000000000 --- a/tests/test_ai_integration_deactivation.py +++ /dev/null @@ -1,251 +0,0 @@ -import pytest - -from sentry_sdk import get_client -from sentry_sdk.integrations import _INTEGRATION_DEACTIVATES - -try: - from sentry_sdk.integrations.langchain import LangchainIntegration - - has_langchain = True -except Exception: - has_langchain = False - -try: - from sentry_sdk.integrations.openai import OpenAIIntegration - - has_openai = True -except Exception: - has_openai = False - -try: - from sentry_sdk.integrations.anthropic import AnthropicIntegration - - has_anthropic = True -except Exception: - has_anthropic = False - - -try: - from sentry_sdk.integrations.openai_agents import OpenAIAgentsIntegration - - has_openai_agents = True -except Exception: - has_openai_agents = False - -try: - from sentry_sdk.integrations.pydantic_ai import PydanticAIIntegration - - has_pydantic_ai = True -except Exception: - has_pydantic_ai = False - - -pytestmark = pytest.mark.skipif( - not ( - has_langchain - and has_openai - and has_anthropic - and has_openai_agents - and has_pydantic_ai - ), - reason="Requires langchain, openai, and anthropic packages to be installed", -) - - -def test_integration_deactivates_map_exists(): - assert "langchain" in _INTEGRATION_DEACTIVATES - assert "openai" in _INTEGRATION_DEACTIVATES["langchain"] - assert "anthropic" in _INTEGRATION_DEACTIVATES["langchain"] - assert "google_genai" in _INTEGRATION_DEACTIVATES["langchain"] - assert "openai_agents" in _INTEGRATION_DEACTIVATES - assert "openai" in _INTEGRATION_DEACTIVATES["openai_agents"] - assert "pydantic_ai" in _INTEGRATION_DEACTIVATES - assert "openai" in _INTEGRATION_DEACTIVATES["pydantic_ai"] - assert "anthropic" in _INTEGRATION_DEACTIVATES["pydantic_ai"] - - -def test_langchain_auto_deactivates_openai_and_anthropic( - sentry_init, reset_integrations -): - sentry_init( - default_integrations=False, - auto_enabling_integrations=True, - ) - - client = get_client() - integration_types = { - type(integration) for integration in client.integrations.values() - } - - if LangchainIntegration in integration_types: - assert OpenAIIntegration not in integration_types - assert AnthropicIntegration not in integration_types - - -def test_user_can_override_with_explicit_openai(sentry_init, reset_integrations): - sentry_init( - default_integrations=False, - auto_enabling_integrations=True, - integrations=[OpenAIIntegration()], - ) - - client = get_client() - integration_types = { - type(integration) for integration in client.integrations.values() - } - - assert OpenAIIntegration in integration_types - - -def test_user_can_override_with_explicit_anthropic(sentry_init, reset_integrations): - sentry_init( - default_integrations=False, - auto_enabling_integrations=True, - integrations=[AnthropicIntegration()], - ) - - client = get_client() - integration_types = { - type(integration) for integration in client.integrations.values() - } - - assert AnthropicIntegration in integration_types - - -def test_user_can_override_with_both_explicit_integrations( - sentry_init, reset_integrations -): - sentry_init( - default_integrations=False, - auto_enabling_integrations=True, - integrations=[OpenAIIntegration(), AnthropicIntegration()], - ) - - client = get_client() - integration_types = { - type(integration) for integration in client.integrations.values() - } - - assert OpenAIIntegration in integration_types - assert AnthropicIntegration in integration_types - - -def test_disabling_integrations_allows_openai_and_anthropic( - sentry_init, reset_integrations -): - sentry_init( - default_integrations=False, - auto_enabling_integrations=True, - disabled_integrations=[ - LangchainIntegration, - OpenAIAgentsIntegration, - PydanticAIIntegration, - ], - ) - - client = get_client() - integration_types = { - type(integration) for integration in client.integrations.values() - } - - assert LangchainIntegration not in integration_types - - -def test_explicit_langchain_still_deactivates_others(sentry_init, reset_integrations): - sentry_init( - default_integrations=False, - auto_enabling_integrations=False, - integrations=[LangchainIntegration()], - ) - - client = get_client() - integration_types = { - type(integration) for integration in client.integrations.values() - } - - if LangchainIntegration in integration_types: - assert OpenAIIntegration not in integration_types - assert AnthropicIntegration not in integration_types - - -def test_langchain_and_openai_both_explicit_both_active( - sentry_init, reset_integrations -): - sentry_init( - default_integrations=False, - auto_enabling_integrations=False, - integrations=[LangchainIntegration(), OpenAIIntegration()], - ) - - client = get_client() - integration_types = { - type(integration) for integration in client.integrations.values() - } - - assert LangchainIntegration in integration_types - assert OpenAIIntegration in integration_types - - -def test_no_langchain_means_openai_and_anthropic_can_auto_enable( - sentry_init, reset_integrations, monkeypatch -): - import sentry_sdk.integrations - - old_iter = sentry_sdk.integrations.iter_default_integrations - - def filtered_iter(with_auto_enabling): - for cls in old_iter(with_auto_enabling): - if cls.identifier != "langchain": - yield cls - - monkeypatch.setattr( - sentry_sdk.integrations, "iter_default_integrations", filtered_iter - ) - - sentry_init( - default_integrations=False, - auto_enabling_integrations=True, - ) - - client = get_client() - integration_types = { - type(integration) for integration in client.integrations.values() - } - - assert LangchainIntegration not in integration_types - - -def test_deactivation_with_default_integrations_enabled( - sentry_init, reset_integrations -): - sentry_init( - default_integrations=True, - auto_enabling_integrations=True, - ) - - client = get_client() - integration_types = { - type(integration) for integration in client.integrations.values() - } - - if LangchainIntegration in integration_types: - assert OpenAIIntegration not in integration_types - assert AnthropicIntegration not in integration_types - - -def test_only_auto_enabling_integrations_without_defaults( - sentry_init, reset_integrations -): - sentry_init( - default_integrations=False, - auto_enabling_integrations=True, - ) - - client = get_client() - integration_types = { - type(integration) for integration in client.integrations.values() - } - - if LangchainIntegration in integration_types: - assert OpenAIIntegration not in integration_types - assert AnthropicIntegration not in integration_types diff --git a/tests/test_ai_monitoring.py b/tests/test_ai_monitoring.py index fa4722db34..e6ea0eef6e 100644 --- a/tests/test_ai_monitoring.py +++ b/tests/test_ai_monitoring.py @@ -1,1099 +1,14 @@ import pytest -import sentry_sdk -from sentry_sdk._types import ( - BLOB_DATA_SUBSTITUTE, - AnnotatedValue, -) -from sentry_sdk.ai.monitoring import ai_track from sentry_sdk.ai.utils import ( - MAX_GEN_AI_MESSAGE_BYTES, - MAX_SINGLE_MESSAGE_CONTENT_CHARS, - _find_truncation_index, get_modality_from_mime_type, parse_data_uri, - redact_blob_message_parts, transform_anthropic_content_part, transform_content_part, transform_generic_content_part, transform_google_content_part, - transform_message_content, transform_openai_content_part, - truncate_and_annotate_messages, - truncate_messages_by_size, ) -from sentry_sdk.utils import safe_serialize - - -def test_ai_track(sentry_init, capture_events): - sentry_init(traces_sample_rate=1.0) - events = capture_events() - - @ai_track("my tool") - def tool(**kwargs): - pass - - @ai_track("some test pipeline") - def pipeline(): - tool() - - with sentry_sdk.start_transaction(): - pipeline() - - transaction = events[0] - assert transaction["type"] == "transaction" - assert len(transaction["spans"]) == 2 - spans = transaction["spans"] - - ai_pipeline_span = spans[0] if spans[0]["op"] == "ai.pipeline" else spans[1] - ai_run_span = spans[0] if spans[0]["op"] == "ai.run" else spans[1] - - assert ai_pipeline_span["description"] == "some test pipeline" - assert ai_run_span["description"] == "my tool" - - -def test_ai_track_span_streaming(sentry_init, capture_items): - sentry_init(traces_sample_rate=1.0, trace_lifecycle="stream") - items = capture_items("span") - - @ai_track("my tool") - def tool(**kwargs): - pass - - @ai_track("some test pipeline") - def pipeline(): - tool() - - with sentry_sdk.traces.start_span(name="span"): - pipeline() - - sentry_sdk.flush() - - spans = [item.payload for item in items] - assert len(spans) == 3 - ai_run_span, ai_pipeline_span, segment = spans - - assert ai_pipeline_span["name"] == "some test pipeline" - assert ai_run_span["name"] == "my tool" - - -def test_ai_track_with_tags(sentry_init, capture_events): - sentry_init(traces_sample_rate=1.0) - events = capture_events() - - @ai_track("my tool") - def tool(**kwargs): - pass - - @ai_track("some test pipeline") - def pipeline(): - tool() - - with sentry_sdk.start_transaction(): - pipeline(sentry_tags={"user": "colin"}, sentry_data={"some_data": "value"}) - - transaction = events[0] - assert transaction["type"] == "transaction" - assert len(transaction["spans"]) == 2 - spans = transaction["spans"] - - ai_pipeline_span = spans[0] if spans[0]["op"] == "ai.pipeline" else spans[1] - ai_run_span = spans[0] if spans[0]["op"] == "ai.run" else spans[1] - - assert ai_pipeline_span["description"] == "some test pipeline" - assert ai_pipeline_span["tags"]["user"] == "colin" - assert ai_pipeline_span["data"]["some_data"] == "value" - assert ai_run_span["description"] == "my tool" - - -def test_ai_track_with_attributes_span_streaming(sentry_init, capture_items): - sentry_init(traces_sample_rate=1.0, trace_lifecycle="stream") - items = capture_items("span") - - @ai_track("my tool") - def tool(**kwargs): - pass - - @ai_track("some test pipeline") - def pipeline(): - tool() - - with sentry_sdk.traces.start_span(name="span"): - pipeline(sentry_tags={"user": "colin"}, sentry_data={"some_data": "value"}) - - sentry_sdk.flush() - - spans = [item.payload for item in items] - - assert len(spans) == 3 - ai_run_span, ai_pipeline_span, segment = spans - - assert ai_pipeline_span["name"] == "some test pipeline" - assert ai_pipeline_span["attributes"]["user"] == "colin" - assert ai_pipeline_span["attributes"]["some_data"] == "value" - assert ai_run_span["name"] == "my tool" - - -@pytest.mark.asyncio -async def test_ai_track_async(sentry_init, capture_events): - sentry_init(traces_sample_rate=1.0) - events = capture_events() - - @ai_track("my async tool") - async def async_tool(**kwargs): - pass - - @ai_track("some async test pipeline") - async def async_pipeline(): - await async_tool() - - with sentry_sdk.start_transaction(): - await async_pipeline() - - transaction = events[0] - assert transaction["type"] == "transaction" - assert len(transaction["spans"]) == 2 - spans = transaction["spans"] - - ai_pipeline_span = spans[0] if spans[0]["op"] == "ai.pipeline" else spans[1] - ai_run_span = spans[0] if spans[0]["op"] == "ai.run" else spans[1] - - assert ai_pipeline_span["description"] == "some async test pipeline" - assert ai_run_span["description"] == "my async tool" - - -@pytest.mark.asyncio -async def test_ai_track_async_span_streaming(sentry_init, capture_items): - sentry_init(traces_sample_rate=1.0, trace_lifecycle="stream") - items = capture_items() - - @ai_track("my async tool") - async def async_tool(**kwargs): - pass - - @ai_track("some async test pipeline") - async def async_pipeline(): - await async_tool() - - with sentry_sdk.traces.start_span(name="span"): - await async_pipeline() - - sentry_sdk.flush() - - spans = [item.payload for item in items] - assert len(spans) == 3 - ai_run_span, ai_pipeline_span, segment = spans - - assert ai_pipeline_span["name"] == "some async test pipeline" - assert ai_run_span["name"] == "my async tool" - - -@pytest.mark.asyncio -async def test_ai_track_async_with_tags(sentry_init, capture_events): - sentry_init(traces_sample_rate=1.0) - events = capture_events() - - @ai_track("my async tool") - async def async_tool(**kwargs): - pass - - @ai_track("some async test pipeline") - async def async_pipeline(): - await async_tool() - - with sentry_sdk.start_transaction(): - await async_pipeline( - sentry_tags={"user": "czyber"}, sentry_data={"some_data": "value"} - ) - - transaction = events[0] - assert transaction["type"] == "transaction" - assert len(transaction["spans"]) == 2 - spans = transaction["spans"] - - ai_pipeline_span = spans[0] if spans[0]["op"] == "ai.pipeline" else spans[1] - ai_run_span = spans[0] if spans[0]["op"] == "ai.run" else spans[1] - - assert ai_pipeline_span["description"] == "some async test pipeline" - assert ai_pipeline_span["tags"]["user"] == "czyber" - assert ai_pipeline_span["data"]["some_data"] == "value" - assert ai_run_span["description"] == "my async tool" - - -@pytest.mark.asyncio -async def test_ai_track_async_with_attributes_span_streaming( - sentry_init, capture_items -): - sentry_init(traces_sample_rate=1.0, trace_lifecycle="stream") - items = capture_items("span") - - @ai_track("my async tool") - async def async_tool(**kwargs): - pass - - @ai_track("some async test pipeline") - async def async_pipeline(): - await async_tool() - - with sentry_sdk.traces.start_span(name="span"): - await async_pipeline( - sentry_tags={"user": "czyber"}, sentry_data={"some_data": "value"} - ) - - sentry_sdk.flush() - - spans = [item.payload for item in items] - assert len(spans) == 3 - ai_run_span, ai_pipeline_span, segment = spans - - assert ai_pipeline_span["name"] == "some async test pipeline" - assert ai_pipeline_span["attributes"]["user"] == "czyber" - assert ai_pipeline_span["attributes"]["some_data"] == "value" - assert ai_run_span["name"] == "my async tool" - - -def test_ai_track_with_explicit_op(sentry_init, capture_events): - sentry_init(traces_sample_rate=1.0) - events = capture_events() - - @ai_track("my tool", op="custom.operation") - def tool(**kwargs): - pass - - with sentry_sdk.start_transaction(): - tool() - - transaction = events[0] - assert transaction["type"] == "transaction" - assert len(transaction["spans"]) == 1 - span = transaction["spans"][0] - - assert span["description"] == "my tool" - assert span["op"] == "custom.operation" - - -def test_ai_track_with_explicit_op_span_streaming(sentry_init, capture_items): - sentry_init(traces_sample_rate=1.0, trace_lifecycle="stream") - items = capture_items("span") - - @ai_track("my tool", op="custom.operation") - def tool(**kwargs): - pass - - with sentry_sdk.traces.start_span(name="span"): - tool() - - sentry_sdk.flush() - - spans = [item.payload for item in items] - assert len(spans) == 2 - ai_run_span, segment = spans - - assert ai_run_span["name"] == "my tool" - assert ai_run_span["attributes"]["sentry.op"] == "custom.operation" - - -@pytest.mark.asyncio -async def test_ai_track_async_with_explicit_op(sentry_init, capture_events): - sentry_init(traces_sample_rate=1.0) - events = capture_events() - - @ai_track("my async tool", op="custom.async.operation") - async def async_tool(**kwargs): - pass - - with sentry_sdk.start_transaction(): - await async_tool() - - transaction = events[0] - assert transaction["type"] == "transaction" - assert len(transaction["spans"]) == 1 - span = transaction["spans"][0] - - assert span["description"] == "my async tool" - assert span["op"] == "custom.async.operation" - - -@pytest.mark.asyncio -async def test_ai_track_async_with_explicit_op_span_streaming( - sentry_init, capture_items -): - sentry_init(traces_sample_rate=1.0, trace_lifecycle="stream") - items = capture_items() - - @ai_track("my async tool", op="custom.async.operation") - async def async_tool(**kwargs): - pass - - with sentry_sdk.traces.start_span(name="span"): - await async_tool() - - sentry_sdk.flush() - - spans = [item.payload for item in items] - assert len(spans) == 2 - ai_run_span, segment = spans - - assert ai_run_span["name"] == "my async tool" - assert ai_run_span["attributes"]["sentry.op"] == "custom.async.operation" - - -@pytest.fixture -def sample_messages(): - """Sample messages similar to what gen_ai integrations would use""" - return [ - {"role": "system", "content": "You are a helpful assistant."}, - { - "role": "user", - "content": "What is the difference between a list and a tuple in Python?", - }, - { - "role": "assistant", - "content": "Lists are mutable and use [], tuples are immutable and use ().", - }, - {"role": "user", "content": "Can you give me some examples?"}, - { - "role": "assistant", - "content": "Sure! Here are examples:\n\n```python\n# List\nmy_list = [1, 2, 3]\nmy_list.append(4)\n\n# Tuple\nmy_tuple = (1, 2, 3)\n# my_tuple.append(4) would error\n```", - }, - ] - - -@pytest.fixture -def large_messages(): - """Messages that will definitely exceed size limits""" - large_content = "This is a very long message. " * 100 - return [ - {"role": "system", "content": large_content}, - {"role": "user", "content": large_content}, - {"role": "assistant", "content": large_content}, - {"role": "user", "content": large_content}, - ] - - -class TestTruncateMessagesBySize: - def test_no_truncation_needed(self, sample_messages): - """Test that messages under the limit are not truncated""" - result, truncation_index = truncate_messages_by_size( - sample_messages, max_bytes=MAX_GEN_AI_MESSAGE_BYTES - ) - assert len(result) == len(sample_messages) - assert result == sample_messages - assert truncation_index == 0 - - def test_truncation_removes_oldest_first(self, large_messages): - """Test that oldest messages are removed first during truncation""" - small_limit = 3000 - result, truncation_index = truncate_messages_by_size( - large_messages, max_bytes=small_limit - ) - assert len(result) < len(large_messages) - - assert result[-1] == large_messages[-1] - assert truncation_index == len(large_messages) - len(result) - - def test_empty_messages_list(self): - """Test handling of empty messages list""" - result, truncation_index = truncate_messages_by_size( - [], max_bytes=MAX_GEN_AI_MESSAGE_BYTES // 500 - ) - assert result == [] - assert truncation_index == 0 - - def test_find_truncation_index( - self, - ): - """Test that the truncation index is found correctly""" - # when represented in JSON, these are each 7 bytes long - messages = ["A" * 5, "B" * 5, "C" * 5, "D" * 5, "E" * 5] - truncation_index = _find_truncation_index(messages, 20) - assert truncation_index == 3 - assert messages[truncation_index:] == ["D" * 5, "E" * 5] - - messages = ["A" * 5, "B" * 5, "C" * 5, "D" * 5, "E" * 5] - truncation_index = _find_truncation_index(messages, 40) - assert truncation_index == 0 - assert messages[truncation_index:] == [ - "A" * 5, - "B" * 5, - "C" * 5, - "D" * 5, - "E" * 5, - ] - - def test_progressive_truncation(self, large_messages): - """Test that truncation works progressively with different limits""" - limits = [ - MAX_GEN_AI_MESSAGE_BYTES // 5, - MAX_GEN_AI_MESSAGE_BYTES // 10, - MAX_GEN_AI_MESSAGE_BYTES // 25, - MAX_GEN_AI_MESSAGE_BYTES // 100, - MAX_GEN_AI_MESSAGE_BYTES // 500, - ] - prev_count = len(large_messages) - - for limit in limits: - result = truncate_messages_by_size(large_messages, max_bytes=limit) - current_count = len(result) - - assert current_count <= prev_count - assert current_count >= 1 - prev_count = current_count - - def test_single_message_truncation(self): - large_content = "This is a very long message. " * 10_000 - - messages = [ - {"role": "system", "content": "You are a helpful assistant."}, - {"role": "user", "content": large_content}, - ] - - result, truncation_index = truncate_messages_by_size( - messages, max_single_message_chars=MAX_SINGLE_MESSAGE_CONTENT_CHARS - ) - - assert len(result) == 1 - assert ( - len(result[0]["content"].rstrip("...")) <= MAX_SINGLE_MESSAGE_CONTENT_CHARS - ) - - # If the last message is too large, the system message is not present - system_msgs = [m for m in result if m.get("role") == "system"] - assert len(system_msgs) == 0 - - # Confirm the user message is truncated with '...' - user_msgs = [m for m in result if m.get("role") == "user"] - assert len(user_msgs) == 1 - assert user_msgs[0]["content"].endswith("...") - assert len(user_msgs[0]["content"]) < len(large_content) - - def test_single_message_truncation_list_content_exceeds_limit(self): - """Test that list-based content (e.g. pydantic-ai multimodal format) is truncated.""" - large_text = "A" * 200_000 - - messages = [ - { - "role": "user", - "content": [ - {"type": "text", "text": large_text}, - ], - }, - ] - - result, _ = truncate_messages_by_size(messages) - - text_part = result[0]["content"][0] - assert text_part["text"].endswith("...") - assert len(text_part["text"]) == MAX_SINGLE_MESSAGE_CONTENT_CHARS + 3 - - def test_single_message_truncation_list_content_under_limit(self): - """Test that small text parts are preserved when non-text parts push size over byte limit.""" - short_text = "Hello world" - large_data_url = "data:image/png;base64," + "A" * 200_000 - - messages = [ - { - "role": "user", - "content": [ - {"type": "text", "text": short_text}, - {"type": "image_url", "image_url": {"url": large_data_url}}, - ], - }, - ] - - result, _ = truncate_messages_by_size(messages) - - text_part = result[0]["content"][0] - assert text_part["text"] == short_text - - def test_single_message_truncation_list_content_mixed_parts(self): - """Test truncation with mixed content types (text + non-text parts).""" - max_chars = 50 - large_data_url = "data:image/png;base64," + "X" * 200_000 - - messages = [ - { - "role": "user", - "content": [ - {"type": "text", "text": "A" * 30}, - {"type": "image_url", "image_url": {"url": large_data_url}}, - {"type": "text", "text": "B" * 30}, - ], - }, - ] - - result, _ = truncate_messages_by_size( - messages, max_single_message_chars=max_chars - ) - - parts = result[0]["content"] - # First text part uses 30 chars of the 50 budget - assert parts[0]["text"] == "A" * 30 - # Image part is unchanged - assert parts[1]["type"] == "image_url" - # Second text part is truncated to remaining 20 chars - assert parts[2]["text"] == "B" * 20 + "..." - - def test_single_message_truncation_list_content_multiple_text_parts(self): - """Test that budget is distributed across multiple text parts.""" - max_chars = 10 - # Two large text parts that together exceed 128KB byte limit - messages = [ - { - "role": "user", - "content": [ - {"type": "text", "text": "A" * 100_000}, - {"type": "text", "text": "B" * 100_000}, - ], - }, - ] - - result, _ = truncate_messages_by_size( - messages, max_single_message_chars=max_chars - ) - - parts = result[0]["content"] - # First part is truncated to the full budget - assert parts[0]["text"] == "A" * 10 + "..." - # Second part gets truncated to 0 chars + ellipsis - assert parts[1]["text"] == "..." - - @pytest.mark.parametrize("content", [None, 42, True]) - def test_single_message_truncation_non_str_non_list_content(self, content): - messages = [{"role": "user", "content": content}] - - result, _ = truncate_messages_by_size(messages) - - assert result[0]["content"] is content - - -class TestTruncateAndAnnotateMessages: - def test_only_keeps_last_message(self, sample_messages): - class MockSpan: - def __init__(self): - self.span_id = "test_span_id" - self.data = {} - - def set_data(self, key, value): - self.data[key] = value - - class MockScope: - def __init__(self): - self._gen_ai_original_message_count = {} - - span = MockSpan() - scope = MockScope() - result = truncate_and_annotate_messages(sample_messages, span, scope) - - assert isinstance(result, list) - assert not isinstance(result, AnnotatedValue) - assert len(result) == 1 - assert result[0] == sample_messages[-1] - - def test_truncation_sets_metadata_on_scope(self, large_messages): - class MockSpan: - def __init__(self): - self.span_id = "test_span_id" - self.data = {} - - def set_data(self, key, value): - self.data[key] = value - - class MockScope: - def __init__(self): - self._gen_ai_original_message_count = {} - - small_limit = 3000 - span = MockSpan() - scope = MockScope() - original_count = len(large_messages) - result = truncate_and_annotate_messages( - large_messages, span, scope, max_single_message_chars=small_limit - ) - - assert isinstance(result, list) - assert not isinstance(result, AnnotatedValue) - assert len(result) < len(large_messages) - assert scope._gen_ai_original_message_count[span.span_id] == original_count - - def test_scope_tracks_original_message_count(self, large_messages): - class MockSpan: - def __init__(self): - self.span_id = "test_span_id" - self.data = {} - - def set_data(self, key, value): - self.data[key] = value - - class MockScope: - def __init__(self): - self._gen_ai_original_message_count = {} - - small_limit = 3000 - original_count = len(large_messages) - span = MockSpan() - scope = MockScope() - - result = truncate_and_annotate_messages( - large_messages, span, scope, max_single_message_chars=small_limit - ) - - assert scope._gen_ai_original_message_count[span.span_id] == original_count - assert len(result) == 1 - - def test_empty_messages_returns_none(self): - class MockSpan: - def __init__(self): - self.span_id = "test_span_id" - self.data = {} - - def set_data(self, key, value): - self.data[key] = value - - class MockScope: - def __init__(self): - self._gen_ai_original_message_count = {} - - span = MockSpan() - scope = MockScope() - result = truncate_and_annotate_messages([], span, scope) - assert result is None - - result = truncate_and_annotate_messages(None, span, scope) - assert result is None - - def test_truncated_messages_newest_first(self, large_messages): - class MockSpan: - def __init__(self): - self.span_id = "test_span_id" - self.data = {} - - def set_data(self, key, value): - self.data[key] = value - - class MockScope: - def __init__(self): - self._gen_ai_original_message_count = {} - - small_limit = 3000 - span = MockSpan() - scope = MockScope() - result = truncate_and_annotate_messages( - large_messages, span, scope, max_single_message_chars=small_limit - ) - - assert isinstance(result, list) - assert result[0] == large_messages[-len(result)] - - def test_preserves_original_messages_with_blobs(self): - """Test that truncate_and_annotate_messages doesn't mutate the original messages""" - - class MockSpan: - def __init__(self): - self.span_id = "test_span_id" - self.data = {} - - def set_data(self, key, value): - self.data[key] = value - - class MockScope: - def __init__(self): - self._gen_ai_original_message_count = {} - - messages = [ - { - "role": "user", - "content": [ - {"text": "What's in this image?", "type": "text"}, - { - "type": "blob", - "modality": "image", - "content": "data:image/jpeg;base64,original_content", - }, - ], - } - ] - - original_blob_content = messages[0]["content"][1]["content"] - - span = MockSpan() - scope = MockScope() - - # This should NOT mutate the original messages - result = truncate_and_annotate_messages(messages, span, scope) - - # Verify original is unchanged - assert messages[0]["content"][1]["content"] == original_blob_content - - # Verify result has redacted content - assert result[0]["content"][1]["content"] == BLOB_DATA_SUBSTITUTE - - -class TestClientAnnotation: - def test_client_wraps_truncated_messages_in_annotated_value(self, large_messages): - """Test that client.py properly wraps truncated messages in AnnotatedValue using scope data""" - from sentry_sdk._types import AnnotatedValue - from sentry_sdk.consts import SPANDATA - - class MockSpan: - def __init__(self): - self.span_id = "test_span_123" - self.data = {} - - def set_data(self, key, value): - self.data[key] = value - - class MockScope: - def __init__(self): - self._gen_ai_original_message_count = {} - - small_limit = 3000 - span = MockSpan() - scope = MockScope() - original_count = len(large_messages) - - # Simulate what integrations do - truncated_messages = truncate_and_annotate_messages( - large_messages, span, scope, max_single_message_chars=small_limit - ) - span.set_data(SPANDATA.GEN_AI_REQUEST_MESSAGES, truncated_messages) - - # Verify metadata was set on scope - assert span.span_id in scope._gen_ai_original_message_count - assert scope._gen_ai_original_message_count[span.span_id] > 0 - - # Simulate what client.py does - event = {"spans": [{"span_id": span.span_id, "data": span.data.copy()}]} - - # Mimic client.py logic - using scope to get the original length - for event_span in event["spans"]: - span_id = event_span.get("span_id") - span_data = event_span.get("data", {}) - if ( - span_id - and span_id in scope._gen_ai_original_message_count - and SPANDATA.GEN_AI_REQUEST_MESSAGES in span_data - ): - messages = span_data[SPANDATA.GEN_AI_REQUEST_MESSAGES] - n_original_count = scope._gen_ai_original_message_count[span_id] - - span_data[SPANDATA.GEN_AI_REQUEST_MESSAGES] = AnnotatedValue( - safe_serialize(messages), - {"len": n_original_count}, - ) - - # Verify the annotation happened - messages_value = event["spans"][0]["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - assert isinstance(messages_value, AnnotatedValue) - assert messages_value.metadata["len"] == original_count - assert isinstance(messages_value.value, str) - - def test_annotated_value_shows_correct_original_length(self, large_messages): - """Test that the annotated value correctly shows the original message count before truncation""" - from sentry_sdk.consts import SPANDATA - - class MockSpan: - def __init__(self): - self.span_id = "test_span_456" - self.data = {} - - def set_data(self, key, value): - self.data[key] = value - - class MockScope: - def __init__(self): - self._gen_ai_original_message_count = {} - - small_limit = 3000 - span = MockSpan() - scope = MockScope() - original_message_count = len(large_messages) - - truncated_messages = truncate_and_annotate_messages( - large_messages, span, scope, max_single_message_chars=small_limit - ) - - assert len(truncated_messages) < original_message_count - - assert span.span_id in scope._gen_ai_original_message_count - stored_original_length = scope._gen_ai_original_message_count[span.span_id] - assert stored_original_length == original_message_count - - event = { - "spans": [ - { - "span_id": span.span_id, - "data": {SPANDATA.GEN_AI_REQUEST_MESSAGES: truncated_messages}, - } - ] - } - - for event_span in event["spans"]: - span_id = event_span.get("span_id") - span_data = event_span.get("data", {}) - if ( - span_id - and span_id in scope._gen_ai_original_message_count - and SPANDATA.GEN_AI_REQUEST_MESSAGES in span_data - ): - span_data[SPANDATA.GEN_AI_REQUEST_MESSAGES] = AnnotatedValue( - span_data[SPANDATA.GEN_AI_REQUEST_MESSAGES], - {"len": scope._gen_ai_original_message_count[span_id]}, - ) - - messages_value = event["spans"][0]["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES] - assert isinstance(messages_value, AnnotatedValue) - assert messages_value.metadata["len"] == stored_original_length - assert len(messages_value.value) == len(truncated_messages) - - -class TestRedactBlobMessageParts: - def test_redacts_single_blob_content(self): - """Test that blob content is redacted without mutating original messages""" - messages = [ - { - "role": "user", - "content": [ - { - "text": "How many ponies do you see in the image?", - "type": "text", - }, - { - "type": "blob", - "modality": "image", - "mime_type": "image/jpeg", - "content": "data:image/jpeg;base64,/9j/4AAQSkZJRg==", - }, - ], - } - ] - - # Save original blob content for comparison - original_blob_content = messages[0]["content"][1]["content"] - - result = redact_blob_message_parts(messages) - - # Original messages should be UNCHANGED - assert messages[0]["content"][1]["content"] == original_blob_content - - # Result should have redacted content - assert ( - result[0]["content"][0]["text"] - == "How many ponies do you see in the image?" - ) - assert result[0]["content"][0]["type"] == "text" - assert result[0]["content"][1]["type"] == "blob" - assert result[0]["content"][1]["modality"] == "image" - assert result[0]["content"][1]["mime_type"] == "image/jpeg" - assert result[0]["content"][1]["content"] == BLOB_DATA_SUBSTITUTE - - def test_redacts_multiple_blob_parts(self): - """Test that multiple blob parts are redacted without mutation""" - messages = [ - { - "role": "user", - "content": [ - {"text": "Compare these images", "type": "text"}, - { - "type": "blob", - "modality": "image", - "mime_type": "image/jpeg", - "content": "data:image/jpeg;base64,first_image", - }, - { - "type": "blob", - "modality": "image", - "mime_type": "image/png", - "content": "data:image/png;base64,second_image", - }, - ], - } - ] - - original_first = messages[0]["content"][1]["content"] - original_second = messages[0]["content"][2]["content"] - - result = redact_blob_message_parts(messages) - - # Original should be unchanged - assert messages[0]["content"][1]["content"] == original_first - assert messages[0]["content"][2]["content"] == original_second - - # Result should be redacted - assert result[0]["content"][0]["text"] == "Compare these images" - assert result[0]["content"][1]["content"] == BLOB_DATA_SUBSTITUTE - assert result[0]["content"][2]["content"] == BLOB_DATA_SUBSTITUTE - - def test_redacts_blobs_in_multiple_messages(self): - """Test that blob parts are redacted across multiple messages without mutation""" - messages = [ - { - "role": "user", - "content": [ - {"text": "First message", "type": "text"}, - { - "type": "blob", - "modality": "image", - "content": "data:image/jpeg;base64,first", - }, - ], - }, - { - "role": "assistant", - "content": "I see the image.", - }, - { - "role": "user", - "content": [ - {"text": "Second message", "type": "text"}, - { - "type": "blob", - "modality": "image", - "content": "data:image/jpeg;base64,second", - }, - ], - }, - ] - - original_first = messages[0]["content"][1]["content"] - original_second = messages[2]["content"][1]["content"] - - result = redact_blob_message_parts(messages) - - # Original should be unchanged - assert messages[0]["content"][1]["content"] == original_first - assert messages[2]["content"][1]["content"] == original_second - - # Result should be redacted - assert result[0]["content"][1]["content"] == BLOB_DATA_SUBSTITUTE - assert result[1]["content"] == "I see the image." # Unchanged - assert result[2]["content"][1]["content"] == BLOB_DATA_SUBSTITUTE - - def test_redacts_single_blob_within_image_url_content(self): - messages = [ - { - "role": "user", - "content": [ - { - "text": "How many ponies do you see in the image?", - "type": "text", - }, - { - "type": "image_url", - "image_url": {"url": "data:image/jpeg;base64,/9j/4AAQSkZJRg=="}, - }, - ], - } - ] - - original_blob_content = messages[0]["content"][1] - - result = redact_blob_message_parts(messages) - - assert messages[0]["content"][1] == original_blob_content - - assert ( - result[0]["content"][0]["text"] - == "How many ponies do you see in the image?" - ) - assert result[0]["content"][0]["type"] == "text" - assert result[0]["content"][1]["type"] == "image_url" - assert result[0]["content"][1]["image_url"]["url"] == BLOB_DATA_SUBSTITUTE - - def test_does_not_redact_image_url_content_with_non_blobs(self): - messages = [ - { - "role": "user", - "content": [ - { - "text": "How many ponies do you see in the image?", - "type": "text", - }, - { - "type": "image_url", - "image_url": {"url": "https://example.com/image.jpg"}, - }, - ], - } - ] - - original_blob_content = messages[0]["content"][1] - - result = redact_blob_message_parts(messages) - - assert messages[0]["content"][1] == original_blob_content - - assert ( - result[0]["content"][0]["text"] - == "How many ponies do you see in the image?" - ) - assert result[0]["content"][0]["type"] == "text" - assert result[0]["content"][1]["type"] == "image_url" - assert ( - result[0]["content"][1]["image_url"]["url"] - == "https://example.com/image.jpg" - ) - - def test_no_blobs_returns_original_list(self): - """Test that messages without blobs are returned as-is (performance optimization)""" - messages = [ - {"role": "user", "content": "Simple text message"}, - {"role": "assistant", "content": "Simple response"}, - ] - - result = redact_blob_message_parts(messages) - - # Should return the same list object when no blobs present - assert result is messages - - def test_handles_non_dict_messages(self): - """Test that non-dict messages are handled gracefully""" - messages = [ - "string message", - {"role": "user", "content": "text"}, - None, - 123, - ] - - result = redact_blob_message_parts(messages) - - # Should return same list since no blobs - assert result is messages - - def test_handles_non_dict_content_items(self): - """Test that non-dict content items in arrays are handled""" - messages = [ - { - "role": "user", - "content": [ - "string item", - {"text": "text item", "type": "text"}, - None, - ], - } - ] - - result = redact_blob_message_parts(messages) - - # Should return same list since no blobs - assert result is messages - - def test_redact_blob_message_parts_image_url_string_shorthand(self): - """image_url as a plain string (OpenAI shorthand) must not raise AttributeError""" - messages = [ - { - "role": "user", - "content": [ - {"type": "text", "text": "What is in this image?"}, - { - "type": "image_url", - "image_url": "data:image/jpeg;base64,/9j/abc123==", - }, - ], - } - ] - result = redact_blob_message_parts(messages) - assert result[0]["content"][1]["image_url"] == "[Blob substitute]" class TestParseDataUri: @@ -1972,112 +887,3 @@ def test_google_file_data_not_dict_returns_none(self): """Test that Google file_data with non-dict value returns None""" content_part = {"file_data": "not_a_dict"} assert transform_content_part(content_part) is None - - -class TestTransformMessageContent: - def test_string_content_returned_as_is(self): - """Test that string content is returned unchanged""" - content = "Hello, world!" - result = transform_message_content(content) - - assert result == "Hello, world!" - - def test_list_with_transformable_items(self): - """Test transforming a list with transformable content parts""" - content = [ - {"type": "text", "text": "What's in this image?"}, - { - "type": "image_url", - "image_url": {"url": "data:image/jpeg;base64,/9j/4AAQ"}, - }, - ] - result = transform_message_content(content) - - assert len(result) == 2 - # Text block should be unchanged (transform returns None, so original kept) - assert result[0] == {"type": "text", "text": "What's in this image?"} - # Image should be transformed - assert result[1] == { - "type": "blob", - "modality": "image", - "mime_type": "image/jpeg", - "content": "/9j/4AAQ", - } - - def test_list_with_non_dict_items(self): - """Test that non-dict items in list are kept as-is""" - content = ["text string", 123, {"type": "text", "text": "hi"}] - result = transform_message_content(content) - - assert result == ["text string", 123, {"type": "text", "text": "hi"}] - - def test_tuple_content(self): - """Test that tuple content is also handled""" - content = ( - {"type": "text", "text": "Hello"}, - { - "type": "image_url", - "image_url": {"url": "https://example.com/img.jpg"}, - }, - ) - result = transform_message_content(content) - - assert len(result) == 2 - assert result[0] == {"type": "text", "text": "Hello"} - assert result[1] == { - "type": "uri", - "modality": "image", - "mime_type": "", - "uri": "https://example.com/img.jpg", - } - - def test_other_types_returned_as_is(self): - """Test that other types are returned unchanged""" - assert transform_message_content(123) == 123 - assert transform_message_content(None) is None - assert transform_message_content({"key": "value"}) == {"key": "value"} - - def test_mixed_content_types(self): - """Test transforming mixed content with multiple formats""" - content = [ - {"type": "text", "text": "Look at these:"}, - { - "type": "image_url", - "image_url": {"url": "data:image/png;base64,iVBORw0"}, - }, - { - "type": "image", - "source": { - "type": "base64", - "media_type": "image/jpeg", - "data": "/9j/4AAQ", - }, - }, - {"inline_data": {"mime_type": "audio/wav", "data": "UklGRiQA"}}, - ] - result = transform_message_content(content) - - assert len(result) == 4 - assert result[0] == {"type": "text", "text": "Look at these:"} - assert result[1] == { - "type": "blob", - "modality": "image", - "mime_type": "image/png", - "content": "iVBORw0", - } - assert result[2] == { - "type": "blob", - "modality": "image", - "mime_type": "image/jpeg", - "content": "/9j/4AAQ", - } - assert result[3] == { - "type": "blob", - "modality": "audio", - "mime_type": "audio/wav", - "content": "UklGRiQA", - } - - def test_empty_list(self): - """Test that empty list is returned as empty list""" - assert transform_message_content([]) == [] diff --git a/tests/test_api.py b/tests/test_api.py index c25ed3397d..473eb3b6a5 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -1,13 +1,9 @@ import re from unittest import mock -import pytest - import sentry_sdk from sentry_sdk import ( capture_exception, - configure_scope, - continue_trace, get_baggage, get_client, get_current_scope, @@ -16,13 +12,10 @@ get_isolation_scope, get_traceparent, is_initialized, - push_scope, set_tags, - start_transaction, ) from sentry_sdk.client import Client, NonRecordingClient -from sentry_sdk.traces import StreamedSpan -from sentry_sdk.tracing import Span +from sentry_sdk.traces import Span from tests.conftest import TestTransportWithOptions @@ -35,72 +28,40 @@ def test_get_current_span(): assert get_current_span(fake_scope) is None -def test_get_current_span_span_streaming(): +def test_get_current_span_via_traces(): fake_scope = mock.MagicMock() - fake_scope.streamed_span = mock.MagicMock() - assert sentry_sdk.traces.get_current_span(fake_scope) == fake_scope.streamed_span + fake_scope.span = mock.MagicMock() + assert sentry_sdk.get_current_span(fake_scope) == fake_scope.span - fake_scope.streamed_span = None - assert sentry_sdk.traces.get_current_span(fake_scope) is None + fake_scope.span = None + assert sentry_sdk.get_current_span(fake_scope) is None -def test_get_current_span_current_scope(sentry_init): +def test_get_current_span_current_scope_via_traces(sentry_init): sentry_init() - assert get_current_span() is None + assert sentry_sdk.get_current_span() is None scope = get_current_scope() - fake_span = Span() - scope.span = fake_span - - assert get_current_span() == fake_span - - -def test_get_current_span_current_scope_span_streaming(sentry_init): - sentry_init(trace_lifecycle="stream") + fake_span = Span(name="abc", scope=scope) - assert sentry_sdk.traces.get_current_span() is None - - scope = get_current_scope() - fake_span = StreamedSpan(name="abc", scope=scope) - - assert scope.streamed_span == fake_span - assert sentry_sdk.traces.get_current_span() == fake_span - - -def test_get_current_span_with_transaction(sentry_init): - sentry_init() - - assert get_current_span() is None - - with start_transaction() as new_transaction: - assert get_current_span() == new_transaction + assert scope.span == fake_span + assert sentry_sdk.get_current_span() == fake_span def test_get_current_span_with_segment(sentry_init): - sentry_init(trace_lifecycle="stream") + sentry_init() - assert sentry_sdk.traces.get_current_span() is None + assert sentry_sdk.get_current_span() is None - with sentry_sdk.traces.start_span(name="segment") as new_segment: - assert sentry_sdk.traces.get_current_span() == new_segment + with sentry_sdk.start_span(name="segment") as new_segment: + assert sentry_sdk.get_current_span() == new_segment def test_traceparent_with_tracing_enabled(sentry_init): sentry_init(traces_sample_rate=1.0) - with start_transaction() as transaction: - expected_traceparent = "%s-%s-1" % ( - transaction.trace_id, - transaction.span_id, - ) - assert get_traceparent() == expected_traceparent - - -def test_traceparent_with_tracing_enabled_span_streaming(sentry_init): - sentry_init(traces_sample_rate=1.0, trace_lifecycle="stream") - - with sentry_sdk.traces.start_span(name="span") as segment: + with sentry_sdk.start_span(name="span") as segment: expected_traceparent = "%s-%s-1" % ( segment.trace_id, segment.span_id, @@ -119,17 +80,6 @@ def test_traceparent_with_tracing_disabled(sentry_init): assert get_traceparent() == expected_traceparent -def test_traceparent_with_tracing_disabled_span_streaming(sentry_init): - sentry_init(trace_lifecycle="stream") - - propagation_context = get_isolation_scope()._propagation_context - expected_traceparent = "%s-%s" % ( - propagation_context.trace_id, - propagation_context.span_id, - ) - assert get_traceparent() == expected_traceparent - - def test_baggage_with_tracing_disabled(sentry_init): sentry_init(release="1.0.0", environment="dev") propagation_context = get_isolation_scope()._propagation_context @@ -141,34 +91,13 @@ def test_baggage_with_tracing_disabled(sentry_init): assert get_baggage() == expected_baggage -def test_baggage_with_tracing_disabled_span_streaming(sentry_init): - sentry_init(release="1.0.0", environment="dev", trace_lifecycle="stream") - propagation_context = get_isolation_scope()._propagation_context - expected_baggage = ( - "sentry-trace_id={},sentry-environment=dev,sentry-release=1.0.0".format( - propagation_context.trace_id - ) - ) - assert get_baggage() == expected_baggage - - def test_baggage_with_tracing_enabled(sentry_init): - sentry_init(traces_sample_rate=1.0, release="1.0.0", environment="dev") - with start_transaction() as transaction: - expected_baggage_re = r"^sentry-trace_id={},sentry-sample_rand=0\.\d{{6}},sentry-environment=dev,sentry-release=1\.0\.0,sentry-sample_rate=1\.0,sentry-sampled={}$".format( - transaction.trace_id, "true" if transaction.sampled else "false" - ) - assert re.match(expected_baggage_re, get_baggage()) - - -def test_baggage_with_tracing_enabled_span_streaming(sentry_init): sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream", release="1.0.0", environment="dev", ) - with sentry_sdk.traces.start_span(name="segment") as segment: + with sentry_sdk.start_span(name="segment") as segment: expected_baggage_re = r"^sentry-trace_id={},sentry-sample_rand=0\.\d{{6}},sentry-environment=dev,sentry-release=1\.0\.0,sentry-transaction=segment,sentry-sample_rate=1\.0,sentry-sampled={}$".format( segment.trace_id, "true" if segment.sampled else "false" ) @@ -183,23 +112,7 @@ def test_baggage_with_dsn(sentry_init): environment="dev", transport=TestTransportWithOptions, ) - with start_transaction() as transaction: - expected_baggage_re = r"^sentry-trace_id={},sentry-sample_rand=0\.\d{{6}},sentry-environment=dev,sentry-release=2\.0\.0,sentry-public_key=97333d956c9e40989a0139756c121c34,sentry-sample_rate=1\.0,sentry-sampled={}$".format( - transaction.trace_id, "true" if transaction.sampled else "false" - ) - assert re.match(expected_baggage_re, get_baggage()) - - -def test_baggage_with_dsn_span_streaming(sentry_init): - sentry_init( - dsn="http://97333d956c9e40989a0139756c121c34@sentry-x.sentry-y.s.c.local/976543210", - traces_sample_rate=1.0, - trace_lifecycle="stream", - release="2.0.0", - environment="dev", - transport=TestTransportWithOptions, - ) - with sentry_sdk.traces.start_span(name="segment") as segment: + with sentry_sdk.start_span(name="segment") as segment: expected_baggage_re = r"^sentry-trace_id={},sentry-sample_rand=0\.\d{{6}},sentry-environment=dev,sentry-release=2\.0\.0,sentry-public_key=97333d956c9e40989a0139756c121c34,sentry-transaction=segment,sentry-sample_rate=1\.0,sentry-sampled={}$".format( segment.trace_id, "true" if segment.sampled else "false" ) @@ -212,39 +125,13 @@ def test_continue_trace(sentry_init): trace_id = "471a43a4192642f0b136d5159a501701" parent_span_id = "6e8f22c393e68f19" parent_sampled = 1 - transaction = continue_trace( - { - "sentry-trace": "{}-{}-{}".format(trace_id, parent_span_id, parent_sampled), - "baggage": "sentry-trace_id=566e3688a61d4bc888951642d6f14a19,sentry-sample_rand=0.123456", - }, - name="some name", - ) - with start_transaction(transaction): - assert transaction.name == "some name" - - propagation_context = get_isolation_scope()._propagation_context - assert propagation_context.trace_id == transaction.trace_id == trace_id - assert propagation_context.parent_span_id == parent_span_id - assert propagation_context.parent_sampled == parent_sampled - assert propagation_context.dynamic_sampling_context == { - "trace_id": "566e3688a61d4bc888951642d6f14a19", - "sample_rand": "0.123456", - } - - -def test_continue_trace_span_streaming(sentry_init): - sentry_init(trace_lifecycle="stream") - - trace_id = "471a43a4192642f0b136d5159a501701" - parent_span_id = "6e8f22c393e68f19" - parent_sampled = 1 - sentry_sdk.traces.continue_trace( + sentry_sdk.continue_trace( { "sentry-trace": "{}-{}-{}".format(trace_id, parent_span_id, parent_sampled), "baggage": "sentry-trace_id=566e3688a61d4bc888951642d6f14a19,sentry-sample_rand=0.123456", } ) - with sentry_sdk.traces.start_span(name="some name") as segment: + with sentry_sdk.start_span(name="some name") as segment: assert segment.name == "some name" propagation_context = get_isolation_scope()._propagation_context @@ -312,31 +199,3 @@ def test_set_tags(sentry_init, capture_events): "tag2": "updated", "tag3": "new", }, "Updating tags with empty dict changed tags" - - -def test_configure_scope_deprecation(): - with pytest.warns(DeprecationWarning): - with configure_scope(): - ... - - -def test_push_scope_deprecation(): - with pytest.warns(DeprecationWarning): - with push_scope(): - ... - - -def test_init_context_manager_deprecation(): - with pytest.warns(DeprecationWarning): - with sentry_sdk.init(): - ... - - -def test_init_enter_deprecation(): - with pytest.warns(DeprecationWarning): - sentry_sdk.init().__enter__() - - -def test_init_exit_deprecation(): - with pytest.warns(DeprecationWarning): - sentry_sdk.init().__exit__(None, None, None) diff --git a/tests/test_attributes.py b/tests/test_attributes.py index d76bb13c8f..75e1ecb260 100644 --- a/tests/test_attributes.py +++ b/tests/test_attributes.py @@ -191,7 +191,6 @@ def test_user_attributes(sentry_init, capture_items): sentry_init( traces_sample_rate=1.0, send_default_pii=True, - trace_lifecycle="stream", ) items = capture_items("trace_metric", "span") @@ -205,7 +204,7 @@ def test_user_attributes(sentry_init, capture_items): } ) - with sentry_sdk.traces.start_span(name="login"): + with sentry_sdk.start_span(name="login"): sentry_sdk.metrics.count("test", 1) sentry_sdk.get_client().flush() diff --git a/tests/test_basics.py b/tests/test_basics.py index cb3dffd2fe..d34f29e6a8 100644 --- a/tests/test_basics.py +++ b/tests/test_basics.py @@ -11,7 +11,6 @@ import sentry_sdk import sentry_sdk.scope from sentry_sdk import ( - Hub, add_breadcrumb, capture_event, capture_exception, @@ -20,8 +19,6 @@ isolation_scope, last_event_id, new_scope, - push_scope, - start_transaction, ) from sentry_sdk.integrations import ( _AUTO_ENABLING_INTEGRATIONS, @@ -33,7 +30,6 @@ from sentry_sdk.integrations.logging import LoggingIntegration from sentry_sdk.integrations.stdlib import StdlibIntegration from sentry_sdk.scope import add_global_event_processor -from sentry_sdk.tracing_utils import has_tracing_enabled from sentry_sdk.utils import datetime_from_isoformat, get_sdk_name, reraise @@ -164,40 +160,6 @@ def do_this(): assert len(events) == 0 -def test_option_before_send_transaction(sentry_init, capture_events): - def before_send_transaction(event, hint): - assert event["type"] == "transaction" - event["extra"] = {"before_send_transaction_called": True} - return event - - sentry_init( - before_send_transaction=before_send_transaction, - traces_sample_rate=1.0, - ) - events = capture_events() - transaction = start_transaction(name="foo") - transaction.finish() - - (event,) = events - assert event["transaction"] == "foo" - assert event["extra"] == {"before_send_transaction_called": True} - - -def test_option_before_send_transaction_discard(sentry_init, capture_events): - def before_send_transaction_discard(event, hint): - return None - - sentry_init( - before_send_transaction=before_send_transaction_discard, - traces_sample_rate=1.0, - ) - events = capture_events() - transaction = start_transaction(name="foo") - transaction.finish() - - assert len(events) == 0 - - def test_option_before_breadcrumb(sentry_init, capture_events, monkeypatch): drop_events = False drop_breadcrumbs = False @@ -278,32 +240,6 @@ def do_this(): assert crumb["type"] == "default" -@pytest.mark.parametrize( - "enable_tracing, traces_sample_rate, tracing_enabled, updated_traces_sample_rate", - [ - (None, None, False, None), - (False, 0.0, False, 0.0), - (False, 1.0, False, 1.0), - (None, 1.0, True, 1.0), - (True, 1.0, True, 1.0), - (None, 0.0, True, 0.0), # We use this as - it's configured but turned off - (True, 0.0, True, 0.0), # We use this as - it's configured but turned off - (True, None, True, 1.0), - ], -) -def test_option_enable_tracing( - sentry_init, - enable_tracing, - traces_sample_rate, - tracing_enabled, - updated_traces_sample_rate, -): - sentry_init(enable_tracing=enable_tracing, traces_sample_rate=traces_sample_rate) - options = sentry_sdk.get_client().options - assert has_tracing_enabled(options) is tracing_enabled - assert options["traces_sample_rate"] == updated_traces_sample_rate - - def test_breadcrumb_arguments(sentry_init, capture_events): assert_hint = {"bar": 42} @@ -323,44 +259,6 @@ def before_breadcrumb(crumb, hint): add_breadcrumb(crumb=dict(foo=42)) -def test_push_scope(sentry_init, capture_events, suppress_deprecation_warnings): - sentry_init() - events = capture_events() - - with push_scope() as scope: - scope.level = "warning" - try: - 1 / 0 - except Exception as e: - capture_exception(e) - - (event,) = events - - assert event["level"] == "warning" - assert "exception" in event - - -def test_push_scope_null_client( - sentry_init, capture_events, suppress_deprecation_warnings -): - """ - This test can be removed when we remove push_scope and the Hub from the SDK. - """ - sentry_init() - events = capture_events() - - Hub.current.bind_client(None) - - with push_scope() as scope: - scope.level = "warning" - try: - 1 / 0 - except Exception as e: - capture_exception(e) - - assert len(events) == 0 - - def test_breadcrumbs(sentry_init, capture_events): sentry_init(max_breadcrumbs=10) events = capture_events() @@ -750,17 +648,12 @@ def foo(event, hint): capture_message("dropped") - with start_transaction(name="dropped"): - pass - assert len(events) == 0 # Using Counter because order of record_lost_event calls does not matter assert Counter(record_lost_event_calls) == Counter( [ ("event_processor", "error", None, 1), - ("event_processor", "transaction", None, 1), - ("event_processor", "span", None, 1), ] ) @@ -843,8 +736,7 @@ def _hello_world(word): return "Hello, {}".format(word) -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_functions_to_trace(sentry_init, capture_events, capture_items, span_streaming): +def test_functions_to_trace(sentry_init, capture_items): functions_to_trace = [ {"qualified_name": "tests.test_basics._hello_world"}, {"qualified_name": "time.sleep"}, @@ -858,45 +750,25 @@ def test_functions_to_trace(sentry_init, capture_events, capture_items, span_str sentry_init( traces_sample_rate=1.0, functions_to_trace=functions_to_trace, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") - else: - events = capture_events() - - if span_streaming: - with sentry_sdk.traces.start_span(name="something"): - time.sleep(0) - - for word in ["World", "You"]: - _hello_world(word) - - sentry_sdk.flush() - spans = [item.payload for item in items] - child_spans = [s for s in spans if not s.get("is_segment")] - child_spans.sort(key=lambda s: s["start_timestamp"]) - - assert len(child_spans) == 3 - assert child_spans[0]["name"] == "time.sleep" - assert child_spans[1]["name"] == "tests.test_basics._hello_world" - assert child_spans[2]["name"] == "tests.test_basics._hello_world" - else: - with start_transaction(name="something"): - time.sleep(0) + items = capture_items("span") - for word in ["World", "You"]: - _hello_world(word) + with sentry_sdk.start_span(name="something"): + time.sleep(0) - assert len(events) == 1 + for word in ["World", "You"]: + _hello_world(word) - (event,) = events + sentry_sdk.flush() + spans = [item.payload for item in items] + child_spans = [s for s in spans if not s.get("is_segment")] + child_spans.sort(key=lambda s: s["start_timestamp"]) - assert len(event["spans"]) == 3 - assert event["spans"][0]["description"] == "time.sleep" - assert event["spans"][1]["description"] == "tests.test_basics._hello_world" - assert event["spans"][2]["description"] == "tests.test_basics._hello_world" + assert len(child_spans) == 3 + assert child_spans[0]["name"] == "time.sleep" + assert child_spans[1]["name"] == "tests.test_basics._hello_world" + assert child_spans[2]["name"] == "tests.test_basics._hello_world" finally: _hello_world = original_hello_world time.sleep = original_sleep @@ -910,10 +782,7 @@ def greet(self, new_word=None): return "Hello, {}".format(new_word if new_word else self.word) -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_functions_to_trace_with_class( - sentry_init, capture_events, capture_items, span_streaming -): +def test_functions_to_trace_with_class(sentry_init, capture_items): functions_to_trace = [ {"qualified_name": "tests.test_basics.WorldGreeter.greet"}, ] @@ -924,46 +793,23 @@ def test_functions_to_trace_with_class( sentry_init( traces_sample_rate=1.0, functions_to_trace=functions_to_trace, - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") - else: - events = capture_events() - - if span_streaming: - with sentry_sdk.traces.start_span(name="something"): - wg = WorldGreeter("World") - wg.greet() - wg.greet("You") - - sentry_sdk.flush() - spans = [item.payload for item in items] - child_spans = [s for s in spans if not s.get("is_segment")] - - assert len(child_spans) == 2 - assert child_spans[0]["name"] == "tests.test_basics.WorldGreeter.greet" - assert child_spans[1]["name"] == "tests.test_basics.WorldGreeter.greet" - else: - with start_transaction(name="something"): - wg = WorldGreeter("World") - wg.greet() - wg.greet("You") - - assert len(events) == 1 - - (event,) = events - - assert len(event["spans"]) == 2 - assert ( - event["spans"][0]["description"] - == "tests.test_basics.WorldGreeter.greet" - ) - assert ( - event["spans"][1]["description"] - == "tests.test_basics.WorldGreeter.greet" - ) + items = capture_items("span") + + with sentry_sdk.start_span(name="something"): + wg = WorldGreeter("World") + wg.greet() + wg.greet("You") + + sentry_sdk.flush() + spans = [item.payload for item in items] + child_spans = [s for s in spans if not s.get("is_segment")] + + assert len(child_spans) == 2 + assert child_spans[0]["name"] == "tests.test_basics.WorldGreeter.greet" + assert child_spans[1]["name"] == "tests.test_basics.WorldGreeter.greet" + finally: WorldGreeter.greet = original_function @@ -988,166 +834,99 @@ def class_(cls, arg): # We need to fork here because the test modifies tests.test_basics.TracingTestClass @pytest.mark.forked -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_staticmethod_class_tracing( - sentry_init, capture_events, capture_items, span_streaming -): +def test_staticmethod_class_tracing(sentry_init, capture_items): sentry_init( debug=True, traces_sample_rate=1.0, functions_to_trace=[ {"qualified_name": "tests.test_basics.TracingTestClass.static"} ], - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") + items = capture_items("span") - with sentry_sdk.traces.start_span(name="test"): - assert TracingTestClass.static(1) == 1 + with sentry_sdk.start_span(name="test"): + assert TracingTestClass.static(1) == 1 - sentry_sdk.flush() - spans = [item.payload for item in items] - child_spans = [s for s in spans if not s.get("is_segment")] - - assert len(child_spans) == 1 - assert child_spans[0]["name"] == "tests.test_basics.TracingTestClass.static" - else: - events = capture_events() - - with sentry_sdk.start_transaction(name="test"): - assert TracingTestClass.static(1) == 1 + sentry_sdk.flush() - (event,) = events - assert event["type"] == "transaction" - assert event["transaction"] == "test" + spans = [item.payload for item in items] + child_spans = [s for s in spans if not s.get("is_segment")] - (span,) = event["spans"] - assert span["description"] == "tests.test_basics.TracingTestClass.static" + assert len(child_spans) == 1 + assert child_spans[0]["name"] == "tests.test_basics.TracingTestClass.static" # We need to fork here because the test modifies tests.test_basics.TracingTestClass @pytest.mark.forked -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_staticmethod_instance_tracing( - sentry_init, capture_events, capture_items, span_streaming -): +def test_staticmethod_instance_tracing(sentry_init, capture_items): sentry_init( debug=True, traces_sample_rate=1.0, functions_to_trace=[ {"qualified_name": "tests.test_basics.TracingTestClass.static"} ], - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") - - with sentry_sdk.traces.start_span(name="test"): - assert TracingTestClass().static(1) == 1 + items = capture_items("span") - sentry_sdk.flush() - spans = [item.payload for item in items] - child_spans = [s for s in spans if not s.get("is_segment")] - - assert len(child_spans) == 1 - assert child_spans[0]["name"] == "tests.test_basics.TracingTestClass.static" - else: - events = capture_events() + with sentry_sdk.start_span(name="test"): + assert TracingTestClass().static(1) == 1 - with sentry_sdk.start_transaction(name="test"): - assert TracingTestClass().static(1) == 1 + sentry_sdk.flush() + spans = [item.payload for item in items] + child_spans = [s for s in spans if not s.get("is_segment")] - (event,) = events - assert event["type"] == "transaction" - assert event["transaction"] == "test" - - (span,) = event["spans"] - assert span["description"] == "tests.test_basics.TracingTestClass.static" + assert len(child_spans) == 1 + assert child_spans[0]["name"] == "tests.test_basics.TracingTestClass.static" # We need to fork here because the test modifies tests.test_basics.TracingTestClass @pytest.mark.forked -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_classmethod_class_tracing( - sentry_init, capture_events, capture_items, span_streaming -): +def test_classmethod_class_tracing(sentry_init, capture_items): sentry_init( debug=True, traces_sample_rate=1.0, functions_to_trace=[ {"qualified_name": "tests.test_basics.TracingTestClass.class_"} ], - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") - - with sentry_sdk.traces.start_span(name="test"): - assert TracingTestClass.class_(1) == (TracingTestClass, 1) - - sentry_sdk.flush() - spans = [item.payload for item in items] - child_spans = [s for s in spans if not s.get("is_segment")] - - assert len(child_spans) == 1 - assert child_spans[0]["name"] == "tests.test_basics.TracingTestClass.class_" - else: - events = capture_events() + items = capture_items("span") - with sentry_sdk.start_transaction(name="test"): - assert TracingTestClass.class_(1) == (TracingTestClass, 1) + with sentry_sdk.start_span(name="test"): + assert TracingTestClass.class_(1) == (TracingTestClass, 1) - (event,) = events - assert event["type"] == "transaction" - assert event["transaction"] == "test" + sentry_sdk.flush() + spans = [item.payload for item in items] + child_spans = [s for s in spans if not s.get("is_segment")] - (span,) = event["spans"] - assert span["description"] == "tests.test_basics.TracingTestClass.class_" + assert len(child_spans) == 1 + assert child_spans[0]["name"] == "tests.test_basics.TracingTestClass.class_" # We need to fork here because the test modifies tests.test_basics.TracingTestClass @pytest.mark.forked -@pytest.mark.parametrize("span_streaming", [True, False]) -def test_classmethod_instance_tracing( - sentry_init, capture_events, capture_items, span_streaming -): +def test_classmethod_instance_tracing(sentry_init, capture_items): sentry_init( debug=True, traces_sample_rate=1.0, functions_to_trace=[ {"qualified_name": "tests.test_basics.TracingTestClass.class_"} ], - trace_lifecycle="stream" if span_streaming else "static", ) - if span_streaming: - items = capture_items("span") + items = capture_items("span") - with sentry_sdk.traces.start_span(name="test"): - assert TracingTestClass().class_(1) == (TracingTestClass, 1) + with sentry_sdk.start_span(name="test"): + assert TracingTestClass().class_(1) == (TracingTestClass, 1) - sentry_sdk.flush() - spans = [item.payload for item in items] - child_spans = [s for s in spans if not s.get("is_segment")] - - assert len(child_spans) == 1 - assert child_spans[0]["name"] == "tests.test_basics.TracingTestClass.class_" - else: - events = capture_events() + sentry_sdk.flush() + spans = [item.payload for item in items] + child_spans = [s for s in spans if not s.get("is_segment")] - with sentry_sdk.start_transaction(name="test"): - assert TracingTestClass().class_(1) == (TracingTestClass, 1) - - (event,) = events - assert event["type"] == "transaction" - assert event["transaction"] == "test" - - (span,) = event["spans"] - assert span["description"] == "tests.test_basics.TracingTestClass.class_" + assert len(child_spans) == 1 + assert child_spans[0]["name"] == "tests.test_basics.TracingTestClass.class_" def test_functions_to_trace_no_dot_does_not_crash(sentry_init): @@ -1168,17 +947,6 @@ def test_last_event_id(sentry_init): assert last_event_id() is not None -def test_last_event_id_transaction(sentry_init): - sentry_init(traces_sample_rate=1.0) - - assert last_event_id() is None - - with start_transaction(name="test"): - pass - - assert last_event_id() is None, "Transaction should not set last_event_id" - - def test_last_event_id_scope(sentry_init): sentry_init(traces_sample_rate=1.0) @@ -1187,24 +955,6 @@ def test_last_event_id_scope(sentry_init): assert scope.last_event_id() is None -def test_hub_constructor_deprecation_warning(): - with pytest.warns(sentry_sdk.hub.SentryHubDeprecationWarning): - Hub() - - -def test_hub_current_deprecation_warning(): - with pytest.warns(sentry_sdk.hub.SentryHubDeprecationWarning) as warning_records: - Hub.current - - # Make sure we only issue one deprecation warning - assert len(warning_records) == 1 - - -def test_hub_main_deprecation_warnings(): - with pytest.warns(sentry_sdk.hub.SentryHubDeprecationWarning): - Hub.main - - @pytest.mark.skipif(sys.version_info < (3, 11), reason="add_note() not supported") def test_notes(sentry_init, capture_events): sentry_init() diff --git a/tests/test_client.py b/tests/test_client.py index ad08932690..09f6a5e2d5 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -4,8 +4,6 @@ import subprocess import sys import time -import warnings -from collections import Counter, defaultdict from collections.abc import Mapping from textwrap import dedent from unittest import mock @@ -15,14 +13,11 @@ import sentry_sdk from sentry_sdk import ( Client, - Hub, add_breadcrumb, capture_event, capture_exception, capture_message, - configure_scope, set_tag, - start_transaction, ) from sentry_sdk._compat import PY38 from sentry_sdk.consts import DEFAULT_MAX_BREADCRUMBS @@ -395,13 +390,6 @@ def test_socks_proxy(testcase, http2): ) -def test_simple_transport(sentry_init): - events = [] - sentry_init(transport=events.append) - capture_message("Hello World!") - assert events[0]["message"] == "Hello World!" - - def test_ignore_errors(sentry_init, capture_events): sentry_init(ignore_errors=[ZeroDivisionError]) events = capture_events() @@ -516,6 +504,25 @@ def bar(): assert functions == ["foo", "bar"] +def test_attach_stacktrace_default(sentry_init, capture_events): + sentry_init() + events = capture_events() + + def foo(): + bar() + + def bar(): + capture_message("HI") + + foo() + + (event,) = events + (thread,) = event["threads"]["values"] + functions = [x["function"] for x in thread["stacktrace"]["frames"]] + + assert functions[-2:] == ["foo", "bar"] + + def test_attach_stacktrace_enabled(sentry_init, capture_events): sentry_init(attach_stacktrace=True) events = capture_events() @@ -576,15 +583,6 @@ def test_attach_stacktrace_disabled(sentry_init, capture_events): assert "threads" not in event -def test_attach_stacktrace_transaction(sentry_init, capture_events): - sentry_init(traces_sample_rate=1.0, attach_stacktrace=True) - events = capture_events() - with start_transaction(name="transaction"): - pass - (event,) = events - assert "threads" not in event - - def test_capture_event_works(sentry_init): sentry_init(transport=_TestTransport()) pytest.raises(EnvelopeCapturedError, lambda: capture_event({})) @@ -635,31 +633,6 @@ def capture_envelope(self, envelope): assert output.count(b"HI") == num_messages -def test_configure_scope_available( - sentry_init, request, monkeypatch, suppress_deprecation_warnings -): - """ - Test that scope is configured if client is configured - - This test can be removed once configure_scope and the Hub are removed. - """ - sentry_init() - - with configure_scope() as scope: - assert scope is Hub.current.scope - scope.set_tag("foo", "bar") - - calls = [] - - def callback(scope): - calls.append(scope) - scope.set_tag("foo", "bar") - - assert configure_scope(callback) is None - assert len(calls) == 1 - assert calls[0] is Hub.current.scope - - @pytest.mark.tests_internal_exceptions def test_client_debug_option_enabled(sentry_init, caplog): sentry_init(debug=True) @@ -1307,204 +1280,19 @@ def test_error_sampler(_, sentry_init, capture_events, test_config): [{"py-call-uwsgi-fork-hooks": True}, ["--enable-threads"]], ], ) -def test_uwsgi_warnings(sentry_init, recwarn, opt, missing_flags): +def test_uwsgi_warnings(sentry_init, opt, missing_flags): uwsgi = mock.MagicMock() uwsgi.opt = opt - with mock.patch.dict("sys.modules", uwsgi=uwsgi): - sentry_init(profiles_sample_rate=1.0) - if missing_flags: - assert len(recwarn) == 1 - record = recwarn.pop() - for flag in missing_flags: - assert flag in str(record.message) - else: - assert not recwarn - - -class TestSpanClientReports: - """ - Tests for client reports related to spans. - """ - - __test__ = False - - @staticmethod - def span_dropper(spans_to_drop): - """ - Returns a function that can be used to drop spans from an event. - """ - - def drop_spans(event, _): - event["spans"] = event["spans"][spans_to_drop:] - return event - - return drop_spans - - @staticmethod - def mock_transaction_event(span_count): - """ - Returns a mock transaction event with the given number of spans. - """ - - return defaultdict( - mock.MagicMock, - type="transaction", - spans=[mock.MagicMock() for _ in range(span_count)], - ) - - def __init__(self, span_count): - """Configures a test case with the number of spans dropped and whether the transaction was dropped.""" - self.span_count = span_count - self.expected_record_lost_event_calls = Counter() - self.before_send = lambda event, _: event - self.event_processor = lambda event, _: event - - def _update_resulting_calls(self, reason, drops_transactions=0, drops_spans=0): - """ - Updates the expected calls with the given resulting calls. - """ - if drops_transactions > 0: - self.expected_record_lost_event_calls[ - (reason, "transaction", None, drops_transactions) - ] += 1 - - if drops_spans > 0: - self.expected_record_lost_event_calls[ - (reason, "span", None, drops_spans) - ] += 1 - - def with_before_send( - self, - before_send, - *, - drops_transactions=0, - drops_spans=0, - ): - self.before_send = before_send - self._update_resulting_calls( - "before_send", - drops_transactions, - drops_spans, - ) - - return self - - def with_event_processor( - self, - event_processor, - *, - drops_transactions=0, - drops_spans=0, - ): - self.event_processor = event_processor - self._update_resulting_calls( - "event_processor", - drops_transactions, - drops_spans, - ) - - return self - - def run(self, sentry_init, capture_record_lost_event_calls): - """Runs the test case with the configured parameters.""" - sentry_init(before_send_transaction=self.before_send) - record_lost_event_calls = capture_record_lost_event_calls() - - with sentry_sdk.isolation_scope() as scope: - scope.add_event_processor(self.event_processor) - event = self.mock_transaction_event(self.span_count) - sentry_sdk.get_client().capture_event(event, scope=scope) - - # We use counters to ensure that the calls are made the expected number of times, disregarding order. - assert Counter(record_lost_event_calls) == self.expected_record_lost_event_calls - - -@pytest.mark.parametrize( - "test_config", - ( - TestSpanClientReports(span_count=10), # No spans dropped - TestSpanClientReports(span_count=0).with_before_send( - lambda e, _: None, - drops_transactions=1, - drops_spans=1, - ), - TestSpanClientReports(span_count=10).with_before_send( - lambda e, _: None, - drops_transactions=1, - drops_spans=11, - ), - TestSpanClientReports(span_count=10).with_before_send( - TestSpanClientReports.span_dropper(3), - drops_spans=3, - ), - TestSpanClientReports(span_count=10).with_before_send( - TestSpanClientReports.span_dropper(10), - drops_spans=10, - ), - TestSpanClientReports(span_count=10).with_event_processor( - lambda e, _: None, - drops_transactions=1, - drops_spans=11, - ), - TestSpanClientReports(span_count=10).with_event_processor( - TestSpanClientReports.span_dropper(3), - drops_spans=3, - ), - TestSpanClientReports(span_count=10).with_event_processor( - TestSpanClientReports.span_dropper(10), - drops_spans=10, - ), - TestSpanClientReports(span_count=10) - .with_event_processor( - TestSpanClientReports.span_dropper(3), - drops_spans=3, - ) - .with_before_send( - TestSpanClientReports.span_dropper(5), - drops_spans=5, - ), - TestSpanClientReports(10) - .with_event_processor( - TestSpanClientReports.span_dropper(3), - drops_spans=3, - ) - .with_before_send( - lambda e, _: None, - drops_transactions=1, - drops_spans=8, # 3 of the 11 (incl. transaction) spans already dropped - ), - ), -) -def test_dropped_transaction(sentry_init, capture_record_lost_event_calls, test_config): - test_config.run(sentry_init, capture_record_lost_event_calls) - - -@pytest.mark.parametrize("enable_tracing", [True, False]) -def test_enable_tracing_deprecated(sentry_init, enable_tracing): - with pytest.warns(DeprecationWarning): - sentry_init(enable_tracing=enable_tracing) - - -def test_ignore_spans_warns_without_streaming(sentry_init): - with pytest.warns(UserWarning, match=r"`ignore_spans` parameter only works"): - sentry_init(ignore_spans=["/health"], trace_lifecycle="static") - - -@pytest.mark.parametrize( - "options", - [ - {"ignore_spans": ["/health"], "trace_lifecycle": "stream"}, - {"ignore_spans": ["/health"], "_experiments": {"trace_lifecycle": "stream"}}, - {}, - ], -) -def test_ignore_spans_does_not_warn(sentry_init, options): - with warnings.catch_warnings(record=True) as caught: - warnings.simplefilter("always") - sentry_init(**options) - - ignore_spans_warnings = [w for w in caught if "ignore_spans" in str(w.message)] - assert ignore_spans_warnings == [] + with mock.patch("sentry_sdk.utils.logger") as mock_logger: + with mock.patch.dict("sys.modules", uwsgi=uwsgi): + sentry_init() + if missing_flags: + assert mock_logger.warning.call_count == 1 + message = mock_logger.warning.call_args[0][0] + for flag in missing_flags: + assert flag in message + else: + mock_logger.warning.assert_not_called() def make_options_transport_cls(): @@ -1629,8 +1417,6 @@ async def test_async_proxy(monkeypatch, testcase): @pytest.mark.skipif(not PY38, reason="Async client methods require Python 3.8+") async def test_close_with_async_transport_warns(): """Test close() with AsyncHttpTransport emits a warning.""" - import warnings as _warnings - client = Client( "https://foo@sentry.io/123", _experiments={"transport_async": True}, @@ -1638,10 +1424,11 @@ async def test_close_with_async_transport_warns(): ) assert isinstance(client.transport, AsyncHttpTransport) - with _warnings.catch_warnings(record=True) as w: - _warnings.simplefilter("always") + with mock.patch("sentry_sdk.client.logger") as mock_logger: client.close() - assert any("close_async()" in str(warning.message) for warning in w) + assert any( + "close_async()" in str(c) for c in mock_logger.warning.call_args_list + ) @skip_under_gevent @@ -1694,8 +1481,6 @@ async def test_close_async_no_transport(): @pytest.mark.skipif(not PY38, reason="Async client methods require Python 3.8+") async def test_flush_with_async_transport_warns(): """Test flush() with AsyncHttpTransport emits a warning and returns.""" - import warnings as _warnings - client = Client( "https://foo@sentry.io/123", _experiments={"transport_async": True}, @@ -1703,10 +1488,11 @@ async def test_flush_with_async_transport_warns(): ) assert isinstance(client.transport, AsyncHttpTransport) - with _warnings.catch_warnings(record=True) as w: - _warnings.simplefilter("always") + with mock.patch("sentry_sdk.client.logger") as mock_logger: client.flush(timeout=1.0) - assert any("flush_async()" in str(warning.message) for warning in w) + assert any( + "flush_async()" in str(c) for c in mock_logger.warning.call_args_list + ) await client.close_async() diff --git a/tests/test_dsc.py b/tests/test_dsc.py index 7aa4669c60..76b922fd1d 100644 --- a/tests/test_dsc.py +++ b/tests/test_dsc.py @@ -17,61 +17,6 @@ def test_dsc_head_of_trace(sentry_init, capture_envelopes): - """ - Our service is the head of the trace (it starts a new trace) - and sends a transaction event to Sentry. - """ - sentry_init( - dsn="https://mysecret@o1234.ingest.sentry.io/12312012", - release="myapp@0.0.1", - environment="canary", - traces_sample_rate=1.0, - transport=TestTransportWithOptions, - ) - envelopes = capture_envelopes() - - # We start a new transaction - with sentry_sdk.start_transaction(name="foo"): - pass - - assert len(envelopes) == 1 - - transaction_envelope = envelopes[0] - envelope_trace_header = transaction_envelope.headers["trace"] - - assert "trace_id" in envelope_trace_header - assert type(envelope_trace_header["trace_id"]) == str - - assert "public_key" in envelope_trace_header - assert type(envelope_trace_header["public_key"]) == str - assert envelope_trace_header["public_key"] == "mysecret" - - assert "org_id" in envelope_trace_header - assert type(envelope_trace_header["org_id"]) == str - assert envelope_trace_header["org_id"] == "1234" - - assert "sample_rate" in envelope_trace_header - assert type(envelope_trace_header["sample_rate"]) == str - assert envelope_trace_header["sample_rate"] == "1.0" - - assert "sampled" in envelope_trace_header - assert type(envelope_trace_header["sampled"]) == str - assert envelope_trace_header["sampled"] == "true" - - assert "release" in envelope_trace_header - assert type(envelope_trace_header["release"]) == str - assert envelope_trace_header["release"] == "myapp@0.0.1" - - assert "environment" in envelope_trace_header - assert type(envelope_trace_header["environment"]) == str - assert envelope_trace_header["environment"] == "canary" - - assert "transaction" in envelope_trace_header - assert type(envelope_trace_header["transaction"]) == str - assert envelope_trace_header["transaction"] == "foo" - - -def test_dsc_head_of_trace_span_streaming(sentry_init, capture_envelopes): """ Our service is the head of the trace (it starts a new trace) and sends a segment to Sentry. @@ -81,13 +26,12 @@ def test_dsc_head_of_trace_span_streaming(sentry_init, capture_envelopes): release="myapp@0.0.1", environment="canary", traces_sample_rate=1.0, - trace_lifecycle="stream", transport=TestTransportWithOptions, ) envelopes = capture_envelopes() # We start a new segment - with sentry_sdk.traces.start_span(name="foo"): + with sentry_sdk.start_span(name="foo"): pass sentry_sdk.flush() @@ -130,37 +74,6 @@ def test_dsc_head_of_trace_span_streaming(sentry_init, capture_envelopes): def test_dsc_head_of_trace_uses_custom_org_id(sentry_init, capture_envelopes): - """ - Our service is the head of the trace (it starts a new trace) - and sends a transaction event to Sentry. - """ - sentry_init( - dsn="https://mysecret@o1234.ingest.sentry.io/12312012", - org_id="9999", - release="myapp@0.0.1", - environment="canary", - traces_sample_rate=1.0, - transport=TestTransportWithOptions, - ) - envelopes = capture_envelopes() - - # We start a new transaction - with sentry_sdk.start_transaction(name="foo"): - pass - - assert len(envelopes) == 1 - - transaction_envelope = envelopes[0] - envelope_trace_header = transaction_envelope.headers["trace"] - - assert "org_id" in envelope_trace_header - assert type(envelope_trace_header["org_id"]) == str - assert envelope_trace_header["org_id"] == "9999" - - -def test_dsc_head_of_trace_uses_custom_org_id_span_streaming( - sentry_init, capture_envelopes -): """ Our service is the head of the trace (it starts a new trace) and sends a segment to Sentry. @@ -171,13 +84,12 @@ def test_dsc_head_of_trace_uses_custom_org_id_span_streaming( release="myapp@0.0.1", environment="canary", traces_sample_rate=1.0, - trace_lifecycle="stream", transport=TestTransportWithOptions, ) envelopes = capture_envelopes() # We start a new segment - with sentry_sdk.traces.start_span(name="foo"): + with sentry_sdk.start_span(name="foo"): pass sentry_sdk.flush() @@ -193,77 +105,6 @@ def test_dsc_head_of_trace_uses_custom_org_id_span_streaming( def test_dsc_continuation_of_trace(sentry_init, capture_envelopes): - """ - Another service calls our service and passes tracing information to us. - Our service is continuing the trace and sends a transaction event to Sentry. - """ - sentry_init( - dsn="https://mysecret@o1234.ingest.sentry.io/12312012", - release="myapp@0.0.1", - environment="canary", - traces_sample_rate=1.0, - transport=TestTransportWithOptions, - ) - envelopes = capture_envelopes() - - # This is what the upstream service sends us - sentry_trace = "771a43a4192642f0b136d5159a501700-1234567890abcdef-1" - baggage = ( - "other-vendor-value-1=foo;bar;baz, " - "sentry-trace_id=771a43a4192642f0b136d5159a501700, " - "sentry-public_key=frontendpublickey, " - "sentry-sample_rate=0.01337, " - "sentry-sampled=true, " - "sentry-release=myfrontend@1.2.3, " - "sentry-environment=bird, " - "sentry-transaction=bar, " - "other-vendor-value-2=foo;bar;" - ) - incoming_http_headers = { - "HTTP_SENTRY_TRACE": sentry_trace, - "HTTP_BAGGAGE": baggage, - } - - # We continue the incoming trace and start a new transaction - transaction = sentry_sdk.continue_trace(incoming_http_headers) - with sentry_sdk.start_transaction(transaction, name="foo"): - pass - - assert len(envelopes) == 1 - - transaction_envelope = envelopes[0] - envelope_trace_header = transaction_envelope.headers["trace"] - - assert "trace_id" in envelope_trace_header - assert type(envelope_trace_header["trace_id"]) == str - assert envelope_trace_header["trace_id"] == "771a43a4192642f0b136d5159a501700" - - assert "public_key" in envelope_trace_header - assert type(envelope_trace_header["public_key"]) == str - assert envelope_trace_header["public_key"] == "frontendpublickey" - - assert "sample_rate" in envelope_trace_header - assert type(envelope_trace_header["sample_rate"]) == str - assert envelope_trace_header["sample_rate"] == "1.0" - - assert "sampled" in envelope_trace_header - assert type(envelope_trace_header["sampled"]) == str - assert envelope_trace_header["sampled"] == "true" - - assert "release" in envelope_trace_header - assert type(envelope_trace_header["release"]) == str - assert envelope_trace_header["release"] == "myfrontend@1.2.3" - - assert "environment" in envelope_trace_header - assert type(envelope_trace_header["environment"]) == str - assert envelope_trace_header["environment"] == "bird" - - assert "transaction" in envelope_trace_header - assert type(envelope_trace_header["transaction"]) == str - assert envelope_trace_header["transaction"] == "bar" - - -def test_dsc_continuation_of_trace_span_streaming(sentry_init, capture_envelopes): """ Another service calls our service and passes tracing information to us. Our service is continuing the trace and sends a segment to Sentry. @@ -273,7 +114,6 @@ def test_dsc_continuation_of_trace_span_streaming(sentry_init, capture_envelopes release="myapp@0.0.1", environment="canary", traces_sample_rate=1.0, - trace_lifecycle="stream", transport=TestTransportWithOptions, ) envelopes = capture_envelopes() @@ -298,7 +138,7 @@ def test_dsc_continuation_of_trace_span_streaming(sentry_init, capture_envelopes # We continue the incoming trace and start a new segment sentry_sdk.continue_trace(incoming_http_headers) - with sentry_sdk.traces.start_span(name="foo"): + with sentry_sdk.start_span(name="foo"): pass sentry_sdk.flush() @@ -376,90 +216,10 @@ def my_traces_sampler(sampling_context): "HTTP_BAGGAGE": baggage, } - # We continue the incoming trace and start a new transaction - with mock.patch("sentry_sdk.tracing_utils.Random.randrange", return_value=125000): - transaction = sentry_sdk.continue_trace(incoming_http_headers) - with sentry_sdk.start_transaction(transaction, name="foo"): - pass - - assert len(envelopes) == 1 - - transaction_envelope = envelopes[0] - envelope_trace_header = transaction_envelope.headers["trace"] - - assert "trace_id" in envelope_trace_header - assert type(envelope_trace_header["trace_id"]) == str - assert envelope_trace_header["trace_id"] == "771a43a4192642f0b136d5159a501700" - - assert "public_key" in envelope_trace_header - assert type(envelope_trace_header["public_key"]) == str - assert envelope_trace_header["public_key"] == "frontendpublickey" - - assert "sample_rate" in envelope_trace_header - assert type(envelope_trace_header["sample_rate"]) == str - assert envelope_trace_header["sample_rate"] == "0.25" - - assert "sampled" in envelope_trace_header - assert type(envelope_trace_header["sampled"]) == str - assert envelope_trace_header["sampled"] == "true" - - assert "release" in envelope_trace_header - assert type(envelope_trace_header["release"]) == str - assert envelope_trace_header["release"] == "myfrontend@1.2.3" - - assert "environment" in envelope_trace_header - assert type(envelope_trace_header["environment"]) == str - assert envelope_trace_header["environment"] == "bird" - - assert "transaction" in envelope_trace_header - assert type(envelope_trace_header["transaction"]) == str - assert envelope_trace_header["transaction"] == "bar" - - -def test_dsc_continuation_of_trace_sample_rate_changed_in_traces_sampler_span_streaming( - sentry_init, capture_envelopes -): - """ - Another service calls our service and passes tracing information to us. - Our service is continuing the trace, but modifies the sample rate. - The DSC propagated further should contain the updated sample rate. - """ - - def my_traces_sampler(sampling_context): - return 0.25 - - sentry_init( - dsn="https://mysecret@o1234.ingest.sentry.io/12312012", - release="myapp@0.0.1", - environment="canary", - traces_sampler=my_traces_sampler, - trace_lifecycle="stream", - transport=TestTransportWithOptions, - ) - envelopes = capture_envelopes() - - # This is what the upstream service sends us - sentry_trace = "771a43a4192642f0b136d5159a501700-1234567890abcdef-1" - baggage = ( - "other-vendor-value-1=foo;bar;baz, " - "sentry-trace_id=771a43a4192642f0b136d5159a501700, " - "sentry-public_key=frontendpublickey, " - "sentry-sample_rate=1.0, " - "sentry-sampled=true, " - "sentry-release=myfrontend@1.2.3, " - "sentry-environment=bird, " - "sentry-transaction=bar, " - "other-vendor-value-2=foo;bar;" - ) - incoming_http_headers = { - "HTTP_SENTRY_TRACE": sentry_trace, - "HTTP_BAGGAGE": baggage, - } - # We continue the incoming trace and start a new segment with mock.patch("sentry_sdk.tracing_utils.Random.randrange", return_value=125000): sentry_sdk.continue_trace(incoming_http_headers) - with sentry_sdk.traces.start_span(name="foo"): + with sentry_sdk.start_span(name="foo"): pass sentry_sdk.flush() @@ -510,57 +270,6 @@ def test_dsc_issue(sentry_init, capture_envelopes): ) envelopes = capture_envelopes() - # No transaction is started, just an error is captured - try: - 1 / 0 - except ZeroDivisionError as exp: - sentry_sdk.capture_exception(exp) - - assert len(envelopes) == 1 - - error_envelope = envelopes[0] - - envelope_trace_header = error_envelope.headers["trace"] - - assert "trace_id" in envelope_trace_header - assert type(envelope_trace_header["trace_id"]) == str - - assert "public_key" in envelope_trace_header - assert type(envelope_trace_header["public_key"]) == str - assert envelope_trace_header["public_key"] == "mysecret" - - assert "org_id" in envelope_trace_header - assert type(envelope_trace_header["org_id"]) == str - assert envelope_trace_header["org_id"] == "1234" - - assert "sample_rate" not in envelope_trace_header - - assert "sampled" not in envelope_trace_header - - assert "release" in envelope_trace_header - assert type(envelope_trace_header["release"]) == str - assert envelope_trace_header["release"] == "myapp@0.0.1" - - assert "environment" in envelope_trace_header - assert type(envelope_trace_header["environment"]) == str - assert envelope_trace_header["environment"] == "canary" - - assert "transaction" not in envelope_trace_header - - -def test_dsc_issue_span_streaming(sentry_init, capture_envelopes): - """ - Our service is a standalone service that does not have tracing enabled. Just uses Sentry for error reporting. - """ - sentry_init( - dsn="https://mysecret@o1234.ingest.sentry.io/12312012", - release="myapp@0.0.1", - environment="canary", - trace_lifecycle="stream", - transport=TestTransportWithOptions, - ) - envelopes = capture_envelopes() - # No segment is started, just an error is captured try: 1 / 0 @@ -600,67 +309,6 @@ def test_dsc_issue_span_streaming(sentry_init, capture_envelopes): def test_dsc_issue_with_tracing(sentry_init, capture_envelopes): - """ - Our service has tracing enabled and an error occurs in an transaction. - Envelopes containing errors also have the same DSC than the transaction envelopes. - """ - sentry_init( - dsn="https://mysecret@o1234.ingest.sentry.io/12312012", - release="myapp@0.0.1", - environment="canary", - traces_sample_rate=1.0, - transport=TestTransportWithOptions, - ) - envelopes = capture_envelopes() - - # We start a new transaction and an error occurs - with sentry_sdk.start_transaction(name="foo"): - try: - 1 / 0 - except ZeroDivisionError as exp: - sentry_sdk.capture_exception(exp) - - assert len(envelopes) == 2 - - error_envelope, transaction_envelope = envelopes - - assert error_envelope.headers["trace"] == transaction_envelope.headers["trace"] - - envelope_trace_header = error_envelope.headers["trace"] - - assert "trace_id" in envelope_trace_header - assert type(envelope_trace_header["trace_id"]) == str - - assert "public_key" in envelope_trace_header - assert type(envelope_trace_header["public_key"]) == str - assert envelope_trace_header["public_key"] == "mysecret" - - assert "org_id" in envelope_trace_header - assert type(envelope_trace_header["org_id"]) == str - assert envelope_trace_header["org_id"] == "1234" - - assert "sample_rate" in envelope_trace_header - assert envelope_trace_header["sample_rate"] == "1.0" - assert type(envelope_trace_header["sample_rate"]) == str - - assert "sampled" in envelope_trace_header - assert type(envelope_trace_header["sampled"]) == str - assert envelope_trace_header["sampled"] == "true" - - assert "release" in envelope_trace_header - assert type(envelope_trace_header["release"]) == str - assert envelope_trace_header["release"] == "myapp@0.0.1" - - assert "environment" in envelope_trace_header - assert type(envelope_trace_header["environment"]) == str - assert envelope_trace_header["environment"] == "canary" - - assert "transaction" in envelope_trace_header - assert type(envelope_trace_header["transaction"]) == str - assert envelope_trace_header["transaction"] == "foo" - - -def test_dsc_issue_with_tracing_span_streaming(sentry_init, capture_envelopes): """ Our service has tracing enabled and an error occurs in a segment. Envelopes containing errors also have the same DSC as the segment envelopes. @@ -670,13 +318,12 @@ def test_dsc_issue_with_tracing_span_streaming(sentry_init, capture_envelopes): release="myapp@0.0.1", environment="canary", traces_sample_rate=1.0, - trace_lifecycle="stream", transport=TestTransportWithOptions, ) envelopes = capture_envelopes() # We start a new segment and an error occurs - with sentry_sdk.traces.start_span(name="foo"): + with sentry_sdk.start_span(name="foo"): try: 1 / 0 except ZeroDivisionError as exp: @@ -724,94 +371,6 @@ def test_dsc_issue_with_tracing_span_streaming(sentry_init, capture_envelopes): assert envelope_trace_header["transaction"] == "foo" -@pytest.mark.parametrize( - "traces_sample_rate", - [ - 0, # no traces will be started, but if incoming traces will be continued (by our instrumentations, not happening in this test) - None, # no tracing at all. This service will never create transactions. - ], -) -def test_dsc_issue_twp(sentry_init, capture_envelopes, traces_sample_rate): - """ - Our service does not have tracing enabled, but we receive tracing information from an upstream service. - Error envelopes still contain a DCS. This is called "tracing without performance" or TWP for short. - - This way if I have three services A, B, and C, and A and C have tracing enabled, but B does not, - we still can see the full trace in Sentry, and associate errors send by service B to Sentry. - (This test would be service B in this scenario) - """ - sentry_init( - dsn="https://mysecret@o1234.ingest.sentry.io/12312012", - release="myapp@0.0.1", - environment="canary", - traces_sample_rate=traces_sample_rate, - transport=TestTransportWithOptions, - ) - envelopes = capture_envelopes() - - # This is what the upstream service sends us - sentry_trace = "771a43a4192642f0b136d5159a501700-1234567890abcdef-1" - baggage = ( - "other-vendor-value-1=foo;bar;baz, " - "sentry-trace_id=771a43a4192642f0b136d5159a501700, " - "sentry-public_key=frontendpublickey, " - "sentry-sample_rate=0.01337, " - "sentry-sampled=true, " - "sentry-release=myfrontend@1.2.3, " - "sentry-environment=bird, " - "sentry-transaction=bar, " - "other-vendor-value-2=foo;bar;" - ) - incoming_http_headers = { - "HTTP_SENTRY_TRACE": sentry_trace, - "HTTP_BAGGAGE": baggage, - } - - # We continue the trace (meaning: saving the incoming trace information on the scope) - # but in this test, we do not start a transaction. - sentry_sdk.continue_trace(incoming_http_headers) - - # No transaction is started, just an error is captured - try: - 1 / 0 - except ZeroDivisionError as exp: - sentry_sdk.capture_exception(exp) - - assert len(envelopes) == 1 - - error_envelope = envelopes[0] - - envelope_trace_header = error_envelope.headers["trace"] - - assert "trace_id" in envelope_trace_header - assert type(envelope_trace_header["trace_id"]) == str - assert envelope_trace_header["trace_id"] == "771a43a4192642f0b136d5159a501700" - - assert "public_key" in envelope_trace_header - assert type(envelope_trace_header["public_key"]) == str - assert envelope_trace_header["public_key"] == "frontendpublickey" - - assert "sample_rate" in envelope_trace_header - assert type(envelope_trace_header["sample_rate"]) == str - assert envelope_trace_header["sample_rate"] == "0.01337" - - assert "sampled" in envelope_trace_header - assert type(envelope_trace_header["sampled"]) == str - assert envelope_trace_header["sampled"] == "true" - - assert "release" in envelope_trace_header - assert type(envelope_trace_header["release"]) == str - assert envelope_trace_header["release"] == "myfrontend@1.2.3" - - assert "environment" in envelope_trace_header - assert type(envelope_trace_header["environment"]) == str - assert envelope_trace_header["environment"] == "bird" - - assert "transaction" in envelope_trace_header - assert type(envelope_trace_header["transaction"]) == str - assert envelope_trace_header["transaction"] == "bar" - - @pytest.mark.parametrize( "traces_sample_rate", [ @@ -819,9 +378,7 @@ def test_dsc_issue_twp(sentry_init, capture_envelopes, traces_sample_rate): None, # no tracing at all. This service will never create segments. ], ) -def test_dsc_issue_twp_span_streaming( - sentry_init, capture_envelopes, traces_sample_rate -): +def test_dsc_issue_twp(sentry_init, capture_envelopes, traces_sample_rate): """ Our service does not have tracing enabled, but we receive tracing information from an upstream service. Error envelopes still contain a DSC. This is called "tracing without performance" or TWP for short. @@ -835,7 +392,6 @@ def test_dsc_issue_twp_span_streaming( release="myapp@0.0.1", environment="canary", traces_sample_rate=traces_sample_rate, - trace_lifecycle="stream", transport=TestTransportWithOptions, ) envelopes = capture_envelopes() diff --git a/tests/test_envelope.py b/tests/test_envelope.py index 5549cc6e36..f103ba6006 100644 --- a/tests/test_envelope.py +++ b/tests/test_envelope.py @@ -4,20 +4,14 @@ from sentry_sdk.session import Session -def generate_transaction_item(): +def generate_event_item(): return { "event_id": "15210411201320122115110420122013", - "type": "transaction", - "transaction": "/interactions/other-dogs/new-dog", - "start_timestamp": 1353568872.11122131, - "timestamp": 1356942672.09040815, + "message": "hello", "contexts": { "trace": { "trace_id": "12312012123120121231201212312012", "span_id": "0415201309082013", - "parent_span_id": None, - "description": "", - "op": "greeting.sniff", "dynamic_sampling_context": { "trace_id": "12312012123120121231201212312012", "sample_rate": "1.0", @@ -28,17 +22,6 @@ def generate_transaction_item(): }, } }, - "spans": [ - { - "description": "", - "op": "greeting.sniff", - "parent_span_id": None, - "span_id": "0415201309082013", - "start_timestamp": 1353568872.11122131, - "timestamp": 1356942672.09040815, - "trace_id": "12312012123120121231201212312012", - } - ], } @@ -51,22 +34,6 @@ def test_add_and_get_basic_event(): assert envelope.get_event() == {"message": "Hello, World!"} -def test_add_and_get_transaction_event(): - envelope = Envelope() - - transaction_item = generate_transaction_item() - transaction_item.update({"event_id": "a" * 32}) - envelope.add_transaction(transaction_item) - - # typically it should not be possible to be able to add a second transaction; - # but we do it anyways - another_transaction_item = generate_transaction_item() - envelope.add_transaction(another_transaction_item) - - # should only fetch the first inserted transaction event - assert envelope.get_transaction_event() == transaction_item - - def test_add_and_get_session(): envelope = Envelope() @@ -87,11 +54,10 @@ def test_envelope_headers(sentry_init, capture_envelopes, monkeypatch): sentry_init( dsn="https://dogsarebadatkeepingsecrets@squirrelchasers.ingest.sentry.io/12312012", - traces_sample_rate=1.0, ) envelopes = capture_envelopes() - capture_event(generate_transaction_item()) + capture_event(generate_event_item()) assert len(envelopes) == 1 @@ -245,12 +211,10 @@ def test_envelope_item_data_category_mapping(): """Test that envelope items map to correct data categories for rate limiting.""" test_cases = [ ("event", "error"), - ("transaction", "transaction"), ("log", "log_item"), ("session", "session"), ("attachment", "attachment"), ("client_report", "internal"), - ("profile", "profile"), ("profile_chunk", "profile_chunk"), ("check_in", "monitor"), ("unknown_type", "default"), diff --git a/tests/test_feature_flags.py b/tests/test_feature_flags.py index b6d194f388..4ba432b2d5 100644 --- a/tests/test_feature_flags.py +++ b/tests/test_feature_flags.py @@ -1,14 +1,11 @@ import concurrent.futures as cf import copy -import sys import threading import pytest import sentry_sdk -from sentry_sdk import start_span, start_transaction from sentry_sdk.feature_flags import FlagBuffer, add_feature_flag -from tests.conftest import ApproxDict def test_featureflags_integration(sentry_init, capture_events, uninstall_integration): @@ -136,7 +133,6 @@ def task(flag_key): } -@pytest.mark.skipif(sys.version_info < (3, 7), reason="requires python3.7 or higher") def test_featureflags_integration_asyncio( sentry_init, capture_events, uninstall_integration ): @@ -279,40 +275,3 @@ def reader(): # shared resource. When deepcopying we should have exclusive access to the underlying # memory. assert error_occurred is False - - -def test_flag_limit(sentry_init, capture_events): - sentry_init(traces_sample_rate=1.0) - - events = capture_events() - - with start_transaction(name="hi"): - with start_span(op="foo", name="bar"): - add_feature_flag("0", True) - add_feature_flag("1", True) - add_feature_flag("2", True) - add_feature_flag("3", True) - add_feature_flag("4", True) - add_feature_flag("5", True) - add_feature_flag("6", True) - add_feature_flag("7", True) - add_feature_flag("8", True) - add_feature_flag("9", True) - add_feature_flag("10", True) - - (event,) = events - assert event["spans"][0]["data"] == ApproxDict( - { - "flag.evaluation.0": True, - "flag.evaluation.1": True, - "flag.evaluation.2": True, - "flag.evaluation.3": True, - "flag.evaluation.4": True, - "flag.evaluation.5": True, - "flag.evaluation.6": True, - "flag.evaluation.7": True, - "flag.evaluation.8": True, - "flag.evaluation.9": True, - } - ) - assert "flag.evaluation.10" not in event["spans"][0]["data"] diff --git a/tests/test_logs.py b/tests/test_logs.py index e8a098ff44..3db3c9c8d3 100644 --- a/tests/test_logs.py +++ b/tests/test_logs.py @@ -10,12 +10,7 @@ from sentry_sdk import get_client from sentry_sdk.consts import SPANDATA, VERSION -minimum_python_37 = pytest.mark.skipif( - sys.version_info < (3, 7), reason="Asyncio tests need Python >= 3.7" -) - -@minimum_python_37 def test_logs_enabled_by_default(sentry_init, capture_envelopes): sentry_init() @@ -33,25 +28,6 @@ def test_logs_enabled_by_default(sentry_init, capture_envelopes): assert envelopes -@minimum_python_37 -def test_enable_logs_noop(sentry_init, capture_envelopes): - sentry_init(enable_logs=False) - - envelopes = capture_envelopes() - - sentry_sdk.logger.trace("This is a 'trace' log.") - sentry_sdk.logger.debug("This is a 'debug' log...") - sentry_sdk.logger.info("This is a 'info' log...") - sentry_sdk.logger.warning("This is a 'warning' log...") - sentry_sdk.logger.error("This is a 'error' log...") - sentry_sdk.logger.fatal("This is a 'fatal' log...") - - sentry_sdk.flush() - - assert envelopes - - -@minimum_python_37 def test_logs_basics(sentry_init, capture_items): sentry_init() items = capture_items("log") @@ -84,7 +60,6 @@ def test_logs_basics(sentry_init, capture_items): assert logs[5]["attributes"]["sentry.severity_number"] == 21 -@minimum_python_37 def test_logs_before_send_log(sentry_init, capture_items): before_log_called = False @@ -131,36 +106,6 @@ def _before_log(record, hint): assert before_log_called is True -@minimum_python_37 -def test_logs_before_send_log_experimental_option_still_works( - sentry_init, capture_items -): - before_log_called = False - - def _before_log(record, hint): - nonlocal before_log_called - before_log_called = True - - return record - - sentry_init( - _experiments={ - "before_send_log": _before_log, - }, - ) - items = capture_items("log") - - sentry_sdk.logger.error("This is an error log...") - - get_client().flush() - logs = [item.payload for item in items] - assert len(logs) == 1 - - assert logs[0]["attributes"]["sentry.severity_text"] == "error" - assert before_log_called is True - - -@minimum_python_37 @pytest.mark.tests_internal_exceptions def test_logs_before_send_log_raises_does_not_crash_application( sentry_init, capture_items @@ -182,7 +127,6 @@ def _before_log(record, hint): assert not logs -@minimum_python_37 def test_logs_attributes(sentry_init, capture_items): """ Passing arbitrary attributes to log messages. @@ -216,7 +160,6 @@ def test_logs_attributes(sentry_init, capture_items): assert logs[0]["attributes"]["sentry.sdk.version"] == VERSION -@minimum_python_37 def test_logs_message_params(sentry_init, capture_items): """ This is the official way of how to pass vars to log messages. @@ -283,33 +226,14 @@ def test_logs_message_params(sentry_init, capture_items): assert "sentry.message.template" not in logs[5]["attributes"] -@minimum_python_37 -def test_logs_tied_to_transactions(sentry_init, capture_items): - """ - Log messages are also tied to transactions. - """ - sentry_init(traces_sample_rate=1.0) - items = capture_items("log") - - with sentry_sdk.start_transaction(name="test-transaction") as trx: - sentry_sdk.logger.warning("This is a log tied to a transaction") - - get_client().flush() - logs = [item.payload for item in items] - - assert "span_id" in logs[0] - assert logs[0]["span_id"] == trx.span_id - - -@minimum_python_37 def test_logs_tied_to_segments(sentry_init, capture_items): """ Log messages are also tied to segments. """ - sentry_init(traces_sample_rate=1.0, trace_lifecycle="stream") + sentry_init(traces_sample_rate=1.0) items = capture_items("log") - with sentry_sdk.traces.start_span(name="test-segment") as sgmt: + with sentry_sdk.start_span(name="test-segment") as sgmt: sentry_sdk.logger.warning("This is a log tied to a segment") sentry_sdk.flush() @@ -319,7 +243,6 @@ def test_logs_tied_to_segments(sentry_init, capture_items): assert logs[0]["span_id"] == sgmt.span_id -@minimum_python_37 def test_logs_no_span_id_without_active_span(sentry_init, capture_items): """ Per the metrics spec, span_id is only attached when a span is active @@ -337,7 +260,6 @@ def test_logs_no_span_id_without_active_span(sentry_init, capture_items): assert "span_id" not in logs[0] -@minimum_python_37 def test_logs_tied_to_spans(sentry_init, capture_items): """ Log messages are also tied to spans. @@ -345,33 +267,15 @@ def test_logs_tied_to_spans(sentry_init, capture_items): sentry_init(traces_sample_rate=1.0) items = capture_items("log") - with sentry_sdk.start_transaction(name="test-transaction"): + with sentry_sdk.start_span(name="test-segment"): with sentry_sdk.start_span(name="test-span") as span: sentry_sdk.logger.warning("This is a log tied to a span") - get_client().flush() - logs = [item.payload for item in items] - assert logs[0]["span_id"] == span.span_id - - -@minimum_python_37 -def test_logs_tied_to_spans_span_streaming(sentry_init, capture_items): - """ - Log messages are also tied to spans. - """ - sentry_init(traces_sample_rate=1.0, trace_lifecycle="stream") - items = capture_items("log") - - with sentry_sdk.traces.start_span(name="test-segment"): - with sentry_sdk.traces.start_span(name="test-span") as span: - sentry_sdk.logger.warning("This is a log tied to a span") - sentry_sdk.flush() logs = [item.payload for item in items] assert logs[0]["span_id"] == span.span_id -@minimum_python_37 def test_auto_flush_logs_after_100(sentry_init, capture_envelopes): """ If you log >100 logs, it should automatically trigger a flush. @@ -390,7 +294,6 @@ def test_auto_flush_logs_after_100(sentry_init, capture_envelopes): raise AssertionError("200 logs were never flushed after five seconds") -@minimum_python_37 def test_log_user_attributes(sentry_init, capture_items): """User attributes are sent if send_default_pii is True.""" sentry_init(send_default_pii=True) @@ -413,7 +316,6 @@ def test_log_user_attributes(sentry_init, capture_items): } -@minimum_python_37 def test_log_no_user_attributes_if_no_pii(sentry_init, capture_items): """User attributes are not if PII sending is off.""" sentry_init(send_default_pii=False) @@ -433,7 +335,6 @@ def test_log_no_user_attributes_if_no_pii(sentry_init, capture_items): assert "user.name" not in log["attributes"] -@minimum_python_37 def test_auto_flush_logs_after_5s(sentry_init, capture_envelopes): """ If you log a single log, it should automatically flush after 5 seconds, at most 10 seconds. @@ -451,7 +352,6 @@ def test_auto_flush_logs_after_5s(sentry_init, capture_envelopes): raise AssertionError("1 logs was never flushed after 10 seconds") -@minimum_python_37 @pytest.mark.parametrize( "message,expected_body,params", [ @@ -500,7 +400,6 @@ def test_logs_with_literal_braces( assert "sentry.message.template" not in logs[0]["attributes"] -@minimum_python_37 def test_transport_format(sentry_init, capture_envelopes): sentry_init(server_name="test-server", release="1.0.0") @@ -571,7 +470,6 @@ def test_transport_format(sentry_init, capture_envelopes): } -@minimum_python_37 def test_batcher_drops_logs(sentry_init, monkeypatch): sentry_init(server_name="test-server", release="1.0.0") client = sentry_sdk.get_client() @@ -657,7 +555,6 @@ def record_lost_event(reason, data_category=None, item=None, *, quantity=1): } -@minimum_python_37 def test_log_gets_attributes_from_scopes(sentry_init, capture_items): sentry_init() @@ -684,7 +581,6 @@ def test_log_gets_attributes_from_scopes(sentry_init, capture_items): assert "current.attribute" not in log2["attributes"] -@minimum_python_37 def test_log_attributes_override_scope_attributes(sentry_init, capture_items): sentry_init() @@ -706,7 +602,6 @@ def test_log_attributes_override_scope_attributes(sentry_init, capture_items): assert log["attributes"]["temp.attribute"] == "value2" -@minimum_python_37 def test_log_array_attributes(sentry_init, capture_envelopes): """Test homogeneous list and tuple attributes, and fallback for inhomogeneous collections.""" @@ -762,7 +657,6 @@ def test_log_array_attributes(sentry_init, capture_envelopes): } -@minimum_python_37 def test_attributes_preserialized_in_before_send(sentry_init, capture_items): """We don't surface user-held references to objects in attributes.""" @@ -805,7 +699,6 @@ class Cat: assert isinstance(log["attributes"]["inhomogeneous_tuple"], str) -@minimum_python_37 def test_array_attributes_deep_copied_in_before_send(sentry_init, capture_envelopes): """We don't surface user-held references to objects in attributes.""" @@ -831,7 +724,6 @@ def before_send_log(log, _): get_client().flush() -@minimum_python_37 @pytest.mark.timeout(5) def test_reentrant_add_does_not_deadlock(sentry_init, capture_envelopes): """Adding to the batcher from within a flush must not deadlock. diff --git a/tests/test_metrics.py b/tests/test_metrics.py index e07e507ba7..95388db2b3 100644 --- a/tests/test_metrics.py +++ b/tests/test_metrics.py @@ -9,21 +9,6 @@ from sentry_sdk.consts import SPANDATA, VERSION -def test_metrics_enable_metrics_noop(sentry_init, capture_envelopes): - # The enable_metrics option has no effect anymore. - sentry_init(enable_metrics=False) - - envelopes = capture_envelopes() - - sentry_sdk.metrics.count("test.counter", 1) - sentry_sdk.metrics.gauge("test.gauge", 42) - sentry_sdk.metrics.distribution("test.distribution", 200) - - sentry_sdk.flush() - - assert envelopes - - def test_metrics_basics(sentry_init, capture_items): sentry_init() items = capture_items("trace_metric") @@ -55,22 +40,6 @@ def test_metrics_basics(sentry_init, capture_items): assert metrics[2]["unit"] == "second" -def test_metrics_experimental_option(sentry_init, capture_items): - sentry_init() - items = capture_items("trace_metric") - - sentry_sdk.metrics.count("test.counter", 5) - - get_client().flush() - - metrics = [item.payload for item in items] - assert len(metrics) == 1 - - assert metrics[0]["name"] == "test.counter" - assert metrics[0]["type"] == "counter" - assert metrics[0]["value"] == 5.0 - - def test_metrics_with_attributes(sentry_init, capture_items): sentry_init(release="1.0.0", environment="test", server_name="test-server") items = capture_items("trace_metric") @@ -136,24 +105,7 @@ def test_metrics_with_span(sentry_init, capture_items): sentry_init(traces_sample_rate=1.0) items = capture_items("trace_metric") - with sentry_sdk.start_transaction(op="test", name="test-span") as transaction: - sentry_sdk.metrics.count("test.span.counter", 1) - - get_client().flush() - - metrics = [item.payload for item in items] - assert len(metrics) == 1 - - assert metrics[0]["trace_id"] is not None - assert metrics[0]["trace_id"] == transaction.trace_id - assert metrics[0]["span_id"] == transaction.span_id - - -def test_metrics_with_span_span_streaming(sentry_init, capture_items): - sentry_init(traces_sample_rate=1.0, trace_lifecycle="stream") - items = capture_items("trace_metric") - - with sentry_sdk.traces.start_span(name="test-span") as segment: + with sentry_sdk.start_span(name="test-span") as segment: sentry_sdk.metrics.count("test.span.counter", 1) sentry_sdk.flush() @@ -226,47 +178,6 @@ def _before_metric(record, hint): assert before_metric_called -def test_metrics_experimental_before_send(sentry_init, capture_items): - before_metric_called = False - - def _before_metric(record, hint): - nonlocal before_metric_called - - assert set(record.keys()) == { - "timestamp", - "trace_id", - "span_id", - "name", - "type", - "value", - "unit", - "attributes", - } - - if record["name"] == "test.skip": - return None - - before_metric_called = True - return record - - sentry_init( - _experiments={ - "before_send_metric": _before_metric, - }, - ) - items = capture_items("trace_metric") - - sentry_sdk.metrics.count("test.skip", 1) - sentry_sdk.metrics.count("test.keep", 1) - - get_client().flush() - - metrics = [item.payload for item in items] - assert len(metrics) == 1 - assert metrics[0]["name"] == "test.keep" - assert before_metric_called - - @pytest.mark.tests_internal_exceptions def test_metrics_before_send_raises_does_not_crash_application( sentry_init, capture_items diff --git a/tests/test_monitor.py b/tests/test_monitor.py index 96902abca2..2696dd5c94 100644 --- a/tests/test_monitor.py +++ b/tests/test_monitor.py @@ -58,44 +58,11 @@ def test_monitor_unhealthy(sentry_init): assert monitor.downsample_factor == (i + 1 if i < 10 else 10) -def test_transaction_uses_downsampled_rate( - sentry_init, capture_record_lost_event_calls, monkeypatch -): - sentry_init( - traces_sample_rate=1.0, - transport=UnhealthyTestTransport(), - ) - - record_lost_event_calls = capture_record_lost_event_calls() - - monitor = sentry_sdk.get_client().monitor - monitor.interval = 0.1 - - assert monitor.is_healthy() is True - monitor.run() - assert monitor.is_healthy() is False - assert monitor.downsample_factor == 1 - - # make sure we don't sample the transaction - with mock.patch("sentry_sdk.tracing_utils.Random.randrange", return_value=750000): - with sentry_sdk.start_transaction(name="foobar") as transaction: - assert transaction.sampled is False - assert transaction.sample_rate == 0.5 - - assert Counter(record_lost_event_calls) == Counter( - [ - ("backpressure", "transaction", None, 1), - ("backpressure", "span", None, 1), - ] - ) - - def test_segment_uses_downsampled_rate( sentry_init, capture_record_lost_event_calls, monkeypatch ): sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream", transport=UnhealthyTestTransport(), ) @@ -111,7 +78,7 @@ def test_segment_uses_downsampled_rate( # make sure we don't sample the segment with mock.patch("sentry_sdk.tracing_utils.Random.randrange", return_value=750000): - with sentry_sdk.traces.start_span(name="foobar") as segment: + with sentry_sdk.start_span(name="foobar") as segment: assert segment.sampled is False assert segment._sample_rate == 0.5 diff --git a/tests/test_scope.py b/tests/test_scope.py index f05f17b313..c9e3653577 100644 --- a/tests/test_scope.py +++ b/tests/test_scope.py @@ -87,11 +87,10 @@ def test_set_user_none_values_are_dropped_when_copying_to_attributes( sentry_init( traces_sample_rate=1.0, send_default_pii=True, - trace_lifecycle="stream", ) items = capture_items("span") - with sentry_sdk.traces.start_span(name="test_segment"): + with sentry_sdk.start_span(name="test_segment"): sentry_sdk.get_isolation_scope().set_user( {"email": "ada@beans.com", "username": None} ) @@ -827,36 +826,6 @@ def test_with_use_scope_data(): } -def test_nested_scopes_with_tags(sentry_init, capture_envelopes): - sentry_init(traces_sample_rate=1.0) - envelopes = capture_envelopes() - - with sentry_sdk.isolation_scope() as scope1: - scope1.set_tag("isolation_scope1", 1) - - with sentry_sdk.new_scope() as scope2: - scope2.set_tag("current_scope2", 1) - - with sentry_sdk.start_transaction(name="trx") as trx: - trx.set_tag("trx", 1) - - with sentry_sdk.start_span(op="span1") as span1: - span1.set_tag("a", 1) - - with new_scope() as scope3: - scope3.set_tag("current_scope3", 1) - - with sentry_sdk.start_span(op="span2") as span2: - span2.set_tag("b", 1) - - (envelope,) = envelopes - transaction = envelope.items[0].get_transaction_event() - - assert transaction["tags"] == {"isolation_scope1": 1, "current_scope2": 1, "trx": 1} - assert transaction["spans"][0]["tags"] == {"a": 1} - assert transaction["spans"][1]["tags"] == {"b": 1} - - def test_should_send_default_pii_true(sentry_init): sentry_init(send_default_pii=True) @@ -923,17 +892,6 @@ def test_last_event_id(sentry_init): assert Scope.last_event_id() is not None -def test_last_event_id_transaction(sentry_init): - sentry_init(traces_sample_rate=1.0) - - assert Scope.last_event_id() is None - - with sentry_sdk.start_transaction(name="test"): - pass - - assert Scope.last_event_id() is None, "Transaction should not set last_event_id" - - def test_last_event_id_cleared(sentry_init): sentry_init(traces_sample_rate=1.0) @@ -1016,14 +974,14 @@ def test_handle_error_on_token_reset_isolation_scope(error_cls, scope_manager): def test_trace_context_tracing(sentry_init): sentry_init(traces_sample_rate=1.0) - with sentry_sdk.start_transaction(name="trx") as transaction: - with sentry_sdk.start_span(op="span1"): - with sentry_sdk.start_span(op="span2") as span: + with sentry_sdk.start_span(name="seg") as segment: + with sentry_sdk.start_span(name="span1"): + with sentry_sdk.start_span(name="span2") as span: trace_context = sentry_sdk.get_current_scope().get_trace_context() - assert trace_context["trace_id"] == transaction.trace_id + assert trace_context["trace_id"] == segment.trace_id assert trace_context["span_id"] == span.span_id - assert trace_context["parent_span_id"] == span.parent_span_id + assert trace_context["parent_span_id"] == span._parent_span_id assert "dynamic_sampling_context" in trace_context diff --git a/tests/test_scrubber.py b/tests/test_scrubber.py index 211d6336ac..1b301cee86 100644 --- a/tests/test_scrubber.py +++ b/tests/test_scrubber.py @@ -1,10 +1,10 @@ import logging import sys -from sentry_sdk import capture_event, capture_exception, start_span, start_transaction +from sentry_sdk import capture_event, capture_exception +from sentry_sdk.integrations.logging import LoggingIntegration from sentry_sdk.scrubber import EventScrubber from sentry_sdk.utils import event_from_exception -from tests.conftest import ApproxDict logger = logging.getLogger(__name__) logger.setLevel(logging.DEBUG) @@ -154,8 +154,15 @@ def test_stack_var_scrubbing(sentry_init, capture_events): def test_breadcrumb_extra_scrubbing(sentry_init, capture_events): - sentry_init(max_breadcrumbs=2) + sentry_init( + max_breadcrumbs=2, + integrations=[ + LoggingIntegration(breadcrumb_level=logging.INFO, event_level=logging.ERROR) + ], + ) + events = capture_events() + logger.info("breadcrumb 1", extra=dict(foo=1, password="secret")) logger.info("breadcrumb 2", extra=dict(bar=2, auth="secret")) logger.info("breadcrumb 3", extra=dict(foobar=3, password="secret")) @@ -184,24 +191,6 @@ def test_breadcrumb_extra_scrubbing(sentry_init, capture_events): } -def test_span_data_scrubbing(sentry_init, capture_events): - sentry_init(traces_sample_rate=1.0) - events = capture_events() - - with start_transaction(name="hi"): - with start_span(op="foo", name="bar") as span: - span.set_data("password", "secret") - span.set_data("datafoo", "databar") - - (event,) = events - assert event["spans"][0]["data"] == ApproxDict( - {"password": "[Filtered]", "datafoo": "databar"} - ) - assert event["_meta"]["spans"] == { - "0": {"data": {"password": {"": {"rem": [["!config", "s"]]}}}} - } - - def test_custom_denylist(sentry_init, capture_events): sentry_init( event_scrubber=EventScrubber( diff --git a/tests/test_sessions.py b/tests/test_sessions.py index 731b188727..7f4fdf6748 100644 --- a/tests/test_sessions.py +++ b/tests/test_sessions.py @@ -1,7 +1,7 @@ from unittest import mock import sentry_sdk -from sentry_sdk.sessions import auto_session_tracking, track_session +from sentry_sdk.sessions import track_session def sorted_aggregates(item): @@ -83,47 +83,6 @@ def test_aggregates(sentry_init, capture_envelopes): assert aggregates[0]["errored"] == 1 -def test_aggregates_deprecated( - sentry_init, capture_envelopes, suppress_deprecation_warnings -): - sentry_init( - release="fun-release", - environment="not-fun-env", - ) - envelopes = capture_envelopes() - - with auto_session_tracking(session_mode="request"): - with sentry_sdk.new_scope() as scope: - try: - scope.set_user({"id": "42"}) - raise Exception("all is wrong") - except Exception: - sentry_sdk.capture_exception() - - with auto_session_tracking(session_mode="request"): - pass - - sentry_sdk.get_isolation_scope().start_session(session_mode="request") - sentry_sdk.get_isolation_scope().end_session() - sentry_sdk.flush() - - assert len(envelopes) == 2 - assert envelopes[0].get_event() is not None - - sess = envelopes[1] - assert len(sess.items) == 1 - sess_event = sess.items[0].payload.json - assert sess_event["attrs"] == { - "release": "fun-release", - "environment": "not-fun-env", - } - - aggregates = sorted_aggregates(sess_event) - assert len(aggregates) == 1 - assert aggregates[0]["exited"] == 2 - assert aggregates[0]["errored"] == 1 - - def test_aggregates_explicitly_disabled_session_tracking_request_mode( sentry_init, capture_envelopes ): @@ -157,38 +116,6 @@ def test_aggregates_explicitly_disabled_session_tracking_request_mode( assert "errored" not in aggregates[0] -def test_aggregates_explicitly_disabled_session_tracking_request_mode_deprecated( - sentry_init, capture_envelopes, suppress_deprecation_warnings -): - sentry_init( - release="fun-release", environment="not-fun-env", auto_session_tracking=False - ) - envelopes = capture_envelopes() - - with auto_session_tracking(session_mode="request"): - with sentry_sdk.new_scope(): - try: - raise Exception("all is wrong") - except Exception: - sentry_sdk.capture_exception() - - with auto_session_tracking(session_mode="request"): - pass - - sentry_sdk.get_isolation_scope().start_session(session_mode="request") - sentry_sdk.get_isolation_scope().end_session() - sentry_sdk.flush() - - sess = envelopes[1] - assert len(sess.items) == 1 - sess_event = sess.items[0].payload.json - - aggregates = sorted_aggregates(sess_event) - assert len(aggregates) == 1 - assert aggregates[0]["exited"] == 1 - assert "errored" not in aggregates[0] - - def test_no_thread_on_shutdown_no_errors(sentry_init): sentry_init( release="fun-release", @@ -218,36 +145,6 @@ def test_no_thread_on_shutdown_no_errors(sentry_init): # If we reach this point without error, the test is successful. -def test_no_thread_on_shutdown_no_errors_deprecated( - sentry_init, suppress_deprecation_warnings -): - sentry_init( - release="fun-release", - environment="not-fun-env", - ) - - # make it seem like the interpreter is shutting down - with mock.patch( - "threading.Thread.start", - side_effect=RuntimeError("can't create new thread at interpreter shutdown"), - ): - with auto_session_tracking(session_mode="request"): - with sentry_sdk.new_scope(): - try: - raise Exception("all is wrong") - except Exception: - sentry_sdk.capture_exception() - - with auto_session_tracking(session_mode="request"): - pass - - sentry_sdk.get_isolation_scope().start_session(session_mode="request") - sentry_sdk.get_isolation_scope().end_session() - sentry_sdk.flush() - - # If we reach this point without error, the test is successful. - - def test_top_level_start_session_basic(sentry_init, capture_envelopes): """Test that top-level start_session starts a session on the isolation scope.""" sentry_init(release="test-release", environment="test-env") diff --git a/tests/test_shadowed_module.py b/tests/test_shadowed_module.py index 29b88d242c..858e937241 100644 --- a/tests/test_shadowed_module.py +++ b/tests/test_shadowed_module.py @@ -65,9 +65,6 @@ def find_unrecognized_dependencies(tree): return unrecognized_dependencies -@pytest.mark.skipif( - sys.version_info < (3, 7), reason="asyncpg imports __future__.annotations" -) def test_shadowed_modules_when_importing_integrations( sentry_init, integration_submodule_name ): diff --git a/tests/test_transport.py b/tests/test_transport.py index 3db95c06f6..a21ff3b1e2 100644 --- a/tests/test_transport.py +++ b/tests/test_transport.py @@ -4,7 +4,6 @@ import pickle import socket import sys -from collections import defaultdict from datetime import datetime, timedelta, timezone from unittest import mock @@ -29,20 +28,17 @@ import sentry_sdk from sentry_sdk import ( Client, - Hub, add_breadcrumb, capture_message, - get_isolation_scope, isolation_scope, ) from sentry_sdk._compat import PY37, PY38 from sentry_sdk.envelope import Envelope, Item, PayloadRef, parse_json from sentry_sdk.integrations.asyncio import AsyncioIntegration -from sentry_sdk.integrations.logging import LoggingIntegration, ignore_logger +from sentry_sdk.integrations.logging import LoggingIntegration, ignore_logger_for_events from sentry_sdk.transport import ( KEEP_ALIVE_SOCKET_OPTIONS, AsyncHttpTransport, - HttpTransport, _parse_rate_limits, ) @@ -96,19 +92,6 @@ def inner(**kwargs): return inner -def mock_transaction_envelope(span_count: int) -> "Envelope": - event = defaultdict( - mock.MagicMock, - type="transaction", - spans=[mock.MagicMock() for _ in range(span_count)], - ) - - envelope = Envelope() - envelope.add_transaction(event) - - return envelope - - # The compression-relevant dimensions (level x algo x http2) are fully # crossed; debug, flush method and pickling are rotated through the cases # so every value of every dimension is still exercised. @@ -404,15 +387,15 @@ def test_transport_infinite_loop(capturing_server, request, make_client): client = make_client( debug=True, # Make sure we cannot create events from our own logging - integrations=[LoggingIntegration(event_level=logging.DEBUG)], + integrations=[LoggingIntegration(event_level=logging.DEBUG, level=None)], ) # I am not sure why, but "werkzeug" logger makes an INFO log on sending - # the message "hi" and does creates an infinite look. + # the message "hi" and does creates an infinite loop. # Ignoring this for breaking the infinite loop and still we can test # that our own log messages (sent from `_IGNORED_LOGGERS`) are not leading # to an infinite loop - ignore_logger("werkzeug") + ignore_logger_for_events("werkzeug") sentry_sdk.get_global_scope().set_client(client) with isolation_scope(): @@ -478,24 +461,17 @@ def test_envelope_too_large_response(capturing_server, make_client): capturing_server.respond_with(code=413) client.capture_event({"type": "error"}) - client.capture_event({"type": "transaction"}) client.flush() - # Error, transaction, and client report payloads - assert len(capturing_server.captured) == 3 - report = parse_json(capturing_server.captured[2].envelope.items[0].get_bytes()) + # Error and client report payloads + assert len(capturing_server.captured) == 2 + report = parse_json(capturing_server.captured[-1].envelope.items[0].get_bytes()) - # Client reports for error, transaction and included span - assert len(report["discarded_events"]) == 3 + # Client report for error + assert len(report["discarded_events"]) == 1 assert {"reason": "send_error", "category": "error", "quantity": 1} in report[ "discarded_events" ] - assert {"reason": "send_error", "category": "span", "quantity": 1} in report[ - "discarded_events" - ] - assert {"reason": "send_error", "category": "transaction", "quantity": 1} in report[ - "discarded_events" - ] capturing_server.clear_captured() @@ -504,7 +480,7 @@ def test_simple_rate_limits(capturing_server, make_client): client = make_client() capturing_server.respond_with(code=429, headers={"Retry-After": "4"}) - client.capture_event({"type": "transaction"}) + client.capture_event({"type": "error"}) client.flush() assert len(capturing_server.captured) == 1 @@ -513,7 +489,7 @@ def test_simple_rate_limits(capturing_server, make_client): assert set(client.transport._disabled_until) == set([None]) - client.capture_event({"type": "transaction"}) + client.capture_event({"type": "error"}) client.capture_event({"type": "event"}) client.flush() @@ -537,20 +513,32 @@ def record_lost_event(reason, data_category=None, item=None): capturing_server.respond_with( code=response_code, - headers={"X-Sentry-Rate-Limits": "4711:transaction:organization"}, + headers={"X-Sentry-Rate-Limits": "4711:session:organization"}, ) - client.capture_event({"type": "transaction"}) + session_envelope = Envelope() + session_envelope.add_item( + Item(payload=PayloadRef(json={"sid": "123"}), type="session") + ) + client.transport.capture_envelope(session_envelope) client.flush() assert len(capturing_server.captured) == 1 assert capturing_server.captured[0].path == "/api/132/envelope/" capturing_server.clear_captured() - assert set(client.transport._disabled_until) == set(["transaction"]) + assert set(client.transport._disabled_until) == set(["session"]) - client.capture_event({"type": "transaction"}) - client.capture_event({"type": "transaction"}) + session_envelope = Envelope() + session_envelope.add_item( + Item(payload=PayloadRef(json={"sid": "456"}), type="session") + ) + client.transport.capture_envelope(session_envelope) + session_envelope = Envelope() + session_envelope.add_item( + Item(payload=PayloadRef(json={"sid": "789"}), type="session") + ) + client.transport.capture_envelope(session_envelope) client.flush() assert not capturing_server.captured @@ -562,8 +550,8 @@ def record_lost_event(reason, data_category=None, item=None): assert capturing_server.captured[0].path == "/api/132/envelope/" assert captured_outcomes == [ - ("ratelimit_backoff", "transaction"), - ("ratelimit_backoff", "transaction"), + ("ratelimit_backoff", "session"), + ("ratelimit_backoff", "session"), ] @@ -576,7 +564,7 @@ def test_data_category_limits_reporting( capturing_server.respond_with( code=response_code, headers={ - "X-Sentry-Rate-Limits": "4711:transaction:organization, 4711:attachment:organization" + "X-Sentry-Rate-Limits": "4711:session:organization, 4711:attachment:organization" }, ) @@ -593,17 +581,29 @@ def intercepting_fetch(*args, **kwargs): # get rid of threading making things hard to track monkeypatch.setattr(client.transport._worker, "submit", lambda x: x() or True) - client.capture_event({"type": "transaction"}) + session_envelope = Envelope() + session_envelope.add_item( + Item(payload=PayloadRef(json={"sid": "123"}), type="session") + ) + client.transport.capture_envelope(session_envelope) client.flush() assert len(capturing_server.captured) == 1 assert capturing_server.captured[0].path == "/api/132/envelope/" capturing_server.clear_captured() - assert set(client.transport._disabled_until) == set(["attachment", "transaction"]) + assert set(client.transport._disabled_until) == set(["attachment", "session"]) - client.capture_event({"type": "transaction"}) - client.capture_event({"type": "transaction"}) + session_envelope = Envelope() + session_envelope.add_item( + Item(payload=PayloadRef(json={"sid": "456"}), type="session") + ) + client.transport.capture_envelope(session_envelope) + session_envelope = Envelope() + session_envelope.add_item( + Item(payload=PayloadRef(json={"sid": "789"}), type="session") + ) + client.transport.capture_envelope(session_envelope) capturing_server.clear_captured() # flush out the events but don't flush the client reports @@ -611,15 +611,13 @@ def intercepting_fetch(*args, **kwargs): client.transport._last_client_report_sent = 0 outcomes_enabled = True - scope = get_isolation_scope() - scope.add_attachment(bytes=b"Hello World", filename="hello.txt") - client.capture_event({"type": "error"}, scope=scope) + with isolation_scope() as scope: + scope.add_attachment(bytes=b"Hello World", filename="hello.txt") + client.capture_event({"type": "error"}, scope=scope) client.flush() - # this goes out with an extra envelope because it's flushed after the last item - # that is normally in the queue. This is quite funny in a way because it means - # that the envelope that caused its own over quota report (an error with an - # attachment) will include its outcome since it's pending. + # the error goes through (not rate-limited), attachment is dropped; + # the client report piggybacks on the error envelope assert len(capturing_server.captured) == 1 envelope = capturing_server.captured[0].envelope assert envelope.items[0].type == "event" @@ -628,14 +626,9 @@ def intercepting_fetch(*args, **kwargs): discarded_events = report["discarded_events"] - assert len(discarded_events) == 3 - assert { - "category": "transaction", - "reason": "ratelimit_backoff", - "quantity": 2, - } in discarded_events + assert len(discarded_events) == 2 assert { - "category": "span", + "category": "session", "reason": "ratelimit_backoff", "quantity": 2, } in discarded_events @@ -647,8 +640,12 @@ def intercepting_fetch(*args, **kwargs): capturing_server.clear_captured() - # here we sent a normal event - client.capture_event({"type": "transaction"}) + # send a session (dropped) and a normal error (goes through) + session_envelope = Envelope() + session_envelope.add_item( + Item(payload=PayloadRef(json={"sid": "000"}), type="session") + ) + client.transport.capture_envelope(session_envelope) client.capture_event({"type": "error", "release": "foo"}) client.flush() @@ -664,14 +661,9 @@ def intercepting_fetch(*args, **kwargs): report = parse_json(envelope.items[0].get_bytes()) discarded_events = report["discarded_events"] - assert len(discarded_events) == 2 - assert { - "category": "transaction", - "reason": "ratelimit_backoff", - "quantity": 1, - } in discarded_events + assert len(discarded_events) == 1 assert { - "category": "span", + "category": "session", "reason": "ratelimit_backoff", "quantity": 1, } in discarded_events @@ -829,14 +821,11 @@ def test_log_item_limits(capturing_server, response_code, item, make_client): assert set(client.transport._disabled_until) == {"log_item"} client.transport.capture_envelope(envelope) - client.capture_event({"type": "transaction"}) client.flush() - assert len(capturing_server.captured) == 2 + assert len(capturing_server.captured) == 1 envelope = capturing_server.captured[0].envelope - assert envelope.items[0].type == "transaction" - envelope = capturing_server.captured[1].envelope assert envelope.items[0].type == "client_report" report = parse_json(envelope.items[0].get_bytes()) @@ -857,24 +846,6 @@ def test_log_item_limits(capturing_server, response_code, item, make_client): } in report["discarded_events"] -def test_hub_cls_backwards_compat(): - class TestCustomHubClass(Hub): - pass - - transport = HttpTransport( - defaultdict(lambda: None, {"dsn": "https://123abc@example.com/123"}) - ) - - with pytest.deprecated_call(): - assert transport.hub_cls is Hub - - with pytest.deprecated_call(): - transport.hub_cls = TestCustomHubClass - - with pytest.deprecated_call(): - assert transport.hub_cls is TestCustomHubClass - - @pytest.mark.parametrize("quantity", (1, 2, 10)) def test_record_lost_event_quantity(capturing_server, make_client, quantity): client = make_client() @@ -896,41 +867,6 @@ def test_record_lost_event_quantity(capturing_server, make_client, quantity): ] -@pytest.mark.parametrize("span_count", (0, 1, 2, 10)) -def test_record_lost_event_transaction_item(capturing_server, make_client, span_count): - client = make_client() - transport = client.transport - - envelope = mock_transaction_envelope(span_count) - (transaction_item,) = envelope.items - - transport.record_lost_event(reason="test", item=transaction_item) - client.flush() - - (captured,) = capturing_server.captured # Should only be one envelope - envelope = captured.envelope - (item,) = envelope.items # Envelope should only have one item - - assert item.type == "client_report" - - report = parse_json(item.get_bytes()) - discarded_events = report["discarded_events"] - - assert len(discarded_events) == 2 - - assert { - "category": "transaction", - "reason": "test", - "quantity": 1, - } in discarded_events - - assert { - "category": "span", - "reason": "test", - "quantity": span_count + 1, - } in discarded_events - - @skip_under_gevent @pytest.mark.asyncio @pytest.mark.parametrize( diff --git a/tests/test_utils.py b/tests/test_utils.py index 2be8698640..d9fa6a0276 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -115,20 +115,6 @@ def test_datetime_from_isoformat(input_str, expected_output): assert datetime_from_isoformat(input_str) == expected_output, input_str -@pytest.mark.parametrize( - ("input_str", "expected_output"), - isoformat_inputs_and_datetime_outputs, -) -def test_datetime_from_isoformat_with_py_36_or_lower(input_str, expected_output): - """ - `fromisoformat` was added in Python version 3.7 - """ - with mock.patch("sentry_sdk.utils.datetime") as datetime_mocked: - datetime_mocked.fromisoformat.side_effect = AttributeError() - datetime_mocked.strptime = datetime.strptime - assert datetime_from_isoformat(input_str) == expected_output, input_str - - @pytest.mark.parametrize( "env_var_value,strict,expected", [ diff --git a/tests/tracing/test_conversation_id.py b/tests/tracing/test_conversation_id.py index 44d3d5221d..72cc553e08 100644 --- a/tests/tracing/test_conversation_id.py +++ b/tests/tracing/test_conversation_id.py @@ -1,40 +1,18 @@ -import pytest - import sentry_sdk -from sentry_sdk import start_span def test_conversation_id_propagates_to_span_with_gen_ai_operation_name( - sentry_init, capture_events -): - """Span with gen_ai.operation.name data should get conversation_id.""" - sentry_init(traces_sample_rate=1.0) - events = capture_events() - - scope = sentry_sdk.get_current_scope() - scope.set_conversation_id("conv-op-name-test") - - with sentry_sdk.start_transaction(name="test-tx"): - with start_span(op="http.client") as span: - span.set_data("gen_ai.operation.name", "chat") - - (event,) = events - span_data = event["spans"][0]["data"] - assert span_data.get("gen_ai.conversation.id") == "conv-op-name-test" - - -def test_conversation_id_propagates_to_span_with_gen_ai_operation_name_span_streaming( sentry_init, capture_items ): """Span with gen_ai.operation.name attribute should get conversation_id.""" - sentry_init(traces_sample_rate=1.0, trace_lifecycle="stream") + sentry_init(traces_sample_rate=1.0) items = capture_items("span") scope = sentry_sdk.get_current_scope() scope.set_conversation_id("conv-op-name-test") - with sentry_sdk.traces.start_span(name="test-sg"): - with sentry_sdk.traces.start_span( + with sentry_sdk.start_span(name="test-sg"): + with sentry_sdk.start_span( name="client", attributes={"sentry.op": "http.client"} ) as span: span.set_attribute("gen_ai.operation.name", "chat") @@ -49,35 +27,16 @@ def test_conversation_id_propagates_to_span_with_gen_ai_operation_name_span_stre assert "gen_ai.conversation.id" not in segment["attributes"] -def test_conversation_id_propagates_to_span_with_ai_op(sentry_init, capture_events): +def test_conversation_id_propagates_to_span_with_ai_op(sentry_init, capture_items): """Span with ai.* op should get conversation_id.""" sentry_init(traces_sample_rate=1.0) - events = capture_events() - - scope = sentry_sdk.get_current_scope() - scope.set_conversation_id("conv-ai-op-test") - - with sentry_sdk.start_transaction(name="test-tx"): - with start_span(op="ai.chat.completions"): - pass - - (event,) = events - span_data = event["spans"][0]["data"] - assert span_data.get("gen_ai.conversation.id") == "conv-ai-op-test" - - -def test_conversation_id_propagates_to_span_with_ai_op_span_streaming( - sentry_init, capture_items -): - """Span with ai.* op should get conversation_id.""" - sentry_init(traces_sample_rate=1.0, trace_lifecycle="stream") items = capture_items("span") scope = sentry_sdk.get_current_scope() scope.set_conversation_id("conv-ai-op-test") - with sentry_sdk.traces.start_span(name="test-tx"): - with sentry_sdk.traces.start_span( + with sentry_sdk.start_span(name="test-tx"): + with sentry_sdk.start_span( name="completion", attributes={"sentry.op": "ai.chat.completions"} ): pass @@ -92,52 +51,13 @@ def test_conversation_id_propagates_to_span_with_ai_op_span_streaming( assert "gen_ai.conversation.id" not in segment["attributes"] -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) def test_conversation_id_propagates_to_span_with_gen_ai_op( - sentry_init, capture_events, capture_items, stream_gen_ai_spans -): - """Span with gen_ai.* op should get conversation_id.""" - sentry_init( - traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - ) - - if stream_gen_ai_spans: - items = capture_items("span") - - scope = sentry_sdk.get_current_scope() - scope.set_conversation_id("conv-gen-ai-op-test") - - with sentry_sdk.start_transaction(name="test-tx"): - with start_span(op="gen_ai.invoke_agent"): - pass - - spans = [item.payload for item in items] - span_data = spans[0]["attributes"] - else: - events = capture_events() - - scope = sentry_sdk.get_current_scope() - scope.set_conversation_id("conv-gen-ai-op-test") - - with sentry_sdk.start_transaction(name="test-tx"): - with start_span(op="gen_ai.invoke_agent"): - pass - - (event,) = events - span_data = event["spans"][0]["data"] - - assert span_data.get("gen_ai.conversation.id") == "conv-gen-ai-op-test" - - -def test_conversation_id_propagates_to_span_with_gen_ai_op_span_streaming( sentry_init, capture_items, ): """Span with gen_ai.* op should get conversation_id.""" sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream", ) items = capture_items("span") @@ -145,8 +65,8 @@ def test_conversation_id_propagates_to_span_with_gen_ai_op_span_streaming( scope = sentry_sdk.get_current_scope() scope.set_conversation_id("conv-gen-ai-op-test") - with sentry_sdk.traces.start_span(name="test-tx"): - with sentry_sdk.traces.start_span( + with sentry_sdk.start_span(name="test-tx"): + with sentry_sdk.start_span( name="invoke", attributes={"sentry.op": "gen_ai.invoke_agent"} ): pass @@ -159,35 +79,16 @@ def test_conversation_id_propagates_to_span_with_gen_ai_op_span_streaming( assert "gen_ai.conversation.id" not in segment["attributes"] -def test_conversation_id_not_propagated_to_non_ai_span(sentry_init, capture_events): +def test_conversation_id_not_propagated_to_non_ai_span(sentry_init, capture_items): """Non-AI span should NOT get conversation_id.""" sentry_init(traces_sample_rate=1.0) - events = capture_events() - - scope = sentry_sdk.get_current_scope() - scope.set_conversation_id("conv-should-not-appear") - - with sentry_sdk.start_transaction(name="test-tx"): - with start_span(op="http.client") as span: - span.set_data("some.other.data", "value") - - (event,) = events - span_data = event["spans"][0]["data"] - assert "gen_ai.conversation.id" not in span_data - - -def test_conversation_id_not_propagated_to_non_ai_span_span_streaming( - sentry_init, capture_items -): - """Non-AI span should NOT get conversation_id.""" - sentry_init(traces_sample_rate=1.0, trace_lifecycle="stream") items = capture_items("span") scope = sentry_sdk.get_current_scope() scope.set_conversation_id("conv-should-not-appear") - with sentry_sdk.traces.start_span(name="test-sg"): - with sentry_sdk.traces.start_span( + with sentry_sdk.start_span(name="test-sg"): + with sentry_sdk.start_span( name="client", attributes={"sentry.op": "http.client"} ) as span: span.set_attribute("some.other.data", "value") @@ -202,36 +103,16 @@ def test_conversation_id_not_propagated_to_non_ai_span_span_streaming( assert "gen_ai.conversation.id" not in segment["attributes"] -def test_conversation_id_not_propagated_when_not_set(sentry_init, capture_events): +def test_conversation_id_not_propagated_when_not_set(sentry_init, capture_items): """AI span should not have conversation_id if not set on scope.""" sentry_init(traces_sample_rate=1.0) - events = capture_events() - - # Ensure no conversation_id is set - scope = sentry_sdk.get_current_scope() - scope.remove_conversation_id() - - with sentry_sdk.start_transaction(name="test-tx"): - with start_span(op="ai.chat.completions"): - pass - - (event,) = events - span_data = event["spans"][0]["data"] - assert "gen_ai.conversation.id" not in span_data - - -def test_conversation_id_not_propagated_when_not_set_span_streaming( - sentry_init, capture_items -): - """AI span should not have conversation_id if not set on scope.""" - sentry_init(traces_sample_rate=1.0, trace_lifecycle="stream") items = capture_items("span") scope = sentry_sdk.get_current_scope() scope.remove_conversation_id() - with sentry_sdk.traces.start_span(name="test-sg"): - with sentry_sdk.traces.start_span( + with sentry_sdk.start_span(name="test-sg"): + with sentry_sdk.start_span( name="completion", attributes={"sentry.op": "ai.chat.completions"} ): pass @@ -246,35 +127,16 @@ def test_conversation_id_not_propagated_when_not_set_span_streaming( assert "gen_ai.conversation.id" not in segment["attributes"] -def test_conversation_id_not_propagated_to_span_without_op(sentry_init, capture_events): +def test_conversation_id_not_propagated_to_span_without_op(sentry_init, capture_items): """Span without op and without gen_ai.operation.name should NOT get conversation_id.""" sentry_init(traces_sample_rate=1.0) - events = capture_events() - - scope = sentry_sdk.get_current_scope() - scope.set_conversation_id("conv-no-op-test") - - with sentry_sdk.start_transaction(name="test-tx"): - with start_span(name="unnamed-span") as span: - span.set_data("regular.data", "value") - - (event,) = events - span_data = event["spans"][0]["data"] - assert "gen_ai.conversation.id" not in span_data - - -def test_conversation_id_not_propagated_to_span_without_op_span_streaming( - sentry_init, capture_items -): - """Span without op and without gen_ai.operation.name should NOT get conversation_id.""" - sentry_init(traces_sample_rate=1.0, trace_lifecycle="stream") items = capture_items("span") scope = sentry_sdk.get_current_scope() scope.set_conversation_id("conv-no-op-test") - with sentry_sdk.traces.start_span(name="test-sg"): - with sentry_sdk.traces.start_span(name="unnamed-span") as span: + with sentry_sdk.start_span(name="test-sg"): + with sentry_sdk.start_span(name="unnamed-span") as span: span.set_attribute("regular.data", "value") sentry_sdk.flush() @@ -288,36 +150,17 @@ def test_conversation_id_not_propagated_to_span_without_op_span_streaming( def test_conversation_id_propagates_with_gen_ai_operation_name_no_op( - sentry_init, capture_events -): - """Span with gen_ai.operation.name but no op should still get conversation_id.""" - sentry_init(traces_sample_rate=1.0) - events = capture_events() - - scope = sentry_sdk.get_current_scope() - scope.set_conversation_id("conv-no-op-but-data-test") - - with sentry_sdk.start_transaction(name="test-tx"): - with start_span(name="unnamed-span") as span: - span.set_data("gen_ai.operation.name", "embedding") - - (event,) = events - span_data = event["spans"][0]["data"] - assert span_data.get("gen_ai.conversation.id") == "conv-no-op-but-data-test" - - -def test_conversation_id_propagates_with_gen_ai_operation_name_no_op_span_streaming( sentry_init, capture_items ): """Span with gen_ai.operation.name but no op should still get conversation_id.""" - sentry_init(traces_sample_rate=1.0, trace_lifecycle="stream") + sentry_init(traces_sample_rate=1.0) items = capture_items("span") scope = sentry_sdk.get_current_scope() scope.set_conversation_id("conv-no-op-but-data-test") - with sentry_sdk.traces.start_span(name="test-sg"): - with sentry_sdk.traces.start_span(name="unnamed-span") as span: + with sentry_sdk.start_span(name="test-sg"): + with sentry_sdk.start_span(name="unnamed-span") as span: span.set_attribute("gen_ai.operation.name", "embedding") sentry_sdk.flush() @@ -332,35 +175,15 @@ def test_conversation_id_propagates_with_gen_ai_operation_name_no_op_span_stream assert "gen_ai.conversation.id" not in segment["attributes"] -def test_conversation_id_propagates_to_transaction_with_ai_op( - sentry_init, capture_events -): - """Transaction with ai.* op should get conversation_id.""" - sentry_init(traces_sample_rate=1.0) - events = capture_events() - - scope = sentry_sdk.get_current_scope() - scope.set_conversation_id("conv-tx-ai-op-test") - - with sentry_sdk.start_transaction(op="ai.workflow", name="AI Workflow"): - pass - - (event,) = events - trace_data = event["contexts"]["trace"]["data"] - assert trace_data.get("gen_ai.conversation.id") == "conv-tx-ai-op-test" - - -def test_conversation_id_propagates_to_segment_with_ai_op_span_streaming( - sentry_init, capture_items -): +def test_conversation_id_propagates_to_segment_with_ai_op(sentry_init, capture_items): """Segment with ai.* op should get conversation_id.""" - sentry_init(traces_sample_rate=1.0, trace_lifecycle="stream") + sentry_init(traces_sample_rate=1.0) items = capture_items("span") scope = sentry_sdk.get_current_scope() scope.set_conversation_id("conv-tx-ai-op-test") - with sentry_sdk.traces.start_span( + with sentry_sdk.start_span( name="AI Workflow", attributes={"sentry.op": "ai.workflow"} ): pass @@ -371,35 +194,15 @@ def test_conversation_id_propagates_to_segment_with_ai_op_span_streaming( assert segment["attributes"].get("gen_ai.conversation.id") == "conv-tx-ai-op-test" -def test_conversation_id_not_propagated_to_non_ai_transaction( - sentry_init, capture_events -): - """Non-AI transaction should NOT get conversation_id.""" - sentry_init(traces_sample_rate=1.0) - events = capture_events() - - scope = sentry_sdk.get_current_scope() - scope.set_conversation_id("conv-tx-should-not-appear") - - with sentry_sdk.start_transaction(op="http.server", name="HTTP Request"): - pass - - (event,) = events - trace_data = event["contexts"]["trace"]["data"] - assert "gen_ai.conversation.id" not in trace_data - - -def test_conversation_id_not_propagated_to_non_ai_segment_span_streaming( - sentry_init, capture_items -): +def test_conversation_id_not_propagated_to_non_ai_segment(sentry_init, capture_items): """Non-AI segment should NOT get conversation_id.""" - sentry_init(traces_sample_rate=1.0, trace_lifecycle="stream") + sentry_init(traces_sample_rate=1.0) items = capture_items("span") scope = sentry_sdk.get_current_scope() scope.set_conversation_id("conv-tx-should-not-appear") - with sentry_sdk.traces.start_span( + with sentry_sdk.start_span( name="HTTP Request", attributes={"sentry.op": "http.server"} ): pass diff --git a/tests/tracing/test_decorator.py b/tests/tracing/test_decorator.py index e315b6f1ca..4b9d107845 100644 --- a/tests/tracing/test_decorator.py +++ b/tests/tracing/test_decorator.py @@ -1,13 +1,8 @@ import inspect -from unittest import mock import pytest import sentry_sdk -from sentry_sdk.consts import SPANTEMPLATE -from sentry_sdk.tracing_utils import create_span_decorator -from sentry_sdk.utils import logger -from tests.conftest import patch_start_tracing_child def my_example_function(): @@ -18,82 +13,14 @@ async def my_async_example_function(): return "return_of_async_function" -@pytest.mark.forked -def test_trace_decorator(): - with patch_start_tracing_child() as fake_start_child: - result = my_example_function() - fake_start_child.assert_not_called() - assert result == "return_of_sync_function" - - start_child_span_decorator = create_span_decorator() - result2 = start_child_span_decorator(my_example_function)() - fake_start_child.assert_called_once_with( - op="function", name="test_decorator.my_example_function" - ) - assert result2 == "return_of_sync_function" - - -def test_trace_decorator_no_trx(): - with patch_start_tracing_child(fake_transaction_is_none=True): - with mock.patch.object(logger, "debug", mock.Mock()) as fake_debug: - result = my_example_function() - fake_debug.assert_not_called() - assert result == "return_of_sync_function" - - start_child_span_decorator = create_span_decorator() - result2 = start_child_span_decorator(my_example_function)() - fake_debug.assert_called_once_with( - "Cannot create a child span for %s. " - "Please start a Sentry transaction before calling this function.", - "test_decorator.my_example_function", - ) - assert result2 == "return_of_sync_function" - - -@pytest.mark.forked -@pytest.mark.asyncio -async def test_trace_decorator_async(): - with patch_start_tracing_child() as fake_start_child: - result = await my_async_example_function() - fake_start_child.assert_not_called() - assert result == "return_of_async_function" - - start_child_span_decorator = create_span_decorator() - result2 = await start_child_span_decorator(my_async_example_function)() - fake_start_child.assert_called_once_with( - op="function", - name="test_decorator.my_async_example_function", - ) - assert result2 == "return_of_async_function" - - -@pytest.mark.asyncio -async def test_trace_decorator_async_no_trx(): - with patch_start_tracing_child(fake_transaction_is_none=True): - with mock.patch.object(logger, "debug", mock.Mock()) as fake_debug: - result = await my_async_example_function() - fake_debug.assert_not_called() - assert result == "return_of_async_function" - - start_child_span_decorator = create_span_decorator() - result2 = await start_child_span_decorator(my_async_example_function)() - fake_debug.assert_any_call( - "Cannot create a child span for %s. " - "Please start a Sentry transaction before calling this function.", - "test_decorator.my_async_example_function", - ) - assert result2 == "return_of_async_function" - - -def test_trace_decorator_span_streaming(sentry_init, capture_items): +def test_trace_decorator(sentry_init, capture_items): sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream", ) items = capture_items("span") - @sentry_sdk.traces.trace + @sentry_sdk.trace def traced_function(): return "ok" @@ -107,22 +34,20 @@ def traced_function(): (span,) = spans assert ( - span["name"] - == "test_decorator.test_trace_decorator_span_streaming..traced_function" + span["name"] == "test_decorator.test_trace_decorator..traced_function" ) assert span["attributes"]["sentry.op"] == "function" assert span["status"] == "ok" -def test_trace_decorator_arguments_span_streaming(sentry_init, capture_items): +def test_trace_decorator_arguments(sentry_init, capture_items): sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream", ) items = capture_items("span") - @sentry_sdk.traces.trace(name="traced", attributes={"traced.attribute": 123}) + @sentry_sdk.trace(name="traced", attributes={"traced.attribute": 123}) def traced_function(): return "ok" @@ -141,17 +66,16 @@ def traced_function(): assert span["status"] == "ok" -def test_trace_decorator_inactive_span_streaming(sentry_init, capture_items): +def test_trace_decorator_inactive(sentry_init, capture_items): sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream", ) items = capture_items("span") - @sentry_sdk.traces.trace(name="outer", active=False) + @sentry_sdk.trace(name="outer", active=False) def traced_function(): - with sentry_sdk.traces.start_span(name="inner"): + with sentry_sdk.start_span(name="inner"): return "ok" result = traced_function() @@ -170,15 +94,14 @@ def traced_function(): @pytest.mark.asyncio -async def test_trace_decorator_async_span_streaming(sentry_init, capture_items): +async def test_trace_decorator_async(sentry_init, capture_items): sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream", ) items = capture_items("span") - @sentry_sdk.traces.trace + @sentry_sdk.trace async def traced_function(): return "ok" @@ -193,24 +116,21 @@ async def traced_function(): assert ( span["name"] - == "test_decorator.test_trace_decorator_async_span_streaming..traced_function" + == "test_decorator.test_trace_decorator_async..traced_function" ) assert span["attributes"]["sentry.op"] == "function" assert span["status"] == "ok" @pytest.mark.asyncio -async def test_trace_decorator_async_arguments_span_streaming( - sentry_init, capture_items -): +async def test_trace_decorator_async_arguments(sentry_init, capture_items): sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream", ) items = capture_items("span") - @sentry_sdk.traces.trace(name="traced", attributes={"traced.attribute": 123}) + @sentry_sdk.trace(name="traced", attributes={"traced.attribute": 123}) async def traced_function(): return "ok" @@ -230,19 +150,16 @@ async def traced_function(): @pytest.mark.asyncio -async def test_trace_decorator_async_inactive_span_streaming( - sentry_init, capture_items -): +async def test_trace_decorator_async_inactive(sentry_init, capture_items): sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream", ) items = capture_items("span") - @sentry_sdk.traces.trace(name="outer", active=False) + @sentry_sdk.trace(name="outer", active=False) async def traced_function(): - with sentry_sdk.traces.start_span(name="inner"): + with sentry_sdk.start_span(name="inner"): return "ok" result = await traced_function() @@ -260,20 +177,19 @@ async def traced_function(): assert span2["name"] == "outer" -def test_trace_decorator_child_span_streaming(sentry_init, capture_items): +def test_trace_decorator_child(sentry_init, capture_items): """Spans created with @trace show up as children if a span is active.""" sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream", ) items = capture_items("span") - @sentry_sdk.traces.trace + @sentry_sdk.trace def _some_function_traced_stream(a, b, c): return True - with sentry_sdk.traces.start_span(name="segment") as segment: + with sentry_sdk.start_span(name="segment") as segment: result = _some_function_traced_stream(1, 2, 3) assert result is True @@ -285,7 +201,7 @@ def _some_function_traced_stream(a, b, c): assert ( child_span["name"] - == "test_decorator.test_trace_decorator_child_span_streaming.._some_function_traced_stream" + == "test_decorator.test_trace_decorator_child.._some_function_traced_stream" ) assert child_span["parent_span_id"] == segment.span_id assert segment_span["name"] == "segment" @@ -293,20 +209,19 @@ def _some_function_traced_stream(a, b, c): @pytest.mark.asyncio -async def test_trace_decorator_async_child_span_streaming(sentry_init, capture_items): +async def test_trace_decorator_async_child(sentry_init, capture_items): """Spans created with @trace show up as children if a span is active.""" sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream", ) items = capture_items("span") - @sentry_sdk.traces.trace + @sentry_sdk.trace async def _some_function_traced_stream(a, b, c): return True - with sentry_sdk.traces.start_span(name="segment") as segment: + with sentry_sdk.start_span(name="segment") as segment: result = await _some_function_traced_stream(1, 2, 3) assert result is True @@ -318,7 +233,7 @@ async def _some_function_traced_stream(a, b, c): assert ( child_span["name"] - == "test_decorator.test_trace_decorator_async_child_span_streaming.._some_function_traced_stream" + == "test_decorator.test_trace_decorator_async_child.._some_function_traced_stream" ) assert child_span["parent_span_id"] == segment.span_id assert segment_span["name"] == "segment" @@ -334,17 +249,9 @@ def _some_function(a, b, c): pass @sentry_sdk.trace - def _some_function_traced(a, b, c): - pass - - @sentry_sdk.traces.trace def _some_function_traced_stream(a, b, c): pass - assert inspect.getcallargs(_some_function, 1, 2, 3) == inspect.getcallargs( - _some_function_traced, 1, 2, 3 - ) - assert inspect.getcallargs(_some_function, 1, 2, 3) == inspect.getcallargs( _some_function_traced_stream, 1, 2, 3 ) @@ -360,564 +267,9 @@ async def _some_function(a, b, c): pass @sentry_sdk.trace - async def _some_function_traced(a, b, c): - pass - - @sentry_sdk.traces.trace async def _some_function_traced_stream(a, b, c): pass - assert inspect.getcallargs(_some_function, 1, 2, 3) == inspect.getcallargs( - _some_function_traced, 1, 2, 3 - ) assert inspect.getcallargs(_some_function, 1, 2, 3) == inspect.getcallargs( _some_function_traced_stream, 1, 2, 3 ) - - -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) -def test_span_templates_ai_dicts( - sentry_init, - capture_events, - capture_items, - stream_gen_ai_spans, -): - @sentry_sdk.trace(template=SPANTEMPLATE.AI_TOOL) - def my_tool(arg1, arg2): - return { - "output": "my_tool_result", - "usage": { - "prompt_tokens": 10, - "completion_tokens": 20, - "total_tokens": 30, - }, - } - - @sentry_sdk.trace(template=SPANTEMPLATE.AI_CHAT) - def my_chat(model=None, **kwargs): - return { - "content": "my_chat_result", - "usage": { - "input_tokens": 11, - "output_tokens": 22, - "total_tokens": 33, - }, - "model": f"{model}-v123", - } - - @sentry_sdk.trace(template=SPANTEMPLATE.AI_AGENT) - def my_agent(): - my_tool(1, 2) - my_chat( - model="my-gpt-4o-mini", - prompt="What is the weather in Tokyo?", - system_prompt="You are a helpful assistant that can answer questions about the weather.", - max_tokens=100, - temperature=0.5, - top_p=0.9, - top_k=40, - frequency_penalty=1.0, - presence_penalty=2.0, - ) - - if stream_gen_ai_spans: - sentry_init( - traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - ) - items = capture_items("span") - - with sentry_sdk.start_transaction(name="test-transaction"): - my_agent() - - (agent_span, tool_span, chat_span) = (item.payload for item in items) - - assert ( - agent_span["name"] - == "invoke_agent test_decorator.test_span_templates_ai_dicts..my_agent" - ) - assert agent_span["attributes"] == { - "gen_ai.agent.name": "test_decorator.test_span_templates_ai_dicts..my_agent", - "gen_ai.operation.name": "invoke_agent", - "process.runtime.name": mock.ANY, - "process.runtime.version": mock.ANY, - "sentry.environment": "production", - "sentry.op": "gen_ai.invoke_agent", - "sentry.origin": "manual", - "sentry.release": mock.ANY, - "sentry.sdk.name": "sentry.python", - "sentry.sdk.version": mock.ANY, - "sentry.segment.id": mock.ANY, - "sentry.segment.name": "test-transaction", - "server.address": mock.ANY, - "thread.id": mock.ANY, - "thread.name": mock.ANY, - } - - assert ( - tool_span["name"] - == "execute_tool test_decorator.test_span_templates_ai_dicts..my_tool" - ) - assert tool_span["attributes"] == { - "gen_ai.tool.name": "test_decorator.test_span_templates_ai_dicts..my_tool", - "gen_ai.operation.name": "execute_tool", - "gen_ai.usage.input_tokens": 10, - "gen_ai.usage.output_tokens": 20, - "gen_ai.usage.total_tokens": 30, - "process.runtime.name": mock.ANY, - "process.runtime.version": mock.ANY, - "sentry.environment": "production", - "sentry.op": "gen_ai.execute_tool", - "sentry.origin": "manual", - "sentry.release": mock.ANY, - "sentry.sdk.name": "sentry.python", - "sentry.sdk.version": mock.ANY, - "sentry.segment.id": mock.ANY, - "sentry.segment.name": "test-transaction", - "server.address": mock.ANY, - "thread.id": mock.ANY, - "thread.name": mock.ANY, - } - assert "gen_ai.tool.description" not in tool_span["attributes"] - - assert chat_span["name"] == "chat my-gpt-4o-mini" - assert chat_span["attributes"] == { - "gen_ai.operation.name": "chat", - "gen_ai.request.frequency_penalty": 1.0, - "gen_ai.request.max_tokens": 100, - "gen_ai.request.messages": "[{'role': 'user', 'content': 'What is the weather in Tokyo?'}, {'role': 'system', 'content': 'You are a helpful assistant that can answer questions about the weather.'}]", - "gen_ai.request.model": "my-gpt-4o-mini", - "gen_ai.request.presence_penalty": 2.0, - "gen_ai.request.temperature": 0.5, - "gen_ai.request.top_k": 40, - "gen_ai.request.top_p": 0.9, - "gen_ai.response.model": "my-gpt-4o-mini-v123", - "gen_ai.usage.input_tokens": 11, - "gen_ai.usage.output_tokens": 22, - "gen_ai.usage.total_tokens": 33, - "process.runtime.name": mock.ANY, - "process.runtime.version": mock.ANY, - "sentry.environment": "production", - "sentry.op": "gen_ai.chat", - "sentry.origin": "manual", - "sentry.release": mock.ANY, - "sentry.sdk.name": "sentry.python", - "sentry.sdk.version": mock.ANY, - "sentry.segment.id": mock.ANY, - "sentry.segment.name": "test-transaction", - "server.address": mock.ANY, - "thread.id": mock.ANY, - "thread.name": mock.ANY, - } - else: - sentry_init( - traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - ) - events = capture_events() - - with sentry_sdk.start_transaction(name="test-transaction"): - my_agent() - - (event,) = events - (agent_span, tool_span, chat_span) = event["spans"] - - assert agent_span["op"] == "gen_ai.invoke_agent" - assert ( - agent_span["description"] - == "invoke_agent test_decorator.test_span_templates_ai_dicts..my_agent" - ) - assert agent_span["data"] == { - "gen_ai.agent.name": "test_decorator.test_span_templates_ai_dicts..my_agent", - "gen_ai.operation.name": "invoke_agent", - "thread.id": mock.ANY, - "thread.name": mock.ANY, - } - - assert tool_span["op"] == "gen_ai.execute_tool" - assert ( - tool_span["description"] - == "execute_tool test_decorator.test_span_templates_ai_dicts..my_tool" - ) - assert tool_span["data"] == { - "gen_ai.tool.name": "test_decorator.test_span_templates_ai_dicts..my_tool", - "gen_ai.operation.name": "execute_tool", - "gen_ai.usage.input_tokens": 10, - "gen_ai.usage.output_tokens": 20, - "gen_ai.usage.total_tokens": 30, - "thread.id": mock.ANY, - "thread.name": mock.ANY, - } - assert "gen_ai.tool.description" not in tool_span["data"] - - assert chat_span["op"] == "gen_ai.chat" - assert chat_span["description"] == "chat my-gpt-4o-mini" - assert chat_span["data"] == { - "gen_ai.operation.name": "chat", - "gen_ai.request.frequency_penalty": 1.0, - "gen_ai.request.max_tokens": 100, - "gen_ai.request.messages": "[{'role': 'user', 'content': 'What is the weather in Tokyo?'}, {'role': 'system', 'content': 'You are a helpful assistant that can answer questions about the weather.'}]", - "gen_ai.request.model": "my-gpt-4o-mini", - "gen_ai.request.presence_penalty": 2.0, - "gen_ai.request.temperature": 0.5, - "gen_ai.request.top_k": 40, - "gen_ai.request.top_p": 0.9, - "gen_ai.response.model": "my-gpt-4o-mini-v123", - "gen_ai.usage.input_tokens": 11, - "gen_ai.usage.output_tokens": 22, - "gen_ai.usage.total_tokens": 33, - "thread.id": mock.ANY, - "thread.name": mock.ANY, - } - - -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) -def test_span_templates_ai_objects( - sentry_init, - capture_events, - capture_items, - stream_gen_ai_spans, -): - @sentry_sdk.trace(template=SPANTEMPLATE.AI_TOOL) - def my_tool(arg1, arg2): - """This is a tool function.""" - mock_usage = mock.Mock() - mock_usage.prompt_tokens = 10 - mock_usage.completion_tokens = 20 - mock_usage.total_tokens = 30 - - mock_result = mock.Mock() - mock_result.output = "my_tool_result" - mock_result.usage = mock_usage - - return mock_result - - @sentry_sdk.trace(template=SPANTEMPLATE.AI_CHAT) - def my_chat(model=None, **kwargs): - mock_result = mock.Mock() - mock_result.content = "my_chat_result" - mock_result.usage = mock.Mock( - input_tokens=11, - output_tokens=22, - total_tokens=33, - ) - mock_result.model = f"{model}-v123" - - return mock_result - - @sentry_sdk.trace(template=SPANTEMPLATE.AI_AGENT) - def my_agent(): - my_tool(1, 2) - my_chat( - model="my-gpt-4o-mini", - prompt="What is the weather in Tokyo?", - system_prompt="You are a helpful assistant that can answer questions about the weather.", - max_tokens=100, - temperature=0.5, - top_p=0.9, - top_k=40, - frequency_penalty=1.0, - presence_penalty=2.0, - ) - - sentry_init( - traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - ) - - if stream_gen_ai_spans: - items = capture_items("span") - - with sentry_sdk.start_transaction(name="test-transaction"): - my_agent() - - (agent_span, tool_span, chat_span) = (item.payload for item in items) - - assert ( - agent_span["name"] - == "invoke_agent test_decorator.test_span_templates_ai_objects..my_agent" - ) - assert agent_span["attributes"] == { - "gen_ai.agent.name": "test_decorator.test_span_templates_ai_objects..my_agent", - "gen_ai.operation.name": "invoke_agent", - "process.runtime.name": mock.ANY, - "process.runtime.version": mock.ANY, - "sentry.environment": "production", - "sentry.op": "gen_ai.invoke_agent", - "sentry.origin": "manual", - "sentry.release": mock.ANY, - "sentry.sdk.name": "sentry.python", - "sentry.sdk.version": mock.ANY, - "sentry.segment.id": mock.ANY, - "sentry.segment.name": "test-transaction", - "server.address": mock.ANY, - "thread.id": mock.ANY, - "thread.name": mock.ANY, - } - - assert ( - tool_span["name"] - == "execute_tool test_decorator.test_span_templates_ai_objects..my_tool" - ) - assert tool_span["attributes"] == { - "gen_ai.tool.name": "test_decorator.test_span_templates_ai_objects..my_tool", - "gen_ai.tool.description": "This is a tool function.", - "gen_ai.operation.name": "execute_tool", - "gen_ai.usage.input_tokens": 10, - "gen_ai.usage.output_tokens": 20, - "gen_ai.usage.total_tokens": 30, - "process.runtime.name": mock.ANY, - "process.runtime.version": mock.ANY, - "sentry.environment": "production", - "sentry.op": "gen_ai.execute_tool", - "sentry.origin": "manual", - "sentry.release": mock.ANY, - "sentry.sdk.name": "sentry.python", - "sentry.sdk.version": mock.ANY, - "sentry.segment.id": mock.ANY, - "sentry.segment.name": "test-transaction", - "server.address": mock.ANY, - "thread.id": mock.ANY, - "thread.name": mock.ANY, - } - - assert chat_span["name"] == "chat my-gpt-4o-mini" - assert chat_span["attributes"] == { - "gen_ai.operation.name": "chat", - "gen_ai.request.frequency_penalty": 1.0, - "gen_ai.request.max_tokens": 100, - "gen_ai.request.messages": "[{'role': 'user', 'content': 'What is the weather in Tokyo?'}, {'role': 'system', 'content': 'You are a helpful assistant that can answer questions about the weather.'}]", - "gen_ai.request.model": "my-gpt-4o-mini", - "gen_ai.request.presence_penalty": 2.0, - "gen_ai.request.temperature": 0.5, - "gen_ai.request.top_k": 40, - "gen_ai.request.top_p": 0.9, - "gen_ai.response.model": "my-gpt-4o-mini-v123", - "gen_ai.usage.input_tokens": 11, - "gen_ai.usage.output_tokens": 22, - "gen_ai.usage.total_tokens": 33, - "process.runtime.name": mock.ANY, - "process.runtime.version": mock.ANY, - "sentry.environment": "production", - "sentry.op": "gen_ai.chat", - "sentry.origin": "manual", - "sentry.release": mock.ANY, - "sentry.sdk.name": "sentry.python", - "sentry.sdk.version": mock.ANY, - "sentry.segment.id": mock.ANY, - "sentry.segment.name": "test-transaction", - "server.address": mock.ANY, - "thread.id": mock.ANY, - "thread.name": mock.ANY, - } - else: - events = capture_events() - - with sentry_sdk.start_transaction(name="test-transaction"): - my_agent() - - (event,) = events - (agent_span, tool_span, chat_span) = event["spans"] - - assert agent_span["op"] == "gen_ai.invoke_agent" - assert ( - agent_span["description"] - == "invoke_agent test_decorator.test_span_templates_ai_objects..my_agent" - ) - assert agent_span["data"] == { - "gen_ai.agent.name": "test_decorator.test_span_templates_ai_objects..my_agent", - "gen_ai.operation.name": "invoke_agent", - "thread.id": mock.ANY, - "thread.name": mock.ANY, - } - - assert tool_span["op"] == "gen_ai.execute_tool" - assert ( - tool_span["description"] - == "execute_tool test_decorator.test_span_templates_ai_objects..my_tool" - ) - assert tool_span["data"] == { - "gen_ai.tool.name": "test_decorator.test_span_templates_ai_objects..my_tool", - "gen_ai.tool.description": "This is a tool function.", - "gen_ai.operation.name": "execute_tool", - "gen_ai.usage.input_tokens": 10, - "gen_ai.usage.output_tokens": 20, - "gen_ai.usage.total_tokens": 30, - "thread.id": mock.ANY, - "thread.name": mock.ANY, - } - - assert chat_span["op"] == "gen_ai.chat" - assert chat_span["description"] == "chat my-gpt-4o-mini" - assert chat_span["data"] == { - "gen_ai.operation.name": "chat", - "gen_ai.request.frequency_penalty": 1.0, - "gen_ai.request.max_tokens": 100, - "gen_ai.request.messages": "[{'role': 'user', 'content': 'What is the weather in Tokyo?'}, {'role': 'system', 'content': 'You are a helpful assistant that can answer questions about the weather.'}]", - "gen_ai.request.model": "my-gpt-4o-mini", - "gen_ai.request.presence_penalty": 2.0, - "gen_ai.request.temperature": 0.5, - "gen_ai.request.top_k": 40, - "gen_ai.request.top_p": 0.9, - "gen_ai.response.model": "my-gpt-4o-mini-v123", - "gen_ai.usage.input_tokens": 11, - "gen_ai.usage.output_tokens": 22, - "gen_ai.usage.total_tokens": 33, - "thread.id": mock.ANY, - "thread.name": mock.ANY, - } - - -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) -@pytest.mark.parametrize("send_default_pii", [True, False]) -def test_span_templates_ai_pii( - sentry_init, - capture_events, - capture_items, - send_default_pii, - stream_gen_ai_spans, -): - @sentry_sdk.trace(template=SPANTEMPLATE.AI_TOOL) - def my_tool(arg1, arg2, **kwargs): - """This is a tool function.""" - return "tool_output" - - @sentry_sdk.trace(template=SPANTEMPLATE.AI_CHAT) - def my_chat(model=None, **kwargs): - return "chat_output" - - @sentry_sdk.trace(template=SPANTEMPLATE.AI_AGENT) - def my_agent(*args, **kwargs): - my_tool(1, 2, tool_arg1="3", tool_arg2="4") - my_chat( - model="my-gpt-4o-mini", - prompt="What is the weather in Tokyo?", - system_prompt="You are a helpful assistant that can answer questions about the weather.", - max_tokens=100, - temperature=0.5, - top_p=0.9, - top_k=40, - frequency_penalty=1.0, - presence_penalty=2.0, - ) - return "agent_output" - - sentry_init( - traces_sample_rate=1.0, - send_default_pii=send_default_pii, - stream_gen_ai_spans=stream_gen_ai_spans, - ) - - if stream_gen_ai_spans: - items = capture_items("span") - - with sentry_sdk.start_transaction(name="test-transaction"): - my_agent(22, 33, arg1=44, arg2=55) - - (_, tool_span, chat_span) = (item.payload for item in items) - tool_data = tool_span["attributes"] - chat_data = chat_span["attributes"] - else: - events = capture_events() - - with sentry_sdk.start_transaction(name="test-transaction"): - my_agent(22, 33, arg1=44, arg2=55) - - (event,) = events - (_, tool_span, chat_span) = event["spans"] - tool_data = tool_span["data"] - chat_data = chat_span["data"] - - if send_default_pii: - assert ( - tool_data["gen_ai.tool.input"] - == "{'args': (1, 2), 'kwargs': {'tool_arg1': '3', 'tool_arg2': '4'}}" - ) - assert tool_data["gen_ai.tool.output"] == "'tool_output'" - else: - assert "gen_ai.tool.input" not in tool_data - assert "gen_ai.tool.output" not in tool_data - - # Without `data_collection`, prompts are recorded regardless of `send_default_pii`. - assert chat_data["gen_ai.request.messages"] == ( - "[{'role': 'user', 'content': 'What is the weather in Tokyo?'}, " - "{'role': 'system', 'content': 'You are a helpful assistant that can answer " - "questions about the weather.'}]" - ) - - -@pytest.mark.parametrize("stream_gen_ai_spans", [True, False]) -@pytest.mark.parametrize("collect_outputs", [True, False]) -@pytest.mark.parametrize("collect_inputs", [True, False]) -def test_span_templates_ai_data_collection( - sentry_init, - capture_events, - capture_items, - collect_inputs, - collect_outputs, - stream_gen_ai_spans, -): - @sentry_sdk.trace(template=SPANTEMPLATE.AI_TOOL) - def my_tool(arg1, arg2, **kwargs): - """This is a tool function.""" - return "tool_output" - - @sentry_sdk.trace(template=SPANTEMPLATE.AI_CHAT) - def my_chat(model=None, **kwargs): - return "chat_output" - - @sentry_sdk.trace(template=SPANTEMPLATE.AI_AGENT) - def my_agent(*args, **kwargs): - my_tool(1, 2, tool_arg1="3", tool_arg2="4") - my_chat( - model="my-gpt-4o-mini", - prompt="What is the weather in Tokyo?", - system_prompt="You are a helpful assistant.", - ) - return "agent_output" - - sentry_init( - traces_sample_rate=1.0, - stream_gen_ai_spans=stream_gen_ai_spans, - data_collection={ - "gen_ai": {"inputs": collect_inputs, "outputs": collect_outputs} - }, - ) - - if stream_gen_ai_spans: - items = capture_items("span") - - with sentry_sdk.start_transaction(name="test-transaction"): - my_agent(22, 33, arg1=44, arg2=55) - - (_, tool_span, chat_span) = (item.payload for item in items) - tool_data = tool_span["attributes"] - chat_data = chat_span["attributes"] - else: - events = capture_events() - - with sentry_sdk.start_transaction(name="test-transaction"): - my_agent(22, 33, arg1=44, arg2=55) - - (event,) = events - (_, tool_span, chat_span) = event["spans"] - tool_data = tool_span["data"] - chat_data = chat_span["data"] - - if collect_inputs: - assert ( - tool_data["gen_ai.tool.input"] - == "{'args': (1, 2), 'kwargs': {'tool_arg1': '3', 'tool_arg2': '4'}}" - ) - assert chat_data["gen_ai.request.messages"] == ( - "[{'role': 'user', 'content': 'What is the weather in Tokyo?'}, " - "{'role': 'system', 'content': 'You are a helpful assistant.'}]" - ) - else: - assert "gen_ai.tool.input" not in tool_data - assert "gen_ai.request.messages" not in chat_data - - if collect_outputs: - assert tool_data["gen_ai.tool.output"] == "'tool_output'" - else: - assert "gen_ai.tool.output" not in tool_data diff --git a/tests/tracing/test_deprecated.py b/tests/tracing/test_deprecated.py deleted file mode 100644 index f030a465ff..0000000000 --- a/tests/tracing/test_deprecated.py +++ /dev/null @@ -1,38 +0,0 @@ -import warnings - -import pytest - -import sentry_sdk -import sentry_sdk.tracing - - -@pytest.mark.parametrize( - "parameter_value_getter", - # Use lambda to avoid Hub deprecation warning here (will suppress it in the test) - (lambda: sentry_sdk.Hub(), lambda: sentry_sdk.Scope()), -) -def test_passing_hub_parameter_to_transaction_finish( - suppress_deprecation_warnings, parameter_value_getter -): - parameter_value = parameter_value_getter() - transaction = sentry_sdk.tracing.Transaction() - with pytest.warns(DeprecationWarning): - transaction.finish(hub=parameter_value) - - -def test_passing_hub_object_to_scope_transaction_finish(suppress_deprecation_warnings): - transaction = sentry_sdk.tracing.Transaction() - - # Do not move the following line under the `with` statement. Otherwise, the Hub.__init__ deprecation - # warning will be confused with the transaction.finish deprecation warning that we are testing. - hub = sentry_sdk.Hub() - - with pytest.warns(DeprecationWarning): - transaction.finish(hub) - - -def test_no_warnings_scope_to_transaction_finish(): - transaction = sentry_sdk.tracing.Transaction() - with warnings.catch_warnings(): - warnings.simplefilter("error") - transaction.finish(sentry_sdk.Scope()) diff --git a/tests/tracing/test_http_headers.py b/tests/tracing/test_http_headers.py index 818c934fc2..7fa8edbf44 100644 --- a/tests/tracing/test_http_headers.py +++ b/tests/tracing/test_http_headers.py @@ -3,39 +3,17 @@ import pytest import sentry_sdk -from sentry_sdk.traces import StreamedSpan -from sentry_sdk.tracing import Transaction +from sentry_sdk.traces import Span from sentry_sdk.tracing_utils import extract_sentrytrace_data -@pytest.mark.parametrize("sampled", [True, False, None]) -def test_to_traceparent(sampled): - transaction = Transaction( - name="/interactions/other-dogs/new-dog", - op="greeting.sniff", - trace_id="12312012123120121231201212312012", - sampled=sampled, - ) - - traceparent = transaction.to_traceparent() - - parts = traceparent.split("-") - assert parts[0] == "12312012123120121231201212312012" # trace_id - assert parts[1] == transaction.span_id # parent_span_id - if sampled is None: - assert len(parts) == 2 - else: - assert parts[2] == "1" if sampled is True else "0" # sampled - - @pytest.mark.parametrize("traces_sample_rate", [1.0, 0.0, None]) -def test_to_traceparent_span_streaming(sentry_init, traces_sample_rate): +def test_to_traceparent(sentry_init, traces_sample_rate): sentry_init( traces_sample_rate=traces_sample_rate, - trace_lifecycle="stream", ) - with sentry_sdk.traces.start_span(name="/interactions/other-dogs/new-dog") as span: + with sentry_sdk.start_span(name="/interactions/other-dogs/new-dog") as span: traceparent = sentry_sdk.get_traceparent() parts = traceparent.split("-") @@ -88,36 +66,17 @@ def test_sentrytrace_extraction_leading_empty_fragment(): } -def test_iter_headers(monkeypatch): - monkeypatch.setattr( - Transaction, - "to_traceparent", - mock.Mock(return_value="12312012123120121231201212312012-0415201309082013-0"), - ) - - transaction = Transaction( - name="/interactions/other-dogs/new-dog", - op="greeting.sniff", - ) - - headers = dict(transaction.iter_headers()) - assert ( - headers["sentry-trace"] == "12312012123120121231201212312012-0415201309082013-0" - ) - - -def test_iter_headers_span_streaming(sentry_init, monkeypatch): +def test_iter_headers(sentry_init, monkeypatch): sentry_init( traces_sample_rate=0.0, - trace_lifecycle="stream", ) monkeypatch.setattr( - StreamedSpan, + Span, "_to_traceparent", mock.Mock(return_value="12312012123120121231201212312012-0415201309082013-0"), ) - with sentry_sdk.traces.start_span(name="/interactions/other-dogs/new-dog") as span: + with sentry_sdk.start_span(name="/interactions/other-dogs/new-dog") as span: headers = dict(span._iter_headers()) assert ( headers["sentry-trace"] diff --git a/tests/tracing/test_ignore_status_codes.py b/tests/tracing/test_ignore_status_codes.py deleted file mode 100644 index fdad1a1e46..0000000000 --- a/tests/tracing/test_ignore_status_codes.py +++ /dev/null @@ -1,139 +0,0 @@ -from collections import Counter - -import pytest - -import sentry_sdk -from sentry_sdk import start_span, start_transaction - - -def test_no_ignored_codes(sentry_init, capture_events): - sentry_init( - traces_sample_rate=1.0, - ) - events = capture_events() - - with start_transaction(op="http", name="GET /"): - span_or_tx = sentry_sdk.get_current_span() - span_or_tx.set_data("http.response.status_code", 404) - - assert len(events) == 1 - - -@pytest.mark.parametrize("status_code", [200, 404]) -def test_single_code_ignored(sentry_init, capture_events, status_code): - sentry_init( - traces_sample_rate=1.0, - trace_ignore_status_codes={ - 404, - }, - ) - events = capture_events() - - with start_transaction(op="http", name="GET /"): - span_or_tx = sentry_sdk.get_current_span() - span_or_tx.set_data("http.response.status_code", status_code) - - if status_code == 404: - assert not events - else: - assert len(events) == 1 - - -@pytest.mark.parametrize("status_code", [200, 305, 307, 399, 404]) -def test_range_ignored(sentry_init, capture_events, status_code): - sentry_init( - traces_sample_rate=1.0, - trace_ignore_status_codes=set( - range( - 305, - 400, - ), - ), - ) - events = capture_events() - - with start_transaction(op="http", name="GET /"): - span_or_tx = sentry_sdk.get_current_span() - span_or_tx.set_data("http.response.status_code", status_code) - - if 305 <= status_code <= 399: - assert not events - else: - assert len(events) == 1 - - -@pytest.mark.parametrize("status_code", [200, 301, 303, 355, 404]) -def test_variety_ignored(sentry_init, capture_events, status_code): - sentry_init( - traces_sample_rate=1.0, - trace_ignore_status_codes={ - 301, - 302, - 303, - *range( - 305, - 400, - ), - *range( - 401, - 405, - ), - }, - ) - events = capture_events() - - with start_transaction(op="http", name="GET /"): - span_or_tx = sentry_sdk.get_current_span() - span_or_tx.set_data("http.response.status_code", status_code) - - if ( - 301 <= status_code <= 303 - or 305 <= status_code <= 399 - or 401 <= status_code <= 404 - ): - assert not events - else: - assert len(events) == 1 - - -def test_transaction_not_ignored_when_status_code_has_invalid_type( - sentry_init, capture_events -): - sentry_init( - traces_sample_rate=1.0, - trace_ignore_status_codes=set( - range(401, 404), - ), - ) - events = capture_events() - - with start_transaction(op="http", name="GET /"): - span_or_tx = sentry_sdk.get_current_span() - span_or_tx.set_data("http.response.status_code", "404") - - assert len(events) == 1 - - -def test_records_lost_events(sentry_init, capture_record_lost_event_calls): - sentry_init( - traces_sample_rate=1.0, - trace_ignore_status_codes={ - 404, - }, - ) - record_lost_event_calls = capture_record_lost_event_calls() - - with start_transaction(op="http", name="GET /"): - span_or_tx = sentry_sdk.get_current_span() - span_or_tx.set_data("http.response.status_code", 404) - - with start_span(op="child-span"): - with start_span(op="child-child-span"): - pass - - assert Counter(record_lost_event_calls) == Counter( - [ - ("event_processor", "transaction", None, 1), - ("event_processor", "span", None, 3), - ] - ) diff --git a/tests/tracing/test_integration_tests.py b/tests/tracing/test_integration_tests.py index 59bb1f9d02..555ce40c29 100644 --- a/tests/tracing/test_integration_tests.py +++ b/tests/tracing/test_integration_tests.py @@ -7,66 +7,22 @@ import pytest import sentry_sdk -from sentry_sdk import ( - capture_message, - continue_trace, - start_span, - start_transaction, -) -from sentry_sdk.consts import SPANSTATUS +from sentry_sdk import capture_message from sentry_sdk.transport import Transport from tests.conftest import TestTransportWithOptions @pytest.mark.parametrize("sample_rate", [0.0, 1.0]) -def test_basic(sentry_init, capture_events, sample_rate): +def test_basic(sentry_init, capture_items, sample_rate): sentry_init(traces_sample_rate=sample_rate) - events = capture_events() - - with start_transaction(name="hi") as transaction: - transaction.set_status(SPANSTATUS.OK) - with pytest.raises(ZeroDivisionError): - with start_span(op="foo", name="foodesc"): - 1 / 0 - - with start_span(op="bar", name="bardesc"): - pass - - if sample_rate: - assert len(events) == 1 - event = events[0] - - assert event["transaction"] == "hi" - assert event["transaction_info"]["source"] == "custom" - - span1, span2 = event["spans"] - parent_span = event - assert span1["status"] == "internal_error" - assert span1["tags"]["status"] == "internal_error" - assert span1["op"] == "foo" - assert span1["description"] == "foodesc" - assert "status" not in span2 - assert "status" not in span2.get("tags", {}) - assert span2["op"] == "bar" - assert span2["description"] == "bardesc" - assert parent_span["transaction"] == "hi" - assert "status" not in event["tags"] - assert event["contexts"]["trace"]["status"] == "ok" - else: - assert not events - - -@pytest.mark.parametrize("sample_rate", [0.0, 1.0]) -def test_basic_span_streaming(sentry_init, capture_items, sample_rate): - sentry_init(traces_sample_rate=sample_rate, trace_lifecycle="stream") items = capture_items() - with sentry_sdk.traces.start_span(name="hi"): + with sentry_sdk.start_span(name="hi"): with pytest.raises(ZeroDivisionError): - with sentry_sdk.traces.start_span(name="foo"): + with sentry_sdk.start_span(name="foo"): 1 / 0 - with sentry_sdk.traces.start_span(name="bar"): + with sentry_sdk.start_span(name="bar"): pass sentry_sdk.flush() @@ -91,13 +47,11 @@ def test_basic_span_streaming(sentry_init, capture_items, sample_rate): assert not items -def test_error_event_linked_without_performance_span_streaming( - sentry_init, capture_items -): - sentry_init(traces_sample_rate=None, trace_lifecycle="stream") +def test_error_event_linked_without_performance(sentry_init, capture_items): + sentry_init(traces_sample_rate=None) items = capture_items("event") - with sentry_sdk.traces.start_span( + with sentry_sdk.start_span( name="no-op span", attributes={"sentry.segment.name.source": "custom segment source"}, ): @@ -112,111 +66,13 @@ def test_error_event_linked_without_performance_span_streaming( @pytest.mark.parametrize("parent_sampled", [True, False, None]) @pytest.mark.parametrize("sample_rate", [0.0, 1.0]) -def test_continue_trace(sentry_init, capture_envelopes, parent_sampled, sample_rate): - """ - Ensure data is actually passed along via headers, and that they are read - correctly. - """ - sentry_init(traces_sample_rate=sample_rate) - envelopes = capture_envelopes() - - # make a parent transaction (normally this would be in a different service) - with start_transaction(name="hi", sampled=True if sample_rate == 0 else None): - with start_span() as old_span: - old_span.sampled = parent_sampled - headers = dict( - sentry_sdk.get_current_scope().iter_trace_propagation_headers(old_span) - ) - headers["baggage"] = ( - "other-vendor-value-1=foo;bar;baz, " - "sentry-trace_id=771a43a4192642f0b136d5159a501700, " - "sentry-public_key=49d0f7386ad645858ae85020e393bef3, " - "sentry-sample_rate=0.01337, sentry-user_id=Amelie, " - "sentry-sample_rand=0.250000, " - "other-vendor-value-2=foo;bar;" - ) - - # child transaction, to prove that we can read 'sentry-trace' header data correctly - child_transaction = continue_trace(headers, name="WRONG") - assert child_transaction is not None - assert child_transaction.parent_sampled == parent_sampled - assert child_transaction.trace_id == old_span.trace_id - assert child_transaction.same_process_as_parent is False - assert child_transaction.parent_span_id == old_span.span_id - assert child_transaction.span_id != old_span.span_id - - baggage = child_transaction._baggage - assert baggage - assert not baggage.mutable - assert baggage.sentry_items == { - "public_key": "49d0f7386ad645858ae85020e393bef3", - "trace_id": "771a43a4192642f0b136d5159a501700", - "user_id": "Amelie", - "sample_rand": "0.250000", - "sample_rate": "0.01337", - } - - # add child transaction to the scope, to show that the captured message will - # be tagged with the trace id (since it happens while the transaction is - # open) - with start_transaction(child_transaction): - # change the transaction name from "WRONG" to make sure the change - # is reflected in the final data - sentry_sdk.get_current_scope().transaction = "ho" - capture_message("hello") - - if parent_sampled is False or (sample_rate == 0 and parent_sampled is None): - # in this case the child transaction won't be captured - trace1, message = envelopes - message_payload = message.get_event() - trace1_payload = trace1.get_transaction_event() - - assert trace1_payload["transaction"] == "hi" - else: - trace1, message, trace2 = envelopes - trace1_payload = trace1.get_transaction_event() - message_payload = message.get_event() - trace2_payload = trace2.get_transaction_event() - - assert trace1_payload["transaction"] == "hi" - assert trace2_payload["transaction"] == "ho" - - assert ( - trace1_payload["contexts"]["trace"]["trace_id"] - == trace2_payload["contexts"]["trace"]["trace_id"] - == child_transaction.trace_id - == message_payload["contexts"]["trace"]["trace_id"] - ) - - if parent_sampled is not None: - expected_sample_rate = str(float(parent_sampled)) - else: - expected_sample_rate = str(sample_rate) - - assert trace2.headers["trace"] == baggage.dynamic_sampling_context() - assert trace2.headers["trace"] == { - "public_key": "49d0f7386ad645858ae85020e393bef3", - "trace_id": "771a43a4192642f0b136d5159a501700", - "user_id": "Amelie", - "sample_rand": "0.250000", - "sample_rate": expected_sample_rate, - } - - assert message_payload["message"] == "hello" - - -@pytest.mark.parametrize("parent_sampled", [True, False, None]) -@pytest.mark.parametrize("sample_rate", [0.0, 1.0]) -def test_continue_trace_span_streaming( - sentry_init, capture_items, parent_sampled, sample_rate -): +def test_continue_trace(sentry_init, capture_items, parent_sampled, sample_rate): """ Ensure data is actually passed along via headers, and that they are read correctly. """ sentry_init( traces_sample_rate=sample_rate, - trace_lifecycle="stream", ) items = capture_items() @@ -247,10 +103,10 @@ def test_continue_trace_span_streaming( ), } - sentry_sdk.traces.continue_trace(headers) + sentry_sdk.continue_trace(headers) # child segment, to prove that we can read 'sentry-trace' header data correctly - with sentry_sdk.traces.start_span(name="WRONG") as child_segment: + with sentry_sdk.start_span(name="WRONG") as child_segment: assert child_segment is not None assert child_segment._parent_sampled == parent_sampled assert child_segment.trace_id == trace_id @@ -330,99 +186,24 @@ def test_continue_trace_span_streaming( assert message_payload["message"] == "hello" -@pytest.mark.parametrize("sample_rate", [0.0, 1.0]) -def test_propagate_traces_deprecation_warning(sentry_init, sample_rate): - sentry_init(traces_sample_rate=sample_rate, propagate_traces=False) - - with start_transaction(name="hi"): - with start_span() as old_span: - with pytest.warns(DeprecationWarning): - dict( - sentry_sdk.get_current_scope().iter_trace_propagation_headers( - old_span - ) - ) - - @pytest.mark.parametrize("sample_rate", [0.5, 1.0]) def test_dynamic_sampling_head_sdk_creates_dsc( sentry_init, capture_envelopes, sample_rate, monkeypatch -): - sentry_init(traces_sample_rate=sample_rate, release="foo") - envelopes = capture_envelopes() - - # make sure transaction is sampled for both cases - with mock.patch("sentry_sdk.tracing_utils.Random.randrange", return_value=250000): - transaction = continue_trace({}, name="Head SDK tx") - - baggage = transaction._baggage - assert baggage is None - - with start_transaction(transaction): - with start_span(op="foo", name="foodesc"): - pass - - # finish will create a new baggage entry - baggage = transaction._baggage - trace_id = transaction.trace_id - - assert baggage - assert not baggage.mutable - assert baggage.third_party_items == "" - assert baggage.sentry_items == { - "environment": "production", - "release": "foo", - "sample_rate": str(sample_rate), - "sampled": "true" if transaction.sampled else "false", - "sample_rand": "0.250000", - "transaction": "Head SDK tx", - "trace_id": trace_id, - } - - expected_baggage = ( - "sentry-trace_id=%s," - "sentry-sample_rand=0.250000," - "sentry-environment=production," - "sentry-release=foo," - "sentry-transaction=Head%%20SDK%%20tx," - "sentry-sample_rate=%s," - "sentry-sampled=%s" - % (trace_id, sample_rate, "true" if transaction.sampled else "false") - ) - assert baggage.serialize() == expected_baggage - - (envelope,) = envelopes - assert envelope.headers["trace"] == baggage.dynamic_sampling_context() - assert envelope.headers["trace"] == { - "environment": "production", - "release": "foo", - "sample_rate": str(sample_rate), - "sample_rand": "0.250000", - "sampled": "true" if transaction.sampled else "false", - "transaction": "Head SDK tx", - "trace_id": trace_id, - } - - -@pytest.mark.parametrize("sample_rate", [0.5, 1.0]) -def test_dynamic_sampling_head_sdk_creates_dsc_span_streaming( - sentry_init, capture_envelopes, sample_rate, monkeypatch ): sentry_init( traces_sample_rate=sample_rate, release="foo", - trace_lifecycle="stream", ) envelopes = capture_envelopes() # make sure segment is sampled for both cases with mock.patch("sentry_sdk.tracing_utils.Random.randrange", return_value=250000): - sentry_sdk.traces.new_trace() - with sentry_sdk.traces.start_span(name="Head SDK segment") as segment: + sentry_sdk.new_trace() + with sentry_sdk.start_span(name="Head SDK segment") as segment: baggage = segment._baggage assert baggage is None - with sentry_sdk.traces.start_span(name="foo"): + with sentry_sdk.start_span(name="foo"): pass sentry_sdk.flush() @@ -467,47 +248,18 @@ def test_dynamic_sampling_head_sdk_creates_dsc_span_streaming( } -@pytest.mark.parametrize( - "args,expected_refcount", - [({"traces_sample_rate": 1.0}, 100), ({"traces_sample_rate": 0.0}, 0)], -) -def test_memory_usage(sentry_init, capture_events, args, expected_refcount): - sentry_init(**args) - - references = weakref.WeakSet() - - with start_transaction(name="hi"): - for i in range(100): - with start_span(op="helloworld", name="hi {}".format(i)) as span: - - def foo(): - pass - - references.add(foo) - span.set_tag("foo", foo) - pass - - del foo - del span - - # required only for pypy (cpython frees immediately) - gc.collect() - - assert len(references) == expected_refcount - - @pytest.mark.parametrize( "args", [{"traces_sample_rate": 1.0}, {"traces_sample_rate": 0.0}], ) -def test_memory_usage_span_streaming(sentry_init, capture_events, args): - sentry_init(**args, trace_lifecycle="stream") +def test_memory_usage(sentry_init, capture_events, args): + sentry_init(**args) references = weakref.WeakSet() - with sentry_sdk.traces.start_span(name="hi"): + with sentry_sdk.start_span(name="hi"): for i in range(100): - with sentry_sdk.traces.start_span(name=f"hi {i}") as span: + with sentry_sdk.start_span(name=f"hi {i}") as span: def foo(): pass @@ -526,19 +278,6 @@ def foo(): assert len(references) == 0 -def test_transactions_do_not_go_through_before_send(sentry_init, capture_events): - def before_send(event, hint): - raise RuntimeError("should not be called") - - sentry_init(traces_sample_rate=1.0, before_send=before_send) - events = capture_events() - - with start_transaction(name="/"): - pass - - assert len(events) == 1 - - def test_segments_do_not_go_through_before_send(sentry_init, capture_items): def before_send(event, hint): raise RuntimeError("should not be called") @@ -546,11 +285,10 @@ def before_send(event, hint): sentry_init( traces_sample_rate=1.0, before_send=before_send, - trace_lifecycle="stream", ) items = capture_items() - with sentry_sdk.traces.start_span(name="/"): + with sentry_sdk.start_span(name="/"): pass sentry_sdk.flush() @@ -558,45 +296,25 @@ def before_send(event, hint): assert len(items) == 1 -def test_start_span_after_finish(sentry_init, capture_events): - class CustomTransport(Transport): - def capture_envelope(self, envelope): - pass - - def capture_event(self, event): - start_span(op="toolate", name="justdont") - pass - - sentry_init(traces_sample_rate=1, transport=CustomTransport()) - events = capture_events() - - with start_transaction(name="hi"): - with start_span(op="bar", name="bardesc"): - pass - - assert len(events) == 1 - - -def test_start_span_after_finish_span_streaming(sentry_init, capture_items): +def test_start_span_after_finish(sentry_init, capture_items): class CustomTransport(Transport): def capture_envelope(self, envelope): - with sentry_sdk.traces.start_span(name="toolate"): + with sentry_sdk.start_span(name="toolate"): pass sentry_sdk.flush() def capture_event(self, event): - with sentry_sdk.traces.start_span(name="justdont"): + with sentry_sdk.start_span(name="justdont"): pass sentry_sdk.flush() sentry_init( traces_sample_rate=1, transport=CustomTransport(), - trace_lifecycle="stream", ) items = capture_items() - with sentry_sdk.traces.start_span(name="hi"): + with sentry_sdk.start_span(name="hi"): pass sentry_sdk.flush() @@ -605,43 +323,18 @@ def capture_event(self, event): def test_trace_propagation_meta_head_sdk(sentry_init): - sentry_init(traces_sample_rate=1.0, release="foo") - - transaction = continue_trace({}, name="Head SDK tx") - meta = None - span = None - - with start_transaction(transaction): - with start_span(op="foo", name="foodesc") as current_span: - span = current_span - meta = sentry_sdk.get_current_scope().trace_propagation_meta() - - ind = meta.find(">") + 1 - sentry_trace, baggage = meta[:ind], meta[ind:] - - assert 'meta name="sentry-trace"' in sentry_trace - sentry_trace_content = re.findall('content="([^"]*)"', sentry_trace)[0] - assert sentry_trace_content == span.to_traceparent() - - assert 'meta name="baggage"' in baggage - baggage_content = re.findall('content="([^"]*)"', baggage)[0] - assert baggage_content == transaction.get_baggage().serialize() - - -def test_trace_propagation_meta_head_sdk_span_streaming(sentry_init): sentry_init( traces_sample_rate=1.0, release="foo", - trace_lifecycle="stream", ) - sentry_sdk.traces.new_trace() + sentry_sdk.new_trace() meta = None span = None - with sentry_sdk.traces.start_span(name="Head SDK segment") as segment: - with sentry_sdk.traces.start_span(name="foo") as current_span: + with sentry_sdk.start_span(name="Head SDK segment") as segment: + with sentry_sdk.start_span(name="foo") as current_span: span = current_span meta = sentry_sdk.get_current_scope().trace_propagation_meta() @@ -664,43 +357,14 @@ def test_trace_propagation_meta_head_sdk_span_streaming(sentry_init): ], ) def test_non_error_exceptions( - sentry_init, capture_events, exception_cls, exception_value -): - sentry_init(traces_sample_rate=1.0) - events = capture_events() - - with start_transaction(name="hi") as transaction: - transaction.set_status(SPANSTATUS.OK) - with pytest.raises(exception_cls): - with start_span(op="foo", name="foodesc"): - raise exception_cls(exception_value) - - assert len(events) == 1 - event = events[0] - - span = event["spans"][0] - assert "status" not in span - assert "status" not in span.get("tags", {}) - assert "status" not in event["tags"] - assert event["contexts"]["trace"]["status"] == "ok" - - -@pytest.mark.parametrize( - "exception_cls,exception_value", - [ - (SystemExit, 0), - ], -) -def test_non_error_exceptions_span_streaming( sentry_init, capture_items, exception_cls, exception_value ): - sentry_init(traces_sample_rate=1.0, trace_lifecycle="stream") + sentry_init(traces_sample_rate=1.0) items = capture_items() - with sentry_sdk.traces.start_span(name="hi") as segment: - segment.status = SPANSTATUS.OK + with sentry_sdk.start_span(name="hi"): with pytest.raises(exception_cls): - with sentry_sdk.traces.start_span(name="foo"): + with sentry_sdk.start_span(name="foo"): raise exception_cls(exception_value) sentry_sdk.flush() @@ -713,41 +377,13 @@ def test_non_error_exceptions_span_streaming( @pytest.mark.parametrize("exception_value", [None, 0, False]) -def test_good_sysexit_doesnt_fail_transaction( - sentry_init, capture_events, exception_value -): +def test_good_sysexit_doesnt_fail_segment(sentry_init, capture_items, exception_value): sentry_init(traces_sample_rate=1.0) - events = capture_events() - - with start_transaction(name="hi") as transaction: - transaction.set_status(SPANSTATUS.OK) - with pytest.raises(SystemExit): - with start_span(op="foo", name="foodesc"): - if exception_value is not False: - sys.exit(exception_value) - else: - sys.exit() - - assert len(events) == 1 - event = events[0] - - span = event["spans"][0] - assert "status" not in span - assert "status" not in span.get("tags", {}) - assert "status" not in event["tags"] - assert event["contexts"]["trace"]["status"] == "ok" - - -@pytest.mark.parametrize("exception_value", [None, 0, False]) -def test_good_sysexit_doesnt_fail_segment_span_streaming( - sentry_init, capture_items, exception_value -): - sentry_init(traces_sample_rate=1.0, trace_lifecycle="stream") items = capture_items() - with sentry_sdk.traces.start_span(name="hi"): + with sentry_sdk.start_span(name="hi"): with pytest.raises(SystemExit): - with sentry_sdk.traces.start_span(name="foo"): + with sentry_sdk.start_span(name="foo"): if exception_value is not False: sys.exit(exception_value) else: @@ -802,62 +438,9 @@ def test_continue_trace_strict_trace_continuation( ), } - transaction = continue_trace(headers, name="strict trace") + sentry_sdk.continue_trace(headers) - if should_continue_trace: - assert transaction.trace_id == "771a43a4192642f0b136d5159a501700" - assert transaction.parent_span_id == "1234567890abcdef" - assert transaction.parent_sampled - else: - assert transaction.trace_id != "771a43a4192642f0b136d5159a501700" - assert transaction.parent_span_id != "1234567890abcdef" - assert transaction.parent_sampled is None - - -@pytest.mark.parametrize( - "strict_trace_continuation,baggage_org_id,dsn_org_id,should_continue_trace", - ( - (True, "sentry-org_id=1234", "o1234", True), - (True, "sentry-org_id=1234", "o9999", False), - (True, "sentry-org_id=9999", "o1234", False), - (False, "sentry-org_id=1234", "o1234", True), - (False, "sentry-org_id=9999", "o1234", False), - (False, "sentry-org_id=1234", "o9999", False), - (False, "sentry-org_id=1234", "not_org_id", True), - (False, "", "o1234", True), - ), -) -def test_continue_trace_strict_trace_continuation_span_streaming( - sentry_init, - strict_trace_continuation, - baggage_org_id, - dsn_org_id, - should_continue_trace, -): - sentry_init( - dsn=f"https://mysecret@{dsn_org_id}.ingest.sentry.io/12312012", - strict_trace_continuation=strict_trace_continuation, - traces_sample_rate=1.0, - transport=TestTransportWithOptions, - trace_lifecycle="stream", - ) - - headers = { - "sentry-trace": "771a43a4192642f0b136d5159a501700-1234567890abcdef-1", - "baggage": ( - "other-vendor-value-1=foo;bar;baz," - "sentry-trace_id=771a43a4192642f0b136d5159a501700," - f"{baggage_org_id}," - "sentry-public_key=49d0f7386ad645858ae85020e393bef3," - "sentry-sample_rate=0.01337," - "sentry-user_id=Am%C3%A9lie," - "other-vendor-value-2=foo;bar;" - ), - } - - sentry_sdk.traces.continue_trace(headers) - - with sentry_sdk.traces.start_span(name="strict trace") as segment: + with sentry_sdk.start_span(name="strict trace") as segment: headers = sentry_sdk.get_current_scope().iter_trace_propagation_headers(segment) if should_continue_trace: @@ -871,46 +454,35 @@ def test_continue_trace_strict_trace_continuation_span_streaming( assert segment._parent_sampled is None -def test_continue_trace_forces_new_traces_when_no_propagation(sentry_init): - """This is to make sure we don't have a long running trace because of TWP logic for the no propagation case.""" - - sentry_init(traces_sample_rate=1.0) - - tx1 = continue_trace({}, name="tx1") - tx2 = continue_trace({}, name="tx2") - - assert tx1.trace_id != tx2.trace_id - - -def test_continue_trace_forces_new_traces_when_no_propagation_span_streaming( +def test_continue_trace_forces_new_traces_when_no_propagation( sentry_init, ): """This is to make sure we don't have a long running trace because of TWP logic for the no propagation case.""" - sentry_init(traces_sample_rate=1.0, trace_lifecycle="stream") + sentry_init(traces_sample_rate=1.0) - sentry_sdk.traces.continue_trace({}) - with sentry_sdk.traces.start_span(name="segment1") as segment1: + sentry_sdk.continue_trace({}) + with sentry_sdk.start_span(name="segment1") as segment1: pass - sentry_sdk.traces.continue_trace({}) - with sentry_sdk.traces.start_span(name="segment2") as segment2: + sentry_sdk.continue_trace({}) + with sentry_sdk.start_span(name="segment2") as segment2: pass assert segment1.trace_id != segment2.trace_id -def test_continue_trace_forces_new_traces_when_no_propagation_with_new_trace_span_streaming( +def test_continue_trace_forces_new_traces_when_no_propagation_with_new_trace( sentry_init, ): - sentry_init(traces_sample_rate=1.0, trace_lifecycle="stream") + sentry_init(traces_sample_rate=1.0) - sentry_sdk.traces.new_trace() - with sentry_sdk.traces.start_span(name="segment1") as segment1: + sentry_sdk.new_trace() + with sentry_sdk.start_span(name="segment1") as segment1: pass - sentry_sdk.traces.new_trace() - with sentry_sdk.traces.start_span(name="segment2") as segment2: + sentry_sdk.new_trace() + with sentry_sdk.start_span(name="segment2") as segment2: pass assert segment1.trace_id != segment2.trace_id diff --git a/tests/tracing/test_misc.py b/tests/tracing/test_misc.py index 9690f2ffc0..7c38828627 100644 --- a/tests/tracing/test_misc.py +++ b/tests/tracing/test_misc.py @@ -1,349 +1,45 @@ -from unittest import mock from unittest.mock import MagicMock import pytest import sentry_sdk -from sentry_sdk import set_measurement, start_span, start_transaction from sentry_sdk.consts import MATCH_ALL -from sentry_sdk.traces import StreamedSpan -from sentry_sdk.tracing import Span, Transaction +from sentry_sdk.traces import Span from sentry_sdk.tracing_utils import should_propagate_trace from sentry_sdk.utils import Dsn -from tests.conftest import ApproxDict - - -def test_span_trimming(sentry_init, capture_events): - sentry_init(traces_sample_rate=1.0, _experiments={"max_spans": 3}) - events = capture_events() - - with start_transaction(name="hi"): - for i in range(10): - with start_span(op="foo{}".format(i)): - pass - - (event,) = events - - assert len(event["spans"]) == 3 - - span1, span2, span3 = event["spans"] - assert span1["op"] == "foo0" - assert span2["op"] == "foo1" - assert span3["op"] == "foo2" - - assert event["_meta"]["spans"][""]["len"] == 10 - assert "_dropped_spans" not in event - assert "dropped_spans" not in event - - -def test_span_trimming_produces_client_report( - sentry_init, capture_events, capture_record_lost_event_calls -): - sentry_init(traces_sample_rate=1.0, _experiments={"max_spans": 3}) - events = capture_events() - record_lost_event_calls = capture_record_lost_event_calls() - - with start_transaction(name="hi"): - for i in range(10): - with start_span(op="foo{}".format(i)): - pass - - (event,) = events - - assert len(event["spans"]) == 3 - - # 7 spans were dropped (10 total - 3 kept = 7 dropped) - assert ("buffer_overflow", "span", None, 7) in record_lost_event_calls - - -def test_span_data_scrubbing_and_trimming(sentry_init, capture_events): - sentry_init(traces_sample_rate=1.0, _experiments={"max_spans": 3}) - events = capture_events() - - with start_transaction(name="hi"): - with start_span(op="foo", name="bar") as span: - span.set_data("password", "secret") - span.set_data("datafoo", "databar") - - for i in range(10): - with start_span(op="foo{}".format(i)): - pass - - (event,) = events - assert event["spans"][0]["data"] == ApproxDict( - {"password": "[Filtered]", "datafoo": "databar"} - ) - assert event["_meta"]["spans"] == { - "0": {"data": {"password": {"": {"rem": [["!config", "s"]]}}}}, - "": {"len": 11}, - } - - -def test_transaction_naming(sentry_init, capture_events): - sentry_init(traces_sample_rate=1.0) - events = capture_events() - - # default name in event if no name is passed - with start_transaction() as transaction: - pass - assert len(events) == 1 - assert events[0]["transaction"] == "" - - # the name can be set once the transaction's already started - with start_transaction() as transaction: - transaction.name = "name-known-after-transaction-started" - assert len(events) == 2 - assert events[1]["transaction"] == "name-known-after-transaction-started" - - # passing in a name works, too - with start_transaction(name="a"): - pass - assert len(events) == 3 - assert events[2]["transaction"] == "a" - - -def test_transaction_data(sentry_init, capture_events): - sentry_init(traces_sample_rate=1.0) - events = capture_events() - - with start_transaction(name="test-transaction"): - span_or_tx = sentry_sdk.get_current_span() - span_or_tx.set_data("foo", "bar") - with start_span(op="test-span") as span: - span.set_data("spanfoo", "spanbar") - - assert len(events) == 1 - - transaction = events[0] - transaction_data = transaction["contexts"]["trace"]["data"] - - assert "data" not in transaction.keys() - assert transaction_data.items() >= {"foo": "bar"}.items() - - assert len(transaction["spans"]) == 1 - - span = transaction["spans"][0] - span_data = span["data"] - - assert "contexts" not in span.keys() - assert span_data.items() >= {"spanfoo": "spanbar"}.items() - - -def test_start_transaction(sentry_init): - sentry_init(traces_sample_rate=1.0) - - # you can have it start a transaction for you - result1 = start_transaction( - name="/interactions/other-dogs/new-dog", op="greeting.sniff" - ) - assert isinstance(result1, Transaction) - assert result1.name == "/interactions/other-dogs/new-dog" - assert result1.op == "greeting.sniff" - - # or you can pass it an already-created transaction - preexisting_transaction = Transaction( - name="/interactions/other-dogs/new-dog", op="greeting.sniff" - ) - result2 = start_transaction(preexisting_transaction) - assert result2 is preexisting_transaction - - -def test_finds_transaction_on_scope(sentry_init): - sentry_init(traces_sample_rate=1.0) - - transaction = start_transaction(name="dogpark") - - scope = sentry_sdk.get_current_scope() - - # See note in Scope class re: getters and setters of the `transaction` - # property. For the moment, assigning to scope.transaction merely sets the - # transaction name, rather than putting the transaction on the scope, so we - # have to assign to _span directly. - scope._span = transaction - - # Reading scope.property, however, does what you'd expect, and returns the - # transaction on the scope. - assert scope.transaction is not None - assert isinstance(scope.transaction, Transaction) - assert scope.transaction.name == "dogpark" - - # If the transaction is also set as the span on the scope, it can be found - # by accessing _span, too. - assert scope._span is not None - assert isinstance(scope._span, Transaction) - assert scope._span.name == "dogpark" def test_finds_segment_on_scope(sentry_init): sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream", ) - with sentry_sdk.traces.start_span(name="dogpark"): + with sentry_sdk.start_span(name="dogpark"): scope = sentry_sdk.get_current_scope() - assert scope.streamed_span is not None - assert isinstance(scope.streamed_span, StreamedSpan) - assert scope.streamed_span.name == "dogpark" + assert scope.span is not None + assert isinstance(scope.span, Span) + assert scope.span.name == "dogpark" assert scope._span is not None - assert isinstance(scope._span, StreamedSpan) + assert isinstance(scope._span, Span) assert scope._span.name == "dogpark" -def test_finds_transaction_when_descendent_span_is_on_scope( - sentry_init, -): - sentry_init(traces_sample_rate=1.0) - - transaction = start_transaction(name="dogpark") - child_span = transaction.start_child(op="sniffing") - - scope = sentry_sdk.get_current_scope() - scope._span = child_span - - # this is the same whether it's the transaction itself or one of its - # decedents directly attached to the scope - assert scope.transaction is not None - assert isinstance(scope.transaction, Transaction) - assert scope.transaction.name == "dogpark" - - # here we see that it is in fact the span on the scope, rather than the - # transaction itself - assert scope._span is not None - assert isinstance(scope._span, Span) - assert scope._span.op == "sniffing" - - -def test_finds_orphan_span_on_scope(sentry_init): - # this is deprecated behavior which may be removed at some point (along with - # the start_span function) - sentry_init(traces_sample_rate=1.0) - - span = start_span(op="sniffing") - - scope = sentry_sdk.get_current_scope() - scope._span = span - - assert scope._span is not None - assert isinstance(scope._span, Span) - assert scope._span.op == "sniffing" - - -def test_finds_non_orphan_span_on_scope(sentry_init): - sentry_init(traces_sample_rate=1.0) - - transaction = start_transaction(name="dogpark") - child_span = transaction.start_child(op="sniffing") - - scope = sentry_sdk.get_current_scope() - scope._span = child_span - - assert scope._span is not None - assert isinstance(scope._span, Span) - assert scope._span.op == "sniffing" - - -def test_finds_non_orphan_span_on_scope_span_streaming(sentry_init): +def test_finds_span_on_scope(sentry_init): sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream", ) - segment = sentry_sdk.traces.start_span(name="dogpark") - sentry_sdk.traces.start_span(name="sniffing", parent_span=segment) + segment = sentry_sdk.start_span(name="dogpark") + sentry_sdk.start_span(name="sniffing", parent_span=segment) scope = sentry_sdk.get_current_scope() assert scope._span is not None - assert isinstance(scope._span, StreamedSpan) + assert isinstance(scope._span, Span) assert scope._span.name == "sniffing" -def test_set_measurement(sentry_init, capture_events): - sentry_init(traces_sample_rate=1.0) - - events = capture_events() - - transaction = start_transaction(name="measuring stuff") - - with pytest.raises(TypeError): - transaction.set_measurement() - - with pytest.raises(TypeError): - transaction.set_measurement("metric.foo") - - transaction.set_measurement("metric.foo", 123) - transaction.set_measurement("metric.bar", 456, unit="second") - transaction.set_measurement("metric.baz", 420.69, unit="custom") - transaction.set_measurement("metric.foobar", 12, unit="percent") - transaction.set_measurement("metric.foobar", 17.99, unit="percent") - - transaction.finish() - - (event,) = events - assert event["measurements"]["metric.foo"] == {"value": 123, "unit": ""} - assert event["measurements"]["metric.bar"] == {"value": 456, "unit": "second"} - assert event["measurements"]["metric.baz"] == {"value": 420.69, "unit": "custom"} - assert event["measurements"]["metric.foobar"] == {"value": 17.99, "unit": "percent"} - - -def test_set_measurement_public_api(sentry_init, capture_events): - sentry_init(traces_sample_rate=1.0) - - events = capture_events() - - with start_transaction(name="measuring stuff"): - set_measurement("metric.foo", 123) - set_measurement("metric.bar", 456, unit="second") - - (event,) = events - assert event["measurements"]["metric.foo"] == {"value": 123, "unit": ""} - assert event["measurements"]["metric.bar"] == {"value": 456, "unit": "second"} - - -def test_set_measurement_deprecated(sentry_init): - sentry_init(traces_sample_rate=1.0) - - with start_transaction(name="measuring stuff") as trx: - with pytest.warns(DeprecationWarning): - set_measurement("metric.foo", 123) - - with pytest.warns(DeprecationWarning): - trx.set_measurement("metric.bar", 456) - - with start_span(op="measuring span") as span: - with pytest.warns(DeprecationWarning): - span.set_measurement("metric.baz", 420.69, unit="custom") - - -def test_set_meaurement_compared_to_set_data(sentry_init, capture_events): - """ - This is just a test to see the difference - between measurements and data in the resulting event payload. - """ - sentry_init(traces_sample_rate=1.0) - - events = capture_events() - - with start_transaction(name="measuring stuff") as transaction: - transaction.set_measurement("metric.foo", 123) - transaction.set_data("metric.bar", 456) - - with start_span(op="measuring span") as span: - span.set_measurement("metric.baz", 420.69, unit="custom") - span.set_data("metric.qux", 789) - - (event,) = events - assert event["measurements"]["metric.foo"] == {"value": 123, "unit": ""} - assert event["contexts"]["trace"]["data"]["metric.bar"] == 456 - assert event["spans"][0]["measurements"]["metric.baz"] == { - "value": 420.69, - "unit": "custom", - } - assert event["spans"][0]["data"]["metric.qux"] == 789 - - @pytest.mark.parametrize( "trace_propagation_targets,url,expected_propagation_decision", [ @@ -419,142 +115,13 @@ def test_should_propagate_trace_to_sentry( assert should_propagate_trace(client, url) == expected_propagation_decision -def test_start_transaction_updates_scope_name_source(sentry_init): +def test_start_span_segment_updates_scope_name(sentry_init): sentry_init(traces_sample_rate=1.0) scope = sentry_sdk.get_current_scope() - with start_transaction(name="foobar", source="route"): + with sentry_sdk.start_span( + name="foobar", attributes={"sentry.segment.name.source": "test"} + ): assert scope._transaction == "foobar" - assert scope._transaction_info == {"source": "route"} - - -@pytest.mark.parametrize("sampled", (True, None)) -def test_transaction_dropped_debug_not_started(sentry_init, sampled): - sentry_init(traces_sample_rate=1.0) - - tx = Transaction(sampled=sampled) - - with mock.patch("sentry_sdk.tracing.logger") as mock_logger: - with tx: - pass - - mock_logger.debug.assert_any_call( - "Discarding transaction because it was not started with sentry_sdk.start_transaction" - ) - - with pytest.raises(AssertionError): - # We should NOT see the "sampled = False" message here - mock_logger.debug.assert_any_call( - "Discarding transaction because sampled = False" - ) - - -def test_transaction_dropped_sampled_false(sentry_init): - sentry_init(traces_sample_rate=1.0) - - tx = Transaction(sampled=False) - - with mock.patch("sentry_sdk.tracing.logger") as mock_logger: - with sentry_sdk.start_transaction(tx): - pass - - mock_logger.debug.assert_any_call("Discarding transaction because sampled = False") - - with pytest.raises(AssertionError): - # We should not see the "not started" message here - mock_logger.debug.assert_any_call( - "Discarding transaction because it was not started with sentry_sdk.start_transaction" - ) - - -def test_transaction_not_started_warning(sentry_init): - sentry_init(traces_sample_rate=1.0) - - tx = Transaction() - - with mock.patch("sentry_sdk.tracing.logger") as mock_logger: - with tx: - pass - - mock_logger.debug.assert_any_call( - "Transaction was entered without being started with sentry_sdk.start_transaction." - "The transaction will not be sent to Sentry. To fix, start the transaction by" - "passing it to sentry_sdk.start_transaction." - ) - - -def test_span_set_data_update_data(sentry_init, capture_events): - sentry_init(traces_sample_rate=1.0) - - events = capture_events() - - with sentry_sdk.start_transaction(name="test-transaction"): - with start_span(op="test-span") as span: - span.set_data("key0", "value0") - span.set_data("key1", "value1") - - span.update_data( - { - "key1": "updated-value1", - "key2": "value2", - "key3": "value3", - } - ) - - (event,) = events - span = event["spans"][0] - - assert span["data"] == { - "key0": "value0", - "key1": "updated-value1", - "key2": "value2", - "key3": "value3", - "thread.id": mock.ANY, - "thread.name": mock.ANY, - } - - -def test_update_current_span(sentry_init, capture_events): - sentry_init(traces_sample_rate=1.0) - - events = capture_events() - - with sentry_sdk.start_transaction(name="test-transaction"): - with start_span(op="test-span-op", name="test-span-name"): - sentry_sdk.update_current_span( - op="updated-span-op", - name="updated-span-name", - attributes={ - "key0": "value0", - "key1": "value1", - }, - ) - - sentry_sdk.update_current_span( - op="updated-span-op-2", - ) - - sentry_sdk.update_current_span( - name="updated-span-name-3", - ) - - sentry_sdk.update_current_span( - attributes={ - "key1": "updated-value-4", - "key2": "value2", - }, - ) - - (event,) = events - span = event["spans"][0] - - assert span["op"] == "updated-span-op-2" - assert span["description"] == "updated-span-name-3" - assert span["data"] == { - "key0": "value0", - "key1": "updated-value-4", - "key2": "value2", - "thread.id": mock.ANY, - "thread.name": mock.ANY, - } + assert scope._transaction_info == {"source": "test"} diff --git a/tests/tracing/test_noop_span.py b/tests/tracing/test_noop_span.py deleted file mode 100644 index 36778cd485..0000000000 --- a/tests/tracing/test_noop_span.py +++ /dev/null @@ -1,52 +0,0 @@ -import sentry_sdk -from sentry_sdk.tracing import NoOpSpan - -# These tests make sure that the examples from the documentation [1] -# are working when OTel (OpenTelemetry) instrumentation is turned on, -# and therefore, the Sentry tracing should not do anything. -# -# 1: https://docs.sentry.io/platforms/python/performance/instrumentation/custom-instrumentation/ - - -def test_noop_start_transaction(sentry_init): - sentry_init(instrumenter="otel") - - with sentry_sdk.start_transaction( - op="task", name="test_transaction_name" - ) as transaction: - assert isinstance(transaction, NoOpSpan) - assert sentry_sdk.get_current_scope().span is transaction - - transaction.name = "new name" - - -def test_noop_start_span(sentry_init): - sentry_init(instrumenter="otel") - - with sentry_sdk.start_span(op="http", name="GET /") as span: - assert isinstance(span, NoOpSpan) - assert sentry_sdk.get_current_scope().span is span - - span.set_tag("http.response.status_code", 418) - span.set_data("http.entity_type", "teapot") - - -def test_noop_transaction_start_child(sentry_init): - sentry_init(instrumenter="otel") - - transaction = sentry_sdk.start_transaction(name="task") - assert isinstance(transaction, NoOpSpan) - - with transaction.start_child(op="child_task") as child: - assert isinstance(child, NoOpSpan) - assert sentry_sdk.get_current_scope().span is child - - -def test_noop_span_start_child(sentry_init): - sentry_init(instrumenter="otel") - span = sentry_sdk.start_span(name="task") - assert isinstance(span, NoOpSpan) - - with span.start_child(op="child_task") as child: - assert isinstance(child, NoOpSpan) - assert sentry_sdk.get_current_scope().span is child diff --git a/tests/tracing/test_propagation.py b/tests/tracing/test_propagation.py index cbecfeeb2c..6ef1697f1a 100644 --- a/tests/tracing/test_propagation.py +++ b/tests/tracing/test_propagation.py @@ -1,60 +1,20 @@ -import pytest - import sentry_sdk -def test_standalone_span_iter_headers(sentry_init): - sentry_init(traces_sample_rate=1.0) - - with sentry_sdk.start_span(op="test") as span: - with pytest.raises(StopIteration): - # We should not have any propagation headers - next(span.iter_headers()) - - -def test_span_in_span_iter_headers(sentry_init): - sentry_init(traces_sample_rate=1.0) - - with sentry_sdk.start_span(op="test"): - with sentry_sdk.start_span(op="test2") as span_inner: - with pytest.raises(StopIteration): - # We should not have any propagation headers - next(span_inner.iter_headers()) - - -def test_span_in_transaction(sentry_init): +def test_span_in_segment(sentry_init): sentry_init(traces_sample_rate=1.0) - with sentry_sdk.start_transaction(op="test"): - with sentry_sdk.start_span(op="test2") as span: - # Ensure the headers are there - next(span.iter_headers()) - - -def test_span_in_transaction_span_streaming(sentry_init): - sentry_init(traces_sample_rate=1.0, trace_lifecycle="stream") - - with sentry_sdk.traces.start_span(name="test"): - with sentry_sdk.traces.start_span(name="test2") as span: + with sentry_sdk.start_span(name="test"): + with sentry_sdk.start_span(name="test2") as span: # Ensure the headers are there next(span._iter_headers()) -def test_span_in_span_in_transaction(sentry_init): +def test_span_in_span_in_segment(sentry_init): sentry_init(traces_sample_rate=1.0) - with sentry_sdk.start_transaction(op="test"): - with sentry_sdk.start_span(op="test2"): - with sentry_sdk.start_span(op="test3") as span_inner: - # Ensure the headers are there - next(span_inner.iter_headers()) - - -def test_span_in_span_in_transaction_span_streaming(sentry_init): - sentry_init(traces_sample_rate=1.0, trace_lifecycle="stream") - - with sentry_sdk.traces.start_span(name="test"): - with sentry_sdk.traces.start_span(name="test2"): - with sentry_sdk.traces.start_span(name="test3") as span_inner: + with sentry_sdk.start_span(name="test"): + with sentry_sdk.start_span(name="test2"): + with sentry_sdk.start_span(name="test3") as span_inner: # Ensure the headers are there next(span_inner._iter_headers()) diff --git a/tests/tracing/test_sample_rand.py b/tests/tracing/test_sample_rand.py index e9835d1de1..baec6b033e 100644 --- a/tests/tracing/test_sample_rand.py +++ b/tests/tracing/test_sample_rand.py @@ -3,7 +3,6 @@ import pytest import sentry_sdk -from sentry_sdk.tracing_utils import Baggage # Boundary cases for the sampling decision `sample_rand < sample_rate`: # equality (strict <), below, above, and the degenerate rates 0.0 (never @@ -20,34 +19,7 @@ @pytest.mark.parametrize("sample_rand,sample_rate", SAMPLE_RAND_RATE_CASES) -def test_deterministic_sampled(sentry_init, capture_events, sample_rate, sample_rand): - """ - Test that sample_rand is generated on new traces, that it is used to - make the sampling decision, and that it is included in the transaction's - baggage. - """ - sentry_init(traces_sample_rate=sample_rate) - events = capture_events() - - with mock.patch( - "sentry_sdk.tracing_utils.Random.randrange", - return_value=int(sample_rand * 1000000), - ): - with sentry_sdk.start_transaction() as transaction: - assert ( - transaction.get_baggage().sentry_items["sample_rand"] - == f"{sample_rand:.6f}" # noqa: E231 - ) - - # Transaction event captured if sample_rand < sample_rate, indicating that - # sample_rand is used to make the sampling decision. - assert len(events) == int(sample_rand < sample_rate) - - -@pytest.mark.parametrize("sample_rand,sample_rate", SAMPLE_RAND_RATE_CASES) -def test_deterministic_sampled_span_streaming( - sentry_init, capture_items, sample_rate, sample_rand -): +def test_deterministic_sampled(sentry_init, capture_items, sample_rate, sample_rand): """ Test that sample_rand is generated on new traces, that it is used to make the sampling decision, and that it is included in the segment's @@ -55,7 +27,6 @@ def test_deterministic_sampled_span_streaming( """ sentry_init( traces_sample_rate=sample_rate, - trace_lifecycle="stream", ) items = capture_items("span") @@ -63,7 +34,7 @@ def test_deterministic_sampled_span_streaming( "sentry_sdk.tracing_utils.Random.randrange", return_value=int(sample_rand * 1000000), ): - with sentry_sdk.traces.start_span(name="span") as span: + with sentry_sdk.start_span(name="span") as span: assert ( span._get_baggage().sentry_items["sample_rand"] == f"{sample_rand:.6f}" # noqa: E231 ) @@ -76,30 +47,7 @@ def test_deterministic_sampled_span_streaming( @pytest.mark.parametrize("sample_rand,sample_rate", SAMPLE_RAND_RATE_CASES) -def test_transaction_uses_incoming_sample_rand( - sentry_init, capture_events, sample_rate, sample_rand -): - """ - Test that the transaction uses the sample_rand value from the incoming baggage. - """ - baggage = Baggage(sentry_items={"sample_rand": f"{sample_rand:.6f}"}) # noqa: E231 - - sentry_init(traces_sample_rate=sample_rate) - events = capture_events() - - with sentry_sdk.start_transaction(baggage=baggage) as transaction: - assert ( - transaction.get_baggage().sentry_items["sample_rand"] - == f"{sample_rand:.6f}" # noqa: E231 - ) - - # Transaction event captured if sample_rand < sample_rate, indicating that - # sample_rand is used to make the sampling decision. - assert len(events) == int(sample_rand < sample_rate) - - -@pytest.mark.parametrize("sample_rand,sample_rate", SAMPLE_RAND_RATE_CASES) -def test_segment_uses_incoming_sample_rand_span_streaming( +def test_segment_uses_incoming_sample_rand( sentry_init, capture_items, sample_rate, sample_rand ): """ @@ -107,18 +55,17 @@ def test_segment_uses_incoming_sample_rand_span_streaming( """ sentry_init( traces_sample_rate=sample_rate, - trace_lifecycle="stream", ) items = capture_items("span") - sentry_sdk.traces.continue_trace( + sentry_sdk.continue_trace( { "sentry-trace": "0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331", "baggage": f"sentry-sample_rand={sample_rand:.6f}", } ) - with sentry_sdk.traces.start_span(name="span") as span: + with sentry_sdk.start_span(name="span") as span: assert ( span._get_baggage().sentry_items["sample_rand"] == f"{sample_rand:.6f}" # noqa: E231 ) diff --git a/tests/tracing/test_sample_rand_propagation.py b/tests/tracing/test_sample_rand_propagation.py index 4b63d86442..7eda59cf6c 100644 --- a/tests/tracing/test_sample_rand_propagation.py +++ b/tests/tracing/test_sample_rand_propagation.py @@ -12,59 +12,28 @@ import sentry_sdk -def test_continue_trace_with_sample_rand(): - """ - Test that an incoming sample_rand is propagated onto the transaction's baggage. - """ - headers = { - "sentry-trace": "00000000000000000000000000000000-0000000000000000-0", - "baggage": "sentry-sample_rand=0.1,sentry-sample_rate=0.5", - } - - transaction = sentry_sdk.continue_trace(headers) - assert transaction.get_baggage().sentry_items["sample_rand"] == "0.1" - - -def test_continue_trace_with_sample_rand_span_streaming(sentry_init): +def test_continue_trace_with_sample_rand(sentry_init): """ Test that an incoming sample_rand is propagated onto the segment's baggage. """ - sentry_init(traces_sample_rate=1.0, trace_lifecycle="stream") + sentry_init(traces_sample_rate=1.0) headers = { "sentry-trace": "00000000000000000000000000000000-0000000000000000-1", "baggage": "sentry-sample_rand=0.100000,sentry-sample_rate=0.5", } - sentry_sdk.traces.continue_trace(headers) - with sentry_sdk.traces.start_span(name="span") as segment: + sentry_sdk.continue_trace(headers) + with sentry_sdk.start_span(name="span") as segment: assert segment._get_baggage().sentry_items["sample_rand"] == "0.100000" -def test_continue_trace_missing_sample_rand(): - """ - Test that a missing sample_rand is filled in onto the transaction's baggage. - """ - - headers = { - "sentry-trace": "00000000000000000000000000000000-0000000000000000", - "baggage": "sentry-placeholder=asdf", - } - - with mock.patch( - "sentry_sdk.tracing_utils.Random.randrange", Mock(return_value=500000) - ): - transaction = sentry_sdk.continue_trace(headers) - - assert transaction.get_baggage().sentry_items["sample_rand"] == "0.500000" - - -def test_continue_trace_missing_sample_rand_span_streaming(sentry_init): +def test_continue_trace_missing_sample_rand(sentry_init): """ Test that a missing sample_rand is filled in onto the segment's baggage. """ - sentry_init(traces_sample_rate=1.0, trace_lifecycle="stream") + sentry_init(traces_sample_rate=1.0) headers = { "sentry-trace": "00000000000000000000000000000000-0000000000000000", @@ -74,6 +43,6 @@ def test_continue_trace_missing_sample_rand_span_streaming(sentry_init): with mock.patch( "sentry_sdk.tracing_utils.Random.randrange", Mock(return_value=500000) ): - sentry_sdk.traces.continue_trace(headers) - with sentry_sdk.traces.start_span(name="span") as span: + sentry_sdk.continue_trace(headers) + with sentry_sdk.start_span(name="span") as span: assert span._get_baggage().sentry_items["sample_rand"] == "0.500000" diff --git a/tests/tracing/test_sampling.py b/tests/tracing/test_sampling.py index 0685498d13..2754e07e68 100644 --- a/tests/tracing/test_sampling.py +++ b/tests/tracing/test_sampling.py @@ -5,73 +5,32 @@ import pytest import sentry_sdk -from sentry_sdk import capture_exception, start_span, start_transaction -from sentry_sdk.tracing_utils import Baggage +from sentry_sdk import capture_exception from sentry_sdk.utils import logger -def test_sampling_decided_only_for_transactions(sentry_init, capture_events): - sentry_init(traces_sample_rate=0.5) - - with start_transaction(name="hi") as transaction: - assert transaction.sampled is not None - - with start_span() as span: - assert span.sampled == transaction.sampled - - with start_span() as span: - assert span.sampled is None - - def test_sampling_decided_only_for_segments(sentry_init, capture_events): sentry_init( traces_sample_rate=0.5, - trace_lifecycle="stream", ) - with sentry_sdk.traces.start_span(name="hi") as segment: + with sentry_sdk.start_span(name="hi") as segment: assert segment.sampled is not None - with sentry_sdk.traces.start_span(name="hey") as span: + with sentry_sdk.start_span(name="hey") as span: assert span.sampled == segment.sampled -@pytest.mark.parametrize("sampled", [True, False]) -def test_nested_transaction_sampling_override(sentry_init, sampled): - sentry_init(traces_sample_rate=1.0) - - with start_transaction(name="outer", sampled=sampled) as outer_transaction: - assert outer_transaction.sampled is sampled - with start_transaction( - name="inner", sampled=(not sampled) - ) as inner_transaction: - assert inner_transaction.sampled is not sampled - assert outer_transaction.sampled is sampled - - -def test_no_double_sampling(sentry_init, capture_events): - # Transactions should not be subject to the global/error sample rate. - # Only the traces_sample_rate should apply. - sentry_init(traces_sample_rate=1.0, sample_rate=0.0) - events = capture_events() - - with start_transaction(name="/"): - pass - - assert len(events) == 1 - - -def test_no_double_sampling_span_streaming(sentry_init, capture_items): +def test_no_double_sampling(sentry_init, capture_items): # Segments should not be subject to the global/error sample rate. # Only the traces_sample_rate should apply. sentry_init( traces_sample_rate=1.0, sample_rate=0.0, - trace_lifecycle="stream", ) items = capture_items() - with sentry_sdk.traces.start_span(name="/"): + with sentry_sdk.start_span(name="/"): pass sentry_sdk.flush() @@ -80,17 +39,27 @@ def test_no_double_sampling_span_streaming(sentry_init, capture_items): @pytest.mark.parametrize("sampling_decision", [True, False]) -def test_get_transaction_and_span_from_scope_regardless_of_sampling_decision( +def test_get_span_from_scope_regardless_of_sampling_decision( sentry_init, sampling_decision ): sentry_init(traces_sample_rate=1.0) - with start_transaction(name="/", sampled=sampling_decision): - with start_span(op="child-span"): - with start_span(op="child-child-span"): + sentry_sdk.continue_trace( + { + "sentry-trace": f"0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-{int(sampling_decision)}" + } + ) + + with sentry_sdk.start_span(name="/"): + with sentry_sdk.start_span(name="child-span"): + with sentry_sdk.start_span(name="child-child-span"): scope = sentry_sdk.get_current_scope() - assert scope.span.op == "child-child-span" - assert scope.transaction.name == "/" + if sampling_decision is True: + assert scope.span.name == "child-child-span" + else: + # noop spans are not set on the scope unless they're segments + assert scope.span.name == "/" + assert scope._transaction == "/" @pytest.mark.parametrize( @@ -101,36 +70,19 @@ def test_uses_traces_sample_rate_correctly( sentry_init, traces_sample_rate, expected_decision, -): - sentry_init(traces_sample_rate=traces_sample_rate) - - baggage = Baggage(sentry_items={"sample_rand": "0.500000"}) - transaction = start_transaction(name="dogpark", baggage=baggage) - assert transaction.sampled is expected_decision - - -@pytest.mark.parametrize( - "traces_sample_rate,expected_decision", - [(0.0, False), (0.25, False), (0.75, True), (1.00, True)], -) -def test_uses_traces_sample_rate_correctly_span_streaming( - sentry_init, - traces_sample_rate, - expected_decision, ): sentry_init( traces_sample_rate=traces_sample_rate, - trace_lifecycle="stream", ) - sentry_sdk.traces.continue_trace( + sentry_sdk.continue_trace( { "sentry-trace": "0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331", "baggage": "sentry-sample_rand=0.500000", } ) - with sentry_sdk.traces.start_span(name="dogpark") as span: + with sentry_sdk.start_span(name="dogpark") as span: assert span.sampled is expected_decision @@ -142,81 +94,34 @@ def test_uses_traces_sampler_return_value_correctly( sentry_init, traces_sampler_return_value, expected_decision, -): - sentry_init(traces_sampler=mock.Mock(return_value=traces_sampler_return_value)) - - baggage = Baggage(sentry_items={"sample_rand": "0.500000"}) - transaction = start_transaction(name="dogpark", baggage=baggage) - assert transaction.sampled is expected_decision - - -@pytest.mark.parametrize( - "traces_sampler_return_value,expected_decision", - [(0.0, False), (0.25, False), (0.75, True), (1.00, True)], -) -def test_uses_traces_sampler_return_value_correctly_span_streaming( - sentry_init, - traces_sampler_return_value, - expected_decision, ): sentry_init( traces_sampler=mock.Mock(return_value=traces_sampler_return_value), - trace_lifecycle="stream", ) - sentry_sdk.traces.continue_trace( + sentry_sdk.continue_trace( { "sentry-trace": "0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331", "baggage": "sentry-sample_rand=0.500000", } ) - with sentry_sdk.traces.start_span(name="dogpark") as span: + with sentry_sdk.start_span(name="dogpark") as span: assert span.sampled is expected_decision @pytest.mark.parametrize("traces_sampler_return_value", [True, False]) def test_tolerates_traces_sampler_returning_a_boolean( sentry_init, traces_sampler_return_value -): - sentry_init(traces_sampler=mock.Mock(return_value=traces_sampler_return_value)) - - transaction = start_transaction(name="dogpark") - assert transaction.sampled is traces_sampler_return_value - - -@pytest.mark.parametrize("traces_sampler_return_value", [True, False]) -def test_tolerates_traces_sampler_returning_a_boolean_span_streaming( - sentry_init, traces_sampler_return_value ): sentry_init( traces_sampler=mock.Mock(return_value=traces_sampler_return_value), - trace_lifecycle="stream", ) - with sentry_sdk.traces.start_span(name="dogpark") as span: + with sentry_sdk.start_span(name="dogpark") as span: assert span.sampled is traces_sampler_return_value -@pytest.mark.parametrize( - "traces_sample_rate,expected_decision", - [(0.0, False), (0.25, False), (0.75, True), (1.00, True)], -) -def test_traces_sampler_raising_falls_back_to_traces_sample_rate( - sentry_init, - traces_sample_rate, - expected_decision, -): - sentry_init( - traces_sampler=mock.Mock(side_effect=ValueError("boom")), - traces_sample_rate=traces_sample_rate, - ) - - baggage = Baggage(sentry_items={"sample_rand": "0.500000"}) - transaction = start_transaction(name="dogpark", baggage=baggage) - assert transaction.sampled is expected_decision - - @pytest.mark.parametrize("parent_sampling_decision", [True, False]) def test_traces_sampler_raising_falls_back_to_parent_sampling_decision( sentry_init, parent_sampling_decision @@ -228,18 +133,21 @@ def test_traces_sampler_raising_falls_back_to_parent_sampling_decision( traces_sample_rate=0.0 if parent_sampling_decision else 1.0, ) - baggage = Baggage(sentry_items={"sample_rand": "0.500000"}) - transaction = start_transaction( - name="dogpark", baggage=baggage, parent_sampled=parent_sampling_decision + sentry_sdk.continue_trace( + { + "sentry-trace": f"0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-{int(parent_sampling_decision)}" + } ) - assert transaction.sampled is parent_sampling_decision + + with sentry_sdk.start_span(name="dogpark") as span: + assert span.sampled is parent_sampling_decision @pytest.mark.parametrize( "traces_sample_rate,expected_decision", [(0.0, False), (0.25, False), (0.75, True), (1.00, True)], ) -def test_traces_sampler_raising_falls_back_to_traces_sample_rate_span_streaming( +def test_traces_sampler_raising_falls_back_to_traces_sample_rate( sentry_init, traces_sample_rate, expected_decision, @@ -247,17 +155,16 @@ def test_traces_sampler_raising_falls_back_to_traces_sample_rate_span_streaming( sentry_init( traces_sampler=mock.Mock(side_effect=ValueError("boom")), traces_sample_rate=traces_sample_rate, - trace_lifecycle="stream", ) - sentry_sdk.traces.continue_trace( + sentry_sdk.continue_trace( { "sentry-trace": "0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331", "baggage": "sentry-sample_rand=0.500000", } ) - with sentry_sdk.traces.start_span(name="dogpark") as span: + with sentry_sdk.start_span(name="dogpark") as span: assert span.sampled is expected_decision @@ -265,7 +172,7 @@ def test_traces_sampler_raising_falls_back_to_traces_sample_rate_span_streaming( "traces_sample_rate,expected_decision", [(0.0, False), (0.25, False), (0.75, True), (1.00, True)], ) -def test_traces_sampler_raising_no_incoming_trace_falls_back_to_traces_sample_rate_span_streaming( +def test_traces_sampler_raising_no_incoming_trace_falls_back_to_traces_sample_rate( sentry_init, traces_sample_rate, expected_decision, @@ -274,7 +181,6 @@ def test_traces_sampler_raising_no_incoming_trace_falls_back_to_traces_sample_ra sentry_init( traces_sampler=mock.Mock(side_effect=ValueError("boom")), traces_sample_rate=traces_sample_rate, - trace_lifecycle="stream", ) # no continue_trace, so no propagated sample_rand; make it deterministic @@ -282,7 +188,7 @@ def test_traces_sampler_raising_no_incoming_trace_falls_back_to_traces_sample_ra "sentry_sdk.tracing_utils._generate_sample_rand", lambda *a, **kw: 0.5 ) - with sentry_sdk.traces.start_span(name="dogpark") as span: + with sentry_sdk.start_span(name="dogpark") as span: assert span.sampled is expected_decision @@ -293,48 +199,22 @@ def test_traces_sampler_raising_no_incoming_trace_and_no_traces_sample_rate( traces_sampler=mock.Mock(side_effect=ValueError("boom")), ) - transaction = start_transaction(name="dogpark") - assert transaction.sampled is False - - -def test_traces_sampler_raising_no_incoming_trace_and_no_traces_sample_rate_span_streaming( - sentry_init, -): - sentry_init( - traces_sampler=mock.Mock(side_effect=ValueError("boom")), - trace_lifecycle="stream", - ) - - with sentry_sdk.traces.start_span(name="dogpark") as span: + with sentry_sdk.start_span(name="dogpark") as span: assert span.sampled is False @pytest.mark.parametrize("sampling_decision", [True, False]) -def test_only_captures_transaction_when_sampled_is_true( - sentry_init, sampling_decision, capture_events -): - sentry_init(traces_sampler=mock.Mock(return_value=sampling_decision)) - events = capture_events() - - transaction = start_transaction(name="dogpark") - transaction.finish() - - assert len(events) == (1 if sampling_decision else 0) - - -@pytest.mark.parametrize("sampling_decision", [True, False]) -def test_only_captures_segment_when_sampled_is_true_span_streaming( +def test_only_captures_segment_when_sampled_is_true( sentry_init, sampling_decision, capture_items ): sentry_init( traces_sampler=mock.Mock( return_value=sampling_decision, ), - trace_lifecycle="stream", ) items = capture_items() - span = sentry_sdk.traces.start_span(name="dogpark") + span = sentry_sdk.start_span(name="dogpark") span.end() sentry_sdk.flush() @@ -358,50 +238,13 @@ def test_prefers_traces_sampler_to_traces_sample_rate( traces_sampler=traces_sampler, ) - transaction = start_transaction(name="dogpark") - assert traces_sampler.called is True - assert transaction.sampled is traces_sampler_return_value - - -@pytest.mark.parametrize( - "traces_sample_rate,traces_sampler_return_value", [(0, True), (1, False)] -) -def test_prefers_traces_sampler_to_traces_sample_rate_span_streaming( - sentry_init, - traces_sample_rate, - traces_sampler_return_value, -): - # make traces_sample_rate imply the opposite of traces_sampler, to prove - # that traces_sampler takes precedence - traces_sampler = mock.Mock(return_value=traces_sampler_return_value) - sentry_init( - traces_sample_rate=traces_sample_rate, - traces_sampler=traces_sampler, - trace_lifecycle="stream", - ) - - span = sentry_sdk.traces.start_span(name="dogpark") + span = sentry_sdk.start_span(name="dogpark") assert traces_sampler.called is True assert span.sampled is traces_sampler_return_value -@pytest.mark.parametrize("parent_sampling_decision", [True, False]) -def test_ignores_inherited_sample_decision_when_traces_sampler_defined( - sentry_init, parent_sampling_decision -): - # make traces_sampler pick the opposite of the inherited decision, to prove - # that traces_sampler takes precedence - traces_sampler = mock.Mock(return_value=not parent_sampling_decision) - sentry_init(traces_sampler=traces_sampler) - - transaction = start_transaction( - name="dogpark", parent_sampled=parent_sampling_decision - ) - assert transaction.sampled is not parent_sampling_decision - - @pytest.mark.parametrize("parent_sampling_decision", ["1", "0"]) -def test_ignores_inherited_sample_decision_when_traces_sampler_defined_span_streaming( +def test_ignores_inherited_sample_decision_when_traces_sampler_defined( sentry_init, parent_sampling_decision ): # make traces_sampler pick the opposite of the inherited decision, to prove @@ -409,58 +252,26 @@ def test_ignores_inherited_sample_decision_when_traces_sampler_defined_span_stre traces_sampler = mock.Mock(return_value=not bool(int(parent_sampling_decision))) sentry_init( traces_sampler=traces_sampler, - trace_lifecycle="stream", ) - sentry_sdk.traces.continue_trace( + sentry_sdk.continue_trace( { "sentry-trace": f"0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-{parent_sampling_decision}" } ) - span = sentry_sdk.traces.start_span(name="dogpark") + span = sentry_sdk.start_span(name="dogpark") assert span.sampled is not bool(int(parent_sampling_decision)) -@pytest.mark.parametrize("explicit_decision", [True, False]) -def test_traces_sampler_doesnt_overwrite_explicitly_passed_sampling_decision( - sentry_init, explicit_decision -): - # make traces_sampler pick the opposite of the explicit decision, to prove - # that the explicit decision takes precedence - traces_sampler = mock.Mock(return_value=not explicit_decision) - sentry_init(traces_sampler=traces_sampler) - - transaction = start_transaction(name="dogpark", sampled=explicit_decision) - assert transaction.sampled is explicit_decision - - -@pytest.mark.parametrize("parent_sampling_decision", [True, False]) -def test_inherits_parent_sampling_decision_when_traces_sampler_undefined( - sentry_init, parent_sampling_decision -): - # make sure the parent sampling decision is the opposite of what - # traces_sample_rate would produce, to prove the inheritance takes - # precedence - sentry_init(traces_sample_rate=0.5) - mock_random_value = 0.25 if parent_sampling_decision is False else 0.75 - - with mock.patch.object(random, "random", return_value=mock_random_value): - transaction = start_transaction( - name="dogpark", parent_sampled=parent_sampling_decision - ) - assert transaction.sampled is parent_sampling_decision - - @pytest.mark.parametrize("parent_sampling_decision", ["1", "0"]) -def test_inherits_parent_sampling_decision_when_traces_sampler_undefined_span_streaming( +def test_inherits_parent_sampling_decision_when_traces_sampler_undefined( sentry_init, parent_sampling_decision ): sentry_init( traces_sample_rate=0.5, - trace_lifecycle="stream", ) - sentry_sdk.traces.continue_trace( + sentry_sdk.continue_trace( { "sentry-trace": f"0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-{parent_sampling_decision}" } @@ -471,52 +282,10 @@ def test_inherits_parent_sampling_decision_when_traces_sampler_undefined_span_st # precedence mock_random_value = 0.25 if parent_sampling_decision == "0" else 0.75 with mock.patch.object(random, "random", return_value=mock_random_value): - span = sentry_sdk.traces.start_span(name="dogpark") + span = sentry_sdk.start_span(name="dogpark") assert span.sampled is bool(int(parent_sampling_decision)) -@pytest.mark.parametrize("parent_sampling_decision", [True, False]) -def test_passes_parent_sampling_decision_in_sampling_context( - sentry_init, parent_sampling_decision -): - sentry_init(traces_sample_rate=1.0) - - sentry_trace_header = ( - "12312012123120121231201212312012-1121201211212012-{sampled}".format( - sampled=int(parent_sampling_decision) - ) - ) - - transaction = sentry_sdk.continue_trace( - {"sentry-trace": sentry_trace_header}, - name="dogpark", - ) - - def mock_set_initial_sampling_decision(_, sampling_context): - assert "parent_sampled" in sampling_context - assert sampling_context["parent_sampled"] is parent_sampling_decision - - with mock.patch( - "sentry_sdk.tracing.Transaction._set_initial_sampling_decision", - mock_set_initial_sampling_decision, - ): - start_transaction(transaction=transaction) - - -def test_passes_custom_sampling_context_from_start_transaction_to_traces_sampler( - sentry_init, - DictionaryContaining, # noqa: N803 -): - traces_sampler = mock.Mock() - sentry_init(traces_sampler=traces_sampler) - - start_transaction(custom_sampling_context={"dogs": "yes", "cats": "maybe"}) - - traces_sampler.assert_any_call( - DictionaryContaining({"dogs": "yes", "cats": "maybe"}) - ) - - def test_custom_sampling_context(sentry_init): class MyClass: ... @@ -531,7 +300,6 @@ def traces_sampler(sampling_context): sentry_init( traces_sampler=traces_sampler, - trace_lifecycle="stream", ) sentry_sdk.get_current_scope().set_custom_sampling_context( @@ -541,7 +309,7 @@ def traces_sampler(sampling_context): } ) - with sentry_sdk.traces.start_span(name="span"): + with sentry_sdk.start_span(name="span"): ... @@ -555,21 +323,20 @@ def traces_sampler(sampling_context): sentry_init( traces_sampler=traces_sampler, - trace_lifecycle="stream", ) - sentry_sdk.traces.new_trace() + sentry_sdk.new_trace() sentry_sdk.get_current_scope().set_custom_sampling_context({"custom_value": 1}) - with sentry_sdk.traces.start_span(name="span", attributes={"first": True}): + with sentry_sdk.start_span(name="span", attributes={"first": True}): ... - sentry_sdk.traces.new_trace() + sentry_sdk.new_trace() sentry_sdk.get_current_scope().set_custom_sampling_context({"custom_value": 2}) - with sentry_sdk.traces.start_span(name="span", attributes={"first": False}): + with sentry_sdk.start_span(name="span", attributes={"first": False}): ... @@ -599,37 +366,13 @@ def test_warns_and_sets_sampled_to_false_on_invalid_traces_sampler_return_value( sentry_init, traces_sampler_return_value, StringContaining, # noqa: N803 -): - sentry_init(traces_sampler=mock.Mock(return_value=traces_sampler_return_value)) - - with mock.patch.object(logger, "warning", mock.Mock()): - transaction = start_transaction(name="dogpark") - logger.warning.assert_any_call(StringContaining("Given sample rate is invalid")) - assert transaction.sampled is False - - -@pytest.mark.parametrize( - "traces_sampler_return_value", - [ - "dogs are great", # wrong type - None, # wrong type - float("NaN"), # wrong type (edge: float, but not a valid rate) - -1.121, # wrong value - 1.231, # wrong value - ], -) -def test_warns_and_sets_sampled_to_false_on_invalid_traces_sampler_return_value_span_streaming( - sentry_init, - traces_sampler_return_value, - StringContaining, # noqa: N803 ): sentry_init( traces_sampler=mock.Mock(return_value=traces_sampler_return_value), - trace_lifecycle="stream", ) with mock.patch.object(logger, "warning", mock.Mock()): - span = sentry_sdk.traces.start_span(name="dogpark") + span = sentry_sdk.start_span(name="dogpark") logger.warning.assert_any_call(StringContaining("Given sample rate is invalid")) assert span.sampled is False @@ -637,11 +380,11 @@ def test_warns_and_sets_sampled_to_false_on_invalid_traces_sampler_return_value_ @pytest.mark.parametrize( "traces_sample_rate,sampled_output,expected_record_lost_event_calls", [ - (None, False, []), + (None, None, []), ( 0.0, False, - [("sample_rate", "transaction", None, 1), ("sample_rate", "span", None, 1)], + [("sample_rate", "span", None, 1)], ), (1.0, True, []), ], @@ -656,9 +399,9 @@ def test_records_lost_event_only_if_traces_sample_rate_enabled( sentry_init(traces_sample_rate=traces_sample_rate) record_lost_event_calls = capture_record_lost_event_calls() - transaction = start_transaction(name="dogpark") - assert transaction.sampled is sampled_output - transaction.finish() + span = sentry_sdk.start_span(name="dogpark") + assert span.sampled is sampled_output + span.end() # Use Counter because order of calls does not matter assert Counter(record_lost_event_calls) == Counter(expected_record_lost_event_calls) @@ -667,11 +410,11 @@ def test_records_lost_event_only_if_traces_sample_rate_enabled( @pytest.mark.parametrize( "traces_sampler,sampled_output,expected_record_lost_event_calls", [ - (None, False, []), + (None, None, []), ( lambda _x: 0.0, False, - [("sample_rate", "transaction", None, 1), ("sample_rate", "span", None, 1)], + [("sample_rate", "span", None, 1)], ), (lambda _x: 1.0, True, []), ], @@ -686,9 +429,9 @@ def test_records_lost_event_only_if_traces_sampler_enabled( sentry_init(traces_sampler=traces_sampler) record_lost_event_calls = capture_record_lost_event_calls() - transaction = start_transaction(name="dogpark") - assert transaction.sampled is sampled_output - transaction.finish() + segment = sentry_sdk.start_span(name="dogpark") + assert segment.sampled is sampled_output + segment.end() # Use Counter because order of calls does not matter assert Counter(record_lost_event_calls) == Counter(expected_record_lost_event_calls) @@ -699,16 +442,15 @@ def test_unsampled_spans_produce_client_report_if_traces_sample_rate_defined( ): sentry_init( traces_sample_rate=0.0, - trace_lifecycle="stream", ) items = capture_items("span") record_lost_event_calls = capture_record_lost_event_calls() - with sentry_sdk.traces.start_span(name="segment"): - with sentry_sdk.traces.start_span(name="child1"): + with sentry_sdk.start_span(name="segment"): + with sentry_sdk.start_span(name="child1"): pass - with sentry_sdk.traces.start_span(name="child2"): + with sentry_sdk.start_span(name="child2"): pass sentry_sdk.get_client().flush() @@ -728,16 +470,15 @@ def test_unsampled_spans_produce_client_report_if_traces_sampler_defined( ): sentry_init( traces_sampler=lambda _: 0.0, - trace_lifecycle="stream", ) items = capture_items("span") record_lost_event_calls = capture_record_lost_event_calls() - with sentry_sdk.traces.start_span(name="segment"): - with sentry_sdk.traces.start_span(name="child1"): + with sentry_sdk.start_span(name="segment"): + with sentry_sdk.start_span(name="child1"): pass - with sentry_sdk.traces.start_span(name="child2"): + with sentry_sdk.start_span(name="child2"): pass sentry_sdk.get_client().flush() @@ -757,16 +498,15 @@ def test_no_client_reports_if_tracing_is_off( ): sentry_init( traces_sample_rate=None, - trace_lifecycle="stream", ) items = capture_items("span") record_lost_event_calls = capture_record_lost_event_calls() - with sentry_sdk.traces.start_span(name="segment"): - with sentry_sdk.traces.start_span(name="child1"): + with sentry_sdk.start_span(name="segment"): + with sentry_sdk.start_span(name="child1"): pass - with sentry_sdk.traces.start_span(name="child2"): + with sentry_sdk.start_span(name="child2"): pass sentry_sdk.get_client().flush() diff --git a/tests/tracing/test_span_batcher.py b/tests/tracing/test_span_batcher.py index 8eae824ce0..c4fe6b376a 100644 --- a/tests/tracing/test_span_batcher.py +++ b/tests/tracing/test_span_batcher.py @@ -13,31 +13,26 @@ def test_envelope_by_trace_id(sentry_init, capture_envelopes, monkeypatch): """Envelopes only contain spans of one trace ID.""" sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream", ) envelopes = capture_envelopes() with sentry_sdk.new_scope(): - sentry_sdk.traces.new_trace() + sentry_sdk.new_trace() # Keep parent open as its bucket in the batcher would be emptied when it is finished. - parent_a = sentry_sdk.traces.start_span(name="parent a") - with sentry_sdk.traces.start_span( - name="span 1a", parent_span=parent_a - ) as span1: + parent_a = sentry_sdk.start_span(name="parent a") + with sentry_sdk.start_span(name="span 1a", parent_span=parent_a) as span1: trace_id1 = span1.trace_id - with sentry_sdk.traces.start_span(name="span 1b", parent_span=parent_a): + with sentry_sdk.start_span(name="span 1b", parent_span=parent_a): pass with sentry_sdk.new_scope(): - sentry_sdk.traces.new_trace() - parent_b = sentry_sdk.traces.start_span(name="parent b") + sentry_sdk.new_trace() + parent_b = sentry_sdk.start_span(name="parent b") # Keep parent open as its bucket in the batcher would be emptied when it is finished. - with sentry_sdk.traces.start_span( - name="span 2a", parent_span=parent_b - ) as span2: + with sentry_sdk.start_span(name="span 2a", parent_span=parent_b) as span2: trace_id2 = span2.trace_id - with sentry_sdk.traces.start_span(name="span 2b", parent_span=parent_b): + with sentry_sdk.start_span(name="span 2b", parent_span=parent_b): pass sentry_sdk.flush() @@ -68,21 +63,20 @@ def test_max_envelope_size(sentry_init, capture_envelopes, monkeypatch): sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream", ) envelopes = capture_envelopes() - with sentry_sdk.traces.start_span(name="custom parent"): - with sentry_sdk.traces.start_span(name="span 1"): + with sentry_sdk.start_span(name="custom parent"): + with sentry_sdk.start_span(name="span 1"): pass - with sentry_sdk.traces.start_span(name="span 2"): + with sentry_sdk.start_span(name="span 2"): pass - with sentry_sdk.traces.start_span(name="span 3"): + with sentry_sdk.start_span(name="span 3"): pass - with sentry_sdk.traces.start_span(name="span 4"): + with sentry_sdk.start_span(name="span 4"): pass - with sentry_sdk.traces.start_span(name="span 5"): + with sentry_sdk.start_span(name="span 5"): pass sentry_sdk.flush() @@ -110,18 +104,17 @@ def test_drop_after_max_reached( sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream", ) envelopes = capture_envelopes() record_lost_event_calls = capture_record_lost_event_calls() - with sentry_sdk.traces.start_span(name="custom parent"): - with sentry_sdk.traces.start_span(name="span 1"): + with sentry_sdk.start_span(name="custom parent"): + with sentry_sdk.start_span(name="span 1"): pass - with sentry_sdk.traces.start_span(name="span 2"): + with sentry_sdk.start_span(name="span 2"): pass - with sentry_sdk.traces.start_span(name="span 3"): + with sentry_sdk.start_span(name="span 3"): pass sentry_sdk.flush() @@ -144,7 +137,6 @@ def test_drop_isolated_per_bucket( sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream", ) envelopes = capture_envelopes() @@ -152,21 +144,21 @@ def test_drop_isolated_per_bucket( with sentry_sdk.new_scope(): # Keep parent open as its bucket in the batcher would be emptied when it is finished. - parent_a = sentry_sdk.traces.start_span(name="parent a") - with sentry_sdk.traces.start_span(name="a1", parent_span=parent_a) as span_a: + parent_a = sentry_sdk.start_span(name="parent a") + with sentry_sdk.start_span(name="a1", parent_span=parent_a) as span_a: trace_id_a = span_a.trace_id - with sentry_sdk.traces.start_span(name="a2", parent_span=parent_a): + with sentry_sdk.start_span(name="a2", parent_span=parent_a): pass - with sentry_sdk.traces.start_span(name="a3"): + with sentry_sdk.start_span(name="a3"): pass with sentry_sdk.new_scope(): - sentry_sdk.traces.new_trace() + sentry_sdk.new_trace() # Keep parent open as its bucket in the batcher would be emptied when it is finished. - parent_b = sentry_sdk.traces.start_span(name="parent b") - with sentry_sdk.traces.start_span(name="b1", parent_span=parent_b) as span_b: + parent_b = sentry_sdk.start_span(name="parent b") + with sentry_sdk.start_span(name="b1", parent_span=parent_b) as span_b: trace_id_b = span_b.trace_id - with sentry_sdk.traces.start_span(name="b2", parent_span=parent_b): + with sentry_sdk.start_span(name="b2", parent_span=parent_b): pass sentry_sdk.flush() @@ -195,13 +187,12 @@ def test_length_based_flushing(sentry_init, capture_items, monkeypatch): sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream", ) items = capture_items("span") - with sentry_sdk.traces.start_span(name="custom parent"): - with sentry_sdk.traces.start_span(name="span"): + with sentry_sdk.start_span(name="custom parent"): + with sentry_sdk.start_span(name="span"): pass time.sleep(0.1) @@ -219,13 +210,12 @@ def test_weight_based_flushing(sentry_init, capture_envelopes, monkeypatch): sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream", ) envelopes = capture_envelopes() - with sentry_sdk.traces.start_span(name="custom parent"): - with sentry_sdk.traces.start_span(name="span"): + with sentry_sdk.start_span(name="custom parent"): + with sentry_sdk.start_span(name="span"): pass time.sleep(0.1) @@ -245,13 +235,12 @@ def test_weight_based_flushing_by_attribute_size( sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream", ) envelopes = capture_envelopes() - with sentry_sdk.traces.start_span(name="custom parent"): - with sentry_sdk.traces.start_span(name="small span") as bare_span: + with sentry_sdk.start_span(name="custom parent"): + with sentry_sdk.start_span(name="small span") as bare_span: pass bare_span_size = SpanBatcher._estimate_size(bare_span._to_json()) @@ -264,9 +253,7 @@ def test_weight_based_flushing_by_attribute_size( # The first span alone is well under the byte limit, so no flush yet. assert len(envelopes) == 0 - with sentry_sdk.traces.start_span( - name="big span", attributes={"big": big_attr} - ): + with sentry_sdk.start_span(name="big span", attributes={"big": big_attr}): pass time.sleep(0.1) @@ -283,26 +270,25 @@ def test_bucket_recreated_after_flush(sentry_init, capture_envelopes, monkeypatc sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream", ) envelopes = capture_envelopes() - sentry_sdk.traces.new_trace() + sentry_sdk.new_trace() - with sentry_sdk.traces.start_span(name="custom parent"): - with sentry_sdk.traces.start_span(name="span 1") as span1: + with sentry_sdk.start_span(name="custom parent"): + with sentry_sdk.start_span(name="span 1") as span1: trace_id = span1.trace_id - with sentry_sdk.traces.start_span(name="span 2"): + with sentry_sdk.start_span(name="span 2"): pass time.sleep(0.1) assert len(envelopes) == 1 - with sentry_sdk.traces.start_span(name="span 3"): + with sentry_sdk.start_span(name="span 3"): pass - with sentry_sdk.traces.start_span(name="span 4"): + with sentry_sdk.start_span(name="span 4"): pass time.sleep(0.1) @@ -333,13 +319,12 @@ def test_quiet_buckets_flush_eventually(sentry_init, capture_envelopes, monkeypa sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream", ) envelopes = capture_envelopes() - with sentry_sdk.traces.start_span(name="custom parent"): - with sentry_sdk.traces.start_span(name="span 1"): + with sentry_sdk.start_span(name="custom parent"): + with sentry_sdk.start_span(name="span 1"): pass time.sleep(0.3) @@ -359,28 +344,27 @@ def test_quiet_buckets_flushed_with_busy_neighbors( sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream", ) envelopes = capture_envelopes() - sentry_sdk.traces.new_trace() + sentry_sdk.new_trace() with sentry_sdk.new_scope(): # Keep parent open as its bucket in the batcher would be emptied when it is finished. - parent_a = sentry_sdk.traces.start_span(name="parent a") - with sentry_sdk.traces.start_span(name="span 1", parent_span=parent_a) as span1: + parent_a = sentry_sdk.start_span(name="parent a") + with sentry_sdk.start_span(name="span 1", parent_span=parent_a) as span1: trace_id1 = span1.trace_id with sentry_sdk.new_scope(): - sentry_sdk.traces.new_trace() + sentry_sdk.new_trace() # Keep parent open as its bucket in the batcher would be emptied when it is finished. - parent_b = sentry_sdk.traces.start_span(name="parent b") - with sentry_sdk.traces.start_span(name="span 2", parent_span=parent_b) as span2: + parent_b = sentry_sdk.start_span(name="parent b") + with sentry_sdk.start_span(name="span 2", parent_span=parent_b) as span2: trace_id2 = span2.trace_id for i in range(3, 10): - with sentry_sdk.traces.start_span(name=f"span {i}", parent_span=parent_b): + with sentry_sdk.start_span(name=f"span {i}", parent_span=parent_b): pass time.sleep(0.3) @@ -412,12 +396,11 @@ def test_transport_format(sentry_init, capture_envelopes): server_name="test-server", release="1.0.0", traces_sample_rate=1.0, - trace_lifecycle="stream", ) envelopes = capture_envelopes() - with sentry_sdk.traces.start_span(name="test"): + with sentry_sdk.start_span(name="test"): ... sentry_sdk.get_client().flush() @@ -465,11 +448,11 @@ def test_trace_bucket_flushes_when_segment_ends( """All currently completed spans in a trace are flushed when the segment is finished.""" monkeypatch.setattr(SpanBatcher, "FLUSH_WAIT_TIME", 100000) - sentry_init(traces_sample_rate=1.0, trace_lifecycle="stream") + sentry_init(traces_sample_rate=1.0) items = capture_items("span") - with sentry_sdk.traces.start_span(name="segment span"): - with sentry_sdk.traces.start_span(name="child"): + with sentry_sdk.start_span(name="segment span"): + with sentry_sdk.start_span(name="child"): pass time.sleep(0.1) @@ -498,7 +481,6 @@ def test_span_batcher_lock_reset_in_child_after_fork(sentry_init): """ sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream", ) batcher = sentry_sdk.get_client().span_batcher assert batcher is not None diff --git a/tests/tracing/test_span_name.py b/tests/tracing/test_span_name.py deleted file mode 100644 index 9c1768990a..0000000000 --- a/tests/tracing/test_span_name.py +++ /dev/null @@ -1,59 +0,0 @@ -import pytest - -import sentry_sdk - - -def test_start_span_description(sentry_init, capture_events): - sentry_init(traces_sample_rate=1.0) - events = capture_events() - - with sentry_sdk.start_transaction(name="hi"): - with pytest.deprecated_call(): - with sentry_sdk.start_span(op="foo", description="span-desc"): - ... - - (event,) = events - - assert event["spans"][0]["description"] == "span-desc" - - -def test_start_span_name(sentry_init, capture_events): - sentry_init(traces_sample_rate=1.0) - events = capture_events() - - with sentry_sdk.start_transaction(name="hi"): - with sentry_sdk.start_span(op="foo", name="span-name"): - ... - - (event,) = events - - assert event["spans"][0]["description"] == "span-name" - - -def test_start_child_description(sentry_init, capture_events): - sentry_init(traces_sample_rate=1.0) - events = capture_events() - - with sentry_sdk.start_transaction(name="hi"): - with pytest.deprecated_call(): - with sentry_sdk.start_span(op="foo", description="span-desc") as span: - with span.start_child(op="bar", description="child-desc"): - ... - - (event,) = events - - assert event["spans"][-1]["description"] == "child-desc" - - -def test_start_child_name(sentry_init, capture_events): - sentry_init(traces_sample_rate=1.0) - events = capture_events() - - with sentry_sdk.start_transaction(name="hi"): - with sentry_sdk.start_span(op="foo", name="span-name") as span: - with span.start_child(op="bar", name="child-name"): - ... - - (event,) = events - - assert event["spans"][-1]["description"] == "child-name" diff --git a/tests/tracing/test_span_origin.py b/tests/tracing/test_span_origin.py index fbdf8c356b..758de8b066 100644 --- a/tests/tracing/test_span_origin.py +++ b/tests/tracing/test_span_origin.py @@ -1,48 +1,11 @@ import sentry_sdk -def test_span_origin_manual(sentry_init, capture_events): +def test_span_origin_manual(sentry_init, capture_items): sentry_init(traces_sample_rate=1.0) - events = capture_events() - - with sentry_sdk.start_transaction(name="hi"): - with sentry_sdk.start_span(op="foo", name="bar"): - pass - - (event,) = events - - assert len(events) == 1 - assert event["spans"][0]["origin"] == "manual" - assert event["contexts"]["trace"]["origin"] == "manual" - - -def test_span_origin_custom(sentry_init, capture_events): - sentry_init(traces_sample_rate=1.0) - events = capture_events() - - with sentry_sdk.start_transaction(name="hi"): - with sentry_sdk.start_span(op="foo", name="bar", origin="foo.foo2.foo3"): - pass - - with sentry_sdk.start_transaction(name="ho", origin="ho.ho2.ho3"): - with sentry_sdk.start_span(op="baz", name="qux", origin="baz.baz2.baz3"): - pass - - (first_transaction, second_transaction) = events - - assert len(events) == 2 - assert first_transaction["contexts"]["trace"]["origin"] == "manual" - assert first_transaction["spans"][0]["origin"] == "foo.foo2.foo3" - - assert second_transaction["contexts"]["trace"]["origin"] == "ho.ho2.ho3" - assert second_transaction["spans"][0]["origin"] == "baz.baz2.baz3" - - -def test_span_origin_manual_span_streaming(sentry_init, capture_items): - sentry_init(trace_lifecycle="stream", traces_sample_rate=1.0) items = capture_items("span") - with sentry_sdk.traces.start_span(name="hi"): + with sentry_sdk.start_span(name="hi"): pass sentry_sdk.flush() @@ -53,16 +16,16 @@ def test_span_origin_manual_span_streaming(sentry_init, capture_items): assert span["attributes"]["sentry.origin"] == "manual" -def test_span_origin_custom_span_streaming(sentry_init, capture_items): - sentry_init(trace_lifecycle="stream", traces_sample_rate=1.0) +def test_span_origin_custom(sentry_init, capture_items): + sentry_init(traces_sample_rate=1.0) items = capture_items("span") - with sentry_sdk.traces.start_span( + with sentry_sdk.start_span( name="hi", attributes={"sentry.origin": "foo.foo2.foo3"} ): pass - with sentry_sdk.traces.start_span( + with sentry_sdk.start_span( name="ho", attributes={"sentry.origin": "baz.baz2.baz3"} ): pass diff --git a/tests/tracing/test_span_streaming.py b/tests/tracing/test_span_streaming.py index 8aef2f7d17..1aeaf27785 100644 --- a/tests/tracing/test_span_streaming.py +++ b/tests/tracing/test_span_streaming.py @@ -1,7 +1,6 @@ import re import sys import time -import warnings from unittest import mock import pytest @@ -9,11 +8,10 @@ import sentry_sdk from sentry_sdk.profiler.continuous_profiler import get_profiler_id from sentry_sdk.traces import ( - NoOpStreamedSpan, + NoOpSpan, + Span, SpanStatus, - StreamedSpan, ) -from sentry_sdk.tracing_utils import has_span_streaming_enabled minimum_python_38 = pytest.mark.skipif( sys.version_info < (3, 8), reason="Asyncio tests need Python >= 3.8" @@ -23,14 +21,13 @@ def test_start_span(sentry_init, capture_items): sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream", ) items = capture_items("span") - with sentry_sdk.traces.start_span(name="segment") as segment: + with sentry_sdk.start_span(name="segment") as segment: assert segment._is_segment() is True - with sentry_sdk.traces.start_span(name="child") as child: + with sentry_sdk.start_span(name="child") as child: assert child._is_segment() is False assert child._segment == segment @@ -63,13 +60,12 @@ def test_start_span(sentry_init, capture_items): def test_start_span_no_context_manager(sentry_init, capture_items): sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream", ) items = capture_items("span") - segment = sentry_sdk.traces.start_span(name="segment") - child = sentry_sdk.traces.start_span(name="child") + segment = sentry_sdk.start_span(name="segment") + child = sentry_sdk.start_span(name="child") assert child._segment == segment child.end() segment.end() @@ -111,12 +107,11 @@ def traces_sampler(sampling_context): sentry_init( traces_sampler=traces_sampler, - trace_lifecycle="stream", ) items = capture_items("span") - segment = sentry_sdk.traces.start_span(name="segment") + segment = sentry_sdk.start_span(name="segment") segment.set_attribute("delayed_attribute", 12) segment.end() @@ -133,14 +128,11 @@ def traces_sampler(sampling_context): def test_start_span_attributes(sentry_init, capture_items): sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream", ) items = capture_items("span") - with sentry_sdk.traces.start_span( - name="segment", attributes={"my_attribute": "my_value"} - ): + with sentry_sdk.start_span(name="segment", attributes={"my_attribute": "my_value"}): ... sentry_sdk.get_client().flush() @@ -165,14 +157,11 @@ def traces_sampler(sampling_context): sentry_init( traces_sampler=traces_sampler, - trace_lifecycle="stream", ) items = capture_items("span") - with sentry_sdk.traces.start_span( - name="segment", attributes={"my_attribute": "my_value"} - ): + with sentry_sdk.start_span(name="segment", attributes={"my_attribute": "my_value"}): ... sentry_sdk.get_client().flush() @@ -206,12 +195,11 @@ def traces_sampler(sampling_context): sentry_init( traces_sampler=traces_sampler, - trace_lifecycle="stream", ) items = capture_items("span") - with sentry_sdk.traces.start_span(name="span") as span: + with sentry_sdk.start_span(name="span") as span: trace_id = span._trace_id assert received_trace_id == trace_id @@ -235,13 +223,12 @@ def before_send_span(span, hint): sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream", before_send_span=before_send_span, ) items = capture_items("span") - with sentry_sdk.traces.start_span( + with sentry_sdk.start_span( name="span", attributes={ "drop": True, @@ -276,13 +263,12 @@ def before_send_span(span, hint): sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream", before_send_span=before_send_span, ) items = capture_items("span") - with sentry_sdk.traces.start_span(name="span"): + with sentry_sdk.start_span(name="span"): ... sentry_sdk.get_client().flush() @@ -303,13 +289,12 @@ def before_send_span(span, hint): sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream", before_send_span=before_send_span, ) items = capture_items("span") - with sentry_sdk.traces.start_span(name="span"): + with sentry_sdk.start_span(name="span"): ... sentry_sdk.get_client().flush() @@ -332,7 +317,6 @@ def before_send_span(span, hint): sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream", before_send_span=before_send_span, ignore_spans=[ "ignored", @@ -341,7 +325,7 @@ def before_send_span(span, hint): items = capture_items("span") - with sentry_sdk.traces.start_span(name="ignored"): + with sentry_sdk.start_span(name="ignored"): ... sentry_sdk.get_client().flush() @@ -362,13 +346,12 @@ def before_send_span(span, hint): sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream", before_send_span=before_send_span, ) items = capture_items("span") - with sentry_sdk.traces.start_span(name="span", attributes={"original": "value"}): + with sentry_sdk.start_span(name="span", attributes={"original": "value"}): ... sentry_sdk.get_client().flush() @@ -384,93 +367,14 @@ def before_send_span(span, hint): assert "mutated" not in span["attributes"] -def test_before_send_span_set_in_experiments(sentry_init, capture_items): - def before_send_span(span, hint): - span["name"] = "from experiments" - return span - - sentry_init( - traces_sample_rate=1.0, - trace_lifecycle="stream", - _experiments={ - "before_send_span": before_send_span, - }, - ) - - items = capture_items("span") - - with sentry_sdk.traces.start_span(name="span"): - ... - - sentry_sdk.get_client().flush() - spans = [item.payload for item in items] - - assert len(spans) == 1 - (span,) = spans - - assert span["name"] == "from experiments" - - -def test_before_send_span_top_level_takes_precedence_over_experiments( - sentry_init, capture_items -): - def top_level(span, hint): - span["name"] = "top-level" - return span - - def experimental(span, hint): - span["name"] = "experimental" - return span - - sentry_init( - traces_sample_rate=1.0, - trace_lifecycle="stream", - before_send_span=top_level, - _experiments={ - "before_send_span": experimental, - }, - ) - - items = capture_items("span") - - with sentry_sdk.traces.start_span(name="span"): - ... - - sentry_sdk.get_client().flush() - spans = [item.payload for item in items] - - assert len(spans) == 1 - (span,) = spans - - assert span["name"] == "top-level" - - -def test_before_send_span_warns_without_span_streaming(sentry_init): - import warnings - - def before_send_span(span, hint): - return span - - with warnings.catch_warnings(record=True) as w: - warnings.simplefilter("always") - sentry_init( - traces_sample_rate=1.0, - before_send_span=before_send_span, - ) - - (warning,) = [x for x in w if "before_send_span" in str(x.message)] - assert "trace_lifecycle" in str(warning.message) - - def test_span_attributes(sentry_init, capture_items): sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream", ) items = capture_items("span") - with sentry_sdk.traces.start_span( + with sentry_sdk.start_span( name="segment", attributes={"attribute1": "value"} ) as span: assert span.get_attributes()["attribute1"] == "value" @@ -499,7 +403,6 @@ def test_span_attributes(sentry_init, capture_items): def test_span_attributes_serialize_early(sentry_init, capture_items): sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream", ) items = capture_items("span") @@ -507,7 +410,7 @@ def test_span_attributes_serialize_early(sentry_init, capture_items): class Class: pass - with sentry_sdk.traces.start_span(name="span") as span: + with sentry_sdk.start_span(name="span") as span: span.set_attributes( { # arrays of different types will be serialized @@ -544,14 +447,13 @@ def traces_sampler(sampling_context): sentry_init( traces_sampler=traces_sampler, - trace_lifecycle="stream", ) items = capture_items("span") - with sentry_sdk.traces.start_span(name="dropped", attributes={"drop": True}): + with sentry_sdk.start_span(name="dropped", attributes={"drop": True}): ... - with sentry_sdk.traces.start_span(name="retained", attributes={"drop": False}): + with sentry_sdk.start_span(name="retained", attributes={"drop": False}): ... sentry_sdk.get_client().flush() @@ -576,14 +478,13 @@ def traces_sampler(sampling_context): sentry_init( traces_sampler=traces_sampler, - trace_lifecycle="stream", ) - with sentry_sdk.traces.start_span(name="segment") as segment: - with sentry_sdk.traces.start_span(name="child1"): + with sentry_sdk.start_span(name="segment") as segment: + with sentry_sdk.start_span(name="child1"): ... - with sentry_sdk.traces.start_span(name="child2"): - with sentry_sdk.traces.start_span(name="child3"): + with sentry_sdk.start_span(name="child2"): + with sentry_sdk.start_span(name="child3"): ... assert traces_sampler_called == 1 @@ -593,14 +494,13 @@ def traces_sampler(sampling_context): def test_start_inactive_span(sentry_init, capture_items): sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream", ) items = capture_items("span") - with sentry_sdk.traces.start_span(name="segment") as segment: - with sentry_sdk.traces.start_span(name="child1", active=False): - with sentry_sdk.traces.start_span(name="child2"): + with sentry_sdk.start_span(name="segment") as segment: + with sentry_sdk.start_span(name="child1", active=False): + with sentry_sdk.start_span(name="child2"): # Should have segment as parent since child1 is inactive pass @@ -630,14 +530,13 @@ def test_start_inactive_span(sentry_init, capture_items): def test_start_span_override_parent(sentry_init, capture_items): sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream", ) items = capture_items("span") - with sentry_sdk.traces.start_span(name="segment") as segment: - with sentry_sdk.traces.start_span(name="child1"): - with sentry_sdk.traces.start_span(name="child2", parent_span=segment): + with sentry_sdk.start_span(name="segment") as segment: + with sentry_sdk.start_span(name="child1"): + with sentry_sdk.start_span(name="child2", parent_span=segment): pass sentry_sdk.get_client().flush() @@ -669,15 +568,14 @@ def test_start_span_override_parent(sentry_init, capture_items): def test_sibling_segments(sentry_init, capture_items): sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream", ) items = capture_items("span") - with sentry_sdk.traces.start_span(name="segment1"): + with sentry_sdk.start_span(name="segment1"): ... - with sentry_sdk.traces.start_span(name="segment2"): + with sentry_sdk.start_span(name="segment2"): ... sentry_sdk.get_client().flush() @@ -702,17 +600,16 @@ def test_sibling_segments(sentry_init, capture_items): def test_sibling_segments_new_trace(sentry_init, capture_items): sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream", ) items = capture_items("span") - with sentry_sdk.traces.start_span(name="segment1"): + with sentry_sdk.start_span(name="segment1"): ... - sentry_sdk.traces.new_trace() + sentry_sdk.new_trace() - with sentry_sdk.traces.start_span(name="segment2"): + with sentry_sdk.start_span(name="segment2"): ... sentry_sdk.get_client().flush() @@ -737,7 +634,6 @@ def test_continue_trace_sampled(sentry_init, capture_items): sentry_init( # parent sampling decision takes precedence over traces_sample_rate traces_sample_rate=0.0, - trace_lifecycle="stream", ) items = capture_items("span") @@ -747,14 +643,14 @@ def test_continue_trace_sampled(sentry_init, capture_items): sample_rand = "0.222222" sampled = "1" - sentry_sdk.traces.continue_trace( + sentry_sdk.continue_trace( { "sentry-trace": f"{trace_id}-{parent_span_id}-{sampled}", "baggage": f"sentry-trace_id={trace_id},sentry-sample_rate=0.5,sentry-sample_rand={sample_rand}", } ) - with sentry_sdk.traces.start_span(name="segment") as span: + with sentry_sdk.start_span(name="segment") as span: ... assert span.sampled is True @@ -777,7 +673,6 @@ def test_continue_trace_unsampled(sentry_init, capture_items): sentry_init( # parent sampling decision takes precedence over traces_sample_rate traces_sample_rate=1.0, - trace_lifecycle="stream", ) items = capture_items("span") @@ -787,14 +682,14 @@ def test_continue_trace_unsampled(sentry_init, capture_items): sample_rand = "0.999999" sampled = "0" - sentry_sdk.traces.continue_trace( + sentry_sdk.continue_trace( { "sentry-trace": f"{trace_id}-{parent_span_id}-{sampled}", "baggage": f"sentry-trace_id={trace_id},sentry-sample_rate=0.5,sentry-sample_rand={sample_rand}", } ) - with sentry_sdk.traces.start_span(name="segment") as span: + with sentry_sdk.start_span(name="segment") as span: ... assert span.sampled is False @@ -829,7 +724,6 @@ def test_backpressure_outcome( sentry_init( traces_sample_rate=0.5, enable_backpressure_handling=True, - trace_lifecycle="stream", ) items = capture_items("span") @@ -841,14 +735,14 @@ def test_backpressure_outcome( trace_id = "0af7651916cd43dd8448eb211c80319c" parent_span_id = "b7ad6b7169203331" - sentry_sdk.traces.continue_trace( + sentry_sdk.continue_trace( { "sentry-trace": f"{trace_id}-{parent_span_id}", "baggage": f"sentry-trace_id={trace_id},sentry-sample_rand={sample_rand}", } ) - with sentry_sdk.traces.start_span(name="span") as span: + with sentry_sdk.start_span(name="span") as span: pass sentry_sdk.get_client().flush() @@ -875,7 +769,6 @@ def test_continue_trace_no_sample_rand(sentry_init, capture_items): sentry_init( # parent sampling decision takes precedence over traces_sample_rate traces_sample_rate=0.0, - trace_lifecycle="stream", ) items = capture_items("span") @@ -884,14 +777,14 @@ def test_continue_trace_no_sample_rand(sentry_init, capture_items): parent_span_id = "b7ad6b7169203331" sampled = "1" - sentry_sdk.traces.continue_trace( + sentry_sdk.continue_trace( { "sentry-trace": f"{trace_id}-{parent_span_id}-{sampled}", "baggage": f"sentry-trace_id={trace_id},sentry-sample_rate=0.5", } ) - with sentry_sdk.traces.start_span(name="segment") as span: + with sentry_sdk.start_span(name="segment") as span: ... assert span.sampled is True @@ -930,12 +823,11 @@ def test_outgoing_traceparent_and_baggage_head_sdk(sentry_init, traces_sample_ra sentry_init( traces_sample_rate=traces_sample_rate, - trace_lifecycle="stream", ) - sentry_sdk.traces.new_trace() + sentry_sdk.new_trace() - with sentry_sdk.traces.start_span(name="span") as span: + with sentry_sdk.start_span(name="span") as span: assert span.sampled is expected_sampled trace_id = span.trace_id @@ -997,7 +889,6 @@ def test_outgoing_traceparent_and_baggage_incoming_trace( # test_outgoing_traceparent_and_baggage_incoming_trace_deferred sentry_init( traces_sample_rate=traces_sample_rate, - trace_lifecycle="stream", ) trace_id = "0af7651916cd43dd8448eb211c80319c" @@ -1026,7 +917,7 @@ def test_outgoing_traceparent_and_baggage_incoming_trace( } ) - sentry_sdk.traces.continue_trace( + sentry_sdk.continue_trace( { "sentry-trace": incoming_sentry_trace, "baggage": ",".join( @@ -1035,7 +926,7 @@ def test_outgoing_traceparent_and_baggage_incoming_trace( } ) - with sentry_sdk.traces.start_span(name="span") as span: + with sentry_sdk.start_span(name="span") as span: assert span.sampled is parent_sampled traceparent = sentry_sdk.get_traceparent() @@ -1077,7 +968,6 @@ def test_outgoing_traceparent_and_baggage_inconsistent_incoming_trace( # sampling decision sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream", ) trace_id = "0af7651916cd43dd8448eb211c80319c" @@ -1093,7 +983,7 @@ def test_outgoing_traceparent_and_baggage_inconsistent_incoming_trace( "sentry-sampled": "true", } - sentry_sdk.traces.continue_trace( + sentry_sdk.continue_trace( { "sentry-trace": incoming_sentry_trace, "baggage": ",".join( @@ -1102,7 +992,7 @@ def test_outgoing_traceparent_and_baggage_inconsistent_incoming_trace( } ) - with sentry_sdk.traces.start_span(name="span") as span: + with sentry_sdk.start_span(name="span") as span: assert span.sampled is False traceparent = sentry_sdk.get_traceparent() @@ -1135,7 +1025,6 @@ def test_outgoing_traceparent_and_baggage_incoming_trace_deferred( """The SDK handles a deferred incoming sampling decision correctly.""" sentry_init( traces_sample_rate=traces_sample_rate, - trace_lifecycle="stream", ) if traces_sample_rate == 0.0: @@ -1150,7 +1039,7 @@ def test_outgoing_traceparent_and_baggage_incoming_trace_deferred( incoming_baggage = {"sentry-trace_id": trace_id, "sentry-sample_rand": "0.500000"} - sentry_sdk.traces.continue_trace( + sentry_sdk.continue_trace( { "sentry-trace": f"{trace_id}-{parent_span_id}-", "baggage": ",".join( @@ -1159,7 +1048,7 @@ def test_outgoing_traceparent_and_baggage_incoming_trace_deferred( } ) - with sentry_sdk.traces.start_span(name="span") as span: + with sentry_sdk.start_span(name="span") as span: assert span.sampled is expected_sampled traceparent = sentry_sdk.get_traceparent() @@ -1191,7 +1080,6 @@ def test_outgoing_traceparent_and_baggage_incoming_trace_deferred( def test_outgoing_traceparent_and_baggage_ignored_segment(sentry_init): sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream", ignore_spans=[ "ignored", ], @@ -1207,7 +1095,7 @@ def test_outgoing_traceparent_and_baggage_ignored_segment(sentry_init): "sentry-sample_rate": "1.0", } - sentry_sdk.traces.continue_trace( + sentry_sdk.continue_trace( { "sentry-trace": f"{trace_id}-{parent_span_id}-1", "baggage": ",".join( @@ -1216,7 +1104,7 @@ def test_outgoing_traceparent_and_baggage_ignored_segment(sentry_init): } ) - with sentry_sdk.traces.start_span(name="ignored") as span: + with sentry_sdk.start_span(name="ignored") as span: assert span.sampled is False traceparent = sentry_sdk.get_traceparent() @@ -1230,7 +1118,6 @@ def test_outgoing_traceparent_and_baggage_ignored_segment(sentry_init): def test_outgoing_traceparent_and_baggage_ignored_child_span(sentry_init): sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream", ignore_spans=[ "ignored", ], @@ -1245,7 +1132,7 @@ def test_outgoing_traceparent_and_baggage_ignored_child_span(sentry_init): "sentry-sample_rate": "1.0", } - sentry_sdk.traces.continue_trace( + sentry_sdk.continue_trace( { "sentry-trace": f"{trace_id}-{parent_span_id}-1", "baggage": ",".join( @@ -1254,10 +1141,10 @@ def test_outgoing_traceparent_and_baggage_ignored_child_span(sentry_init): } ) - with sentry_sdk.traces.start_span(name="span") as segment: + with sentry_sdk.start_span(name="span") as segment: assert segment.sampled is True - with sentry_sdk.traces.start_span(name="ignored") as child: + with sentry_sdk.start_span(name="ignored") as child: assert child.sampled is False traceparent = sentry_sdk.get_traceparent() @@ -1275,15 +1162,14 @@ def test_outgoing_traceparent_and_baggage_ignored_child_span(sentry_init): def test_set_span_status(sentry_init, capture_items): sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream", ) items = capture_items("span") - with sentry_sdk.traces.start_span(name="span") as span: + with sentry_sdk.start_span(name="span") as span: span.status = SpanStatus.ERROR - with sentry_sdk.traces.start_span(name="span") as span: + with sentry_sdk.start_span(name="span") as span: span.status = "error" sentry_sdk.get_client().flush() @@ -1299,13 +1185,12 @@ def test_set_span_status(sentry_init, capture_items): def test_set_span_status_on_error(sentry_init, capture_items): sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream", ) items = capture_items("span") with pytest.raises(ValueError): - with sentry_sdk.traces.start_span(name="span") as span: + with sentry_sdk.start_span(name="span") as span: raise ValueError("oh no!") sentry_sdk.get_client().flush() @@ -1320,13 +1205,12 @@ def test_set_span_status_on_error(sentry_init, capture_items): def test_set_span_status_on_ignored_span(sentry_init, capture_items): sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream", ignore_spans=["ignored"], ) items = capture_items("span") - with sentry_sdk.traces.start_span(name="ignored") as span: + with sentry_sdk.start_span(name="ignored") as span: span.status = "error" sentry_sdk.get_client().flush() @@ -1413,57 +1297,21 @@ def test_set_span_status_on_ignored_span(sentry_init, capture_items): ] -@pytest.mark.parametrize( - ("ignore_spans", "name", "attributes", "ignored"), IGNORE_SPANS_CASES -) -def test_ignore_spans_set_in_experiments( - sentry_init, capture_items, ignore_spans, name, attributes, ignored -): - sentry_init( - traces_sample_rate=1.0, - _experiments={ - "trace_lifecycle": "stream", - "ignore_spans": ignore_spans, - }, - ) - - items = capture_items("span") - - with sentry_sdk.traces.start_span(name=name, attributes=attributes) as span: - if ignored: - assert span.sampled is False - assert isinstance(span, NoOpStreamedSpan) - else: - assert span.sampled is True - assert isinstance(span, StreamedSpan) - - sentry_sdk.get_client().flush() - spans = [item.payload for item in items] - - if ignored: - assert len(spans) == 0 - else: - assert len(spans) == 1 - (span,) = spans - assert span["name"] == name - - def test_ignore_spans_basic( sentry_init, capture_items, capture_record_lost_event_calls ): sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream", ignore_spans=["ignored"], ) items = capture_items("span") lost_event_calls = capture_record_lost_event_calls() - with sentry_sdk.traces.start_span(name="ignored") as ignored_span: + with sentry_sdk.start_span(name="ignored") as ignored_span: assert ignored_span.sampled is False - with sentry_sdk.traces.start_span(name="not ignored") as span: + with sentry_sdk.start_span(name="not ignored") as span: assert span.sampled is True sentry_sdk.get_client().flush() @@ -1485,24 +1333,23 @@ def test_ignore_spans_ignored_segment_drops_whole_tree( # Ignored segments should drop the whole span tree. sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream", ignore_spans=["ignored"], ) items = capture_items("span") lost_event_calls = capture_record_lost_event_calls() - with sentry_sdk.traces.start_span(name="ignored") as ignored_span: + with sentry_sdk.start_span(name="ignored") as ignored_span: assert ignored_span.sampled is False - assert isinstance(ignored_span, NoOpStreamedSpan) + assert isinstance(ignored_span, NoOpSpan) - with sentry_sdk.traces.start_span(name="not ignored") as span1: + with sentry_sdk.start_span(name="not ignored") as span1: assert span1.sampled is False - assert isinstance(span1, NoOpStreamedSpan) + assert isinstance(span1, NoOpSpan) - with sentry_sdk.traces.start_span(name="not ignored") as span2: + with sentry_sdk.start_span(name="not ignored") as span2: assert span2.sampled is False - assert isinstance(span2, NoOpStreamedSpan) + assert isinstance(span2, NoOpSpan) sentry_sdk.get_client().flush() spans = [item.payload for item in items] @@ -1520,23 +1367,22 @@ def test_ignore_spans_ignored_segment_drops_whole_tree_explicit_parent_span( # Ignored segments should drop the whole span tree. sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream", ignore_spans=["ignored"], ) items = capture_items("span") lost_event_calls = capture_record_lost_event_calls() - ignored_span = sentry_sdk.traces.start_span(name="ignored") - assert isinstance(ignored_span, NoOpStreamedSpan) + ignored_span = sentry_sdk.start_span(name="ignored") + assert isinstance(ignored_span, NoOpSpan) assert ignored_span.sampled is False - span1 = sentry_sdk.traces.start_span(name="not ignored 1", parent_span=ignored_span) - assert isinstance(span1, NoOpStreamedSpan) + span1 = sentry_sdk.start_span(name="not ignored 1", parent_span=ignored_span) + assert isinstance(span1, NoOpSpan) assert span1.sampled is False - span2 = sentry_sdk.traces.start_span(name="not ignored 2", parent_span=ignored_span) - assert isinstance(span2, NoOpStreamedSpan) + span2 = sentry_sdk.start_span(name="not ignored 2", parent_span=ignored_span) + assert isinstance(span2, NoOpSpan) assert span2.sampled is False span1.end() @@ -1560,23 +1406,22 @@ def test_ignore_spans_set_ignored_child_span_as_parent( # Ignored non-segment spans should NOT drop the whole subtree under them. sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream", ignore_spans=["ignored"], ) items = capture_items("span") lost_event_calls = capture_record_lost_event_calls() - with sentry_sdk.traces.start_span(name="segment") as segment: + with sentry_sdk.start_span(name="segment") as segment: assert segment.sampled is True - with sentry_sdk.traces.start_span(name="ignored") as ignored_span1: + with sentry_sdk.start_span(name="ignored") as ignored_span1: assert ignored_span1.sampled is False - with sentry_sdk.traces.start_span(name="ignored") as ignored_span2: + with sentry_sdk.start_span(name="ignored") as ignored_span2: assert ignored_span2.sampled is False - with sentry_sdk.traces.start_span(name="child") as span: + with sentry_sdk.start_span(name="child") as span: assert span.sampled is True assert span._parent_span_id == segment.span_id @@ -1600,30 +1445,27 @@ def test_ignore_spans_set_ignored_child_span_as_parent_explicit_parent_span( # Ignored non-segment spans should NOT drop the whole subtree under them. sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream", ignore_spans=["ignored"], ) items = capture_items("span") lost_event_calls = capture_record_lost_event_calls() - segment = sentry_sdk.traces.start_span(name="segment") - assert not isinstance(segment, NoOpStreamedSpan) + segment = sentry_sdk.start_span(name="segment") + assert not isinstance(segment, NoOpSpan) assert segment.sampled is True assert segment._parent_span_id is None - ignored_span1 = sentry_sdk.traces.start_span(name="ignored", parent_span=segment) - assert isinstance(ignored_span1, NoOpStreamedSpan) + ignored_span1 = sentry_sdk.start_span(name="ignored", parent_span=segment) + assert isinstance(ignored_span1, NoOpSpan) assert ignored_span1.sampled is False - ignored_span2 = sentry_sdk.traces.start_span( - name="ignored", parent_span=ignored_span1 - ) - assert isinstance(ignored_span2, NoOpStreamedSpan) + ignored_span2 = sentry_sdk.start_span(name="ignored", parent_span=ignored_span1) + assert isinstance(ignored_span2, NoOpSpan) assert ignored_span2.sampled is False - span = sentry_sdk.traces.start_span(name="child", parent_span=ignored_span2) - assert not isinstance(span, NoOpStreamedSpan) + span = sentry_sdk.start_span(name="child", parent_span=ignored_span2) + assert not isinstance(span, NoOpSpan) assert span.sampled is True assert span._parent_span_id == segment.span_id span.end() @@ -1649,27 +1491,26 @@ def test_ignore_spans_set_ignored_child_span_as_parent_explicit_parent_span( def test_ignore_spans_reparenting(sentry_init, capture_items): sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream", ignore_spans=["ignored"], ) items = capture_items("span") - with sentry_sdk.traces.start_span(name="segment") as span1: + with sentry_sdk.start_span(name="segment") as span1: assert span1.sampled is True assert span1._parent_span_id is None - with sentry_sdk.traces.start_span(name="ignored") as span2: + with sentry_sdk.start_span(name="ignored") as span2: assert span2.sampled is False - with sentry_sdk.traces.start_span(name="child 1") as span3: + with sentry_sdk.start_span(name="child 1") as span3: assert span3.sampled is True assert span3._parent_span_id == span1.span_id - with sentry_sdk.traces.start_span(name="ignored") as span4: + with sentry_sdk.start_span(name="ignored") as span4: assert span4.sampled is False - with sentry_sdk.traces.start_span(name="child 2") as span5: + with sentry_sdk.start_span(name="child 2") as span5: assert span5.sampled is True assert span5._parent_span_id == span3.span_id @@ -1690,17 +1531,16 @@ def test_ignored_spans_produce_client_report( ): sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream", ignore_spans=["ignored"], ) items = capture_items("span") record_lost_event_calls = capture_record_lost_event_calls() - with sentry_sdk.traces.start_span(name="ignored"): - with sentry_sdk.traces.start_span(name="span1"): + with sentry_sdk.start_span(name="ignored"): + with sentry_sdk.start_span(name="span1"): pass - with sentry_sdk.traces.start_span(name="span2"): + with sentry_sdk.start_span(name="span2"): pass sentry_sdk.get_client().flush() @@ -1725,7 +1565,6 @@ def test_segment_span_has_profiler_id( profile_lifecycle="trace", profiler_mode="thread", profile_session_sample_rate=1.0, - trace_lifecycle="stream", _experiments={ "continuous_profiling_auto_start": True, }, @@ -1733,7 +1572,7 @@ def test_segment_span_has_profiler_id( items = capture_items("span") envelopes = capture_envelopes() - with sentry_sdk.traces.start_span(name="profiled segment"): + with sentry_sdk.start_span(name="profiled segment"): time.sleep(0.1) sentry_sdk.get_client().flush() @@ -1760,7 +1599,6 @@ def test_segment_span_no_profiler_id_when_unsampled( profile_lifecycle="trace", profiler_mode="thread", profile_session_sample_rate=0.0, - trace_lifecycle="stream", _experiments={ "continuous_profiling_auto_start": True, }, @@ -1768,7 +1606,7 @@ def test_segment_span_no_profiler_id_when_unsampled( items = capture_items("span") envelopes = capture_envelopes() - with sentry_sdk.traces.start_span(name="segment"): + with sentry_sdk.start_span(name="segment"): time.sleep(0.05) sentry_sdk.get_client().flush() @@ -1796,14 +1634,13 @@ def test_profile_stops_when_segment_ends( profile_lifecycle="trace", profiler_mode="thread", profile_session_sample_rate=1.0, - trace_lifecycle="stream", _experiments={ "continuous_profiling_auto_start": True, }, ) capture_envelopes() - with sentry_sdk.traces.start_span(name="segment") as span: + with sentry_sdk.start_span(name="segment") as span: time.sleep(0.1) assert span._continuous_profile is not None assert span._continuous_profile.active is True @@ -1820,12 +1657,11 @@ def test_default_attributes(sentry_init, capture_envelopes): release="1.0.0", dist="1.0", traces_sample_rate=1.0, - trace_lifecycle="stream", ) envelopes = capture_envelopes() - with sentry_sdk.traces.start_span(name="test"): + with sentry_sdk.start_span(name="test"): ... sentry_sdk.get_client().flush() @@ -1868,52 +1704,6 @@ def test_default_attributes(sentry_init, capture_envelopes): } -@pytest.mark.parametrize( - ("options", "expected"), - [ - ({"trace_lifecycle": "stream"}, True), - ({"_experiments": {"trace_lifecycle": "stream"}}, True), - ( - { - "trace_lifecycle": "stream", - "_experiments": {"trace_lifecycle": "static"}, - }, - True, - ), - ( - { - "trace_lifecycle": "static", - "_experiments": {"trace_lifecycle": "stream"}, - }, - False, - ), - ({"trace_lifecycle": "static"}, False), - ({"_experiments": {"trace_lifecycle": "static"}}, False), - ({}, False), - ({"_experiments": {}}, False), - ({"_experiments": None}, False), - (None, False), - ], -) -def test_has_span_streaming_enabled(options, expected): - assert has_span_streaming_enabled(options) is expected - - -def test_trace_lifecycle_top_level_enables_streaming(sentry_init, capture_items): - sentry_init(traces_sample_rate=1.0, trace_lifecycle="stream") - - items = capture_items("span") - - with sentry_sdk.traces.start_span(name="segment") as segment: - assert isinstance(segment, StreamedSpan) - - sentry_sdk.get_client().flush() - spans = [item.payload for item in items] - - assert len(spans) == 1 - assert spans[0]["name"] == "segment" - - @pytest.mark.parametrize( ("ignore_spans", "name", "attributes", "ignored"), IGNORE_SPANS_CASES ) @@ -1922,19 +1712,18 @@ def test_ignore_spans_top_level( ): sentry_init( traces_sample_rate=1.0, - trace_lifecycle="stream", ignore_spans=ignore_spans, ) items = capture_items("span") - with sentry_sdk.traces.start_span(name=name, attributes=attributes) as span: + with sentry_sdk.start_span(name=name, attributes=attributes) as span: if ignored: assert span.sampled is False - assert isinstance(span, NoOpStreamedSpan) + assert isinstance(span, NoOpSpan) else: assert span.sampled is True - assert isinstance(span, StreamedSpan) + assert isinstance(span, Span) sentry_sdk.get_client().flush() spans = [item.payload for item in items] @@ -1945,97 +1734,3 @@ def test_ignore_spans_top_level( assert len(spans) == 1 (span,) = spans assert span["name"] == name - - -def test_ignore_spans_top_level_with_trace_lifecycle_in_experiments( - sentry_init, capture_items -): - sentry_init( - traces_sample_rate=1.0, - ignore_spans=["ignored"], - _experiments={"trace_lifecycle": "stream"}, - ) - - items = capture_items("span") - - with sentry_sdk.traces.start_span(name="ignored") as ignored_span: - assert ignored_span.sampled is False - assert isinstance(ignored_span, NoOpStreamedSpan) - - with sentry_sdk.traces.start_span(name="not ignored") as span: - assert span.sampled is True - - sentry_sdk.get_client().flush() - spans = [item.payload for item in items] - - assert len(spans) == 1 - (span,) = spans - assert span["name"] == "not ignored" - - -def test_ignore_spans_empty_top_level_overrides_experiments(sentry_init, capture_items): - # An explicit empty top-level ignore_spans should disable ignoring, - # taking precedence over any rules set in _experiments. - sentry_init( - traces_sample_rate=1.0, - trace_lifecycle="stream", - ignore_spans=[], - _experiments={"ignore_spans": ["ignored"]}, - ) - - items = capture_items("span") - - with sentry_sdk.traces.start_span(name="ignored") as span: - assert span.sampled is True - assert isinstance(span, StreamedSpan) - - sentry_sdk.get_client().flush() - spans = [item.payload for item in items] - - assert len(spans) == 1 - (span,) = spans - assert span["name"] == "ignored" - - -@pytest.mark.parametrize( - ("options", "streaming_enabled"), - [ - ( - { - "trace_lifecycle": "stream", - "_experiments": {"trace_lifecycle": "static"}, - }, - True, - ), - ( - { - "trace_lifecycle": "static", - "_experiments": {"trace_lifecycle": "stream"}, - }, - False, - ), - ], -) -def test_top_level_trace_lifecycle_takes_precedence_over_experiments( - sentry_init, capture_items, options, streaming_enabled -): - sentry_init(traces_sample_rate=1.0, **options) - - items = capture_items("span") - - with warnings.catch_warnings(): - warnings.simplefilter("ignore") - with sentry_sdk.traces.start_span(name="segment") as segment: - if streaming_enabled: - assert isinstance(segment, StreamedSpan) - else: - assert isinstance(segment, NoOpStreamedSpan) - - sentry_sdk.get_client().flush() - spans = [item.payload for item in items] - - if streaming_enabled: - assert len(spans) == 1 - assert spans[0]["name"] == "segment" - else: - assert len(spans) == 0 diff --git a/tests/utils/test_contextvars.py b/tests/utils/test_contextvars.py deleted file mode 100644 index 50881314c1..0000000000 --- a/tests/utils/test_contextvars.py +++ /dev/null @@ -1,52 +0,0 @@ -import random -import time -from unittest import mock - -import pytest - - -def _run_contextvar_threaded_test(): - import threading - - # Need to explicitly call _get_contextvars because the SDK has already - # decided upon gevent on import. - from sentry_sdk import utils - - _, ContextVar = utils._get_contextvars() # noqa: N806 - - ts = [] - - var = ContextVar("test_contextvar_leaks") - - success = [] - - def run(): - value = int(random.random() * 1000) - var.set(value) - - for _ in range(100): - time.sleep(0) - assert var.get(None) == value - - success.append(1) - - for _ in range(20): - t = threading.Thread(target=run) - t.start() - ts.append(t) - - for t in ts: - t.join() - - assert len(success) == 20 - - -@pytest.mark.forked -def test_leaks(maybe_monkeypatched_threading): - _run_contextvar_threaded_test() - - -@pytest.mark.forked -@mock.patch("sentry_sdk.utils._is_contextvars_broken", return_value=True) -def test_leaks_when_is_contextvars_broken_is_false(maybe_monkeypatched_threading): - _run_contextvar_threaded_test() diff --git a/tox.ini b/tox.ini index 294282486b..8870e65f49 100644 --- a/tox.ini +++ b/tox.ini @@ -17,13 +17,10 @@ requires = tox-uv envlist = # === Common === - {py3.6,py3.7,py3.8,py3.9,py3.10,py3.11,py3.12,py3.13,py3.14,py3.14t,py3.15,py3.15t}-common + {py3.7,py3.8,py3.9,py3.10,py3.11,py3.12,py3.13,py3.14,py3.14t,py3.15,py3.15t}-common # === Gevent === - {py3.6,py3.8,py3.10,py3.11,py3.12}-gevent - - # === Integration Deactivation === - {py3.9,py3.10,py3.11,py3.12,py3.13,py3.14}-integration_deactivation + {py3.7,py3.8,py3.10,py3.11,py3.12}-gevent # === Shadowed Module === {py3.7,py3.8,py3.9,py3.10,py3.11,py3.12,py3.13,py3.14,py3.14t,py3.15,py3.15t}-shadowed_module @@ -37,48 +34,37 @@ envlist = {py3.8,py3.9,py3.11,py3.13}-aws_lambda # Cloud Resource Context - {py3.6,py3.12,py3.13}-cloud_resource_context + {py3.7,py3.12,py3.13}-cloud_resource_context # GCP {py3.7}-gcp - # OpenTelemetry (OTel) - {py3.7,py3.9,py3.12,py3.13,py3.14,py3.14t}-opentelemetry - # OpenTelemetry with OTLP {py3.7,py3.9,py3.12,py3.13,py3.14}-otlp - # OpenTelemetry Experimental (POTel) - {py3.8,py3.9,py3.10,py3.11,py3.12,py3.13}-potel - # === Integrations - Auto-generated === # These come from the populate_tox.py script. # ~~~ MCP ~~~ - {py3.10,py3.12,py3.13}-mcp-v1.15.0 - {py3.10,py3.13,py3.14,py3.14t}-mcp-v1.30.0 + {py3.10,py3.13,py3.14,py3.14t}-mcp-v2.0.1 + {py3.10,py3.13,py3.14,py3.14t}-mcp-v2.1.1 {py3.10,py3.13,py3.14,py3.14t}-mcp-v2.2.0 {py3.10,py3.13,py3.14,py3.14t}-mcp-latest - {py3.10,py3.14,py3.15,py3.15t}-fastmcp-v0.1.0 - {py3.10,py3.14,py3.15,py3.15t}-fastmcp-v0.4.1 - {py3.10,py3.14,py3.15,py3.15t}-fastmcp-v1.0 - {py3.10,py3.12,py3.13}-fastmcp-v2.14.7 - {py3.10,py3.12,py3.13}-fastmcp-v3.4.7 {py3.10,py3.12,py3.13}-fastmcp-v4.0.5 {py3.10,py3.12,py3.13}-fastmcp-latest # ~~~ Agents ~~~ - {py3.10,py3.11,py3.12}-openai_agents-v0.0.19 - {py3.10,py3.13,py3.14,py3.14t}-openai_agents-v0.7.0 + {py3.10,py3.13,py3.14,py3.14t}-openai_agents-v0.10.5 {py3.10,py3.13,py3.14,py3.14t}-openai_agents-v0.14.8 + {py3.10,py3.13,py3.14,py3.14t}-openai_agents-v0.18.3 {py3.10,py3.13,py3.14,py3.14t}-openai_agents-v0.22.3 {py3.10,py3.13,py3.14,py3.14t}-openai_agents-latest - {py3.10,py3.12,py3.13}-pydantic_ai-v1.0.18 + {py3.10,py3.13,py3.14}-pydantic_ai-v1.76.0 {py3.10,py3.13,py3.14}-pydantic_ai-v1.107.6 - {py3.10,py3.13,py3.14,py3.14t}-pydantic_ai-v2.46.0 + {py3.10,py3.13,py3.14,py3.14t}-pydantic_ai-v2.47.0 {py3.10,py3.13,py3.14,py3.14t}-pydantic_ai-latest @@ -94,7 +80,7 @@ envlist = {py3.10,py3.13,py3.14}-langchain-notiktoken-latest {py3.9,py3.13,py3.14}-langgraph-v0.6.11 - {py3.10,py3.12,py3.13}-langgraph-v1.2.11 + {py3.10,py3.12,py3.13}-langgraph-v1.2.12 {py3.10,py3.12,py3.13}-langgraph-latest @@ -135,24 +121,24 @@ envlist = {py3.8,py3.11,py3.12}-openai-base-v1.0.1 {py3.8,py3.12,py3.13}-openai-base-v1.109.1 {py3.10,py3.13,py3.14,py3.14t}-openai-base-v2.54.0 - {py3.10,py3.13,py3.14,py3.14t}-openai-base-v3.16.2 + {py3.10,py3.13,py3.14,py3.14t}-openai-base-v3.17.0 {py3.10,py3.13,py3.14,py3.14t}-openai-base-latest {py3.8,py3.11,py3.12}-openai-notiktoken-v1.0.1 {py3.8,py3.12,py3.13}-openai-notiktoken-v1.109.1 {py3.10,py3.13,py3.14,py3.14t}-openai-notiktoken-v2.54.0 - {py3.10,py3.13,py3.14,py3.14t}-openai-notiktoken-v3.16.2 + {py3.10,py3.13,py3.14,py3.14t}-openai-notiktoken-v3.17.0 {py3.10,py3.13,py3.14,py3.14t}-openai-notiktoken-latest # ~~~ Cloud ~~~ - {py3.6,py3.7,py3.8}-boto3-v1.16.63 + {py3.7,py3.8}-boto3-v1.16.63 {py3.7,py3.10,py3.11}-boto3-v1.24.96 {py3.8,py3.12,py3.13}-boto3-v1.35.99 - {py3.10,py3.13,py3.14,py3.14t}-boto3-v1.43.98 + {py3.10,py3.13,py3.14,py3.14t}-boto3-v1.43.99 {py3.10,py3.13,py3.14,py3.14t}-boto3-latest - {py3.6,py3.7,py3.8}-chalice-v1.16.0 + {py3.7,py3.8}-chalice-v1.22.4 {py3.10,py3.13,py3.14,py3.14t}-chalice-v1.33.0 {py3.10,py3.13,py3.14,py3.14t}-chalice-latest @@ -170,13 +156,12 @@ envlist = {py3.9,py3.13,py3.14}-clickhouse_driver-v0.2.11 {py3.9,py3.13,py3.14}-clickhouse_driver-latest - {py3.6}-pymongo-v3.5.1 - {py3.6,py3.10,py3.11}-pymongo-v3.13.0 + {py3.7}-pymongo-v3.7.2 + {py3.7,py3.10,py3.11}-pymongo-v3.13.0 {py3.9,py3.13,py3.14,py3.14t}-pymongo-v4.18.1 {py3.9,py3.13,py3.14,py3.14t}-pymongo-latest - {py3.6}-redis-v2.10.6 - {py3.6,py3.7,py3.8}-redis-v3.5.3 + {py3.7,py3.9,py3.10}-redis-v4.2.2 {py3.7,py3.10,py3.11}-redis-v4.6.0 {py3.8,py3.11,py3.12}-redis-v5.3.1 {py3.9,py3.12,py3.13}-redis-v6.4.0 @@ -184,12 +169,7 @@ envlist = {py3.10,py3.13,py3.14,py3.14t}-redis-v8.1.0 {py3.10,py3.13,py3.14,py3.14t}-redis-latest - {py3.6}-redis_py_cluster_legacy-v1.3.6 - {py3.6,py3.7,py3.8}-redis_py_cluster_legacy-v2.1.3 - {py3.6,py3.7,py3.8}-redis_py_cluster_legacy-latest - - {py3.6,py3.8,py3.9}-sqlalchemy-v1.2.19 - {py3.6,py3.11,py3.12}-sqlalchemy-v1.4.54 + {py3.7,py3.11,py3.12}-sqlalchemy-v1.4.54 {py3.7,py3.14,py3.15,py3.15t}-sqlalchemy-v2.0.54 {py3.11,py3.14,py3.15,py3.15t}-sqlalchemy-v2.1.0rc2 {py3.7,py3.14,py3.15,py3.15t}-sqlalchemy-latest @@ -218,12 +198,12 @@ envlist = {py3.10,py3.13,py3.14,py3.14t}-ariadne-v1.1.0 {py3.10,py3.13,py3.14,py3.14t}-ariadne-latest - {py3.6,py3.9,py3.10}-gql-v3.4.1 + {py3.7,py3.9,py3.10}-gql-v3.4.1 {py3.9,py3.12,py3.13}-gql-v4.0.0 {py3.10,py3.13,py3.14,py3.14t}-gql-v4.4.0b0 {py3.9,py3.12,py3.13}-gql-latest - {py3.6,py3.9,py3.10}-graphene-v3.3 + {py3.7,py3.9,py3.10}-graphene-v3.3 {py3.8,py3.12,py3.13}-graphene-v3.4.3 {py3.8,py3.12,py3.13}-graphene-latest @@ -239,8 +219,8 @@ envlist = {py3.10,py3.14,py3.15}-grpc-v1.84.0 {py3.10,py3.14,py3.15}-grpc-latest - {py3.6,py3.8,py3.9}-httpx0-v0.16.1 - {py3.6,py3.9,py3.10}-httpx0-v0.20.0 + {py3.7,py3.8,py3.9}-httpx0-v0.16.1 + {py3.7,py3.9,py3.10}-httpx0-v0.20.0 {py3.7,py3.10,py3.11}-httpx0-v0.24.1 {py3.9,py3.11,py3.12}-httpx0-v0.28.1 {py3.9,py3.11,py3.12}-httpx0-latest @@ -256,7 +236,7 @@ envlist = {py3.11,py3.13,py3.14}-pyreqwest-v0.13.0 {py3.11,py3.13,py3.14}-pyreqwest-latest - {py3.6}-requests-v2.12.5 + {py3.7,py3.10,py3.11}-requests-v2.30.0 {py3.10,py3.14,py3.15,py3.15t}-requests-v2.34.2 {py3.10,py3.14,py3.15,py3.15t}-requests-latest @@ -268,13 +248,17 @@ envlist = {py3.7}-beam-v2.14.0 {py3.10,py3.13,py3.14}-beam-v2.76.0 + {py3.10,py3.13,py3.14}-beam-v2.77.0rc1 {py3.10,py3.13,py3.14}-beam-latest - {py3.6,py3.7,py3.8}-celery-v4.4.7 + {py3.7,py3.8}-celery-v5.0.5 + {py3.7,py3.9,py3.10}-celery-v5.2.7 + {py3.8,py3.11,py3.12}-celery-v5.4.0 {py3.9,py3.12,py3.13}-celery-v5.6.3 + {py3.10,py3.13,py3.14,py3.14t}-celery-v5.7.0a1 {py3.9,py3.12,py3.13}-celery-latest - {py3.6,py3.7}-dramatiq-v1.9.0 + {py3.7}-dramatiq-v1.9.0 {py3.10,py3.13,py3.14,py3.14t}-dramatiq-v2.2.1 {py3.10,py3.13,py3.14,py3.14t}-dramatiq-latest @@ -285,8 +269,7 @@ envlist = {py3.10,py3.13,py3.14}-ray-v2.58.0 {py3.10,py3.13,py3.14}-ray-latest - {py3.6}-rq-v0.6.0 - {py3.6,py3.7}-rq-v0.13.0 + {py3.7}-rq-v1.0 {py3.7,py3.11,py3.12}-rq-v1.16.2 {py3.10,py3.13,py3.14,py3.14t}-rq-v2.12.0 {py3.10,py3.13,py3.14,py3.14t}-rq-latest @@ -298,45 +281,44 @@ envlist = # ~~~ Web 1 ~~~ - {py3.6,py3.7}-django-v1.11.29 - {py3.6,py3.8,py3.9}-django-v2.2.28 - {py3.6,py3.9,py3.10}-django-v3.2.25 + {py3.7}-django-v2.0.13 + {py3.7,py3.8,py3.9}-django-v2.2.28 + {py3.7,py3.9,py3.10}-django-v3.2.25 {py3.8,py3.11,py3.12}-django-v4.2.30 {py3.10,py3.13,py3.14,py3.14t}-django-v5.2.17 {py3.12,py3.13,py3.14,py3.14t}-django-v6.1.1 {py3.12,py3.13,py3.14,py3.14t}-django-latest - {py3.6,py3.7,py3.8}-flask-v1.1.4 + {py3.7,py3.9,py3.10}-flask-v2.0.3 {py3.8,py3.14,py3.15,py3.15t}-flask-v2.3.3 {py3.9,py3.14,py3.15,py3.15t}-flask-v3.1.3 {py3.9,py3.14,py3.15,py3.15t}-flask-latest - {py3.6,py3.9,py3.10}-starlette-v0.16.0 + {py3.7,py3.9,py3.10}-starlette-v0.20.4 {py3.10,py3.13,py3.14,py3.14t}-starlette-v0.52.1 {py3.10,py3.13,py3.14,py3.14t}-starlette-v1.6.0 {py3.10,py3.13,py3.14,py3.14t}-starlette-latest - {py3.6,py3.9,py3.10}-fastapi-v0.79.1 - {py3.7,py3.10,py3.11}-fastapi-v0.100.1 - {py3.8,py3.13,py3.14,py3.14t}-fastapi-v0.121.3 + {py3.7,py3.9,py3.10}-fastapi-v0.85.2 + {py3.8,py3.10,py3.11}-fastapi-v0.104.1 + {py3.8,py3.13,py3.14,py3.14t}-fastapi-v0.123.10 {py3.10,py3.13,py3.14,py3.14t}-fastapi-v0.141.1 {py3.10,py3.13,py3.14,py3.14t}-fastapi-latest # ~~~ Web 2 ~~~ - {py3.7}-aiohttp-v3.4.4 {py3.7,py3.8,py3.9}-aiohttp-v3.7.4 - {py3.8,py3.12,py3.13}-aiohttp-v3.10.11 + {py3.8,py3.11,py3.12}-aiohttp-v3.9.5 + {py3.9,py3.12,py3.13}-aiohttp-v3.11.18 {py3.10,py3.13,py3.14,py3.14t}-aiohttp-v3.14.3 {py3.10,py3.13,py3.14,py3.14t}-aiohttp-latest - {py3.6,py3.7}-bottle-v0.12.25 + {py3.7}-bottle-v0.12.25 {py3.8,py3.12,py3.13}-bottle-v0.13.4 {py3.8,py3.12,py3.13}-bottle-latest - {py3.6}-falcon-v1.4.1 - {py3.6,py3.7}-falcon-v2.0.0 - {py3.6,py3.11,py3.12}-falcon-v3.1.3 + {py3.7,py3.8,py3.9}-falcon-v3.0.1 + {py3.7,py3.11,py3.12}-falcon-v3.1.3 {py3.9,py3.11,py3.12}-falcon-v4.3.1 {py3.9,py3.11,py3.12}-falcon-latest @@ -346,17 +328,16 @@ envlist = {py3.8,py3.13,py3.14,py3.14t}-litestar-v2.24.0 {py3.8,py3.13,py3.14,py3.14t}-litestar-latest - {py3.6}-pyramid-v1.8.6 - {py3.6,py3.8,py3.9}-pyramid-v1.10.8 + {py3.7,py3.10,py3.11}-pyramid-v2.0.2 {py3.10,py3.13,py3.14,py3.14t}-pyramid-v2.1 {py3.10,py3.13,py3.14,py3.14t}-pyramid-latest - {py3.7,py3.9,py3.10}-quart-v0.16.3 + {py3.8,py3.12,py3.13}-quart-v0.19.9 {py3.13,py3.14,py3.15,py3.15t}-quart-v0.23.1 {py3.13,py3.14,py3.15,py3.15t}-quart-latest - {py3.6}-sanic-v0.8.3 - {py3.6,py3.8,py3.9}-sanic-v20.12.7 + {py3.7,py3.9,py3.10}-sanic-v22.3.2 + {py3.7,py3.10,py3.11}-sanic-v22.12.0 {py3.8,py3.10,py3.11}-sanic-v23.12.2 {py3.10,py3.13,py3.14,py3.14t}-sanic-v25.12.1 {py3.10,py3.13,py3.14,py3.14t}-sanic-latest @@ -365,26 +346,26 @@ envlist = {py3.8,py3.10,py3.11}-starlite-v1.51.16 {py3.8,py3.10,py3.11}-starlite-latest - {py3.6,py3.7,py3.8}-tornado-v6.0.4 + {py3.7,py3.8}-tornado-v6.0.4 {py3.9,py3.12,py3.13}-tornado-v6.5.10 + {py3.11,py3.14,py3.15,py3.15t}-tornado-v6.6a1 {py3.9,py3.12,py3.13}-tornado-latest # ~~~ Misc ~~~ - {py3.6,py3.12,py3.13}-loguru-v0.7.3 - {py3.6,py3.12,py3.13}-loguru-latest + {py3.7,py3.12,py3.13}-loguru-v0.7.3 + {py3.7,py3.12,py3.13}-loguru-latest - {py3.6,py3.7,py3.8}-pure_eval-v0.0.3 + {py3.7,py3.8}-pure_eval-v0.0.3 {py3.8,py3.14,py3.15,py3.15t}-pure_eval-v0.2.4 {py3.8,py3.14,py3.15,py3.15t}-pure_eval-latest - {py3.6}-trytond-v4.6.22 - {py3.6}-trytond-v4.8.18 - {py3.6,py3.7,py3.8}-trytond-v5.8.16 - {py3.8,py3.10,py3.11}-trytond-v6.8.17 - {py3.9,py3.12,py3.13}-trytond-v7.8.16 - {py3.10,py3.14,py3.15,py3.15t}-trytond-v8.0.10 - {py3.10,py3.14,py3.15,py3.15t}-trytond-latest + {py3.7}-trytond_wsgi-v5.4.20 + {py3.7,py3.8}-trytond_wsgi-v5.8.16 + {py3.8,py3.10,py3.11}-trytond_wsgi-v6.8.17 + {py3.9,py3.12,py3.13}-trytond_wsgi-v7.8.16 + {py3.10,py3.14,py3.15,py3.15t}-trytond_wsgi-v8.0.10 + {py3.10,py3.14,py3.15,py3.15t}-trytond_wsgi-latest {py3.7,py3.12,py3.13}-typer-v0.15.4 {py3.10,py3.13,py3.14,py3.14t}-typer-v0.27.2 @@ -413,20 +394,20 @@ deps = # See https://github.com/pytest-dev/pytest/issues/9621 # and https://github.com/pytest-dev/pytest-forked/issues/67 # for justification of the upper bound on pytest - {py3.6,py3.7}-common: pytest<7.0.0 + py3.7-common: pytest<7.0.0 # Handled by importlib.metadata on Python 3.8+ - {py3.6,py3.7}-common: setuptools<82 + py3.7-common: setuptools<82 {py3.8,py3.9,py3.10,py3.11,py3.12,py3.13,py3.14,py3.14t,py3.15,py3.15t}-common: pytest # coverage 7.11.1-7.11.3 makes some of our tests flake {py3.14,py3.14t,py3.15,py3.15t}-common: coverage==7.11.0 # === Gevent === - {py3.6,py3.7,py3.8,py3.9,py3.10,py3.11}-gevent: gevent>=22.10.0, <22.11.0 + {py3.7,py3.8,py3.9,py3.10,py3.11}-gevent: gevent>=22.10.0, <22.11.0 {py3.12}-gevent: gevent # See https://github.com/pytest-dev/pytest/issues/9621 # and https://github.com/pytest-dev/pytest-forked/issues/67 # for justification of the upper bound on pytest - {py3.6,py3.7}-gevent: pytest<7.0.0 + py3.7-gevent: pytest<7.0.0 {py3.8,py3.9,py3.10,py3.11,py3.12}-gevent: pytest gevent: brotli gevent: executing @@ -443,11 +424,6 @@ deps = {py3.10,py3.11}-gevent: zope.event<5.0.0 {py3.10,py3.11}-gevent: zope.interface<8.0 - # === Integration Deactivation === - integration_deactivation: openai - integration_deactivation: anthropic - integration_deactivation: langchain - # === Integrations === # Asgi @@ -463,264 +439,319 @@ deps = aws_lambda: uvicorn aws_lambda: pyyaml - # OpenTelemetry (OTel) - opentelemetry: opentelemetry-distro - opentelemetry: pytest-forked - # OpenTelemetry with OTLP otlp: opentelemetry-distro[otlp] otlp: responses - # OpenTelemetry Experimental (POTel) - potel: opentelemetry-distro - potel: pytest-forked - # === Integrations - Auto-generated === # These come from the populate_tox.py script. # ~~~ MCP ~~~ - mcp-v1.15.0: mcp==1.15.0 - - py3.10-mcp-v1.15.0: pydantic==2.13.4 - py3.10-mcp-v1.15.0: pydantic_core==2.46.4 - py3.10-mcp-v1.15.0: pytest-asyncio==1.4.0 - py3.10-mcp-v1.15.0: backports.asyncio.runner==1.2.0 - py3.10-mcp-v1.15.0: pytest==9.1.1 - py3.10-mcp-v1.15.0: pluggy==1.6.0 - py3.10-mcp-v1.15.0: httpx==0.28.1 - py3.10-mcp-v1.15.0: httpcore==1.0.9 - py3.10-mcp-v1.15.0: annotated-types==0.8.0 - py3.10-mcp-v1.15.0: anyio==4.14.2 - py3.10-mcp-v1.15.0: exceptiongroup==1.3.1 - py3.10-mcp-v1.15.0: h11==0.16.0 - py3.10-mcp-v1.15.0: httpx-sse==0.4.3 - py3.10-mcp-v1.15.0: idna==3.18 - py3.10-mcp-v1.15.0: iniconfig==2.3.0 - py3.10-mcp-v1.15.0: jsonschema==4.26.0 - py3.10-mcp-v1.15.0: attrs==26.1.0 - py3.10-mcp-v1.15.0: jsonschema-specifications==2025.9.1 - py3.10-mcp-v1.15.0: packaging==26.2 - py3.10-mcp-v1.15.0: pydantic-settings==2.14.2 - py3.10-mcp-v1.15.0: Pygments==2.20.0 - py3.10-mcp-v1.15.0: python-dotenv==1.2.2 - py3.10-mcp-v1.15.0: python-multipart==0.0.32 - py3.10-mcp-v1.15.0: referencing==0.37.0 - py3.10-mcp-v1.15.0: rpds-py==0.30.0 - py3.10-mcp-v1.15.0: sse-starlette==3.4.6 - py3.10-mcp-v1.15.0: starlette==1.3.1 - py3.10-mcp-v1.15.0: tomli==2.4.1 - py3.10-mcp-v1.15.0: typing_extensions==4.16.0 - py3.10-mcp-v1.15.0: typing-inspection==0.4.2 - py3.10-mcp-v1.15.0: uvicorn==0.51.0 - py3.10-mcp-v1.15.0: click==8.4.2 - py3.10-mcp-v1.15.0: certifi==2026.7.22 - - py3.12-mcp-v1.15.0: pydantic==2.13.4 - py3.12-mcp-v1.15.0: pydantic_core==2.46.4 - py3.12-mcp-v1.15.0: pytest-asyncio==1.4.0 - py3.12-mcp-v1.15.0: pytest==9.1.1 - py3.12-mcp-v1.15.0: pluggy==1.6.0 - py3.12-mcp-v1.15.0: httpx==0.28.1 - py3.12-mcp-v1.15.0: httpcore==1.0.9 - py3.12-mcp-v1.15.0: annotated-types==0.8.0 - py3.12-mcp-v1.15.0: anyio==4.14.2 - py3.12-mcp-v1.15.0: h11==0.16.0 - py3.12-mcp-v1.15.0: httpx-sse==0.4.3 - py3.12-mcp-v1.15.0: idna==3.18 - py3.12-mcp-v1.15.0: iniconfig==2.3.0 - py3.12-mcp-v1.15.0: jsonschema==4.26.0 - py3.12-mcp-v1.15.0: attrs==26.1.0 - py3.12-mcp-v1.15.0: jsonschema-specifications==2025.9.1 - py3.12-mcp-v1.15.0: packaging==26.2 - py3.12-mcp-v1.15.0: pydantic-settings==2.14.2 - py3.12-mcp-v1.15.0: Pygments==2.20.0 - py3.12-mcp-v1.15.0: python-dotenv==1.2.2 - py3.12-mcp-v1.15.0: python-multipart==0.0.32 - py3.12-mcp-v1.15.0: referencing==0.37.0 - py3.12-mcp-v1.15.0: rpds-py==2026.6.3 - py3.12-mcp-v1.15.0: sse-starlette==3.4.6 - py3.12-mcp-v1.15.0: starlette==1.3.1 - py3.12-mcp-v1.15.0: typing_extensions==4.16.0 - py3.12-mcp-v1.15.0: typing-inspection==0.4.2 - py3.12-mcp-v1.15.0: uvicorn==0.51.0 - py3.12-mcp-v1.15.0: click==8.4.2 - py3.12-mcp-v1.15.0: certifi==2026.7.22 - - py3.13-mcp-v1.15.0: pytest-asyncio==1.4.0 - py3.13-mcp-v1.15.0: httpx==0.28.1 - py3.13-mcp-v1.15.0: httpcore==1.0.9 - py3.13-mcp-v1.15.0: anyio==4.14.2 - py3.13-mcp-v1.15.0: httpx-sse==0.4.3 - py3.13-mcp-v1.15.0: idna==3.18 - py3.13-mcp-v1.15.0: jsonschema==4.26.0 - py3.13-mcp-v1.15.0: pydantic==2.13.4 - py3.13-mcp-v1.15.0: pydantic_core==2.46.4 - py3.13-mcp-v1.15.0: pydantic-settings==2.14.2 - py3.13-mcp-v1.15.0: pytest==9.1.1 - py3.13-mcp-v1.15.0: python-multipart==0.0.32 - py3.13-mcp-v1.15.0: sse-starlette==3.4.6 - py3.13-mcp-v1.15.0: starlette==1.3.1 - py3.13-mcp-v1.15.0: uvicorn==0.51.0 - py3.13-mcp-v1.15.0: certifi==2026.7.22 - py3.13-mcp-v1.15.0: annotated-types==0.8.0 - py3.13-mcp-v1.15.0: attrs==26.1.0 - py3.13-mcp-v1.15.0: click==8.4.2 - py3.13-mcp-v1.15.0: h11==0.16.0 - py3.13-mcp-v1.15.0: iniconfig==2.3.0 - py3.13-mcp-v1.15.0: jsonschema-specifications==2025.9.1 - py3.13-mcp-v1.15.0: packaging==26.2 - py3.13-mcp-v1.15.0: pluggy==1.6.0 - py3.13-mcp-v1.15.0: Pygments==2.20.0 - py3.13-mcp-v1.15.0: python-dotenv==1.2.2 - py3.13-mcp-v1.15.0: referencing==0.37.0 - py3.13-mcp-v1.15.0: rpds-py==2026.6.3 - py3.13-mcp-v1.15.0: typing_extensions==4.16.0 - py3.13-mcp-v1.15.0: typing-inspection==0.4.2 - - mcp-v1.30.0: mcp==1.30.0 - - py3.10-mcp-v1.30.0: httpx==0.28.1 - py3.10-mcp-v1.30.0: httpcore==1.0.9 - py3.10-mcp-v1.30.0: pydantic==2.13.5 - py3.10-mcp-v1.30.0: pydantic_core==2.46.5 - py3.10-mcp-v1.30.0: pytest-asyncio==1.4.0 - py3.10-mcp-v1.30.0: backports.asyncio.runner==1.2.0 - py3.10-mcp-v1.30.0: pytest==9.1.1 - py3.10-mcp-v1.30.0: pluggy==1.6.0 - py3.10-mcp-v1.30.0: annotated-types==0.8.0 - py3.10-mcp-v1.30.0: anyio==4.15.1 - py3.10-mcp-v1.30.0: exceptiongroup==1.3.1 - py3.10-mcp-v1.30.0: h11==0.16.0 - py3.10-mcp-v1.30.0: httpx-sse==0.4.3 - py3.10-mcp-v1.30.0: idna==3.19 - py3.10-mcp-v1.30.0: iniconfig==2.3.0 - py3.10-mcp-v1.30.0: jsonschema==4.26.0 - py3.10-mcp-v1.30.0: attrs==26.1.0 - py3.10-mcp-v1.30.0: jsonschema-specifications==2025.9.1 - py3.10-mcp-v1.30.0: packaging==26.3 - py3.10-mcp-v1.30.0: pydantic-settings==2.15.0 - py3.10-mcp-v1.30.0: Pygments==2.21.0 - py3.10-mcp-v1.30.0: PyJWT==2.14.0 - py3.10-mcp-v1.30.0: cryptography==50.0.1 - py3.10-mcp-v1.30.0: cffi==2.1.1 - py3.10-mcp-v1.30.0: python-dotenv==1.2.3 - py3.10-mcp-v1.30.0: python-multipart==0.0.32 - py3.10-mcp-v1.30.0: referencing==0.37.0 - py3.10-mcp-v1.30.0: rpds-py==0.30.0 - py3.10-mcp-v1.30.0: sse-starlette==3.4.11 - py3.10-mcp-v1.30.0: starlette==1.6.0 - py3.10-mcp-v1.30.0: tomli==2.4.1 - py3.10-mcp-v1.30.0: typing_extensions==4.16.0 - py3.10-mcp-v1.30.0: typing-inspection==0.4.4 - py3.10-mcp-v1.30.0: uvicorn==0.52.4 - py3.10-mcp-v1.30.0: click==8.5.0 - py3.10-mcp-v1.30.0: certifi==2026.7.22 - py3.10-mcp-v1.30.0: pycparser==3.0 - - py3.13-mcp-v1.30.0: httpx==0.28.1 - py3.13-mcp-v1.30.0: httpcore==1.0.9 - py3.13-mcp-v1.30.0: pydantic==2.13.5 - py3.13-mcp-v1.30.0: pydantic_core==2.46.5 - py3.13-mcp-v1.30.0: pytest-asyncio==1.4.0 - py3.13-mcp-v1.30.0: pytest==9.1.1 - py3.13-mcp-v1.30.0: pluggy==1.6.0 - py3.13-mcp-v1.30.0: annotated-types==0.8.0 - py3.13-mcp-v1.30.0: anyio==4.15.1 - py3.13-mcp-v1.30.0: h11==0.16.0 - py3.13-mcp-v1.30.0: httpx-sse==0.4.3 - py3.13-mcp-v1.30.0: idna==3.19 - py3.13-mcp-v1.30.0: iniconfig==2.3.0 - py3.13-mcp-v1.30.0: jsonschema==4.26.0 - py3.13-mcp-v1.30.0: attrs==26.1.0 - py3.13-mcp-v1.30.0: jsonschema-specifications==2025.9.1 - py3.13-mcp-v1.30.0: packaging==26.3 - py3.13-mcp-v1.30.0: pydantic-settings==2.15.0 - py3.13-mcp-v1.30.0: Pygments==2.21.0 - py3.13-mcp-v1.30.0: PyJWT==2.14.0 - py3.13-mcp-v1.30.0: cryptography==50.0.1 - py3.13-mcp-v1.30.0: cffi==2.1.1 - py3.13-mcp-v1.30.0: python-dotenv==1.2.3 - py3.13-mcp-v1.30.0: python-multipart==0.0.32 - py3.13-mcp-v1.30.0: referencing==0.37.0 - py3.13-mcp-v1.30.0: rpds-py==2026.6.3 - py3.13-mcp-v1.30.0: sse-starlette==3.4.11 - py3.13-mcp-v1.30.0: starlette==1.6.0 - py3.13-mcp-v1.30.0: typing_extensions==4.16.0 - py3.13-mcp-v1.30.0: typing-inspection==0.4.4 - py3.13-mcp-v1.30.0: uvicorn==0.52.4 - py3.13-mcp-v1.30.0: click==8.5.0 - py3.13-mcp-v1.30.0: certifi==2026.7.22 - py3.13-mcp-v1.30.0: pycparser==3.0 - - py3.14-mcp-v1.30.0: httpx==0.28.1 - py3.14-mcp-v1.30.0: httpcore==1.0.9 - py3.14-mcp-v1.30.0: pydantic==2.13.5 - py3.14-mcp-v1.30.0: pydantic_core==2.46.5 - py3.14-mcp-v1.30.0: pytest-asyncio==1.4.0 - py3.14-mcp-v1.30.0: pytest==9.1.1 - py3.14-mcp-v1.30.0: pluggy==1.6.0 - py3.14-mcp-v1.30.0: annotated-types==0.8.0 - py3.14-mcp-v1.30.0: anyio==4.15.1 - py3.14-mcp-v1.30.0: h11==0.16.0 - py3.14-mcp-v1.30.0: httpx-sse==0.4.3 - py3.14-mcp-v1.30.0: idna==3.19 - py3.14-mcp-v1.30.0: iniconfig==2.3.0 - py3.14-mcp-v1.30.0: jsonschema==4.26.0 - py3.14-mcp-v1.30.0: attrs==26.1.0 - py3.14-mcp-v1.30.0: jsonschema-specifications==2025.9.1 - py3.14-mcp-v1.30.0: packaging==26.3 - py3.14-mcp-v1.30.0: pydantic-settings==2.15.0 - py3.14-mcp-v1.30.0: Pygments==2.21.0 - py3.14-mcp-v1.30.0: PyJWT==2.14.0 - py3.14-mcp-v1.30.0: cryptography==50.0.1 - py3.14-mcp-v1.30.0: cffi==2.1.1 - py3.14-mcp-v1.30.0: python-dotenv==1.2.3 - py3.14-mcp-v1.30.0: python-multipart==0.0.32 - py3.14-mcp-v1.30.0: referencing==0.37.0 - py3.14-mcp-v1.30.0: rpds-py==2026.6.3 - py3.14-mcp-v1.30.0: sse-starlette==3.4.11 - py3.14-mcp-v1.30.0: starlette==1.6.0 - py3.14-mcp-v1.30.0: typing_extensions==4.16.0 - py3.14-mcp-v1.30.0: typing-inspection==0.4.4 - py3.14-mcp-v1.30.0: uvicorn==0.52.4 - py3.14-mcp-v1.30.0: click==8.5.0 - py3.14-mcp-v1.30.0: certifi==2026.7.22 - py3.14-mcp-v1.30.0: pycparser==3.0 - - py3.14t-mcp-v1.30.0: httpx==0.28.1 - py3.14t-mcp-v1.30.0: httpcore==1.0.9 - py3.14t-mcp-v1.30.0: pydantic==2.13.5 - py3.14t-mcp-v1.30.0: pydantic_core==2.46.5 - py3.14t-mcp-v1.30.0: pytest-asyncio==1.4.0 - py3.14t-mcp-v1.30.0: pytest==9.1.1 - py3.14t-mcp-v1.30.0: pluggy==1.6.0 - py3.14t-mcp-v1.30.0: annotated-types==0.8.0 - py3.14t-mcp-v1.30.0: anyio==4.15.1 - py3.14t-mcp-v1.30.0: h11==0.16.0 - py3.14t-mcp-v1.30.0: httpx-sse==0.4.3 - py3.14t-mcp-v1.30.0: idna==3.19 - py3.14t-mcp-v1.30.0: iniconfig==2.3.0 - py3.14t-mcp-v1.30.0: jsonschema==4.26.0 - py3.14t-mcp-v1.30.0: attrs==26.1.0 - py3.14t-mcp-v1.30.0: jsonschema-specifications==2025.9.1 - py3.14t-mcp-v1.30.0: packaging==26.3 - py3.14t-mcp-v1.30.0: pydantic-settings==2.15.0 - py3.14t-mcp-v1.30.0: Pygments==2.21.0 - py3.14t-mcp-v1.30.0: PyJWT==2.14.0 - py3.14t-mcp-v1.30.0: cryptography==50.0.1 - py3.14t-mcp-v1.30.0: cffi==2.1.1 - py3.14t-mcp-v1.30.0: python-dotenv==1.2.3 - py3.14t-mcp-v1.30.0: python-multipart==0.0.32 - py3.14t-mcp-v1.30.0: referencing==0.37.0 - py3.14t-mcp-v1.30.0: rpds-py==2026.6.3 - py3.14t-mcp-v1.30.0: sse-starlette==3.4.11 - py3.14t-mcp-v1.30.0: starlette==1.6.0 - py3.14t-mcp-v1.30.0: typing_extensions==4.16.0 - py3.14t-mcp-v1.30.0: typing-inspection==0.4.4 - py3.14t-mcp-v1.30.0: uvicorn==0.52.4 - py3.14t-mcp-v1.30.0: click==8.5.0 - py3.14t-mcp-v1.30.0: certifi==2026.7.22 - py3.14t-mcp-v1.30.0: pycparser==3.0 + mcp-v2.0.1: mcp==2.0.1 + + py3.10-mcp-v2.0.1: mcp-types==2.0.1 + py3.10-mcp-v2.0.1: pytest-asyncio==1.4.0 + py3.10-mcp-v2.0.1: httpx==0.28.1 + py3.10-mcp-v2.0.1: httpcore==1.0.9 + py3.10-mcp-v2.0.1: anyio==4.15.1 + py3.10-mcp-v2.0.1: backports.asyncio.runner==1.2.0 + py3.10-mcp-v2.0.1: httpx2==2.13.0 + py3.10-mcp-v2.0.1: httpcore2==2.13.0 + py3.10-mcp-v2.0.1: idna==3.19 + py3.10-mcp-v2.0.1: jsonschema==4.26.0 + py3.10-mcp-v2.0.1: opentelemetry-api==1.44.0 + py3.10-mcp-v2.0.1: pydantic==2.13.5 + py3.10-mcp-v2.0.1: pydantic_core==2.46.5 + py3.10-mcp-v2.0.1: PyJWT==2.14.0 + py3.10-mcp-v2.0.1: pytest==9.1.1 + py3.10-mcp-v2.0.1: python-multipart==0.0.32 + py3.10-mcp-v2.0.1: sse-starlette==3.4.11 + py3.10-mcp-v2.0.1: starlette==1.6.0 + py3.10-mcp-v2.0.1: typing_extensions==4.16.0 + py3.10-mcp-v2.0.1: typing-inspection==0.4.4 + py3.10-mcp-v2.0.1: uvicorn==0.53.0 + py3.10-mcp-v2.0.1: certifi==2026.7.22 + py3.10-mcp-v2.0.1: annotated-types==0.8.0 + py3.10-mcp-v2.0.1: attrs==26.1.0 + py3.10-mcp-v2.0.1: click==8.5.0 + py3.10-mcp-v2.0.1: cryptography==50.0.1 + py3.10-mcp-v2.0.1: exceptiongroup==1.3.1 + py3.10-mcp-v2.0.1: h11==0.16.0 + py3.10-mcp-v2.0.1: iniconfig==2.3.0 + py3.10-mcp-v2.0.1: jsonschema-specifications==2025.9.1 + py3.10-mcp-v2.0.1: packaging==26.3 + py3.10-mcp-v2.0.1: pluggy==1.6.0 + py3.10-mcp-v2.0.1: Pygments==2.21.0 + py3.10-mcp-v2.0.1: referencing==0.37.0 + py3.10-mcp-v2.0.1: rpds-py==0.30.0 + py3.10-mcp-v2.0.1: tomli==2.4.1 + py3.10-mcp-v2.0.1: truststore==0.10.4 + py3.10-mcp-v2.0.1: cffi==2.1.1 + py3.10-mcp-v2.0.1: pycparser==3.0 + + py3.13-mcp-v2.0.1: mcp-types==2.0.1 + py3.13-mcp-v2.0.1: pytest-asyncio==1.4.0 + py3.13-mcp-v2.0.1: httpx==0.28.1 + py3.13-mcp-v2.0.1: httpcore==1.0.9 + py3.13-mcp-v2.0.1: anyio==4.15.1 + py3.13-mcp-v2.0.1: httpx2==2.13.0 + py3.13-mcp-v2.0.1: httpcore2==2.13.0 + py3.13-mcp-v2.0.1: idna==3.19 + py3.13-mcp-v2.0.1: jsonschema==4.26.0 + py3.13-mcp-v2.0.1: opentelemetry-api==1.44.0 + py3.13-mcp-v2.0.1: pydantic==2.13.5 + py3.13-mcp-v2.0.1: pydantic_core==2.46.5 + py3.13-mcp-v2.0.1: PyJWT==2.14.0 + py3.13-mcp-v2.0.1: pytest==9.1.1 + py3.13-mcp-v2.0.1: python-multipart==0.0.32 + py3.13-mcp-v2.0.1: sse-starlette==3.4.11 + py3.13-mcp-v2.0.1: starlette==1.6.0 + py3.13-mcp-v2.0.1: typing_extensions==4.16.0 + py3.13-mcp-v2.0.1: typing-inspection==0.4.4 + py3.13-mcp-v2.0.1: uvicorn==0.53.0 + py3.13-mcp-v2.0.1: certifi==2026.7.22 + py3.13-mcp-v2.0.1: annotated-types==0.8.0 + py3.13-mcp-v2.0.1: attrs==26.1.0 + py3.13-mcp-v2.0.1: click==8.5.0 + py3.13-mcp-v2.0.1: cryptography==50.0.1 + py3.13-mcp-v2.0.1: h11==0.16.0 + py3.13-mcp-v2.0.1: iniconfig==2.3.0 + py3.13-mcp-v2.0.1: jsonschema-specifications==2025.9.1 + py3.13-mcp-v2.0.1: packaging==26.3 + py3.13-mcp-v2.0.1: pluggy==1.6.0 + py3.13-mcp-v2.0.1: Pygments==2.21.0 + py3.13-mcp-v2.0.1: referencing==0.37.0 + py3.13-mcp-v2.0.1: rpds-py==2026.6.3 + py3.13-mcp-v2.0.1: truststore==0.10.4 + py3.13-mcp-v2.0.1: cffi==2.1.1 + py3.13-mcp-v2.0.1: pycparser==3.0 + + py3.14-mcp-v2.0.1: mcp-types==2.0.1 + py3.14-mcp-v2.0.1: pytest-asyncio==1.4.0 + py3.14-mcp-v2.0.1: pytest==9.1.1 + py3.14-mcp-v2.0.1: pluggy==1.6.0 + py3.14-mcp-v2.0.1: httpx==0.28.1 + py3.14-mcp-v2.0.1: httpcore==1.0.9 + py3.14-mcp-v2.0.1: anyio==4.15.1 + py3.14-mcp-v2.0.1: h11==0.16.0 + py3.14-mcp-v2.0.1: httpx2==2.13.0 + py3.14-mcp-v2.0.1: httpcore2==2.13.0 + py3.14-mcp-v2.0.1: idna==3.19 + py3.14-mcp-v2.0.1: iniconfig==2.3.0 + py3.14-mcp-v2.0.1: jsonschema==4.26.0 + py3.14-mcp-v2.0.1: attrs==26.1.0 + py3.14-mcp-v2.0.1: jsonschema-specifications==2025.9.1 + py3.14-mcp-v2.0.1: opentelemetry-api==1.44.0 + py3.14-mcp-v2.0.1: packaging==26.3 + py3.14-mcp-v2.0.1: pydantic==2.13.5 + py3.14-mcp-v2.0.1: pydantic_core==2.46.5 + py3.14-mcp-v2.0.1: annotated-types==0.8.0 + py3.14-mcp-v2.0.1: Pygments==2.21.0 + py3.14-mcp-v2.0.1: PyJWT==2.14.0 + py3.14-mcp-v2.0.1: cryptography==50.0.1 + py3.14-mcp-v2.0.1: cffi==2.1.1 + py3.14-mcp-v2.0.1: python-multipart==0.0.32 + py3.14-mcp-v2.0.1: referencing==0.37.0 + py3.14-mcp-v2.0.1: rpds-py==2026.6.3 + py3.14-mcp-v2.0.1: sse-starlette==3.4.11 + py3.14-mcp-v2.0.1: starlette==1.6.0 + py3.14-mcp-v2.0.1: truststore==0.10.4 + py3.14-mcp-v2.0.1: typing_extensions==4.16.0 + py3.14-mcp-v2.0.1: typing-inspection==0.4.4 + py3.14-mcp-v2.0.1: uvicorn==0.53.0 + py3.14-mcp-v2.0.1: click==8.5.0 + py3.14-mcp-v2.0.1: certifi==2026.7.22 + py3.14-mcp-v2.0.1: pycparser==3.0 + + py3.14t-mcp-v2.0.1: mcp-types==2.0.1 + py3.14t-mcp-v2.0.1: pytest-asyncio==1.4.0 + py3.14t-mcp-v2.0.1: pytest==9.1.1 + py3.14t-mcp-v2.0.1: pluggy==1.6.0 + py3.14t-mcp-v2.0.1: httpx==0.28.1 + py3.14t-mcp-v2.0.1: httpcore==1.0.9 + py3.14t-mcp-v2.0.1: anyio==4.15.1 + py3.14t-mcp-v2.0.1: h11==0.16.0 + py3.14t-mcp-v2.0.1: httpx2==2.13.0 + py3.14t-mcp-v2.0.1: httpcore2==2.13.0 + py3.14t-mcp-v2.0.1: idna==3.19 + py3.14t-mcp-v2.0.1: iniconfig==2.3.0 + py3.14t-mcp-v2.0.1: jsonschema==4.26.0 + py3.14t-mcp-v2.0.1: attrs==26.1.0 + py3.14t-mcp-v2.0.1: jsonschema-specifications==2025.9.1 + py3.14t-mcp-v2.0.1: opentelemetry-api==1.44.0 + py3.14t-mcp-v2.0.1: packaging==26.3 + py3.14t-mcp-v2.0.1: pydantic==2.13.5 + py3.14t-mcp-v2.0.1: pydantic_core==2.46.5 + py3.14t-mcp-v2.0.1: annotated-types==0.8.0 + py3.14t-mcp-v2.0.1: Pygments==2.21.0 + py3.14t-mcp-v2.0.1: PyJWT==2.14.0 + py3.14t-mcp-v2.0.1: cryptography==50.0.1 + py3.14t-mcp-v2.0.1: cffi==2.1.1 + py3.14t-mcp-v2.0.1: python-multipart==0.0.32 + py3.14t-mcp-v2.0.1: referencing==0.37.0 + py3.14t-mcp-v2.0.1: rpds-py==2026.6.3 + py3.14t-mcp-v2.0.1: sse-starlette==3.4.11 + py3.14t-mcp-v2.0.1: starlette==1.6.0 + py3.14t-mcp-v2.0.1: truststore==0.10.4 + py3.14t-mcp-v2.0.1: typing_extensions==4.16.0 + py3.14t-mcp-v2.0.1: typing-inspection==0.4.4 + py3.14t-mcp-v2.0.1: uvicorn==0.53.0 + py3.14t-mcp-v2.0.1: click==8.5.0 + py3.14t-mcp-v2.0.1: certifi==2026.7.22 + py3.14t-mcp-v2.0.1: pycparser==3.0 + + mcp-v2.1.1: mcp==2.1.1 + + py3.10-mcp-v2.1.1: mcp-types==2.1.1 + py3.10-mcp-v2.1.1: pytest-asyncio==1.4.0 + py3.10-mcp-v2.1.1: httpx==0.28.1 + py3.10-mcp-v2.1.1: httpcore==1.0.9 + py3.10-mcp-v2.1.1: anyio==4.15.1 + py3.10-mcp-v2.1.1: backports.asyncio.runner==1.2.0 + py3.10-mcp-v2.1.1: httpx2==2.13.0 + py3.10-mcp-v2.1.1: httpcore2==2.13.0 + py3.10-mcp-v2.1.1: idna==3.19 + py3.10-mcp-v2.1.1: jsonschema==4.26.0 + py3.10-mcp-v2.1.1: opentelemetry-api==1.44.0 + py3.10-mcp-v2.1.1: pydantic==2.13.5 + py3.10-mcp-v2.1.1: pydantic_core==2.46.5 + py3.10-mcp-v2.1.1: PyJWT==2.14.0 + py3.10-mcp-v2.1.1: pytest==9.1.1 + py3.10-mcp-v2.1.1: python-multipart==0.0.32 + py3.10-mcp-v2.1.1: sse-starlette==3.4.11 + py3.10-mcp-v2.1.1: starlette==1.6.0 + py3.10-mcp-v2.1.1: typing_extensions==4.16.0 + py3.10-mcp-v2.1.1: typing-inspection==0.4.4 + py3.10-mcp-v2.1.1: uvicorn==0.53.0 + py3.10-mcp-v2.1.1: certifi==2026.7.22 + py3.10-mcp-v2.1.1: annotated-types==0.8.0 + py3.10-mcp-v2.1.1: attrs==26.1.0 + py3.10-mcp-v2.1.1: click==8.5.0 + py3.10-mcp-v2.1.1: cryptography==50.0.1 + py3.10-mcp-v2.1.1: exceptiongroup==1.3.1 + py3.10-mcp-v2.1.1: h11==0.16.0 + py3.10-mcp-v2.1.1: iniconfig==2.3.0 + py3.10-mcp-v2.1.1: jsonschema-specifications==2025.9.1 + py3.10-mcp-v2.1.1: packaging==26.3 + py3.10-mcp-v2.1.1: pluggy==1.6.0 + py3.10-mcp-v2.1.1: Pygments==2.21.0 + py3.10-mcp-v2.1.1: referencing==0.37.0 + py3.10-mcp-v2.1.1: rpds-py==0.30.0 + py3.10-mcp-v2.1.1: tomli==2.4.1 + py3.10-mcp-v2.1.1: truststore==0.10.4 + py3.10-mcp-v2.1.1: cffi==2.1.1 + py3.10-mcp-v2.1.1: pycparser==3.0 + + py3.13-mcp-v2.1.1: mcp-types==2.1.1 + py3.13-mcp-v2.1.1: pytest-asyncio==1.4.0 + py3.13-mcp-v2.1.1: httpx==0.28.1 + py3.13-mcp-v2.1.1: httpcore==1.0.9 + py3.13-mcp-v2.1.1: anyio==4.15.1 + py3.13-mcp-v2.1.1: httpx2==2.13.0 + py3.13-mcp-v2.1.1: httpcore2==2.13.0 + py3.13-mcp-v2.1.1: idna==3.19 + py3.13-mcp-v2.1.1: jsonschema==4.26.0 + py3.13-mcp-v2.1.1: opentelemetry-api==1.44.0 + py3.13-mcp-v2.1.1: pydantic==2.13.5 + py3.13-mcp-v2.1.1: pydantic_core==2.46.5 + py3.13-mcp-v2.1.1: PyJWT==2.14.0 + py3.13-mcp-v2.1.1: pytest==9.1.1 + py3.13-mcp-v2.1.1: python-multipart==0.0.32 + py3.13-mcp-v2.1.1: sse-starlette==3.4.11 + py3.13-mcp-v2.1.1: starlette==1.6.0 + py3.13-mcp-v2.1.1: typing_extensions==4.16.0 + py3.13-mcp-v2.1.1: typing-inspection==0.4.4 + py3.13-mcp-v2.1.1: uvicorn==0.53.0 + py3.13-mcp-v2.1.1: certifi==2026.7.22 + py3.13-mcp-v2.1.1: annotated-types==0.8.0 + py3.13-mcp-v2.1.1: attrs==26.1.0 + py3.13-mcp-v2.1.1: click==8.5.0 + py3.13-mcp-v2.1.1: cryptography==50.0.1 + py3.13-mcp-v2.1.1: h11==0.16.0 + py3.13-mcp-v2.1.1: iniconfig==2.3.0 + py3.13-mcp-v2.1.1: jsonschema-specifications==2025.9.1 + py3.13-mcp-v2.1.1: packaging==26.3 + py3.13-mcp-v2.1.1: pluggy==1.6.0 + py3.13-mcp-v2.1.1: Pygments==2.21.0 + py3.13-mcp-v2.1.1: referencing==0.37.0 + py3.13-mcp-v2.1.1: rpds-py==2026.6.3 + py3.13-mcp-v2.1.1: truststore==0.10.4 + py3.13-mcp-v2.1.1: cffi==2.1.1 + py3.13-mcp-v2.1.1: pycparser==3.0 + + py3.14-mcp-v2.1.1: mcp-types==2.1.1 + py3.14-mcp-v2.1.1: pytest-asyncio==1.4.0 + py3.14-mcp-v2.1.1: pytest==9.1.1 + py3.14-mcp-v2.1.1: pluggy==1.6.0 + py3.14-mcp-v2.1.1: httpx==0.28.1 + py3.14-mcp-v2.1.1: httpcore==1.0.9 + py3.14-mcp-v2.1.1: anyio==4.15.1 + py3.14-mcp-v2.1.1: h11==0.16.0 + py3.14-mcp-v2.1.1: httpx2==2.13.0 + py3.14-mcp-v2.1.1: httpcore2==2.13.0 + py3.14-mcp-v2.1.1: idna==3.19 + py3.14-mcp-v2.1.1: iniconfig==2.3.0 + py3.14-mcp-v2.1.1: jsonschema==4.26.0 + py3.14-mcp-v2.1.1: attrs==26.1.0 + py3.14-mcp-v2.1.1: jsonschema-specifications==2025.9.1 + py3.14-mcp-v2.1.1: opentelemetry-api==1.44.0 + py3.14-mcp-v2.1.1: packaging==26.3 + py3.14-mcp-v2.1.1: pydantic==2.13.5 + py3.14-mcp-v2.1.1: pydantic_core==2.46.5 + py3.14-mcp-v2.1.1: annotated-types==0.8.0 + py3.14-mcp-v2.1.1: Pygments==2.21.0 + py3.14-mcp-v2.1.1: PyJWT==2.14.0 + py3.14-mcp-v2.1.1: cryptography==50.0.1 + py3.14-mcp-v2.1.1: cffi==2.1.1 + py3.14-mcp-v2.1.1: python-multipart==0.0.32 + py3.14-mcp-v2.1.1: referencing==0.37.0 + py3.14-mcp-v2.1.1: rpds-py==2026.6.3 + py3.14-mcp-v2.1.1: sse-starlette==3.4.11 + py3.14-mcp-v2.1.1: starlette==1.6.0 + py3.14-mcp-v2.1.1: truststore==0.10.4 + py3.14-mcp-v2.1.1: typing_extensions==4.16.0 + py3.14-mcp-v2.1.1: typing-inspection==0.4.4 + py3.14-mcp-v2.1.1: uvicorn==0.53.0 + py3.14-mcp-v2.1.1: click==8.5.0 + py3.14-mcp-v2.1.1: certifi==2026.7.22 + py3.14-mcp-v2.1.1: pycparser==3.0 + + py3.14t-mcp-v2.1.1: mcp-types==2.1.1 + py3.14t-mcp-v2.1.1: pytest-asyncio==1.4.0 + py3.14t-mcp-v2.1.1: pytest==9.1.1 + py3.14t-mcp-v2.1.1: pluggy==1.6.0 + py3.14t-mcp-v2.1.1: httpx==0.28.1 + py3.14t-mcp-v2.1.1: httpcore==1.0.9 + py3.14t-mcp-v2.1.1: anyio==4.15.1 + py3.14t-mcp-v2.1.1: h11==0.16.0 + py3.14t-mcp-v2.1.1: httpx2==2.13.0 + py3.14t-mcp-v2.1.1: httpcore2==2.13.0 + py3.14t-mcp-v2.1.1: idna==3.19 + py3.14t-mcp-v2.1.1: iniconfig==2.3.0 + py3.14t-mcp-v2.1.1: jsonschema==4.26.0 + py3.14t-mcp-v2.1.1: attrs==26.1.0 + py3.14t-mcp-v2.1.1: jsonschema-specifications==2025.9.1 + py3.14t-mcp-v2.1.1: opentelemetry-api==1.44.0 + py3.14t-mcp-v2.1.1: packaging==26.3 + py3.14t-mcp-v2.1.1: pydantic==2.13.5 + py3.14t-mcp-v2.1.1: pydantic_core==2.46.5 + py3.14t-mcp-v2.1.1: annotated-types==0.8.0 + py3.14t-mcp-v2.1.1: Pygments==2.21.0 + py3.14t-mcp-v2.1.1: PyJWT==2.14.0 + py3.14t-mcp-v2.1.1: cryptography==50.0.1 + py3.14t-mcp-v2.1.1: cffi==2.1.1 + py3.14t-mcp-v2.1.1: python-multipart==0.0.32 + py3.14t-mcp-v2.1.1: referencing==0.37.0 + py3.14t-mcp-v2.1.1: rpds-py==2026.6.3 + py3.14t-mcp-v2.1.1: sse-starlette==3.4.11 + py3.14t-mcp-v2.1.1: starlette==1.6.0 + py3.14t-mcp-v2.1.1: truststore==0.10.4 + py3.14t-mcp-v2.1.1: typing_extensions==4.16.0 + py3.14t-mcp-v2.1.1: typing-inspection==0.4.4 + py3.14t-mcp-v2.1.1: uvicorn==0.53.0 + py3.14t-mcp-v2.1.1: click==8.5.0 + py3.14t-mcp-v2.1.1: certifi==2026.7.22 + py3.14t-mcp-v2.1.1: pycparser==3.0 mcp-v2.2.0: mcp==2.2.0 @@ -1031,994 +1062,6 @@ deps = mcp: pytest-asyncio mcp: httpx - fastmcp-v0.1.0: fastmcp==0.1.0 - - py3.10-fastmcp-v0.1.0: mcp==1.29.0 - py3.10-fastmcp-v0.1.0: httpx==0.28.1 - py3.10-fastmcp-v0.1.0: httpcore==1.0.9 - py3.10-fastmcp-v0.1.0: pydantic==2.13.4 - py3.10-fastmcp-v0.1.0: pydantic_core==2.46.4 - py3.10-fastmcp-v0.1.0: pytest-asyncio==1.4.0 - py3.10-fastmcp-v0.1.0: backports.asyncio.runner==1.2.0 - py3.10-fastmcp-v0.1.0: pytest==9.1.1 - py3.10-fastmcp-v0.1.0: pluggy==1.6.0 - py3.10-fastmcp-v0.1.0: annotated-types==0.8.0 - py3.10-fastmcp-v0.1.0: anyio==4.14.2 - py3.10-fastmcp-v0.1.0: exceptiongroup==1.3.1 - py3.10-fastmcp-v0.1.0: h11==0.16.0 - py3.10-fastmcp-v0.1.0: httpx-sse==0.4.3 - py3.10-fastmcp-v0.1.0: idna==3.18 - py3.10-fastmcp-v0.1.0: iniconfig==2.3.0 - py3.10-fastmcp-v0.1.0: jsonschema==4.26.0 - py3.10-fastmcp-v0.1.0: attrs==26.1.0 - py3.10-fastmcp-v0.1.0: jsonschema-specifications==2025.9.1 - py3.10-fastmcp-v0.1.0: packaging==26.2 - py3.10-fastmcp-v0.1.0: pydantic-settings==2.14.2 - py3.10-fastmcp-v0.1.0: Pygments==2.20.0 - py3.10-fastmcp-v0.1.0: PyJWT==2.13.0 - py3.10-fastmcp-v0.1.0: cryptography==49.0.0 - py3.10-fastmcp-v0.1.0: cffi==2.1.0 - py3.10-fastmcp-v0.1.0: python-dotenv==1.2.2 - py3.10-fastmcp-v0.1.0: python-multipart==0.0.32 - py3.10-fastmcp-v0.1.0: referencing==0.37.0 - py3.10-fastmcp-v0.1.0: rpds-py==0.30.0 - py3.10-fastmcp-v0.1.0: sse-starlette==3.4.6 - py3.10-fastmcp-v0.1.0: starlette==1.3.1 - py3.10-fastmcp-v0.1.0: tomli==2.4.1 - py3.10-fastmcp-v0.1.0: typer==0.27.0 - py3.10-fastmcp-v0.1.0: annotated-doc==0.0.5 - py3.10-fastmcp-v0.1.0: rich==15.0.0 - py3.10-fastmcp-v0.1.0: markdown-it-py==4.2.0 - py3.10-fastmcp-v0.1.0: mdurl==0.1.2 - py3.10-fastmcp-v0.1.0: shellingham==1.5.4 - py3.10-fastmcp-v0.1.0: typing_extensions==4.16.0 - py3.10-fastmcp-v0.1.0: typing-inspection==0.4.2 - py3.10-fastmcp-v0.1.0: uvicorn==0.52.0 - py3.10-fastmcp-v0.1.0: click==8.4.2 - py3.10-fastmcp-v0.1.0: certifi==2026.7.22 - py3.10-fastmcp-v0.1.0: pycparser==3.0 - - py3.14-fastmcp-v0.1.0: mcp==1.29.0 - py3.14-fastmcp-v0.1.0: httpx==0.28.1 - py3.14-fastmcp-v0.1.0: httpcore==1.0.9 - py3.14-fastmcp-v0.1.0: pydantic==2.13.4 - py3.14-fastmcp-v0.1.0: pydantic_core==2.46.4 - py3.14-fastmcp-v0.1.0: pytest-asyncio==1.4.0 - py3.14-fastmcp-v0.1.0: pytest==9.1.1 - py3.14-fastmcp-v0.1.0: pluggy==1.6.0 - py3.14-fastmcp-v0.1.0: annotated-types==0.8.0 - py3.14-fastmcp-v0.1.0: anyio==4.14.2 - py3.14-fastmcp-v0.1.0: h11==0.16.0 - py3.14-fastmcp-v0.1.0: httpx-sse==0.4.3 - py3.14-fastmcp-v0.1.0: idna==3.18 - py3.14-fastmcp-v0.1.0: iniconfig==2.3.0 - py3.14-fastmcp-v0.1.0: jsonschema==4.26.0 - py3.14-fastmcp-v0.1.0: attrs==26.1.0 - py3.14-fastmcp-v0.1.0: jsonschema-specifications==2025.9.1 - py3.14-fastmcp-v0.1.0: packaging==26.2 - py3.14-fastmcp-v0.1.0: pydantic-settings==2.14.2 - py3.14-fastmcp-v0.1.0: Pygments==2.20.0 - py3.14-fastmcp-v0.1.0: PyJWT==2.13.0 - py3.14-fastmcp-v0.1.0: cryptography==49.0.0 - py3.14-fastmcp-v0.1.0: cffi==2.1.0 - py3.14-fastmcp-v0.1.0: python-dotenv==1.2.2 - py3.14-fastmcp-v0.1.0: python-multipart==0.0.32 - py3.14-fastmcp-v0.1.0: referencing==0.37.0 - py3.14-fastmcp-v0.1.0: rpds-py==2026.6.3 - py3.14-fastmcp-v0.1.0: sse-starlette==3.4.6 - py3.14-fastmcp-v0.1.0: starlette==1.3.1 - py3.14-fastmcp-v0.1.0: typer==0.27.0 - py3.14-fastmcp-v0.1.0: annotated-doc==0.0.5 - py3.14-fastmcp-v0.1.0: rich==15.0.0 - py3.14-fastmcp-v0.1.0: markdown-it-py==4.2.0 - py3.14-fastmcp-v0.1.0: mdurl==0.1.2 - py3.14-fastmcp-v0.1.0: shellingham==1.5.4 - py3.14-fastmcp-v0.1.0: typing_extensions==4.16.0 - py3.14-fastmcp-v0.1.0: typing-inspection==0.4.2 - py3.14-fastmcp-v0.1.0: uvicorn==0.52.0 - py3.14-fastmcp-v0.1.0: click==8.4.2 - py3.14-fastmcp-v0.1.0: certifi==2026.7.22 - py3.14-fastmcp-v0.1.0: pycparser==3.0 - - py3.15-fastmcp-v0.1.0: mcp==1.29.1 - py3.15-fastmcp-v0.1.0: httpx==0.28.1 - py3.15-fastmcp-v0.1.0: httpcore==1.0.9 - py3.15-fastmcp-v0.1.0: pydantic==2.13.5 - py3.15-fastmcp-v0.1.0: pydantic_core==2.46.5 - py3.15-fastmcp-v0.1.0: pytest-asyncio==1.4.0 - py3.15-fastmcp-v0.1.0: pytest==9.1.1 - py3.15-fastmcp-v0.1.0: pluggy==1.6.0 - py3.15-fastmcp-v0.1.0: annotated-types==0.8.0 - py3.15-fastmcp-v0.1.0: anyio==4.14.2 - py3.15-fastmcp-v0.1.0: h11==0.16.0 - py3.15-fastmcp-v0.1.0: httpx-sse==0.4.3 - py3.15-fastmcp-v0.1.0: idna==3.19 - py3.15-fastmcp-v0.1.0: iniconfig==2.3.0 - py3.15-fastmcp-v0.1.0: jsonschema==4.26.0 - py3.15-fastmcp-v0.1.0: attrs==26.1.0 - py3.15-fastmcp-v0.1.0: jsonschema-specifications==2025.9.1 - py3.15-fastmcp-v0.1.0: packaging==26.3 - py3.15-fastmcp-v0.1.0: pydantic-settings==2.15.0 - py3.15-fastmcp-v0.1.0: Pygments==2.21.0 - py3.15-fastmcp-v0.1.0: PyJWT==2.13.0 - py3.15-fastmcp-v0.1.0: cryptography==50.0.1 - py3.15-fastmcp-v0.1.0: cffi==2.1.1 - py3.15-fastmcp-v0.1.0: python-dotenv==1.2.3 - py3.15-fastmcp-v0.1.0: python-multipart==0.0.32 - py3.15-fastmcp-v0.1.0: referencing==0.37.0 - py3.15-fastmcp-v0.1.0: rpds-py==2026.6.3 - py3.15-fastmcp-v0.1.0: sse-starlette==3.4.8 - py3.15-fastmcp-v0.1.0: starlette==1.6.0 - py3.15-fastmcp-v0.1.0: typer==0.27.2 - py3.15-fastmcp-v0.1.0: annotated-doc==0.0.5 - py3.15-fastmcp-v0.1.0: rich==15.0.0 - py3.15-fastmcp-v0.1.0: markdown-it-py==4.2.0 - py3.15-fastmcp-v0.1.0: mdurl==0.1.2 - py3.15-fastmcp-v0.1.0: shellingham==1.5.4 - py3.15-fastmcp-v0.1.0: typing_extensions==4.16.0 - py3.15-fastmcp-v0.1.0: typing-inspection==0.4.4 - py3.15-fastmcp-v0.1.0: uvicorn==0.52.4 - py3.15-fastmcp-v0.1.0: click==8.5.0 - py3.15-fastmcp-v0.1.0: certifi==2026.7.22 - py3.15-fastmcp-v0.1.0: pycparser==3.0 - - py3.15t-fastmcp-v0.1.0: mcp==1.29.1 - py3.15t-fastmcp-v0.1.0: httpx==0.28.1 - py3.15t-fastmcp-v0.1.0: httpcore==1.0.9 - py3.15t-fastmcp-v0.1.0: pydantic==2.13.5 - py3.15t-fastmcp-v0.1.0: pydantic_core==2.46.5 - py3.15t-fastmcp-v0.1.0: pytest-asyncio==1.4.0 - py3.15t-fastmcp-v0.1.0: pytest==9.1.1 - py3.15t-fastmcp-v0.1.0: pluggy==1.6.0 - py3.15t-fastmcp-v0.1.0: annotated-types==0.8.0 - py3.15t-fastmcp-v0.1.0: anyio==4.14.2 - py3.15t-fastmcp-v0.1.0: h11==0.16.0 - py3.15t-fastmcp-v0.1.0: httpx-sse==0.4.3 - py3.15t-fastmcp-v0.1.0: idna==3.19 - py3.15t-fastmcp-v0.1.0: iniconfig==2.3.0 - py3.15t-fastmcp-v0.1.0: jsonschema==4.26.0 - py3.15t-fastmcp-v0.1.0: attrs==26.1.0 - py3.15t-fastmcp-v0.1.0: jsonschema-specifications==2025.9.1 - py3.15t-fastmcp-v0.1.0: packaging==26.3 - py3.15t-fastmcp-v0.1.0: pydantic-settings==2.15.0 - py3.15t-fastmcp-v0.1.0: Pygments==2.21.0 - py3.15t-fastmcp-v0.1.0: PyJWT==2.13.0 - py3.15t-fastmcp-v0.1.0: cryptography==50.0.1 - py3.15t-fastmcp-v0.1.0: cffi==2.1.1 - py3.15t-fastmcp-v0.1.0: python-dotenv==1.2.3 - py3.15t-fastmcp-v0.1.0: python-multipart==0.0.32 - py3.15t-fastmcp-v0.1.0: referencing==0.37.0 - py3.15t-fastmcp-v0.1.0: rpds-py==2026.6.3 - py3.15t-fastmcp-v0.1.0: sse-starlette==3.4.8 - py3.15t-fastmcp-v0.1.0: starlette==1.6.0 - py3.15t-fastmcp-v0.1.0: typer==0.27.2 - py3.15t-fastmcp-v0.1.0: annotated-doc==0.0.5 - py3.15t-fastmcp-v0.1.0: rich==15.0.0 - py3.15t-fastmcp-v0.1.0: markdown-it-py==4.2.0 - py3.15t-fastmcp-v0.1.0: mdurl==0.1.2 - py3.15t-fastmcp-v0.1.0: shellingham==1.5.4 - py3.15t-fastmcp-v0.1.0: typing_extensions==4.16.0 - py3.15t-fastmcp-v0.1.0: typing-inspection==0.4.4 - py3.15t-fastmcp-v0.1.0: uvicorn==0.52.4 - py3.15t-fastmcp-v0.1.0: click==8.5.0 - py3.15t-fastmcp-v0.1.0: certifi==2026.7.22 - py3.15t-fastmcp-v0.1.0: pycparser==3.0 - - fastmcp-v0.4.1: fastmcp==0.4.1 - - py3.10-fastmcp-v0.4.1: mcp==1.29.0 - py3.10-fastmcp-v0.4.1: httpx==0.28.1 - py3.10-fastmcp-v0.4.1: httpcore==1.0.9 - py3.10-fastmcp-v0.4.1: pydantic==2.13.4 - py3.10-fastmcp-v0.4.1: pydantic_core==2.46.4 - py3.10-fastmcp-v0.4.1: pytest-asyncio==1.4.0 - py3.10-fastmcp-v0.4.1: backports.asyncio.runner==1.2.0 - py3.10-fastmcp-v0.4.1: pytest==9.1.1 - py3.10-fastmcp-v0.4.1: pluggy==1.6.0 - py3.10-fastmcp-v0.4.1: annotated-types==0.8.0 - py3.10-fastmcp-v0.4.1: anyio==4.14.2 - py3.10-fastmcp-v0.4.1: exceptiongroup==1.3.1 - py3.10-fastmcp-v0.4.1: h11==0.16.0 - py3.10-fastmcp-v0.4.1: httpx-sse==0.4.3 - py3.10-fastmcp-v0.4.1: idna==3.18 - py3.10-fastmcp-v0.4.1: iniconfig==2.3.0 - py3.10-fastmcp-v0.4.1: jsonschema==4.26.0 - py3.10-fastmcp-v0.4.1: attrs==26.1.0 - py3.10-fastmcp-v0.4.1: jsonschema-specifications==2025.9.1 - py3.10-fastmcp-v0.4.1: packaging==26.2 - py3.10-fastmcp-v0.4.1: pydantic-settings==2.14.2 - py3.10-fastmcp-v0.4.1: Pygments==2.20.0 - py3.10-fastmcp-v0.4.1: PyJWT==2.13.0 - py3.10-fastmcp-v0.4.1: cryptography==49.0.0 - py3.10-fastmcp-v0.4.1: cffi==2.1.0 - py3.10-fastmcp-v0.4.1: python-dotenv==1.2.2 - py3.10-fastmcp-v0.4.1: python-multipart==0.0.32 - py3.10-fastmcp-v0.4.1: referencing==0.37.0 - py3.10-fastmcp-v0.4.1: rpds-py==0.30.0 - py3.10-fastmcp-v0.4.1: sse-starlette==3.4.6 - py3.10-fastmcp-v0.4.1: starlette==1.3.1 - py3.10-fastmcp-v0.4.1: tomli==2.4.1 - py3.10-fastmcp-v0.4.1: typer==0.27.0 - py3.10-fastmcp-v0.4.1: annotated-doc==0.0.5 - py3.10-fastmcp-v0.4.1: rich==15.0.0 - py3.10-fastmcp-v0.4.1: markdown-it-py==4.2.0 - py3.10-fastmcp-v0.4.1: mdurl==0.1.2 - py3.10-fastmcp-v0.4.1: shellingham==1.5.4 - py3.10-fastmcp-v0.4.1: typing_extensions==4.16.0 - py3.10-fastmcp-v0.4.1: typing-inspection==0.4.2 - py3.10-fastmcp-v0.4.1: uvicorn==0.52.0 - py3.10-fastmcp-v0.4.1: click==8.4.2 - py3.10-fastmcp-v0.4.1: certifi==2026.7.22 - py3.10-fastmcp-v0.4.1: pycparser==3.0 - - py3.14-fastmcp-v0.4.1: mcp==1.29.0 - py3.14-fastmcp-v0.4.1: httpx==0.28.1 - py3.14-fastmcp-v0.4.1: httpcore==1.0.9 - py3.14-fastmcp-v0.4.1: pydantic==2.13.4 - py3.14-fastmcp-v0.4.1: pydantic_core==2.46.4 - py3.14-fastmcp-v0.4.1: pytest-asyncio==1.4.0 - py3.14-fastmcp-v0.4.1: pytest==9.1.1 - py3.14-fastmcp-v0.4.1: pluggy==1.6.0 - py3.14-fastmcp-v0.4.1: annotated-types==0.8.0 - py3.14-fastmcp-v0.4.1: anyio==4.14.2 - py3.14-fastmcp-v0.4.1: h11==0.16.0 - py3.14-fastmcp-v0.4.1: httpx-sse==0.4.3 - py3.14-fastmcp-v0.4.1: idna==3.18 - py3.14-fastmcp-v0.4.1: iniconfig==2.3.0 - py3.14-fastmcp-v0.4.1: jsonschema==4.26.0 - py3.14-fastmcp-v0.4.1: attrs==26.1.0 - py3.14-fastmcp-v0.4.1: jsonschema-specifications==2025.9.1 - py3.14-fastmcp-v0.4.1: packaging==26.2 - py3.14-fastmcp-v0.4.1: pydantic-settings==2.14.2 - py3.14-fastmcp-v0.4.1: Pygments==2.20.0 - py3.14-fastmcp-v0.4.1: PyJWT==2.13.0 - py3.14-fastmcp-v0.4.1: cryptography==49.0.0 - py3.14-fastmcp-v0.4.1: cffi==2.1.0 - py3.14-fastmcp-v0.4.1: python-dotenv==1.2.2 - py3.14-fastmcp-v0.4.1: python-multipart==0.0.32 - py3.14-fastmcp-v0.4.1: referencing==0.37.0 - py3.14-fastmcp-v0.4.1: rpds-py==2026.6.3 - py3.14-fastmcp-v0.4.1: sse-starlette==3.4.6 - py3.14-fastmcp-v0.4.1: starlette==1.3.1 - py3.14-fastmcp-v0.4.1: typer==0.27.0 - py3.14-fastmcp-v0.4.1: annotated-doc==0.0.5 - py3.14-fastmcp-v0.4.1: rich==15.0.0 - py3.14-fastmcp-v0.4.1: markdown-it-py==4.2.0 - py3.14-fastmcp-v0.4.1: mdurl==0.1.2 - py3.14-fastmcp-v0.4.1: shellingham==1.5.4 - py3.14-fastmcp-v0.4.1: typing_extensions==4.16.0 - py3.14-fastmcp-v0.4.1: typing-inspection==0.4.2 - py3.14-fastmcp-v0.4.1: uvicorn==0.52.0 - py3.14-fastmcp-v0.4.1: click==8.4.2 - py3.14-fastmcp-v0.4.1: certifi==2026.7.22 - py3.14-fastmcp-v0.4.1: pycparser==3.0 - - py3.15-fastmcp-v0.4.1: mcp==1.29.1 - py3.15-fastmcp-v0.4.1: httpx==0.28.1 - py3.15-fastmcp-v0.4.1: httpcore==1.0.9 - py3.15-fastmcp-v0.4.1: pydantic==2.13.5 - py3.15-fastmcp-v0.4.1: pydantic_core==2.46.5 - py3.15-fastmcp-v0.4.1: pytest-asyncio==1.4.0 - py3.15-fastmcp-v0.4.1: pytest==9.1.1 - py3.15-fastmcp-v0.4.1: pluggy==1.6.0 - py3.15-fastmcp-v0.4.1: annotated-types==0.8.0 - py3.15-fastmcp-v0.4.1: anyio==4.14.2 - py3.15-fastmcp-v0.4.1: h11==0.16.0 - py3.15-fastmcp-v0.4.1: httpx-sse==0.4.3 - py3.15-fastmcp-v0.4.1: idna==3.19 - py3.15-fastmcp-v0.4.1: iniconfig==2.3.0 - py3.15-fastmcp-v0.4.1: jsonschema==4.26.0 - py3.15-fastmcp-v0.4.1: attrs==26.1.0 - py3.15-fastmcp-v0.4.1: jsonschema-specifications==2025.9.1 - py3.15-fastmcp-v0.4.1: packaging==26.3 - py3.15-fastmcp-v0.4.1: pydantic-settings==2.15.0 - py3.15-fastmcp-v0.4.1: Pygments==2.21.0 - py3.15-fastmcp-v0.4.1: PyJWT==2.13.0 - py3.15-fastmcp-v0.4.1: cryptography==50.0.1 - py3.15-fastmcp-v0.4.1: cffi==2.1.1 - py3.15-fastmcp-v0.4.1: python-dotenv==1.2.3 - py3.15-fastmcp-v0.4.1: python-multipart==0.0.32 - py3.15-fastmcp-v0.4.1: referencing==0.37.0 - py3.15-fastmcp-v0.4.1: rpds-py==2026.6.3 - py3.15-fastmcp-v0.4.1: sse-starlette==3.4.8 - py3.15-fastmcp-v0.4.1: starlette==1.6.0 - py3.15-fastmcp-v0.4.1: typer==0.27.2 - py3.15-fastmcp-v0.4.1: annotated-doc==0.0.5 - py3.15-fastmcp-v0.4.1: rich==15.0.0 - py3.15-fastmcp-v0.4.1: markdown-it-py==4.2.0 - py3.15-fastmcp-v0.4.1: mdurl==0.1.2 - py3.15-fastmcp-v0.4.1: shellingham==1.5.4 - py3.15-fastmcp-v0.4.1: typing_extensions==4.16.0 - py3.15-fastmcp-v0.4.1: typing-inspection==0.4.4 - py3.15-fastmcp-v0.4.1: uvicorn==0.52.4 - py3.15-fastmcp-v0.4.1: click==8.5.0 - py3.15-fastmcp-v0.4.1: certifi==2026.7.22 - py3.15-fastmcp-v0.4.1: pycparser==3.0 - - py3.15t-fastmcp-v0.4.1: mcp==1.29.1 - py3.15t-fastmcp-v0.4.1: httpx==0.28.1 - py3.15t-fastmcp-v0.4.1: httpcore==1.0.9 - py3.15t-fastmcp-v0.4.1: pydantic==2.13.5 - py3.15t-fastmcp-v0.4.1: pydantic_core==2.46.5 - py3.15t-fastmcp-v0.4.1: pytest-asyncio==1.4.0 - py3.15t-fastmcp-v0.4.1: pytest==9.1.1 - py3.15t-fastmcp-v0.4.1: pluggy==1.6.0 - py3.15t-fastmcp-v0.4.1: annotated-types==0.8.0 - py3.15t-fastmcp-v0.4.1: anyio==4.14.2 - py3.15t-fastmcp-v0.4.1: h11==0.16.0 - py3.15t-fastmcp-v0.4.1: httpx-sse==0.4.3 - py3.15t-fastmcp-v0.4.1: idna==3.19 - py3.15t-fastmcp-v0.4.1: iniconfig==2.3.0 - py3.15t-fastmcp-v0.4.1: jsonschema==4.26.0 - py3.15t-fastmcp-v0.4.1: attrs==26.1.0 - py3.15t-fastmcp-v0.4.1: jsonschema-specifications==2025.9.1 - py3.15t-fastmcp-v0.4.1: packaging==26.3 - py3.15t-fastmcp-v0.4.1: pydantic-settings==2.15.0 - py3.15t-fastmcp-v0.4.1: Pygments==2.21.0 - py3.15t-fastmcp-v0.4.1: PyJWT==2.13.0 - py3.15t-fastmcp-v0.4.1: cryptography==50.0.1 - py3.15t-fastmcp-v0.4.1: cffi==2.1.1 - py3.15t-fastmcp-v0.4.1: python-dotenv==1.2.3 - py3.15t-fastmcp-v0.4.1: python-multipart==0.0.32 - py3.15t-fastmcp-v0.4.1: referencing==0.37.0 - py3.15t-fastmcp-v0.4.1: rpds-py==2026.6.3 - py3.15t-fastmcp-v0.4.1: sse-starlette==3.4.8 - py3.15t-fastmcp-v0.4.1: starlette==1.6.0 - py3.15t-fastmcp-v0.4.1: typer==0.27.2 - py3.15t-fastmcp-v0.4.1: annotated-doc==0.0.5 - py3.15t-fastmcp-v0.4.1: rich==15.0.0 - py3.15t-fastmcp-v0.4.1: markdown-it-py==4.2.0 - py3.15t-fastmcp-v0.4.1: mdurl==0.1.2 - py3.15t-fastmcp-v0.4.1: shellingham==1.5.4 - py3.15t-fastmcp-v0.4.1: typing_extensions==4.16.0 - py3.15t-fastmcp-v0.4.1: typing-inspection==0.4.4 - py3.15t-fastmcp-v0.4.1: uvicorn==0.52.4 - py3.15t-fastmcp-v0.4.1: click==8.5.0 - py3.15t-fastmcp-v0.4.1: certifi==2026.7.22 - py3.15t-fastmcp-v0.4.1: pycparser==3.0 - - fastmcp-v1.0: fastmcp==1.0 - - py3.10-fastmcp-v1.0: mcp==1.29.0 - py3.10-fastmcp-v1.0: httpx==0.28.1 - py3.10-fastmcp-v1.0: httpcore==1.0.9 - py3.10-fastmcp-v1.0: pydantic==2.13.4 - py3.10-fastmcp-v1.0: pydantic_core==2.46.4 - py3.10-fastmcp-v1.0: pytest-asyncio==1.4.0 - py3.10-fastmcp-v1.0: backports.asyncio.runner==1.2.0 - py3.10-fastmcp-v1.0: pytest==9.1.1 - py3.10-fastmcp-v1.0: pluggy==1.6.0 - py3.10-fastmcp-v1.0: annotated-types==0.8.0 - py3.10-fastmcp-v1.0: anyio==4.14.2 - py3.10-fastmcp-v1.0: exceptiongroup==1.3.1 - py3.10-fastmcp-v1.0: h11==0.16.0 - py3.10-fastmcp-v1.0: httpx-sse==0.4.3 - py3.10-fastmcp-v1.0: idna==3.18 - py3.10-fastmcp-v1.0: iniconfig==2.3.0 - py3.10-fastmcp-v1.0: jsonschema==4.26.0 - py3.10-fastmcp-v1.0: attrs==26.1.0 - py3.10-fastmcp-v1.0: jsonschema-specifications==2025.9.1 - py3.10-fastmcp-v1.0: packaging==26.2 - py3.10-fastmcp-v1.0: pydantic-settings==2.14.2 - py3.10-fastmcp-v1.0: Pygments==2.20.0 - py3.10-fastmcp-v1.0: PyJWT==2.13.0 - py3.10-fastmcp-v1.0: cryptography==49.0.0 - py3.10-fastmcp-v1.0: cffi==2.1.0 - py3.10-fastmcp-v1.0: python-dotenv==1.2.2 - py3.10-fastmcp-v1.0: python-multipart==0.0.32 - py3.10-fastmcp-v1.0: referencing==0.37.0 - py3.10-fastmcp-v1.0: rpds-py==0.30.0 - py3.10-fastmcp-v1.0: sse-starlette==3.4.6 - py3.10-fastmcp-v1.0: starlette==1.3.1 - py3.10-fastmcp-v1.0: tomli==2.4.1 - py3.10-fastmcp-v1.0: typer==0.27.0 - py3.10-fastmcp-v1.0: annotated-doc==0.0.5 - py3.10-fastmcp-v1.0: rich==15.0.0 - py3.10-fastmcp-v1.0: markdown-it-py==4.2.0 - py3.10-fastmcp-v1.0: mdurl==0.1.2 - py3.10-fastmcp-v1.0: shellingham==1.5.4 - py3.10-fastmcp-v1.0: typing_extensions==4.16.0 - py3.10-fastmcp-v1.0: typing-inspection==0.4.2 - py3.10-fastmcp-v1.0: uvicorn==0.52.0 - py3.10-fastmcp-v1.0: click==8.4.2 - py3.10-fastmcp-v1.0: certifi==2026.7.22 - py3.10-fastmcp-v1.0: pycparser==3.0 - - py3.14-fastmcp-v1.0: mcp==1.29.0 - py3.14-fastmcp-v1.0: httpx==0.28.1 - py3.14-fastmcp-v1.0: httpcore==1.0.9 - py3.14-fastmcp-v1.0: pydantic==2.13.4 - py3.14-fastmcp-v1.0: pydantic_core==2.46.4 - py3.14-fastmcp-v1.0: pytest-asyncio==1.4.0 - py3.14-fastmcp-v1.0: pytest==9.1.1 - py3.14-fastmcp-v1.0: pluggy==1.6.0 - py3.14-fastmcp-v1.0: annotated-types==0.8.0 - py3.14-fastmcp-v1.0: anyio==4.14.2 - py3.14-fastmcp-v1.0: h11==0.16.0 - py3.14-fastmcp-v1.0: httpx-sse==0.4.3 - py3.14-fastmcp-v1.0: idna==3.18 - py3.14-fastmcp-v1.0: iniconfig==2.3.0 - py3.14-fastmcp-v1.0: jsonschema==4.26.0 - py3.14-fastmcp-v1.0: attrs==26.1.0 - py3.14-fastmcp-v1.0: jsonschema-specifications==2025.9.1 - py3.14-fastmcp-v1.0: packaging==26.2 - py3.14-fastmcp-v1.0: pydantic-settings==2.14.2 - py3.14-fastmcp-v1.0: Pygments==2.20.0 - py3.14-fastmcp-v1.0: PyJWT==2.13.0 - py3.14-fastmcp-v1.0: cryptography==49.0.0 - py3.14-fastmcp-v1.0: cffi==2.1.0 - py3.14-fastmcp-v1.0: python-dotenv==1.2.2 - py3.14-fastmcp-v1.0: python-multipart==0.0.32 - py3.14-fastmcp-v1.0: referencing==0.37.0 - py3.14-fastmcp-v1.0: rpds-py==2026.6.3 - py3.14-fastmcp-v1.0: sse-starlette==3.4.6 - py3.14-fastmcp-v1.0: starlette==1.3.1 - py3.14-fastmcp-v1.0: typer==0.27.0 - py3.14-fastmcp-v1.0: annotated-doc==0.0.5 - py3.14-fastmcp-v1.0: rich==15.0.0 - py3.14-fastmcp-v1.0: markdown-it-py==4.2.0 - py3.14-fastmcp-v1.0: mdurl==0.1.2 - py3.14-fastmcp-v1.0: shellingham==1.5.4 - py3.14-fastmcp-v1.0: typing_extensions==4.16.0 - py3.14-fastmcp-v1.0: typing-inspection==0.4.2 - py3.14-fastmcp-v1.0: uvicorn==0.52.0 - py3.14-fastmcp-v1.0: click==8.4.2 - py3.14-fastmcp-v1.0: certifi==2026.7.22 - py3.14-fastmcp-v1.0: pycparser==3.0 - - py3.15-fastmcp-v1.0: mcp==1.29.1 - py3.15-fastmcp-v1.0: httpx==0.28.1 - py3.15-fastmcp-v1.0: httpcore==1.0.9 - py3.15-fastmcp-v1.0: pydantic==2.13.5 - py3.15-fastmcp-v1.0: pydantic_core==2.46.5 - py3.15-fastmcp-v1.0: pytest-asyncio==1.4.0 - py3.15-fastmcp-v1.0: pytest==9.1.1 - py3.15-fastmcp-v1.0: pluggy==1.6.0 - py3.15-fastmcp-v1.0: annotated-types==0.8.0 - py3.15-fastmcp-v1.0: anyio==4.14.2 - py3.15-fastmcp-v1.0: h11==0.16.0 - py3.15-fastmcp-v1.0: httpx-sse==0.4.3 - py3.15-fastmcp-v1.0: idna==3.19 - py3.15-fastmcp-v1.0: iniconfig==2.3.0 - py3.15-fastmcp-v1.0: jsonschema==4.26.0 - py3.15-fastmcp-v1.0: attrs==26.1.0 - py3.15-fastmcp-v1.0: jsonschema-specifications==2025.9.1 - py3.15-fastmcp-v1.0: packaging==26.3 - py3.15-fastmcp-v1.0: pydantic-settings==2.15.0 - py3.15-fastmcp-v1.0: Pygments==2.21.0 - py3.15-fastmcp-v1.0: PyJWT==2.13.0 - py3.15-fastmcp-v1.0: cryptography==50.0.1 - py3.15-fastmcp-v1.0: cffi==2.1.1 - py3.15-fastmcp-v1.0: python-dotenv==1.2.3 - py3.15-fastmcp-v1.0: python-multipart==0.0.32 - py3.15-fastmcp-v1.0: referencing==0.37.0 - py3.15-fastmcp-v1.0: rpds-py==2026.6.3 - py3.15-fastmcp-v1.0: sse-starlette==3.4.8 - py3.15-fastmcp-v1.0: starlette==1.6.0 - py3.15-fastmcp-v1.0: typer==0.27.2 - py3.15-fastmcp-v1.0: annotated-doc==0.0.5 - py3.15-fastmcp-v1.0: rich==15.0.0 - py3.15-fastmcp-v1.0: markdown-it-py==4.2.0 - py3.15-fastmcp-v1.0: mdurl==0.1.2 - py3.15-fastmcp-v1.0: shellingham==1.5.4 - py3.15-fastmcp-v1.0: typing_extensions==4.16.0 - py3.15-fastmcp-v1.0: typing-inspection==0.4.4 - py3.15-fastmcp-v1.0: uvicorn==0.52.4 - py3.15-fastmcp-v1.0: click==8.5.0 - py3.15-fastmcp-v1.0: certifi==2026.7.22 - py3.15-fastmcp-v1.0: pycparser==3.0 - - py3.15t-fastmcp-v1.0: mcp==1.29.1 - py3.15t-fastmcp-v1.0: httpx==0.28.1 - py3.15t-fastmcp-v1.0: httpcore==1.0.9 - py3.15t-fastmcp-v1.0: pydantic==2.13.5 - py3.15t-fastmcp-v1.0: pydantic_core==2.46.5 - py3.15t-fastmcp-v1.0: pytest-asyncio==1.4.0 - py3.15t-fastmcp-v1.0: pytest==9.1.1 - py3.15t-fastmcp-v1.0: pluggy==1.6.0 - py3.15t-fastmcp-v1.0: annotated-types==0.8.0 - py3.15t-fastmcp-v1.0: anyio==4.14.2 - py3.15t-fastmcp-v1.0: h11==0.16.0 - py3.15t-fastmcp-v1.0: httpx-sse==0.4.3 - py3.15t-fastmcp-v1.0: idna==3.19 - py3.15t-fastmcp-v1.0: iniconfig==2.3.0 - py3.15t-fastmcp-v1.0: jsonschema==4.26.0 - py3.15t-fastmcp-v1.0: attrs==26.1.0 - py3.15t-fastmcp-v1.0: jsonschema-specifications==2025.9.1 - py3.15t-fastmcp-v1.0: packaging==26.3 - py3.15t-fastmcp-v1.0: pydantic-settings==2.15.0 - py3.15t-fastmcp-v1.0: Pygments==2.21.0 - py3.15t-fastmcp-v1.0: PyJWT==2.13.0 - py3.15t-fastmcp-v1.0: cryptography==50.0.1 - py3.15t-fastmcp-v1.0: cffi==2.1.1 - py3.15t-fastmcp-v1.0: python-dotenv==1.2.3 - py3.15t-fastmcp-v1.0: python-multipart==0.0.32 - py3.15t-fastmcp-v1.0: referencing==0.37.0 - py3.15t-fastmcp-v1.0: rpds-py==2026.6.3 - py3.15t-fastmcp-v1.0: sse-starlette==3.4.8 - py3.15t-fastmcp-v1.0: starlette==1.6.0 - py3.15t-fastmcp-v1.0: typer==0.27.2 - py3.15t-fastmcp-v1.0: annotated-doc==0.0.5 - py3.15t-fastmcp-v1.0: rich==15.0.0 - py3.15t-fastmcp-v1.0: markdown-it-py==4.2.0 - py3.15t-fastmcp-v1.0: mdurl==0.1.2 - py3.15t-fastmcp-v1.0: shellingham==1.5.4 - py3.15t-fastmcp-v1.0: typing_extensions==4.16.0 - py3.15t-fastmcp-v1.0: typing-inspection==0.4.4 - py3.15t-fastmcp-v1.0: uvicorn==0.52.4 - py3.15t-fastmcp-v1.0: click==8.5.0 - py3.15t-fastmcp-v1.0: certifi==2026.7.22 - py3.15t-fastmcp-v1.0: pycparser==3.0 - - fastmcp-v2.14.7: fastmcp==2.14.7 - - py3.10-fastmcp-v2.14.7: fakeredis==2.34.1 - py3.10-fastmcp-v2.14.7: mcp==1.29.0 - py3.10-fastmcp-v2.14.7: httpx==0.28.1 - py3.10-fastmcp-v2.14.7: httpcore==1.0.9 - py3.10-fastmcp-v2.14.7: py-key-value-aio==0.3.0 - py3.10-fastmcp-v2.14.7: py-key-value-shared==0.3.0 - py3.10-fastmcp-v2.14.7: pydantic==2.13.4 - py3.10-fastmcp-v2.14.7: pydantic_core==2.46.4 - py3.10-fastmcp-v2.14.7: typing_extensions==4.16.0 - py3.10-fastmcp-v2.14.7: pytest-asyncio==1.4.0 - py3.10-fastmcp-v2.14.7: backports.asyncio.runner==1.2.0 - py3.10-fastmcp-v2.14.7: pytest==9.1.1 - py3.10-fastmcp-v2.14.7: pluggy==1.6.0 - py3.10-fastmcp-v2.14.7: annotated-types==0.8.0 - py3.10-fastmcp-v2.14.7: anyio==4.14.2 - py3.10-fastmcp-v2.14.7: Authlib==1.7.2 - py3.10-fastmcp-v2.14.7: beartype==0.22.9 - py3.10-fastmcp-v2.14.7: cachetools==7.1.6 - py3.10-fastmcp-v2.14.7: cyclopts==4.22.2 - py3.10-fastmcp-v2.14.7: docstring_parser==0.18.0 - py3.10-fastmcp-v2.14.7: rich-rst==2.1.0 - py3.10-fastmcp-v2.14.7: attrs==26.1.0 - py3.10-fastmcp-v2.14.7: diskcache==5.6.3 - py3.10-fastmcp-v2.14.7: exceptiongroup==1.3.1 - py3.10-fastmcp-v2.14.7: h11==0.16.0 - py3.10-fastmcp-v2.14.7: httpx-sse==0.4.3 - py3.10-fastmcp-v2.14.7: idna==3.18 - py3.10-fastmcp-v2.14.7: iniconfig==2.3.0 - py3.10-fastmcp-v2.14.7: joserfc==1.7.4 - py3.10-fastmcp-v2.14.7: cryptography==49.0.0 - py3.10-fastmcp-v2.14.7: cffi==2.1.0 - py3.10-fastmcp-v2.14.7: jsonref==1.1.0 - py3.10-fastmcp-v2.14.7: jsonschema==4.26.0 - py3.10-fastmcp-v2.14.7: jsonschema-path==0.5.0 - py3.10-fastmcp-v2.14.7: pathable==0.6.0 - py3.10-fastmcp-v2.14.7: referencing==0.37.0 - py3.10-fastmcp-v2.14.7: jsonschema-specifications==2025.9.1 - py3.10-fastmcp-v2.14.7: keyring==25.7.0 - py3.10-fastmcp-v2.14.7: importlib_metadata==9.0.0 - py3.10-fastmcp-v2.14.7: lupa==2.8 - py3.10-fastmcp-v2.14.7: openapi-pydantic==0.5.1 - py3.10-fastmcp-v2.14.7: packaging==26.2 - py3.10-fastmcp-v2.14.7: pathvalidate==3.3.1 - py3.10-fastmcp-v2.14.7: platformdirs==4.11.0 - py3.10-fastmcp-v2.14.7: pydantic-settings==2.14.2 - py3.10-fastmcp-v2.14.7: email-validator==2.3.0 - py3.10-fastmcp-v2.14.7: dnspython==2.8.0 - py3.10-fastmcp-v2.14.7: pydocket==0.23.1 - py3.10-fastmcp-v2.14.7: burner-redis==0.1.7 - py3.10-fastmcp-v2.14.7: cloudpickle==3.1.2 - py3.10-fastmcp-v2.14.7: cronsim==2.7 - py3.10-fastmcp-v2.14.7: opentelemetry-api==1.44.0 - py3.10-fastmcp-v2.14.7: prometheus_client==0.26.0 - py3.10-fastmcp-v2.14.7: Pygments==2.20.0 - py3.10-fastmcp-v2.14.7: PyJWT==2.13.0 - py3.10-fastmcp-v2.14.7: pyperclip==1.11.0 - py3.10-fastmcp-v2.14.7: python-dotenv==1.2.2 - py3.10-fastmcp-v2.14.7: python-json-logger==4.1.0 - py3.10-fastmcp-v2.14.7: python-multipart==0.0.32 - py3.10-fastmcp-v2.14.7: PyYAML==6.0.3 - py3.10-fastmcp-v2.14.7: redis==8.0.1 - py3.10-fastmcp-v2.14.7: async-timeout==5.0.1 - py3.10-fastmcp-v2.14.7: rich==15.0.0 - py3.10-fastmcp-v2.14.7: markdown-it-py==4.2.0 - py3.10-fastmcp-v2.14.7: mdurl==0.1.2 - py3.10-fastmcp-v2.14.7: rpds-py==0.30.0 - py3.10-fastmcp-v2.14.7: sortedcontainers==2.4.0 - py3.10-fastmcp-v2.14.7: sse-starlette==3.4.6 - py3.10-fastmcp-v2.14.7: starlette==1.3.1 - py3.10-fastmcp-v2.14.7: taskgroup==0.2.2 - py3.10-fastmcp-v2.14.7: tomli==2.4.1 - py3.10-fastmcp-v2.14.7: typer==0.27.0 - py3.10-fastmcp-v2.14.7: annotated-doc==0.0.5 - py3.10-fastmcp-v2.14.7: shellingham==1.5.4 - py3.10-fastmcp-v2.14.7: typing-inspection==0.4.2 - py3.10-fastmcp-v2.14.7: uncalled-for==0.3.2 - py3.10-fastmcp-v2.14.7: uvicorn==0.52.0 - py3.10-fastmcp-v2.14.7: click==8.4.2 - py3.10-fastmcp-v2.14.7: websockets==16.1.1 - py3.10-fastmcp-v2.14.7: zipp==4.1.0 - py3.10-fastmcp-v2.14.7: certifi==2026.7.22 - py3.10-fastmcp-v2.14.7: jaraco.classes==3.4.0 - py3.10-fastmcp-v2.14.7: jaraco.context==6.1.2 - py3.10-fastmcp-v2.14.7: backports.tarfile==1.2.0 - py3.10-fastmcp-v2.14.7: jaraco.functools==4.6.0 - py3.10-fastmcp-v2.14.7: more-itertools==11.1.0 - py3.10-fastmcp-v2.14.7: pycparser==3.0 - - py3.12-fastmcp-v2.14.7: fakeredis==2.34.1 - py3.12-fastmcp-v2.14.7: mcp==1.29.0 - py3.12-fastmcp-v2.14.7: httpx==0.28.1 - py3.12-fastmcp-v2.14.7: httpcore==1.0.9 - py3.12-fastmcp-v2.14.7: py-key-value-aio==0.3.0 - py3.12-fastmcp-v2.14.7: py-key-value-shared==0.3.0 - py3.12-fastmcp-v2.14.7: pydantic==2.13.4 - py3.12-fastmcp-v2.14.7: pydantic_core==2.46.4 - py3.12-fastmcp-v2.14.7: pytest-asyncio==1.4.0 - py3.12-fastmcp-v2.14.7: pytest==9.1.1 - py3.12-fastmcp-v2.14.7: pluggy==1.6.0 - py3.12-fastmcp-v2.14.7: annotated-types==0.8.0 - py3.12-fastmcp-v2.14.7: anyio==4.14.2 - py3.12-fastmcp-v2.14.7: Authlib==1.7.2 - py3.12-fastmcp-v2.14.7: beartype==0.22.9 - py3.12-fastmcp-v2.14.7: cachetools==7.1.6 - py3.12-fastmcp-v2.14.7: cyclopts==4.22.2 - py3.12-fastmcp-v2.14.7: docstring_parser==0.18.0 - py3.12-fastmcp-v2.14.7: rich-rst==2.1.0 - py3.12-fastmcp-v2.14.7: attrs==26.1.0 - py3.12-fastmcp-v2.14.7: diskcache==5.6.3 - py3.12-fastmcp-v2.14.7: exceptiongroup==1.3.1 - py3.12-fastmcp-v2.14.7: h11==0.16.0 - py3.12-fastmcp-v2.14.7: httpx-sse==0.4.3 - py3.12-fastmcp-v2.14.7: idna==3.18 - py3.12-fastmcp-v2.14.7: iniconfig==2.3.0 - py3.12-fastmcp-v2.14.7: joserfc==1.7.4 - py3.12-fastmcp-v2.14.7: cryptography==49.0.0 - py3.12-fastmcp-v2.14.7: cffi==2.1.0 - py3.12-fastmcp-v2.14.7: jsonref==1.1.0 - py3.12-fastmcp-v2.14.7: jsonschema==4.26.0 - py3.12-fastmcp-v2.14.7: jsonschema-path==0.5.0 - py3.12-fastmcp-v2.14.7: pathable==0.6.0 - py3.12-fastmcp-v2.14.7: referencing==0.37.0 - py3.12-fastmcp-v2.14.7: jsonschema-specifications==2025.9.1 - py3.12-fastmcp-v2.14.7: keyring==25.7.0 - py3.12-fastmcp-v2.14.7: lupa==2.8 - py3.12-fastmcp-v2.14.7: openapi-pydantic==0.5.1 - py3.12-fastmcp-v2.14.7: packaging==26.2 - py3.12-fastmcp-v2.14.7: pathvalidate==3.3.1 - py3.12-fastmcp-v2.14.7: platformdirs==4.11.0 - py3.12-fastmcp-v2.14.7: pydantic-settings==2.14.2 - py3.12-fastmcp-v2.14.7: email-validator==2.3.0 - py3.12-fastmcp-v2.14.7: dnspython==2.8.0 - py3.12-fastmcp-v2.14.7: pydocket==0.23.1 - py3.12-fastmcp-v2.14.7: burner-redis==0.1.7 - py3.12-fastmcp-v2.14.7: cloudpickle==3.1.2 - py3.12-fastmcp-v2.14.7: cronsim==2.7 - py3.12-fastmcp-v2.14.7: opentelemetry-api==1.44.0 - py3.12-fastmcp-v2.14.7: prometheus_client==0.26.0 - py3.12-fastmcp-v2.14.7: Pygments==2.20.0 - py3.12-fastmcp-v2.14.7: PyJWT==2.13.0 - py3.12-fastmcp-v2.14.7: pyperclip==1.11.0 - py3.12-fastmcp-v2.14.7: python-dotenv==1.2.2 - py3.12-fastmcp-v2.14.7: python-json-logger==4.1.0 - py3.12-fastmcp-v2.14.7: python-multipart==0.0.32 - py3.12-fastmcp-v2.14.7: PyYAML==6.0.3 - py3.12-fastmcp-v2.14.7: redis==8.0.1 - py3.12-fastmcp-v2.14.7: rich==15.0.0 - py3.12-fastmcp-v2.14.7: markdown-it-py==4.2.0 - py3.12-fastmcp-v2.14.7: mdurl==0.1.2 - py3.12-fastmcp-v2.14.7: rpds-py==2026.6.3 - py3.12-fastmcp-v2.14.7: sortedcontainers==2.4.0 - py3.12-fastmcp-v2.14.7: sse-starlette==3.4.6 - py3.12-fastmcp-v2.14.7: starlette==1.3.1 - py3.12-fastmcp-v2.14.7: typer==0.27.0 - py3.12-fastmcp-v2.14.7: annotated-doc==0.0.5 - py3.12-fastmcp-v2.14.7: shellingham==1.5.4 - py3.12-fastmcp-v2.14.7: typing_extensions==4.16.0 - py3.12-fastmcp-v2.14.7: typing-inspection==0.4.2 - py3.12-fastmcp-v2.14.7: uncalled-for==0.3.2 - py3.12-fastmcp-v2.14.7: uvicorn==0.52.0 - py3.12-fastmcp-v2.14.7: click==8.4.2 - py3.12-fastmcp-v2.14.7: websockets==16.1.1 - py3.12-fastmcp-v2.14.7: certifi==2026.7.22 - py3.12-fastmcp-v2.14.7: jaraco.classes==3.4.0 - py3.12-fastmcp-v2.14.7: jaraco.context==6.1.2 - py3.12-fastmcp-v2.14.7: jaraco.functools==4.6.0 - py3.12-fastmcp-v2.14.7: more-itertools==11.1.0 - py3.12-fastmcp-v2.14.7: pycparser==3.0 - - py3.13-fastmcp-v2.14.7: pytest-asyncio==1.4.0 - py3.13-fastmcp-v2.14.7: httpx==0.28.1 - py3.13-fastmcp-v2.14.7: httpcore==1.0.9 - py3.13-fastmcp-v2.14.7: Authlib==1.7.2 - py3.13-fastmcp-v2.14.7: cyclopts==4.22.2 - py3.13-fastmcp-v2.14.7: exceptiongroup==1.3.1 - py3.13-fastmcp-v2.14.7: fakeredis==2.34.1 - py3.13-fastmcp-v2.14.7: jsonref==1.1.0 - py3.13-fastmcp-v2.14.7: jsonschema-path==0.5.0 - py3.13-fastmcp-v2.14.7: mcp==1.29.0 - py3.13-fastmcp-v2.14.7: anyio==4.14.2 - py3.13-fastmcp-v2.14.7: idna==3.18 - py3.13-fastmcp-v2.14.7: openapi-pydantic==0.5.1 - py3.13-fastmcp-v2.14.7: packaging==26.2 - py3.13-fastmcp-v2.14.7: platformdirs==4.11.0 - py3.13-fastmcp-v2.14.7: py-key-value-aio==0.3.0 - py3.13-fastmcp-v2.14.7: py-key-value-shared==0.3.0 - py3.13-fastmcp-v2.14.7: pydantic==2.13.4 - py3.13-fastmcp-v2.14.7: pydantic_core==2.46.4 - py3.13-fastmcp-v2.14.7: pydocket==0.23.1 - py3.13-fastmcp-v2.14.7: pyperclip==1.11.0 - py3.13-fastmcp-v2.14.7: pytest==9.1.1 - py3.13-fastmcp-v2.14.7: python-dotenv==1.2.2 - py3.13-fastmcp-v2.14.7: rich==15.0.0 - py3.13-fastmcp-v2.14.7: uvicorn==0.52.0 - py3.13-fastmcp-v2.14.7: websockets==16.1.1 - py3.13-fastmcp-v2.14.7: certifi==2026.7.22 - py3.13-fastmcp-v2.14.7: annotated-types==0.8.0 - py3.13-fastmcp-v2.14.7: attrs==26.1.0 - py3.13-fastmcp-v2.14.7: beartype==0.22.9 - py3.13-fastmcp-v2.14.7: burner-redis==0.1.7 - py3.13-fastmcp-v2.14.7: cachetools==7.1.6 - py3.13-fastmcp-v2.14.7: click==8.4.2 - py3.13-fastmcp-v2.14.7: cloudpickle==3.1.2 - py3.13-fastmcp-v2.14.7: cronsim==2.7 - py3.13-fastmcp-v2.14.7: diskcache==5.6.3 - py3.13-fastmcp-v2.14.7: docstring_parser==0.18.0 - py3.13-fastmcp-v2.14.7: email-validator==2.3.0 - py3.13-fastmcp-v2.14.7: h11==0.16.0 - py3.13-fastmcp-v2.14.7: httpx-sse==0.4.3 - py3.13-fastmcp-v2.14.7: iniconfig==2.3.0 - py3.13-fastmcp-v2.14.7: joserfc==1.7.4 - py3.13-fastmcp-v2.14.7: cryptography==49.0.0 - py3.13-fastmcp-v2.14.7: jsonschema==4.26.0 - py3.13-fastmcp-v2.14.7: keyring==25.7.0 - py3.13-fastmcp-v2.14.7: lupa==2.8 - py3.13-fastmcp-v2.14.7: markdown-it-py==4.2.0 - py3.13-fastmcp-v2.14.7: opentelemetry-api==1.44.0 - py3.13-fastmcp-v2.14.7: pathable==0.6.0 - py3.13-fastmcp-v2.14.7: pathvalidate==3.3.1 - py3.13-fastmcp-v2.14.7: pluggy==1.6.0 - py3.13-fastmcp-v2.14.7: prometheus_client==0.26.0 - py3.13-fastmcp-v2.14.7: pydantic-settings==2.14.2 - py3.13-fastmcp-v2.14.7: Pygments==2.20.0 - py3.13-fastmcp-v2.14.7: PyJWT==2.13.0 - py3.13-fastmcp-v2.14.7: python-json-logger==4.1.0 - py3.13-fastmcp-v2.14.7: python-multipart==0.0.32 - py3.13-fastmcp-v2.14.7: PyYAML==6.0.3 - py3.13-fastmcp-v2.14.7: redis==8.0.1 - py3.13-fastmcp-v2.14.7: referencing==0.37.0 - py3.13-fastmcp-v2.14.7: rich-rst==2.1.0 - py3.13-fastmcp-v2.14.7: sortedcontainers==2.4.0 - py3.13-fastmcp-v2.14.7: sse-starlette==3.4.6 - py3.13-fastmcp-v2.14.7: starlette==1.3.1 - py3.13-fastmcp-v2.14.7: typer==0.27.0 - py3.13-fastmcp-v2.14.7: typing_extensions==4.16.0 - py3.13-fastmcp-v2.14.7: typing-inspection==0.4.2 - py3.13-fastmcp-v2.14.7: uncalled-for==0.3.2 - py3.13-fastmcp-v2.14.7: annotated-doc==0.0.5 - py3.13-fastmcp-v2.14.7: cffi==2.1.0 - py3.13-fastmcp-v2.14.7: dnspython==2.8.0 - py3.13-fastmcp-v2.14.7: jsonschema-specifications==2025.9.1 - py3.13-fastmcp-v2.14.7: mdurl==0.1.2 - py3.13-fastmcp-v2.14.7: rpds-py==2026.6.3 - py3.13-fastmcp-v2.14.7: shellingham==1.5.4 - py3.13-fastmcp-v2.14.7: jaraco.classes==3.4.0 - py3.13-fastmcp-v2.14.7: jaraco.context==6.1.2 - py3.13-fastmcp-v2.14.7: jaraco.functools==4.6.0 - py3.13-fastmcp-v2.14.7: more-itertools==11.1.0 - py3.13-fastmcp-v2.14.7: pycparser==3.0 - - fastmcp-v3.4.7: fastmcp==3.4.7 - - py3.10-fastmcp-v3.4.7: fastmcp-slim==3.4.7 - py3.10-fastmcp-v3.4.7: httpx==0.28.1 - py3.10-fastmcp-v3.4.7: httpcore==1.0.9 - py3.10-fastmcp-v3.4.7: mcp==1.29.0 - py3.10-fastmcp-v3.4.7: py-key-value-aio==0.4.5 - py3.10-fastmcp-v3.4.7: pydantic==2.13.4 - py3.10-fastmcp-v3.4.7: pydantic_core==2.46.4 - py3.10-fastmcp-v3.4.7: PyYAML==6.0.3 - py3.10-fastmcp-v3.4.7: pytest-asyncio==1.4.0 - py3.10-fastmcp-v3.4.7: backports.asyncio.runner==1.2.0 - py3.10-fastmcp-v3.4.7: pytest==9.1.1 - py3.10-fastmcp-v3.4.7: pluggy==1.6.0 - py3.10-fastmcp-v3.4.7: aiofile==3.9.0 - py3.10-fastmcp-v3.4.7: caio==0.9.25 - py3.10-fastmcp-v3.4.7: annotated-types==0.8.0 - py3.10-fastmcp-v3.4.7: anyio==4.14.2 - py3.10-fastmcp-v3.4.7: Authlib==1.7.2 - py3.10-fastmcp-v3.4.7: beartype==0.22.9 - py3.10-fastmcp-v3.4.7: cachetools==7.1.7 - py3.10-fastmcp-v3.4.7: cyclopts==4.23.2 - py3.10-fastmcp-v3.4.7: docstring_parser==0.18.0 - py3.10-fastmcp-v3.4.7: rich-rst==2.1.0 - py3.10-fastmcp-v3.4.7: attrs==26.1.0 - py3.10-fastmcp-v3.4.7: exceptiongroup==1.3.1 - py3.10-fastmcp-v3.4.7: griffelib==2.2.0 - py3.10-fastmcp-v3.4.7: h11==0.16.0 - py3.10-fastmcp-v3.4.7: httpx-sse==0.4.3 - py3.10-fastmcp-v3.4.7: idna==3.19 - py3.10-fastmcp-v3.4.7: iniconfig==2.3.0 - py3.10-fastmcp-v3.4.7: joserfc==1.7.4 - py3.10-fastmcp-v3.4.7: cryptography==50.0.0 - py3.10-fastmcp-v3.4.7: cffi==2.1.1 - py3.10-fastmcp-v3.4.7: jsonref==1.1.0 - py3.10-fastmcp-v3.4.7: jsonschema==4.26.0 - py3.10-fastmcp-v3.4.7: jsonschema-path==0.5.0 - py3.10-fastmcp-v3.4.7: pathable==0.6.0 - py3.10-fastmcp-v3.4.7: referencing==0.37.0 - py3.10-fastmcp-v3.4.7: jsonschema-specifications==2025.9.1 - py3.10-fastmcp-v3.4.7: keyring==25.7.0 - py3.10-fastmcp-v3.4.7: importlib_metadata==9.0.0 - py3.10-fastmcp-v3.4.7: openapi-pydantic==0.5.1 - py3.10-fastmcp-v3.4.7: opentelemetry-api==1.44.0 - py3.10-fastmcp-v3.4.7: packaging==26.3 - py3.10-fastmcp-v3.4.7: platformdirs==4.11.3 - py3.10-fastmcp-v3.4.7: pydantic-settings==2.15.0 - py3.10-fastmcp-v3.4.7: email-validator==2.3.0 - py3.10-fastmcp-v3.4.7: dnspython==2.8.0 - py3.10-fastmcp-v3.4.7: Pygments==2.21.0 - py3.10-fastmcp-v3.4.7: PyJWT==2.13.0 - py3.10-fastmcp-v3.4.7: pyperclip==1.11.0 - py3.10-fastmcp-v3.4.7: python-dotenv==1.2.3 - py3.10-fastmcp-v3.4.7: python-multipart==0.0.32 - py3.10-fastmcp-v3.4.7: rich==15.0.0 - py3.10-fastmcp-v3.4.7: markdown-it-py==4.2.0 - py3.10-fastmcp-v3.4.7: mdurl==0.1.2 - py3.10-fastmcp-v3.4.7: rpds-py==0.30.0 - py3.10-fastmcp-v3.4.7: sse-starlette==3.4.8 - py3.10-fastmcp-v3.4.7: starlette==1.6.0 - py3.10-fastmcp-v3.4.7: tomli==2.4.1 - py3.10-fastmcp-v3.4.7: typing_extensions==4.16.0 - py3.10-fastmcp-v3.4.7: typing-inspection==0.4.4 - py3.10-fastmcp-v3.4.7: uncalled-for==0.4.0 - py3.10-fastmcp-v3.4.7: uvicorn==0.52.4 - py3.10-fastmcp-v3.4.7: click==8.4.2 - py3.10-fastmcp-v3.4.7: watchfiles==1.2.0 - py3.10-fastmcp-v3.4.7: websockets==16.1.1 - py3.10-fastmcp-v3.4.7: zipp==4.1.0 - py3.10-fastmcp-v3.4.7: certifi==2026.7.22 - py3.10-fastmcp-v3.4.7: jaraco.classes==3.4.0 - py3.10-fastmcp-v3.4.7: jaraco.context==6.1.2 - py3.10-fastmcp-v3.4.7: backports.tarfile==1.2.0 - py3.10-fastmcp-v3.4.7: jaraco.functools==4.6.0 - py3.10-fastmcp-v3.4.7: more-itertools==11.1.0 - py3.10-fastmcp-v3.4.7: pycparser==3.0 - - py3.12-fastmcp-v3.4.7: fastmcp-slim==3.4.7 - py3.12-fastmcp-v3.4.7: httpx==0.28.1 - py3.12-fastmcp-v3.4.7: httpcore==1.0.9 - py3.12-fastmcp-v3.4.7: mcp==1.29.0 - py3.12-fastmcp-v3.4.7: py-key-value-aio==0.4.5 - py3.12-fastmcp-v3.4.7: pydantic==2.13.4 - py3.12-fastmcp-v3.4.7: pydantic_core==2.46.4 - py3.12-fastmcp-v3.4.7: PyYAML==6.0.3 - py3.12-fastmcp-v3.4.7: pytest-asyncio==1.4.0 - py3.12-fastmcp-v3.4.7: pytest==9.1.1 - py3.12-fastmcp-v3.4.7: pluggy==1.6.0 - py3.12-fastmcp-v3.4.7: aiofile==3.12.3 - py3.12-fastmcp-v3.4.7: caio==0.12.2 - py3.12-fastmcp-v3.4.7: annotated-types==0.8.0 - py3.12-fastmcp-v3.4.7: anyio==4.14.2 - py3.12-fastmcp-v3.4.7: Authlib==1.7.2 - py3.12-fastmcp-v3.4.7: beartype==0.22.9 - py3.12-fastmcp-v3.4.7: cachetools==7.1.7 - py3.12-fastmcp-v3.4.7: cyclopts==4.23.2 - py3.12-fastmcp-v3.4.7: docstring_parser==0.18.0 - py3.12-fastmcp-v3.4.7: rich-rst==2.1.0 - py3.12-fastmcp-v3.4.7: attrs==26.1.0 - py3.12-fastmcp-v3.4.7: exceptiongroup==1.3.1 - py3.12-fastmcp-v3.4.7: griffelib==2.2.0 - py3.12-fastmcp-v3.4.7: h11==0.16.0 - py3.12-fastmcp-v3.4.7: httpx-sse==0.4.3 - py3.12-fastmcp-v3.4.7: idna==3.19 - py3.12-fastmcp-v3.4.7: iniconfig==2.3.0 - py3.12-fastmcp-v3.4.7: joserfc==1.7.4 - py3.12-fastmcp-v3.4.7: cryptography==50.0.0 - py3.12-fastmcp-v3.4.7: cffi==2.1.1 - py3.12-fastmcp-v3.4.7: jsonref==1.1.0 - py3.12-fastmcp-v3.4.7: jsonschema==4.26.0 - py3.12-fastmcp-v3.4.7: jsonschema-path==0.5.0 - py3.12-fastmcp-v3.4.7: pathable==0.6.0 - py3.12-fastmcp-v3.4.7: referencing==0.37.0 - py3.12-fastmcp-v3.4.7: jsonschema-specifications==2025.9.1 - py3.12-fastmcp-v3.4.7: keyring==25.7.0 - py3.12-fastmcp-v3.4.7: openapi-pydantic==0.5.1 - py3.12-fastmcp-v3.4.7: opentelemetry-api==1.44.0 - py3.12-fastmcp-v3.4.7: packaging==26.3 - py3.12-fastmcp-v3.4.7: platformdirs==4.11.3 - py3.12-fastmcp-v3.4.7: pydantic-settings==2.15.0 - py3.12-fastmcp-v3.4.7: email-validator==2.3.0 - py3.12-fastmcp-v3.4.7: dnspython==2.8.0 - py3.12-fastmcp-v3.4.7: Pygments==2.21.0 - py3.12-fastmcp-v3.4.7: PyJWT==2.13.0 - py3.12-fastmcp-v3.4.7: pyperclip==1.11.0 - py3.12-fastmcp-v3.4.7: python-dotenv==1.2.3 - py3.12-fastmcp-v3.4.7: python-multipart==0.0.32 - py3.12-fastmcp-v3.4.7: rich==15.0.0 - py3.12-fastmcp-v3.4.7: markdown-it-py==4.2.0 - py3.12-fastmcp-v3.4.7: mdurl==0.1.2 - py3.12-fastmcp-v3.4.7: rpds-py==2026.6.3 - py3.12-fastmcp-v3.4.7: sse-starlette==3.4.8 - py3.12-fastmcp-v3.4.7: starlette==1.6.0 - py3.12-fastmcp-v3.4.7: typing_extensions==4.16.0 - py3.12-fastmcp-v3.4.7: typing-inspection==0.4.4 - py3.12-fastmcp-v3.4.7: uncalled-for==0.4.0 - py3.12-fastmcp-v3.4.7: uvicorn==0.52.4 - py3.12-fastmcp-v3.4.7: click==8.4.2 - py3.12-fastmcp-v3.4.7: watchfiles==1.2.0 - py3.12-fastmcp-v3.4.7: websockets==17.0.1 - py3.12-fastmcp-v3.4.7: certifi==2026.7.22 - py3.12-fastmcp-v3.4.7: jaraco.classes==3.4.0 - py3.12-fastmcp-v3.4.7: jaraco.context==6.1.2 - py3.12-fastmcp-v3.4.7: jaraco.functools==4.6.0 - py3.12-fastmcp-v3.4.7: more-itertools==11.1.0 - py3.12-fastmcp-v3.4.7: pycparser==3.0 - - py3.13-fastmcp-v3.4.7: fastmcp-slim==3.4.7 - py3.13-fastmcp-v3.4.7: pytest-asyncio==1.4.0 - py3.13-fastmcp-v3.4.7: httpx==0.28.1 - py3.13-fastmcp-v3.4.7: httpcore==1.0.9 - py3.13-fastmcp-v3.4.7: pytest==9.1.1 - py3.13-fastmcp-v3.4.7: anyio==4.14.2 - py3.13-fastmcp-v3.4.7: idna==3.19 - py3.13-fastmcp-v3.4.7: certifi==2026.7.22 - py3.13-fastmcp-v3.4.7: Authlib==1.7.2 - py3.13-fastmcp-v3.4.7: cyclopts==4.23.2 - py3.13-fastmcp-v3.4.7: exceptiongroup==1.3.1 - py3.13-fastmcp-v3.4.7: griffelib==2.2.0 - py3.13-fastmcp-v3.4.7: h11==0.16.0 - py3.13-fastmcp-v3.4.7: iniconfig==2.3.0 - py3.13-fastmcp-v3.4.7: joserfc==1.7.4 - py3.13-fastmcp-v3.4.7: jsonref==1.1.0 - py3.13-fastmcp-v3.4.7: jsonschema-path==0.5.0 - py3.13-fastmcp-v3.4.7: mcp==1.29.0 - py3.13-fastmcp-v3.4.7: openapi-pydantic==0.5.1 - py3.13-fastmcp-v3.4.7: opentelemetry-api==1.44.0 - py3.13-fastmcp-v3.4.7: packaging==26.3 - py3.13-fastmcp-v3.4.7: platformdirs==4.11.3 - py3.13-fastmcp-v3.4.7: pluggy==1.6.0 - py3.13-fastmcp-v3.4.7: py-key-value-aio==0.4.5 - py3.13-fastmcp-v3.4.7: pydantic==2.13.4 - py3.13-fastmcp-v3.4.7: pydantic_core==2.46.4 - py3.13-fastmcp-v3.4.7: pydantic-settings==2.15.0 - py3.13-fastmcp-v3.4.7: Pygments==2.21.0 - py3.13-fastmcp-v3.4.7: pyperclip==1.11.0 - py3.13-fastmcp-v3.4.7: python-dotenv==1.2.3 - py3.13-fastmcp-v3.4.7: python-multipart==0.0.32 - py3.13-fastmcp-v3.4.7: PyYAML==6.0.3 - py3.13-fastmcp-v3.4.7: rich==15.0.0 - py3.13-fastmcp-v3.4.7: starlette==1.6.0 - py3.13-fastmcp-v3.4.7: typing_extensions==4.16.0 - py3.13-fastmcp-v3.4.7: uncalled-for==0.4.0 - py3.13-fastmcp-v3.4.7: uvicorn==0.52.4 - py3.13-fastmcp-v3.4.7: watchfiles==1.2.0 - py3.13-fastmcp-v3.4.7: websockets==17.0.1 - py3.13-fastmcp-v3.4.7: aiofile==3.12.3 - py3.13-fastmcp-v3.4.7: annotated-types==0.8.0 - py3.13-fastmcp-v3.4.7: attrs==26.1.0 - py3.13-fastmcp-v3.4.7: beartype==0.22.9 - py3.13-fastmcp-v3.4.7: cachetools==7.1.7 - py3.13-fastmcp-v3.4.7: click==8.4.2 - py3.13-fastmcp-v3.4.7: cryptography==50.0.0 - py3.13-fastmcp-v3.4.7: docstring_parser==0.18.0 - py3.13-fastmcp-v3.4.7: email-validator==2.3.0 - py3.13-fastmcp-v3.4.7: httpx-sse==0.4.3 - py3.13-fastmcp-v3.4.7: jsonschema==4.26.0 - py3.13-fastmcp-v3.4.7: keyring==25.7.0 - py3.13-fastmcp-v3.4.7: markdown-it-py==4.2.0 - py3.13-fastmcp-v3.4.7: pathable==0.6.0 - py3.13-fastmcp-v3.4.7: PyJWT==2.13.0 - py3.13-fastmcp-v3.4.7: referencing==0.37.0 - py3.13-fastmcp-v3.4.7: rich-rst==2.1.0 - py3.13-fastmcp-v3.4.7: sse-starlette==3.4.8 - py3.13-fastmcp-v3.4.7: typing-inspection==0.4.4 - py3.13-fastmcp-v3.4.7: caio==0.12.2 - py3.13-fastmcp-v3.4.7: cffi==2.1.1 - py3.13-fastmcp-v3.4.7: dnspython==2.8.0 - py3.13-fastmcp-v3.4.7: jsonschema-specifications==2025.9.1 - py3.13-fastmcp-v3.4.7: mdurl==0.1.2 - py3.13-fastmcp-v3.4.7: rpds-py==2026.6.3 - py3.13-fastmcp-v3.4.7: jaraco.classes==3.4.0 - py3.13-fastmcp-v3.4.7: jaraco.context==6.1.2 - py3.13-fastmcp-v3.4.7: jaraco.functools==4.6.0 - py3.13-fastmcp-v3.4.7: more-itertools==11.1.0 - py3.13-fastmcp-v3.4.7: pycparser==3.0 - fastmcp-v4.0.5: fastmcp==4.0.5 py3.10-fastmcp-v4.0.5: fastmcp-slim==4.0.5 @@ -2485,348 +1528,201 @@ deps = fastmcp: pytest-asyncio fastmcp: httpx - fastmcp-v0.1.0: mcp<2 # ~~~ Agents ~~~ - openai_agents-v0.0.19: openai-agents==0.0.19 - - py3.10-openai_agents-v0.0.19: pytest-asyncio==1.4.0 - py3.10-openai_agents-v0.0.19: httpx==0.28.1 - py3.10-openai_agents-v0.0.19: httpcore==1.0.9 - py3.10-openai_agents-v0.0.19: openai==2.44.0 - py3.10-openai_agents-v0.0.19: anyio==4.14.2 - py3.10-openai_agents-v0.0.19: backports.asyncio.runner==1.2.0 - py3.10-openai_agents-v0.0.19: distro==1.9.0 - py3.10-openai_agents-v0.0.19: griffe==1.15.0 - py3.10-openai_agents-v0.0.19: idna==3.19 - py3.10-openai_agents-v0.0.19: jiter==0.16.0 - py3.10-openai_agents-v0.0.19: mcp==1.29.0 - py3.10-openai_agents-v0.0.19: pydantic==2.13.4 - py3.10-openai_agents-v0.0.19: pydantic_core==2.46.4 - py3.10-openai_agents-v0.0.19: pytest==9.1.1 - py3.10-openai_agents-v0.0.19: requests==2.34.2 - py3.10-openai_agents-v0.0.19: certifi==2026.7.22 - py3.10-openai_agents-v0.0.19: tqdm==4.70.0 - py3.10-openai_agents-v0.0.19: types-requests==2.33.0.20260712 - py3.10-openai_agents-v0.0.19: typing_extensions==4.16.0 - py3.10-openai_agents-v0.0.19: sniffio==1.3.1 - py3.10-openai_agents-v0.0.19: annotated-types==0.8.0 - py3.10-openai_agents-v0.0.19: charset-normalizer==3.5.1 - py3.10-openai_agents-v0.0.19: colorama==0.4.6 - py3.10-openai_agents-v0.0.19: exceptiongroup==1.3.1 - py3.10-openai_agents-v0.0.19: h11==0.16.0 - py3.10-openai_agents-v0.0.19: httpx-sse==0.4.3 - py3.10-openai_agents-v0.0.19: iniconfig==2.3.0 - py3.10-openai_agents-v0.0.19: jsonschema==4.26.0 - py3.10-openai_agents-v0.0.19: packaging==26.3 - py3.10-openai_agents-v0.0.19: pluggy==1.6.0 - py3.10-openai_agents-v0.0.19: pydantic-settings==2.15.0 - py3.10-openai_agents-v0.0.19: Pygments==2.21.0 - py3.10-openai_agents-v0.0.19: PyJWT==2.13.0 - py3.10-openai_agents-v0.0.19: python-multipart==0.0.32 - py3.10-openai_agents-v0.0.19: sse-starlette==3.4.8 - py3.10-openai_agents-v0.0.19: starlette==1.6.0 - py3.10-openai_agents-v0.0.19: tomli==2.4.1 - py3.10-openai_agents-v0.0.19: typing-inspection==0.4.4 - py3.10-openai_agents-v0.0.19: urllib3==2.7.0 - py3.10-openai_agents-v0.0.19: uvicorn==0.52.4 - py3.10-openai_agents-v0.0.19: attrs==26.1.0 - py3.10-openai_agents-v0.0.19: click==8.4.2 - py3.10-openai_agents-v0.0.19: cryptography==50.0.0 - py3.10-openai_agents-v0.0.19: jsonschema-specifications==2025.9.1 - py3.10-openai_agents-v0.0.19: python-dotenv==1.2.3 - py3.10-openai_agents-v0.0.19: referencing==0.37.0 - py3.10-openai_agents-v0.0.19: rpds-py==0.30.0 - py3.10-openai_agents-v0.0.19: cffi==2.1.1 - py3.10-openai_agents-v0.0.19: pycparser==3.0 - - py3.11-openai_agents-v0.0.19: pytest-asyncio==1.4.0 - py3.11-openai_agents-v0.0.19: httpx==0.28.1 - py3.11-openai_agents-v0.0.19: httpcore==1.0.9 - py3.11-openai_agents-v0.0.19: openai==2.44.0 - py3.11-openai_agents-v0.0.19: anyio==4.14.2 - py3.11-openai_agents-v0.0.19: distro==1.9.0 - py3.11-openai_agents-v0.0.19: griffe==1.15.0 - py3.11-openai_agents-v0.0.19: idna==3.19 - py3.11-openai_agents-v0.0.19: jiter==0.16.0 - py3.11-openai_agents-v0.0.19: mcp==1.29.0 - py3.11-openai_agents-v0.0.19: pydantic==2.13.4 - py3.11-openai_agents-v0.0.19: pydantic_core==2.46.4 - py3.11-openai_agents-v0.0.19: pytest==9.1.1 - py3.11-openai_agents-v0.0.19: requests==2.34.2 - py3.11-openai_agents-v0.0.19: certifi==2026.7.22 - py3.11-openai_agents-v0.0.19: tqdm==4.70.0 - py3.11-openai_agents-v0.0.19: types-requests==2.33.0.20260712 - py3.11-openai_agents-v0.0.19: typing_extensions==4.16.0 - py3.11-openai_agents-v0.0.19: sniffio==1.3.1 - py3.11-openai_agents-v0.0.19: annotated-types==0.8.0 - py3.11-openai_agents-v0.0.19: charset-normalizer==3.5.1 - py3.11-openai_agents-v0.0.19: colorama==0.4.6 - py3.11-openai_agents-v0.0.19: h11==0.16.0 - py3.11-openai_agents-v0.0.19: httpx-sse==0.4.3 - py3.11-openai_agents-v0.0.19: iniconfig==2.3.0 - py3.11-openai_agents-v0.0.19: jsonschema==4.26.0 - py3.11-openai_agents-v0.0.19: packaging==26.3 - py3.11-openai_agents-v0.0.19: pluggy==1.6.0 - py3.11-openai_agents-v0.0.19: pydantic-settings==2.15.0 - py3.11-openai_agents-v0.0.19: Pygments==2.21.0 - py3.11-openai_agents-v0.0.19: PyJWT==2.13.0 - py3.11-openai_agents-v0.0.19: python-multipart==0.0.32 - py3.11-openai_agents-v0.0.19: sse-starlette==3.4.8 - py3.11-openai_agents-v0.0.19: starlette==1.6.0 - py3.11-openai_agents-v0.0.19: typing-inspection==0.4.4 - py3.11-openai_agents-v0.0.19: urllib3==2.7.0 - py3.11-openai_agents-v0.0.19: uvicorn==0.52.4 - py3.11-openai_agents-v0.0.19: attrs==26.1.0 - py3.11-openai_agents-v0.0.19: click==8.4.2 - py3.11-openai_agents-v0.0.19: cryptography==50.0.0 - py3.11-openai_agents-v0.0.19: jsonschema-specifications==2025.9.1 - py3.11-openai_agents-v0.0.19: python-dotenv==1.2.3 - py3.11-openai_agents-v0.0.19: referencing==0.37.0 - py3.11-openai_agents-v0.0.19: rpds-py==2026.6.3 - py3.11-openai_agents-v0.0.19: cffi==2.1.1 - py3.11-openai_agents-v0.0.19: pycparser==3.0 - - py3.12-openai_agents-v0.0.19: openai==2.44.0 - py3.12-openai_agents-v0.0.19: httpx==0.28.1 - py3.12-openai_agents-v0.0.19: anyio==4.14.2 - py3.12-openai_agents-v0.0.19: distro==1.9.0 - py3.12-openai_agents-v0.0.19: griffe==1.15.0 - py3.12-openai_agents-v0.0.19: httpcore==1.0.9 - py3.12-openai_agents-v0.0.19: jiter==0.16.0 - py3.12-openai_agents-v0.0.19: mcp==1.29.0 - py3.12-openai_agents-v0.0.19: pydantic==2.13.4 - py3.12-openai_agents-v0.0.19: pydantic_core==2.46.4 - py3.12-openai_agents-v0.0.19: requests==2.34.2 - py3.12-openai_agents-v0.0.19: charset-normalizer==3.5.1 - py3.12-openai_agents-v0.0.19: idna==3.19 - py3.12-openai_agents-v0.0.19: types-requests==2.33.0.20260712 - py3.12-openai_agents-v0.0.19: typing_extensions==4.16.0 - py3.12-openai_agents-v0.0.19: urllib3==2.7.0 - py3.12-openai_agents-v0.0.19: pytest-asyncio==1.4.0 - py3.12-openai_agents-v0.0.19: pytest==9.1.1 - py3.12-openai_agents-v0.0.19: pluggy==1.6.0 - py3.12-openai_agents-v0.0.19: annotated-types==0.8.0 - py3.12-openai_agents-v0.0.19: certifi==2026.7.22 - py3.12-openai_agents-v0.0.19: colorama==0.4.6 - py3.12-openai_agents-v0.0.19: h11==0.16.0 - py3.12-openai_agents-v0.0.19: httpx-sse==0.4.3 - py3.12-openai_agents-v0.0.19: iniconfig==2.3.0 - py3.12-openai_agents-v0.0.19: jsonschema==4.26.0 - py3.12-openai_agents-v0.0.19: attrs==26.1.0 - py3.12-openai_agents-v0.0.19: jsonschema-specifications==2025.9.1 - py3.12-openai_agents-v0.0.19: packaging==26.3 - py3.12-openai_agents-v0.0.19: pydantic-settings==2.15.0 - py3.12-openai_agents-v0.0.19: Pygments==2.21.0 - py3.12-openai_agents-v0.0.19: PyJWT==2.13.0 - py3.12-openai_agents-v0.0.19: cryptography==50.0.0 - py3.12-openai_agents-v0.0.19: cffi==2.1.1 - py3.12-openai_agents-v0.0.19: python-dotenv==1.2.3 - py3.12-openai_agents-v0.0.19: python-multipart==0.0.32 - py3.12-openai_agents-v0.0.19: referencing==0.37.0 - py3.12-openai_agents-v0.0.19: rpds-py==2026.6.3 - py3.12-openai_agents-v0.0.19: sse-starlette==3.4.8 - py3.12-openai_agents-v0.0.19: starlette==1.6.0 - py3.12-openai_agents-v0.0.19: tqdm==4.70.0 - py3.12-openai_agents-v0.0.19: typing-inspection==0.4.4 - py3.12-openai_agents-v0.0.19: uvicorn==0.52.4 - py3.12-openai_agents-v0.0.19: click==8.4.2 - py3.12-openai_agents-v0.0.19: pycparser==3.0 - py3.12-openai_agents-v0.0.19: sniffio==1.3.1 - - openai_agents-v0.7.0: openai-agents==0.7.0 - - py3.10-openai_agents-v0.7.0: pytest-asyncio==1.4.0 - py3.10-openai_agents-v0.7.0: httpx==0.28.1 - py3.10-openai_agents-v0.7.0: httpcore==1.0.9 - py3.10-openai_agents-v0.7.0: openai==2.44.0 - py3.10-openai_agents-v0.7.0: anyio==4.14.2 - py3.10-openai_agents-v0.7.0: backports.asyncio.runner==1.2.0 - py3.10-openai_agents-v0.7.0: distro==1.9.0 - py3.10-openai_agents-v0.7.0: griffe==1.15.0 - py3.10-openai_agents-v0.7.0: idna==3.19 - py3.10-openai_agents-v0.7.0: jiter==0.16.0 - py3.10-openai_agents-v0.7.0: mcp==1.29.0 - py3.10-openai_agents-v0.7.0: pydantic==2.13.4 - py3.10-openai_agents-v0.7.0: pydantic_core==2.46.4 - py3.10-openai_agents-v0.7.0: pytest==9.1.1 - py3.10-openai_agents-v0.7.0: requests==2.34.2 - py3.10-openai_agents-v0.7.0: certifi==2026.7.22 - py3.10-openai_agents-v0.7.0: tqdm==4.70.0 - py3.10-openai_agents-v0.7.0: types-requests==2.33.0.20260712 - py3.10-openai_agents-v0.7.0: typing_extensions==4.16.0 - py3.10-openai_agents-v0.7.0: sniffio==1.3.1 - py3.10-openai_agents-v0.7.0: annotated-types==0.8.0 - py3.10-openai_agents-v0.7.0: charset-normalizer==3.5.1 - py3.10-openai_agents-v0.7.0: colorama==0.4.6 - py3.10-openai_agents-v0.7.0: exceptiongroup==1.3.1 - py3.10-openai_agents-v0.7.0: h11==0.16.0 - py3.10-openai_agents-v0.7.0: httpx-sse==0.4.3 - py3.10-openai_agents-v0.7.0: iniconfig==2.3.0 - py3.10-openai_agents-v0.7.0: jsonschema==4.26.0 - py3.10-openai_agents-v0.7.0: packaging==26.3 - py3.10-openai_agents-v0.7.0: pluggy==1.6.0 - py3.10-openai_agents-v0.7.0: pydantic-settings==2.15.0 - py3.10-openai_agents-v0.7.0: Pygments==2.21.0 - py3.10-openai_agents-v0.7.0: PyJWT==2.13.0 - py3.10-openai_agents-v0.7.0: python-multipart==0.0.32 - py3.10-openai_agents-v0.7.0: sse-starlette==3.4.8 - py3.10-openai_agents-v0.7.0: starlette==1.6.0 - py3.10-openai_agents-v0.7.0: tomli==2.4.1 - py3.10-openai_agents-v0.7.0: typing-inspection==0.4.4 - py3.10-openai_agents-v0.7.0: urllib3==2.7.0 - py3.10-openai_agents-v0.7.0: uvicorn==0.52.4 - py3.10-openai_agents-v0.7.0: attrs==26.1.0 - py3.10-openai_agents-v0.7.0: click==8.4.2 - py3.10-openai_agents-v0.7.0: cryptography==50.0.0 - py3.10-openai_agents-v0.7.0: jsonschema-specifications==2025.9.1 - py3.10-openai_agents-v0.7.0: python-dotenv==1.2.3 - py3.10-openai_agents-v0.7.0: referencing==0.37.0 - py3.10-openai_agents-v0.7.0: rpds-py==0.30.0 - py3.10-openai_agents-v0.7.0: cffi==2.1.1 - py3.10-openai_agents-v0.7.0: pycparser==3.0 - - py3.13-openai_agents-v0.7.0: pytest-asyncio==1.4.0 - py3.13-openai_agents-v0.7.0: httpx==0.28.1 - py3.13-openai_agents-v0.7.0: httpcore==1.0.9 - py3.13-openai_agents-v0.7.0: openai==2.44.0 - py3.13-openai_agents-v0.7.0: anyio==4.14.2 - py3.13-openai_agents-v0.7.0: distro==1.9.0 - py3.13-openai_agents-v0.7.0: griffe==1.15.0 - py3.13-openai_agents-v0.7.0: idna==3.19 - py3.13-openai_agents-v0.7.0: jiter==0.16.0 - py3.13-openai_agents-v0.7.0: mcp==1.29.0 - py3.13-openai_agents-v0.7.0: pydantic==2.13.4 - py3.13-openai_agents-v0.7.0: pydantic_core==2.46.4 - py3.13-openai_agents-v0.7.0: pytest==9.1.1 - py3.13-openai_agents-v0.7.0: requests==2.34.2 - py3.13-openai_agents-v0.7.0: certifi==2026.7.22 - py3.13-openai_agents-v0.7.0: tqdm==4.70.0 - py3.13-openai_agents-v0.7.0: types-requests==2.33.0.20260712 - py3.13-openai_agents-v0.7.0: typing_extensions==4.16.0 - py3.13-openai_agents-v0.7.0: sniffio==1.3.1 - py3.13-openai_agents-v0.7.0: annotated-types==0.8.0 - py3.13-openai_agents-v0.7.0: charset-normalizer==3.5.1 - py3.13-openai_agents-v0.7.0: colorama==0.4.6 - py3.13-openai_agents-v0.7.0: h11==0.16.0 - py3.13-openai_agents-v0.7.0: httpx-sse==0.4.3 - py3.13-openai_agents-v0.7.0: iniconfig==2.3.0 - py3.13-openai_agents-v0.7.0: jsonschema==4.26.0 - py3.13-openai_agents-v0.7.0: packaging==26.3 - py3.13-openai_agents-v0.7.0: pluggy==1.6.0 - py3.13-openai_agents-v0.7.0: pydantic-settings==2.15.0 - py3.13-openai_agents-v0.7.0: Pygments==2.21.0 - py3.13-openai_agents-v0.7.0: PyJWT==2.13.0 - py3.13-openai_agents-v0.7.0: python-multipart==0.0.32 - py3.13-openai_agents-v0.7.0: sse-starlette==3.4.8 - py3.13-openai_agents-v0.7.0: starlette==1.6.0 - py3.13-openai_agents-v0.7.0: typing-inspection==0.4.4 - py3.13-openai_agents-v0.7.0: urllib3==2.7.0 - py3.13-openai_agents-v0.7.0: uvicorn==0.52.4 - py3.13-openai_agents-v0.7.0: attrs==26.1.0 - py3.13-openai_agents-v0.7.0: click==8.4.2 - py3.13-openai_agents-v0.7.0: cryptography==50.0.0 - py3.13-openai_agents-v0.7.0: jsonschema-specifications==2025.9.1 - py3.13-openai_agents-v0.7.0: python-dotenv==1.2.3 - py3.13-openai_agents-v0.7.0: referencing==0.37.0 - py3.13-openai_agents-v0.7.0: rpds-py==2026.6.3 - py3.13-openai_agents-v0.7.0: cffi==2.1.1 - py3.13-openai_agents-v0.7.0: pycparser==3.0 - - py3.14-openai_agents-v0.7.0: openai==2.44.0 - py3.14-openai_agents-v0.7.0: httpx==0.28.1 - py3.14-openai_agents-v0.7.0: anyio==4.14.2 - py3.14-openai_agents-v0.7.0: distro==1.9.0 - py3.14-openai_agents-v0.7.0: griffe==1.15.0 - py3.14-openai_agents-v0.7.0: httpcore==1.0.9 - py3.14-openai_agents-v0.7.0: jiter==0.16.0 - py3.14-openai_agents-v0.7.0: mcp==1.29.0 - py3.14-openai_agents-v0.7.0: pydantic==2.13.4 - py3.14-openai_agents-v0.7.0: pydantic_core==2.46.4 - py3.14-openai_agents-v0.7.0: requests==2.34.2 - py3.14-openai_agents-v0.7.0: charset-normalizer==3.5.1 - py3.14-openai_agents-v0.7.0: idna==3.19 - py3.14-openai_agents-v0.7.0: types-requests==2.33.0.20260712 - py3.14-openai_agents-v0.7.0: typing_extensions==4.16.0 - py3.14-openai_agents-v0.7.0: urllib3==2.7.0 - py3.14-openai_agents-v0.7.0: pytest-asyncio==1.4.0 - py3.14-openai_agents-v0.7.0: pytest==9.1.1 - py3.14-openai_agents-v0.7.0: pluggy==1.6.0 - py3.14-openai_agents-v0.7.0: annotated-types==0.8.0 - py3.14-openai_agents-v0.7.0: certifi==2026.7.22 - py3.14-openai_agents-v0.7.0: colorama==0.4.6 - py3.14-openai_agents-v0.7.0: h11==0.16.0 - py3.14-openai_agents-v0.7.0: httpx-sse==0.4.3 - py3.14-openai_agents-v0.7.0: iniconfig==2.3.0 - py3.14-openai_agents-v0.7.0: jsonschema==4.26.0 - py3.14-openai_agents-v0.7.0: attrs==26.1.0 - py3.14-openai_agents-v0.7.0: jsonschema-specifications==2025.9.1 - py3.14-openai_agents-v0.7.0: packaging==26.3 - py3.14-openai_agents-v0.7.0: pydantic-settings==2.15.0 - py3.14-openai_agents-v0.7.0: Pygments==2.21.0 - py3.14-openai_agents-v0.7.0: PyJWT==2.13.0 - py3.14-openai_agents-v0.7.0: cryptography==50.0.0 - py3.14-openai_agents-v0.7.0: cffi==2.1.1 - py3.14-openai_agents-v0.7.0: python-dotenv==1.2.3 - py3.14-openai_agents-v0.7.0: python-multipart==0.0.32 - py3.14-openai_agents-v0.7.0: referencing==0.37.0 - py3.14-openai_agents-v0.7.0: rpds-py==2026.6.3 - py3.14-openai_agents-v0.7.0: sse-starlette==3.4.8 - py3.14-openai_agents-v0.7.0: starlette==1.6.0 - py3.14-openai_agents-v0.7.0: tqdm==4.70.0 - py3.14-openai_agents-v0.7.0: typing-inspection==0.4.4 - py3.14-openai_agents-v0.7.0: uvicorn==0.52.4 - py3.14-openai_agents-v0.7.0: click==8.4.2 - py3.14-openai_agents-v0.7.0: pycparser==3.0 - py3.14-openai_agents-v0.7.0: sniffio==1.3.1 - - py3.14t-openai_agents-v0.7.0: openai==2.44.0 - py3.14t-openai_agents-v0.7.0: httpx==0.28.1 - py3.14t-openai_agents-v0.7.0: anyio==4.14.2 - py3.14t-openai_agents-v0.7.0: distro==1.9.0 - py3.14t-openai_agents-v0.7.0: griffe==1.15.0 - py3.14t-openai_agents-v0.7.0: httpcore==1.0.9 - py3.14t-openai_agents-v0.7.0: jiter==0.16.0 - py3.14t-openai_agents-v0.7.0: mcp==1.29.0 - py3.14t-openai_agents-v0.7.0: pydantic==2.13.4 - py3.14t-openai_agents-v0.7.0: pydantic_core==2.46.4 - py3.14t-openai_agents-v0.7.0: requests==2.34.2 - py3.14t-openai_agents-v0.7.0: charset-normalizer==3.5.1 - py3.14t-openai_agents-v0.7.0: idna==3.19 - py3.14t-openai_agents-v0.7.0: types-requests==2.33.0.20260712 - py3.14t-openai_agents-v0.7.0: typing_extensions==4.16.0 - py3.14t-openai_agents-v0.7.0: urllib3==2.7.0 - py3.14t-openai_agents-v0.7.0: pytest-asyncio==1.4.0 - py3.14t-openai_agents-v0.7.0: pytest==9.1.1 - py3.14t-openai_agents-v0.7.0: pluggy==1.6.0 - py3.14t-openai_agents-v0.7.0: annotated-types==0.8.0 - py3.14t-openai_agents-v0.7.0: certifi==2026.7.22 - py3.14t-openai_agents-v0.7.0: colorama==0.4.6 - py3.14t-openai_agents-v0.7.0: h11==0.16.0 - py3.14t-openai_agents-v0.7.0: httpx-sse==0.4.3 - py3.14t-openai_agents-v0.7.0: iniconfig==2.3.0 - py3.14t-openai_agents-v0.7.0: jsonschema==4.26.0 - py3.14t-openai_agents-v0.7.0: attrs==26.1.0 - py3.14t-openai_agents-v0.7.0: jsonschema-specifications==2025.9.1 - py3.14t-openai_agents-v0.7.0: packaging==26.3 - py3.14t-openai_agents-v0.7.0: pydantic-settings==2.15.0 - py3.14t-openai_agents-v0.7.0: Pygments==2.21.0 - py3.14t-openai_agents-v0.7.0: PyJWT==2.13.0 - py3.14t-openai_agents-v0.7.0: cryptography==50.0.0 - py3.14t-openai_agents-v0.7.0: cffi==2.1.1 - py3.14t-openai_agents-v0.7.0: python-dotenv==1.2.3 - py3.14t-openai_agents-v0.7.0: python-multipart==0.0.32 - py3.14t-openai_agents-v0.7.0: referencing==0.37.0 - py3.14t-openai_agents-v0.7.0: rpds-py==2026.6.3 - py3.14t-openai_agents-v0.7.0: sse-starlette==3.4.8 - py3.14t-openai_agents-v0.7.0: starlette==1.6.0 - py3.14t-openai_agents-v0.7.0: tqdm==4.70.0 - py3.14t-openai_agents-v0.7.0: typing-inspection==0.4.4 - py3.14t-openai_agents-v0.7.0: uvicorn==0.52.4 - py3.14t-openai_agents-v0.7.0: click==8.4.2 - py3.14t-openai_agents-v0.7.0: pycparser==3.0 - py3.14t-openai_agents-v0.7.0: sniffio==1.3.1 + openai_agents-v0.10.5: openai-agents==0.10.5 + + py3.10-openai_agents-v0.10.5: pytest-asyncio==1.4.0 + py3.10-openai_agents-v0.10.5: httpx==0.28.1 + py3.10-openai_agents-v0.10.5: httpcore==1.0.9 + py3.10-openai_agents-v0.10.5: openai==2.44.0 + py3.10-openai_agents-v0.10.5: anyio==4.15.1 + py3.10-openai_agents-v0.10.5: backports.asyncio.runner==1.2.0 + py3.10-openai_agents-v0.10.5: distro==1.9.0 + py3.10-openai_agents-v0.10.5: griffe==1.15.0 + py3.10-openai_agents-v0.10.5: idna==3.19 + py3.10-openai_agents-v0.10.5: jiter==0.17.0 + py3.10-openai_agents-v0.10.5: mcp==1.30.0 + py3.10-openai_agents-v0.10.5: pydantic==2.13.5 + py3.10-openai_agents-v0.10.5: pydantic_core==2.46.5 + py3.10-openai_agents-v0.10.5: pytest==9.1.1 + py3.10-openai_agents-v0.10.5: requests==2.34.2 + py3.10-openai_agents-v0.10.5: certifi==2026.7.22 + py3.10-openai_agents-v0.10.5: tqdm==4.70.1 + py3.10-openai_agents-v0.10.5: types-requests==2.33.0.20260906 + py3.10-openai_agents-v0.10.5: typing_extensions==4.16.0 + py3.10-openai_agents-v0.10.5: sniffio==1.3.1 + py3.10-openai_agents-v0.10.5: annotated-types==0.8.0 + py3.10-openai_agents-v0.10.5: charset-normalizer==3.5.1 + py3.10-openai_agents-v0.10.5: colorama==0.4.6 + py3.10-openai_agents-v0.10.5: exceptiongroup==1.3.1 + py3.10-openai_agents-v0.10.5: h11==0.16.0 + py3.10-openai_agents-v0.10.5: httpx-sse==0.4.3 + py3.10-openai_agents-v0.10.5: iniconfig==2.3.0 + py3.10-openai_agents-v0.10.5: jsonschema==4.26.0 + py3.10-openai_agents-v0.10.5: packaging==26.3 + py3.10-openai_agents-v0.10.5: pluggy==1.6.0 + py3.10-openai_agents-v0.10.5: pydantic-settings==2.15.0 + py3.10-openai_agents-v0.10.5: Pygments==2.21.0 + py3.10-openai_agents-v0.10.5: PyJWT==2.14.0 + py3.10-openai_agents-v0.10.5: python-multipart==0.0.32 + py3.10-openai_agents-v0.10.5: sse-starlette==3.4.11 + py3.10-openai_agents-v0.10.5: starlette==1.6.0 + py3.10-openai_agents-v0.10.5: tomli==2.4.1 + py3.10-openai_agents-v0.10.5: typing-inspection==0.4.4 + py3.10-openai_agents-v0.10.5: urllib3==2.7.0 + py3.10-openai_agents-v0.10.5: uvicorn==0.52.4 + py3.10-openai_agents-v0.10.5: attrs==26.1.0 + py3.10-openai_agents-v0.10.5: click==8.5.0 + py3.10-openai_agents-v0.10.5: cryptography==50.0.1 + py3.10-openai_agents-v0.10.5: jsonschema-specifications==2025.9.1 + py3.10-openai_agents-v0.10.5: python-dotenv==1.2.3 + py3.10-openai_agents-v0.10.5: referencing==0.37.0 + py3.10-openai_agents-v0.10.5: rpds-py==0.30.0 + py3.10-openai_agents-v0.10.5: cffi==2.1.1 + py3.10-openai_agents-v0.10.5: pycparser==3.0 + + py3.13-openai_agents-v0.10.5: pytest-asyncio==1.4.0 + py3.13-openai_agents-v0.10.5: httpx==0.28.1 + py3.13-openai_agents-v0.10.5: httpcore==1.0.9 + py3.13-openai_agents-v0.10.5: openai==2.44.0 + py3.13-openai_agents-v0.10.5: anyio==4.15.1 + py3.13-openai_agents-v0.10.5: distro==1.9.0 + py3.13-openai_agents-v0.10.5: griffe==1.15.0 + py3.13-openai_agents-v0.10.5: idna==3.19 + py3.13-openai_agents-v0.10.5: jiter==0.17.0 + py3.13-openai_agents-v0.10.5: mcp==1.30.0 + py3.13-openai_agents-v0.10.5: pydantic==2.13.5 + py3.13-openai_agents-v0.10.5: pydantic_core==2.46.5 + py3.13-openai_agents-v0.10.5: pytest==9.1.1 + py3.13-openai_agents-v0.10.5: requests==2.34.2 + py3.13-openai_agents-v0.10.5: certifi==2026.7.22 + py3.13-openai_agents-v0.10.5: tqdm==4.70.1 + py3.13-openai_agents-v0.10.5: types-requests==2.33.0.20260906 + py3.13-openai_agents-v0.10.5: typing_extensions==4.16.0 + py3.13-openai_agents-v0.10.5: sniffio==1.3.1 + py3.13-openai_agents-v0.10.5: annotated-types==0.8.0 + py3.13-openai_agents-v0.10.5: charset-normalizer==3.5.1 + py3.13-openai_agents-v0.10.5: colorama==0.4.6 + py3.13-openai_agents-v0.10.5: h11==0.16.0 + py3.13-openai_agents-v0.10.5: httpx-sse==0.4.3 + py3.13-openai_agents-v0.10.5: iniconfig==2.3.0 + py3.13-openai_agents-v0.10.5: jsonschema==4.26.0 + py3.13-openai_agents-v0.10.5: packaging==26.3 + py3.13-openai_agents-v0.10.5: pluggy==1.6.0 + py3.13-openai_agents-v0.10.5: pydantic-settings==2.15.0 + py3.13-openai_agents-v0.10.5: Pygments==2.21.0 + py3.13-openai_agents-v0.10.5: PyJWT==2.14.0 + py3.13-openai_agents-v0.10.5: python-multipart==0.0.32 + py3.13-openai_agents-v0.10.5: sse-starlette==3.4.11 + py3.13-openai_agents-v0.10.5: starlette==1.6.0 + py3.13-openai_agents-v0.10.5: typing-inspection==0.4.4 + py3.13-openai_agents-v0.10.5: urllib3==2.7.0 + py3.13-openai_agents-v0.10.5: uvicorn==0.52.4 + py3.13-openai_agents-v0.10.5: attrs==26.1.0 + py3.13-openai_agents-v0.10.5: click==8.5.0 + py3.13-openai_agents-v0.10.5: cryptography==50.0.1 + py3.13-openai_agents-v0.10.5: jsonschema-specifications==2025.9.1 + py3.13-openai_agents-v0.10.5: python-dotenv==1.2.3 + py3.13-openai_agents-v0.10.5: referencing==0.37.0 + py3.13-openai_agents-v0.10.5: rpds-py==2026.6.3 + py3.13-openai_agents-v0.10.5: cffi==2.1.1 + py3.13-openai_agents-v0.10.5: pycparser==3.0 + + py3.14-openai_agents-v0.10.5: openai==2.44.0 + py3.14-openai_agents-v0.10.5: httpx==0.28.1 + py3.14-openai_agents-v0.10.5: anyio==4.15.1 + py3.14-openai_agents-v0.10.5: distro==1.9.0 + py3.14-openai_agents-v0.10.5: griffe==1.15.0 + py3.14-openai_agents-v0.10.5: httpcore==1.0.9 + py3.14-openai_agents-v0.10.5: jiter==0.17.0 + py3.14-openai_agents-v0.10.5: mcp==1.30.0 + py3.14-openai_agents-v0.10.5: pydantic==2.13.5 + py3.14-openai_agents-v0.10.5: pydantic_core==2.46.5 + py3.14-openai_agents-v0.10.5: requests==2.34.2 + py3.14-openai_agents-v0.10.5: charset-normalizer==3.5.1 + py3.14-openai_agents-v0.10.5: idna==3.19 + py3.14-openai_agents-v0.10.5: types-requests==2.33.0.20260906 + py3.14-openai_agents-v0.10.5: typing_extensions==4.16.0 + py3.14-openai_agents-v0.10.5: urllib3==2.7.0 + py3.14-openai_agents-v0.10.5: pytest-asyncio==1.4.0 + py3.14-openai_agents-v0.10.5: pytest==9.1.1 + py3.14-openai_agents-v0.10.5: pluggy==1.6.0 + py3.14-openai_agents-v0.10.5: annotated-types==0.8.0 + py3.14-openai_agents-v0.10.5: certifi==2026.7.22 + py3.14-openai_agents-v0.10.5: colorama==0.4.6 + py3.14-openai_agents-v0.10.5: h11==0.16.0 + py3.14-openai_agents-v0.10.5: httpx-sse==0.4.3 + py3.14-openai_agents-v0.10.5: iniconfig==2.3.0 + py3.14-openai_agents-v0.10.5: jsonschema==4.26.0 + py3.14-openai_agents-v0.10.5: attrs==26.1.0 + py3.14-openai_agents-v0.10.5: jsonschema-specifications==2025.9.1 + py3.14-openai_agents-v0.10.5: packaging==26.3 + py3.14-openai_agents-v0.10.5: pydantic-settings==2.15.0 + py3.14-openai_agents-v0.10.5: Pygments==2.21.0 + py3.14-openai_agents-v0.10.5: PyJWT==2.14.0 + py3.14-openai_agents-v0.10.5: cryptography==50.0.1 + py3.14-openai_agents-v0.10.5: cffi==2.1.1 + py3.14-openai_agents-v0.10.5: python-dotenv==1.2.3 + py3.14-openai_agents-v0.10.5: python-multipart==0.0.32 + py3.14-openai_agents-v0.10.5: referencing==0.37.0 + py3.14-openai_agents-v0.10.5: rpds-py==2026.6.3 + py3.14-openai_agents-v0.10.5: sse-starlette==3.4.11 + py3.14-openai_agents-v0.10.5: starlette==1.6.0 + py3.14-openai_agents-v0.10.5: tqdm==4.70.1 + py3.14-openai_agents-v0.10.5: typing-inspection==0.4.4 + py3.14-openai_agents-v0.10.5: uvicorn==0.52.4 + py3.14-openai_agents-v0.10.5: click==8.5.0 + py3.14-openai_agents-v0.10.5: pycparser==3.0 + py3.14-openai_agents-v0.10.5: sniffio==1.3.1 + + py3.14t-openai_agents-v0.10.5: openai==2.44.0 + py3.14t-openai_agents-v0.10.5: httpx==0.28.1 + py3.14t-openai_agents-v0.10.5: anyio==4.15.1 + py3.14t-openai_agents-v0.10.5: distro==1.9.0 + py3.14t-openai_agents-v0.10.5: griffe==1.15.0 + py3.14t-openai_agents-v0.10.5: httpcore==1.0.9 + py3.14t-openai_agents-v0.10.5: jiter==0.17.0 + py3.14t-openai_agents-v0.10.5: mcp==1.30.0 + py3.14t-openai_agents-v0.10.5: pydantic==2.13.5 + py3.14t-openai_agents-v0.10.5: pydantic_core==2.46.5 + py3.14t-openai_agents-v0.10.5: requests==2.34.2 + py3.14t-openai_agents-v0.10.5: charset-normalizer==3.5.1 + py3.14t-openai_agents-v0.10.5: idna==3.19 + py3.14t-openai_agents-v0.10.5: types-requests==2.33.0.20260906 + py3.14t-openai_agents-v0.10.5: typing_extensions==4.16.0 + py3.14t-openai_agents-v0.10.5: urllib3==2.7.0 + py3.14t-openai_agents-v0.10.5: pytest-asyncio==1.4.0 + py3.14t-openai_agents-v0.10.5: pytest==9.1.1 + py3.14t-openai_agents-v0.10.5: pluggy==1.6.0 + py3.14t-openai_agents-v0.10.5: annotated-types==0.8.0 + py3.14t-openai_agents-v0.10.5: certifi==2026.7.22 + py3.14t-openai_agents-v0.10.5: colorama==0.4.6 + py3.14t-openai_agents-v0.10.5: h11==0.16.0 + py3.14t-openai_agents-v0.10.5: httpx-sse==0.4.3 + py3.14t-openai_agents-v0.10.5: iniconfig==2.3.0 + py3.14t-openai_agents-v0.10.5: jsonschema==4.26.0 + py3.14t-openai_agents-v0.10.5: attrs==26.1.0 + py3.14t-openai_agents-v0.10.5: jsonschema-specifications==2025.9.1 + py3.14t-openai_agents-v0.10.5: packaging==26.3 + py3.14t-openai_agents-v0.10.5: pydantic-settings==2.15.0 + py3.14t-openai_agents-v0.10.5: Pygments==2.21.0 + py3.14t-openai_agents-v0.10.5: PyJWT==2.14.0 + py3.14t-openai_agents-v0.10.5: cryptography==50.0.1 + py3.14t-openai_agents-v0.10.5: cffi==2.1.1 + py3.14t-openai_agents-v0.10.5: python-dotenv==1.2.3 + py3.14t-openai_agents-v0.10.5: python-multipart==0.0.32 + py3.14t-openai_agents-v0.10.5: referencing==0.37.0 + py3.14t-openai_agents-v0.10.5: rpds-py==2026.6.3 + py3.14t-openai_agents-v0.10.5: sse-starlette==3.4.11 + py3.14t-openai_agents-v0.10.5: starlette==1.6.0 + py3.14t-openai_agents-v0.10.5: tqdm==4.70.1 + py3.14t-openai_agents-v0.10.5: typing-inspection==0.4.4 + py3.14t-openai_agents-v0.10.5: uvicorn==0.52.4 + py3.14t-openai_agents-v0.10.5: click==8.5.0 + py3.14t-openai_agents-v0.10.5: pycparser==3.0 + py3.14t-openai_agents-v0.10.5: sniffio==1.3.1 openai_agents-v0.14.8: openai-agents==0.14.8 @@ -2834,20 +1730,20 @@ deps = py3.10-openai_agents-v0.14.8: httpx==0.28.1 py3.10-openai_agents-v0.14.8: httpcore==1.0.9 py3.10-openai_agents-v0.14.8: openai==2.44.0 - py3.10-openai_agents-v0.14.8: anyio==4.14.2 + py3.10-openai_agents-v0.14.8: anyio==4.15.1 py3.10-openai_agents-v0.14.8: backports.asyncio.runner==1.2.0 py3.10-openai_agents-v0.14.8: distro==1.9.0 - py3.10-openai_agents-v0.14.8: griffelib==2.2.0 + py3.10-openai_agents-v0.14.8: griffelib==2.3.0 py3.10-openai_agents-v0.14.8: idna==3.19 - py3.10-openai_agents-v0.14.8: jiter==0.16.0 - py3.10-openai_agents-v0.14.8: mcp==1.29.0 - py3.10-openai_agents-v0.14.8: pydantic==2.13.4 - py3.10-openai_agents-v0.14.8: pydantic_core==2.46.4 + py3.10-openai_agents-v0.14.8: jiter==0.17.0 + py3.10-openai_agents-v0.14.8: mcp==1.30.0 + py3.10-openai_agents-v0.14.8: pydantic==2.13.5 + py3.10-openai_agents-v0.14.8: pydantic_core==2.46.5 py3.10-openai_agents-v0.14.8: pytest==9.1.1 py3.10-openai_agents-v0.14.8: requests==2.34.2 py3.10-openai_agents-v0.14.8: certifi==2026.7.22 - py3.10-openai_agents-v0.14.8: tqdm==4.70.0 - py3.10-openai_agents-v0.14.8: types-requests==2.33.0.20260712 + py3.10-openai_agents-v0.14.8: tqdm==4.70.1 + py3.10-openai_agents-v0.14.8: types-requests==2.33.0.20260906 py3.10-openai_agents-v0.14.8: typing_extensions==4.16.0 py3.10-openai_agents-v0.14.8: websockets==16.1.1 py3.10-openai_agents-v0.14.8: sniffio==1.3.1 @@ -2862,17 +1758,17 @@ deps = py3.10-openai_agents-v0.14.8: pluggy==1.6.0 py3.10-openai_agents-v0.14.8: pydantic-settings==2.15.0 py3.10-openai_agents-v0.14.8: Pygments==2.21.0 - py3.10-openai_agents-v0.14.8: PyJWT==2.13.0 + py3.10-openai_agents-v0.14.8: PyJWT==2.14.0 py3.10-openai_agents-v0.14.8: python-multipart==0.0.32 - py3.10-openai_agents-v0.14.8: sse-starlette==3.4.8 + py3.10-openai_agents-v0.14.8: sse-starlette==3.4.11 py3.10-openai_agents-v0.14.8: starlette==1.6.0 py3.10-openai_agents-v0.14.8: tomli==2.4.1 py3.10-openai_agents-v0.14.8: typing-inspection==0.4.4 py3.10-openai_agents-v0.14.8: urllib3==2.7.0 py3.10-openai_agents-v0.14.8: uvicorn==0.52.4 py3.10-openai_agents-v0.14.8: attrs==26.1.0 - py3.10-openai_agents-v0.14.8: click==8.4.2 - py3.10-openai_agents-v0.14.8: cryptography==50.0.0 + py3.10-openai_agents-v0.14.8: click==8.5.0 + py3.10-openai_agents-v0.14.8: cryptography==50.0.1 py3.10-openai_agents-v0.14.8: jsonschema-specifications==2025.9.1 py3.10-openai_agents-v0.14.8: python-dotenv==1.2.3 py3.10-openai_agents-v0.14.8: referencing==0.37.0 @@ -2884,19 +1780,19 @@ deps = py3.13-openai_agents-v0.14.8: httpx==0.28.1 py3.13-openai_agents-v0.14.8: httpcore==1.0.9 py3.13-openai_agents-v0.14.8: openai==2.44.0 - py3.13-openai_agents-v0.14.8: anyio==4.14.2 + py3.13-openai_agents-v0.14.8: anyio==4.15.1 py3.13-openai_agents-v0.14.8: distro==1.9.0 - py3.13-openai_agents-v0.14.8: griffelib==2.2.0 + py3.13-openai_agents-v0.14.8: griffelib==2.3.0 py3.13-openai_agents-v0.14.8: idna==3.19 - py3.13-openai_agents-v0.14.8: jiter==0.16.0 - py3.13-openai_agents-v0.14.8: mcp==1.29.0 - py3.13-openai_agents-v0.14.8: pydantic==2.13.4 - py3.13-openai_agents-v0.14.8: pydantic_core==2.46.4 + py3.13-openai_agents-v0.14.8: jiter==0.17.0 + py3.13-openai_agents-v0.14.8: mcp==1.30.0 + py3.13-openai_agents-v0.14.8: pydantic==2.13.5 + py3.13-openai_agents-v0.14.8: pydantic_core==2.46.5 py3.13-openai_agents-v0.14.8: pytest==9.1.1 py3.13-openai_agents-v0.14.8: requests==2.34.2 py3.13-openai_agents-v0.14.8: certifi==2026.7.22 - py3.13-openai_agents-v0.14.8: tqdm==4.70.0 - py3.13-openai_agents-v0.14.8: types-requests==2.33.0.20260712 + py3.13-openai_agents-v0.14.8: tqdm==4.70.1 + py3.13-openai_agents-v0.14.8: types-requests==2.33.0.20260906 py3.13-openai_agents-v0.14.8: typing_extensions==4.16.0 py3.13-openai_agents-v0.14.8: websockets==16.1.1 py3.13-openai_agents-v0.14.8: sniffio==1.3.1 @@ -2910,16 +1806,16 @@ deps = py3.13-openai_agents-v0.14.8: pluggy==1.6.0 py3.13-openai_agents-v0.14.8: pydantic-settings==2.15.0 py3.13-openai_agents-v0.14.8: Pygments==2.21.0 - py3.13-openai_agents-v0.14.8: PyJWT==2.13.0 + py3.13-openai_agents-v0.14.8: PyJWT==2.14.0 py3.13-openai_agents-v0.14.8: python-multipart==0.0.32 - py3.13-openai_agents-v0.14.8: sse-starlette==3.4.8 + py3.13-openai_agents-v0.14.8: sse-starlette==3.4.11 py3.13-openai_agents-v0.14.8: starlette==1.6.0 py3.13-openai_agents-v0.14.8: typing-inspection==0.4.4 py3.13-openai_agents-v0.14.8: urllib3==2.7.0 py3.13-openai_agents-v0.14.8: uvicorn==0.52.4 py3.13-openai_agents-v0.14.8: attrs==26.1.0 - py3.13-openai_agents-v0.14.8: click==8.4.2 - py3.13-openai_agents-v0.14.8: cryptography==50.0.0 + py3.13-openai_agents-v0.14.8: click==8.5.0 + py3.13-openai_agents-v0.14.8: cryptography==50.0.1 py3.13-openai_agents-v0.14.8: jsonschema-specifications==2025.9.1 py3.13-openai_agents-v0.14.8: python-dotenv==1.2.3 py3.13-openai_agents-v0.14.8: referencing==0.37.0 @@ -3021,6 +1917,195 @@ deps = py3.14t-openai_agents-v0.14.8: pycparser==3.0 py3.14t-openai_agents-v0.14.8: sniffio==1.3.1 + openai_agents-v0.18.3: openai-agents==0.18.3 + + py3.10-openai_agents-v0.18.3: pytest-asyncio==1.4.0 + py3.10-openai_agents-v0.18.3: httpx==0.28.1 + py3.10-openai_agents-v0.18.3: httpcore==1.0.9 + py3.10-openai_agents-v0.18.3: backports.asyncio.runner==1.2.0 + py3.10-openai_agents-v0.18.3: griffelib==2.3.0 + py3.10-openai_agents-v0.18.3: mcp==1.30.0 + py3.10-openai_agents-v0.18.3: anyio==4.15.1 + py3.10-openai_agents-v0.18.3: idna==3.19 + py3.10-openai_agents-v0.18.3: openai==2.54.0 + py3.10-openai_agents-v0.18.3: pydantic==2.13.5 + py3.10-openai_agents-v0.18.3: pydantic_core==2.46.5 + py3.10-openai_agents-v0.18.3: pytest==9.1.1 + py3.10-openai_agents-v0.18.3: requests==2.34.2 + py3.10-openai_agents-v0.18.3: certifi==2026.7.22 + py3.10-openai_agents-v0.18.3: typing_extensions==4.16.0 + py3.10-openai_agents-v0.18.3: websockets==16.1.1 + py3.10-openai_agents-v0.18.3: annotated-types==0.8.0 + py3.10-openai_agents-v0.18.3: charset-normalizer==3.5.1 + py3.10-openai_agents-v0.18.3: distro==1.9.0 + py3.10-openai_agents-v0.18.3: exceptiongroup==1.3.1 + py3.10-openai_agents-v0.18.3: h11==0.16.0 + py3.10-openai_agents-v0.18.3: httpx-sse==0.4.3 + py3.10-openai_agents-v0.18.3: iniconfig==2.3.0 + py3.10-openai_agents-v0.18.3: jiter==0.17.0 + py3.10-openai_agents-v0.18.3: jsonschema==4.26.0 + py3.10-openai_agents-v0.18.3: packaging==26.3 + py3.10-openai_agents-v0.18.3: pluggy==1.6.0 + py3.10-openai_agents-v0.18.3: pydantic-settings==2.15.0 + py3.10-openai_agents-v0.18.3: Pygments==2.21.0 + py3.10-openai_agents-v0.18.3: PyJWT==2.14.0 + py3.10-openai_agents-v0.18.3: python-multipart==0.0.32 + py3.10-openai_agents-v0.18.3: sse-starlette==3.4.11 + py3.10-openai_agents-v0.18.3: starlette==1.6.0 + py3.10-openai_agents-v0.18.3: tomli==2.4.1 + py3.10-openai_agents-v0.18.3: tqdm==4.70.1 + py3.10-openai_agents-v0.18.3: typing-inspection==0.4.4 + py3.10-openai_agents-v0.18.3: urllib3==2.7.0 + py3.10-openai_agents-v0.18.3: uvicorn==0.52.4 + py3.10-openai_agents-v0.18.3: sniffio==1.3.1 + py3.10-openai_agents-v0.18.3: attrs==26.1.0 + py3.10-openai_agents-v0.18.3: click==8.5.0 + py3.10-openai_agents-v0.18.3: cryptography==50.0.1 + py3.10-openai_agents-v0.18.3: jsonschema-specifications==2025.9.1 + py3.10-openai_agents-v0.18.3: python-dotenv==1.2.3 + py3.10-openai_agents-v0.18.3: referencing==0.37.0 + py3.10-openai_agents-v0.18.3: rpds-py==0.30.0 + py3.10-openai_agents-v0.18.3: cffi==2.1.1 + py3.10-openai_agents-v0.18.3: pycparser==3.0 + + py3.13-openai_agents-v0.18.3: pytest-asyncio==1.4.0 + py3.13-openai_agents-v0.18.3: httpx==0.28.1 + py3.13-openai_agents-v0.18.3: httpcore==1.0.9 + py3.13-openai_agents-v0.18.3: griffelib==2.3.0 + py3.13-openai_agents-v0.18.3: mcp==1.30.0 + py3.13-openai_agents-v0.18.3: anyio==4.15.1 + py3.13-openai_agents-v0.18.3: idna==3.19 + py3.13-openai_agents-v0.18.3: openai==2.54.0 + py3.13-openai_agents-v0.18.3: pydantic==2.13.5 + py3.13-openai_agents-v0.18.3: pydantic_core==2.46.5 + py3.13-openai_agents-v0.18.3: pytest==9.1.1 + py3.13-openai_agents-v0.18.3: requests==2.34.2 + py3.13-openai_agents-v0.18.3: certifi==2026.7.22 + py3.13-openai_agents-v0.18.3: typing_extensions==4.16.0 + py3.13-openai_agents-v0.18.3: websockets==16.1.1 + py3.13-openai_agents-v0.18.3: annotated-types==0.8.0 + py3.13-openai_agents-v0.18.3: charset-normalizer==3.5.1 + py3.13-openai_agents-v0.18.3: distro==1.9.0 + py3.13-openai_agents-v0.18.3: h11==0.16.0 + py3.13-openai_agents-v0.18.3: httpx-sse==0.4.3 + py3.13-openai_agents-v0.18.3: iniconfig==2.3.0 + py3.13-openai_agents-v0.18.3: jiter==0.17.0 + py3.13-openai_agents-v0.18.3: jsonschema==4.26.0 + py3.13-openai_agents-v0.18.3: packaging==26.3 + py3.13-openai_agents-v0.18.3: pluggy==1.6.0 + py3.13-openai_agents-v0.18.3: pydantic-settings==2.15.0 + py3.13-openai_agents-v0.18.3: Pygments==2.21.0 + py3.13-openai_agents-v0.18.3: PyJWT==2.14.0 + py3.13-openai_agents-v0.18.3: python-multipart==0.0.32 + py3.13-openai_agents-v0.18.3: sse-starlette==3.4.11 + py3.13-openai_agents-v0.18.3: starlette==1.6.0 + py3.13-openai_agents-v0.18.3: tqdm==4.70.1 + py3.13-openai_agents-v0.18.3: typing-inspection==0.4.4 + py3.13-openai_agents-v0.18.3: urllib3==2.7.0 + py3.13-openai_agents-v0.18.3: uvicorn==0.52.4 + py3.13-openai_agents-v0.18.3: sniffio==1.3.1 + py3.13-openai_agents-v0.18.3: attrs==26.1.0 + py3.13-openai_agents-v0.18.3: click==8.5.0 + py3.13-openai_agents-v0.18.3: cryptography==50.0.1 + py3.13-openai_agents-v0.18.3: jsonschema-specifications==2025.9.1 + py3.13-openai_agents-v0.18.3: python-dotenv==1.2.3 + py3.13-openai_agents-v0.18.3: referencing==0.37.0 + py3.13-openai_agents-v0.18.3: rpds-py==2026.6.3 + py3.13-openai_agents-v0.18.3: cffi==2.1.1 + py3.13-openai_agents-v0.18.3: pycparser==3.0 + + py3.14-openai_agents-v0.18.3: griffelib==2.3.0 + py3.14-openai_agents-v0.18.3: mcp==1.30.0 + py3.14-openai_agents-v0.18.3: httpx==0.28.1 + py3.14-openai_agents-v0.18.3: httpcore==1.0.9 + py3.14-openai_agents-v0.18.3: openai==2.54.0 + py3.14-openai_agents-v0.18.3: anyio==4.15.1 + py3.14-openai_agents-v0.18.3: distro==1.9.0 + py3.14-openai_agents-v0.18.3: jiter==0.17.0 + py3.14-openai_agents-v0.18.3: pydantic==2.13.5 + py3.14-openai_agents-v0.18.3: pydantic_core==2.46.5 + py3.14-openai_agents-v0.18.3: requests==2.34.2 + py3.14-openai_agents-v0.18.3: charset-normalizer==3.5.1 + py3.14-openai_agents-v0.18.3: idna==3.19 + py3.14-openai_agents-v0.18.3: typing_extensions==4.16.0 + py3.14-openai_agents-v0.18.3: urllib3==2.7.0 + py3.14-openai_agents-v0.18.3: websockets==16.1.1 + py3.14-openai_agents-v0.18.3: pytest-asyncio==1.4.0 + py3.14-openai_agents-v0.18.3: pytest==9.1.1 + py3.14-openai_agents-v0.18.3: pluggy==1.6.0 + py3.14-openai_agents-v0.18.3: annotated-types==0.8.0 + py3.14-openai_agents-v0.18.3: certifi==2026.7.22 + py3.14-openai_agents-v0.18.3: h11==0.16.0 + py3.14-openai_agents-v0.18.3: httpx-sse==0.4.3 + py3.14-openai_agents-v0.18.3: iniconfig==2.3.0 + py3.14-openai_agents-v0.18.3: jsonschema==4.26.0 + py3.14-openai_agents-v0.18.3: attrs==26.1.0 + py3.14-openai_agents-v0.18.3: jsonschema-specifications==2025.9.1 + py3.14-openai_agents-v0.18.3: packaging==26.3 + py3.14-openai_agents-v0.18.3: pydantic-settings==2.15.0 + py3.14-openai_agents-v0.18.3: Pygments==2.21.0 + py3.14-openai_agents-v0.18.3: PyJWT==2.14.0 + py3.14-openai_agents-v0.18.3: cryptography==50.0.1 + py3.14-openai_agents-v0.18.3: cffi==2.1.1 + py3.14-openai_agents-v0.18.3: python-dotenv==1.2.3 + py3.14-openai_agents-v0.18.3: python-multipart==0.0.32 + py3.14-openai_agents-v0.18.3: referencing==0.37.0 + py3.14-openai_agents-v0.18.3: rpds-py==2026.6.3 + py3.14-openai_agents-v0.18.3: sse-starlette==3.4.11 + py3.14-openai_agents-v0.18.3: starlette==1.6.0 + py3.14-openai_agents-v0.18.3: tqdm==4.70.1 + py3.14-openai_agents-v0.18.3: typing-inspection==0.4.4 + py3.14-openai_agents-v0.18.3: uvicorn==0.52.4 + py3.14-openai_agents-v0.18.3: click==8.5.0 + py3.14-openai_agents-v0.18.3: pycparser==3.0 + py3.14-openai_agents-v0.18.3: sniffio==1.3.1 + + py3.14t-openai_agents-v0.18.3: griffelib==2.3.0 + py3.14t-openai_agents-v0.18.3: mcp==1.30.0 + py3.14t-openai_agents-v0.18.3: httpx==0.28.1 + py3.14t-openai_agents-v0.18.3: httpcore==1.0.9 + py3.14t-openai_agents-v0.18.3: openai==2.54.0 + py3.14t-openai_agents-v0.18.3: anyio==4.15.1 + py3.14t-openai_agents-v0.18.3: distro==1.9.0 + py3.14t-openai_agents-v0.18.3: jiter==0.17.0 + py3.14t-openai_agents-v0.18.3: pydantic==2.13.5 + py3.14t-openai_agents-v0.18.3: pydantic_core==2.46.5 + py3.14t-openai_agents-v0.18.3: requests==2.34.2 + py3.14t-openai_agents-v0.18.3: charset-normalizer==3.5.1 + py3.14t-openai_agents-v0.18.3: idna==3.19 + py3.14t-openai_agents-v0.18.3: typing_extensions==4.16.0 + py3.14t-openai_agents-v0.18.3: urllib3==2.7.0 + py3.14t-openai_agents-v0.18.3: websockets==16.1.1 + py3.14t-openai_agents-v0.18.3: pytest-asyncio==1.4.0 + py3.14t-openai_agents-v0.18.3: pytest==9.1.1 + py3.14t-openai_agents-v0.18.3: pluggy==1.6.0 + py3.14t-openai_agents-v0.18.3: annotated-types==0.8.0 + py3.14t-openai_agents-v0.18.3: certifi==2026.7.22 + py3.14t-openai_agents-v0.18.3: h11==0.16.0 + py3.14t-openai_agents-v0.18.3: httpx-sse==0.4.3 + py3.14t-openai_agents-v0.18.3: iniconfig==2.3.0 + py3.14t-openai_agents-v0.18.3: jsonschema==4.26.0 + py3.14t-openai_agents-v0.18.3: attrs==26.1.0 + py3.14t-openai_agents-v0.18.3: jsonschema-specifications==2025.9.1 + py3.14t-openai_agents-v0.18.3: packaging==26.3 + py3.14t-openai_agents-v0.18.3: pydantic-settings==2.15.0 + py3.14t-openai_agents-v0.18.3: Pygments==2.21.0 + py3.14t-openai_agents-v0.18.3: PyJWT==2.14.0 + py3.14t-openai_agents-v0.18.3: cryptography==50.0.1 + py3.14t-openai_agents-v0.18.3: cffi==2.1.1 + py3.14t-openai_agents-v0.18.3: python-dotenv==1.2.3 + py3.14t-openai_agents-v0.18.3: python-multipart==0.0.32 + py3.14t-openai_agents-v0.18.3: referencing==0.37.0 + py3.14t-openai_agents-v0.18.3: rpds-py==2026.6.3 + py3.14t-openai_agents-v0.18.3: sse-starlette==3.4.11 + py3.14t-openai_agents-v0.18.3: starlette==1.6.0 + py3.14t-openai_agents-v0.18.3: tqdm==4.70.1 + py3.14t-openai_agents-v0.18.3: typing-inspection==0.4.4 + py3.14t-openai_agents-v0.18.3: uvicorn==0.52.4 + py3.14t-openai_agents-v0.18.3: click==8.5.0 + py3.14t-openai_agents-v0.18.3: pycparser==3.0 + py3.14t-openai_agents-v0.18.3: sniffio==1.3.1 + openai_agents-v0.22.3: openai-agents==0.22.3 py3.10-openai_agents-v0.22.3: griffelib==2.3.0 @@ -3401,340 +2486,445 @@ deps = openai_agents: pytest-asyncio openai_agents: httpx - openai_agents-v0.0.19: openai<2.45 - openai_agents-v0.7.0: openai<2.45 + openai_agents-v0.10.5: openai<2.45 openai_agents-v0.14.8: openai<2.45 - pydantic_ai-v1.0.18: pydantic-ai==1.0.18 - - py3.10-pydantic_ai-v1.0.18: pydantic-ai-slim==1.0.18 - py3.10-pydantic_ai-v1.0.18: pydantic-evals==1.0.18 - py3.10-pydantic_ai-v1.0.18: pydantic-graph==1.0.18 - py3.10-pydantic_ai-v1.0.18: temporalio==1.18.0 - py3.10-pydantic_ai-v1.0.18: nexus-rpc==1.1.0 - py3.10-pydantic_ai-v1.0.18: protobuf==6.33.6 - py3.10-pydantic_ai-v1.0.18: python-dateutil==2.9.0.post0 - py3.10-pydantic_ai-v1.0.18: typing_extensions==4.16.0 - py3.10-pydantic_ai-v1.0.18: pytest-asyncio==1.4.0 - py3.10-pydantic_ai-v1.0.18: backports.asyncio.runner==1.2.0 - py3.10-pydantic_ai-v1.0.18: pytest==9.1.1 - py3.10-pydantic_ai-v1.0.18: pluggy==1.6.0 - py3.10-pydantic_ai-v1.0.18: ag-ui-protocol==0.1.19 - py3.10-pydantic_ai-v1.0.18: anthropic==0.116.0 - py3.10-pydantic_ai-v1.0.18: anyio==4.14.1 - py3.10-pydantic_ai-v1.0.18: distro==1.9.0 - py3.10-pydantic_ai-v1.0.18: docstring_parser==0.18.0 - py3.10-pydantic_ai-v1.0.18: httpx==0.28.1 - py3.10-pydantic_ai-v1.0.18: httpcore==1.0.9 - py3.10-pydantic_ai-v1.0.18: jiter==0.16.0 - py3.10-pydantic_ai-v1.0.18: pydantic==2.13.4 - py3.10-pydantic_ai-v1.0.18: pydantic_core==2.46.4 - py3.10-pydantic_ai-v1.0.18: annotated-types==0.7.0 - py3.10-pydantic_ai-v1.0.18: argcomplete==3.7.0 - py3.10-pydantic_ai-v1.0.18: boto3==1.43.40 - py3.10-pydantic_ai-v1.0.18: botocore==1.43.40 - py3.10-pydantic_ai-v1.0.18: jmespath==1.1.0 - py3.10-pydantic_ai-v1.0.18: s3transfer==0.19.0 - py3.10-pydantic_ai-v1.0.18: urllib3==2.7.0 - py3.10-pydantic_ai-v1.0.18: cohere==7.0.5 - py3.10-pydantic_ai-v1.0.18: fastavro==1.12.2 - py3.10-pydantic_ai-v1.0.18: requests==2.34.2 - py3.10-pydantic_ai-v1.0.18: charset-normalizer==3.4.7 - py3.10-pydantic_ai-v1.0.18: idna==3.18 - py3.10-pydantic_ai-v1.0.18: tokenizers==0.23.1 - py3.10-pydantic_ai-v1.0.18: huggingface_hub==1.22.0 - py3.10-pydantic_ai-v1.0.18: click==8.4.2 - py3.10-pydantic_ai-v1.0.18: hf-xet==1.5.1 - py3.10-pydantic_ai-v1.0.18: types-requests==2.33.0.20260518 - py3.10-pydantic_ai-v1.0.18: certifi==2026.6.17 - py3.10-pydantic_ai-v1.0.18: exceptiongroup==1.3.1 - py3.10-pydantic_ai-v1.0.18: filelock==3.29.5 - py3.10-pydantic_ai-v1.0.18: fsspec==2026.6.0 - py3.10-pydantic_ai-v1.0.18: genai-prices==0.0.69 - py3.10-pydantic_ai-v1.0.18: google-auth==2.55.1 - py3.10-pydantic_ai-v1.0.18: cryptography==49.0.0 - py3.10-pydantic_ai-v1.0.18: cffi==2.0.0 - py3.10-pydantic_ai-v1.0.18: google-genai==2.10.0 - py3.10-pydantic_ai-v1.0.18: tenacity==9.1.4 - py3.10-pydantic_ai-v1.0.18: websockets==16.0 - py3.10-pydantic_ai-v1.0.18: griffe==2.1.0 - py3.10-pydantic_ai-v1.0.18: griffecli==2.1.0 - py3.10-pydantic_ai-v1.0.18: griffelib==2.1.0 - py3.10-pydantic_ai-v1.0.18: colorama==0.4.6 - py3.10-pydantic_ai-v1.0.18: groq==1.5.0 - py3.10-pydantic_ai-v1.0.18: h11==0.16.0 - py3.10-pydantic_ai-v1.0.18: httpx2==2.5.0 - py3.10-pydantic_ai-v1.0.18: httpcore2==2.5.0 - py3.10-pydantic_ai-v1.0.18: iniconfig==2.3.0 - py3.10-pydantic_ai-v1.0.18: logfire==4.37.0 - py3.10-pydantic_ai-v1.0.18: opentelemetry-exporter-otlp-proto-http==1.42.1 - py3.10-pydantic_ai-v1.0.18: opentelemetry-exporter-otlp-proto-common==1.42.1 - py3.10-pydantic_ai-v1.0.18: opentelemetry-proto==1.42.1 - py3.10-pydantic_ai-v1.0.18: googleapis-common-protos==1.75.0 - py3.10-pydantic_ai-v1.0.18: opentelemetry-sdk==1.42.1 - py3.10-pydantic_ai-v1.0.18: opentelemetry-api==1.42.1 - py3.10-pydantic_ai-v1.0.18: opentelemetry-semantic-conventions==0.63b1 - py3.10-pydantic_ai-v1.0.18: executing==2.2.1 - py3.10-pydantic_ai-v1.0.18: logfire-api==4.37.0 - py3.10-pydantic_ai-v1.0.18: mcp==1.28.1 - py3.10-pydantic_ai-v1.0.18: httpx-sse==0.4.3 - py3.10-pydantic_ai-v1.0.18: jsonschema==4.26.0 - py3.10-pydantic_ai-v1.0.18: attrs==26.1.0 - py3.10-pydantic_ai-v1.0.18: jsonschema-specifications==2025.9.1 - py3.10-pydantic_ai-v1.0.18: mistralai==1.12.4 - py3.10-pydantic_ai-v1.0.18: invoke==2.2.1 - py3.10-pydantic_ai-v1.0.18: PyYAML==6.0.3 - py3.10-pydantic_ai-v1.0.18: eval_type_backport==0.4.0 - py3.10-pydantic_ai-v1.0.18: openai==2.44.0 - py3.10-pydantic_ai-v1.0.18: opentelemetry-instrumentation==0.63b1 - py3.10-pydantic_ai-v1.0.18: wrapt==2.2.2 - py3.10-pydantic_ai-v1.0.18: opentelemetry-instrumentation-httpx==0.63b1 - py3.10-pydantic_ai-v1.0.18: opentelemetry-util-http==0.63b1 - py3.10-pydantic_ai-v1.0.18: packaging==26.2 - py3.10-pydantic_ai-v1.0.18: prompt_toolkit==3.0.52 - py3.10-pydantic_ai-v1.0.18: pyasn1_modules==0.4.2 - py3.10-pydantic_ai-v1.0.18: pyasn1==0.6.3 - py3.10-pydantic_ai-v1.0.18: pydantic-settings==2.14.2 - py3.10-pydantic_ai-v1.0.18: Pygments==2.20.0 - py3.10-pydantic_ai-v1.0.18: PyJWT==2.13.0 - py3.10-pydantic_ai-v1.0.18: pyperclip==1.11.0 - py3.10-pydantic_ai-v1.0.18: python-dotenv==1.2.2 - py3.10-pydantic_ai-v1.0.18: python-multipart==0.0.32 - py3.10-pydantic_ai-v1.0.18: referencing==0.37.0 - py3.10-pydantic_ai-v1.0.18: rich==15.0.0 - py3.10-pydantic_ai-v1.0.18: markdown-it-py==4.2.0 - py3.10-pydantic_ai-v1.0.18: mdurl==0.1.2 - py3.10-pydantic_ai-v1.0.18: rpds-py==0.30.0 - py3.10-pydantic_ai-v1.0.18: six==1.17.0 - py3.10-pydantic_ai-v1.0.18: sse-starlette==3.4.5 - py3.10-pydantic_ai-v1.0.18: starlette==1.3.1 - py3.10-pydantic_ai-v1.0.18: tomli==2.4.1 - py3.10-pydantic_ai-v1.0.18: tqdm==4.68.3 - py3.10-pydantic_ai-v1.0.18: truststore==0.10.4 - py3.10-pydantic_ai-v1.0.18: types-protobuf==7.34.1.20260518 - py3.10-pydantic_ai-v1.0.18: typing-inspection==0.4.2 - py3.10-pydantic_ai-v1.0.18: uvicorn==0.50.1 - py3.10-pydantic_ai-v1.0.18: pycparser==3.0 - py3.10-pydantic_ai-v1.0.18: sniffio==1.3.1 - py3.10-pydantic_ai-v1.0.18: wcwidth==0.8.2 - - py3.12-pydantic_ai-v1.0.18: pydantic-ai-slim==1.0.18 - py3.12-pydantic_ai-v1.0.18: pydantic-evals==1.0.18 - py3.12-pydantic_ai-v1.0.18: pydantic-graph==1.0.18 - py3.12-pydantic_ai-v1.0.18: temporalio==1.18.0 - py3.12-pydantic_ai-v1.0.18: nexus-rpc==1.1.0 - py3.12-pydantic_ai-v1.0.18: protobuf==6.33.6 - py3.12-pydantic_ai-v1.0.18: typing_extensions==4.16.0 - py3.12-pydantic_ai-v1.0.18: pytest-asyncio==1.4.0 - py3.12-pydantic_ai-v1.0.18: pytest==9.1.1 - py3.12-pydantic_ai-v1.0.18: pluggy==1.6.0 - py3.12-pydantic_ai-v1.0.18: ag-ui-protocol==0.1.19 - py3.12-pydantic_ai-v1.0.18: anthropic==0.116.0 - py3.12-pydantic_ai-v1.0.18: anyio==4.14.1 - py3.12-pydantic_ai-v1.0.18: distro==1.9.0 - py3.12-pydantic_ai-v1.0.18: docstring_parser==0.18.0 - py3.12-pydantic_ai-v1.0.18: httpx==0.28.1 - py3.12-pydantic_ai-v1.0.18: httpcore==1.0.9 - py3.12-pydantic_ai-v1.0.18: jiter==0.16.0 - py3.12-pydantic_ai-v1.0.18: pydantic==2.13.4 - py3.12-pydantic_ai-v1.0.18: pydantic_core==2.46.4 - py3.12-pydantic_ai-v1.0.18: annotated-types==0.7.0 - py3.12-pydantic_ai-v1.0.18: argcomplete==3.7.0 - py3.12-pydantic_ai-v1.0.18: boto3==1.43.40 - py3.12-pydantic_ai-v1.0.18: botocore==1.43.40 - py3.12-pydantic_ai-v1.0.18: jmespath==1.1.0 - py3.12-pydantic_ai-v1.0.18: python-dateutil==2.9.0.post0 - py3.12-pydantic_ai-v1.0.18: s3transfer==0.19.0 - py3.12-pydantic_ai-v1.0.18: urllib3==2.7.0 - py3.12-pydantic_ai-v1.0.18: cohere==7.0.5 - py3.12-pydantic_ai-v1.0.18: fastavro==1.12.2 - py3.12-pydantic_ai-v1.0.18: requests==2.34.2 - py3.12-pydantic_ai-v1.0.18: charset-normalizer==3.4.7 - py3.12-pydantic_ai-v1.0.18: idna==3.18 - py3.12-pydantic_ai-v1.0.18: tokenizers==0.23.1 - py3.12-pydantic_ai-v1.0.18: huggingface_hub==1.22.0 - py3.12-pydantic_ai-v1.0.18: click==8.4.2 - py3.12-pydantic_ai-v1.0.18: hf-xet==1.5.1 - py3.12-pydantic_ai-v1.0.18: types-requests==2.33.0.20260518 - py3.12-pydantic_ai-v1.0.18: certifi==2026.6.17 - py3.12-pydantic_ai-v1.0.18: filelock==3.29.5 - py3.12-pydantic_ai-v1.0.18: fsspec==2026.6.0 - py3.12-pydantic_ai-v1.0.18: genai-prices==0.0.69 - py3.12-pydantic_ai-v1.0.18: google-auth==2.55.1 - py3.12-pydantic_ai-v1.0.18: cryptography==49.0.0 - py3.12-pydantic_ai-v1.0.18: cffi==2.0.0 - py3.12-pydantic_ai-v1.0.18: google-genai==2.10.0 - py3.12-pydantic_ai-v1.0.18: tenacity==9.1.4 - py3.12-pydantic_ai-v1.0.18: websockets==16.0 - py3.12-pydantic_ai-v1.0.18: griffe==2.1.0 - py3.12-pydantic_ai-v1.0.18: griffecli==2.1.0 - py3.12-pydantic_ai-v1.0.18: griffelib==2.1.0 - py3.12-pydantic_ai-v1.0.18: colorama==0.4.6 - py3.12-pydantic_ai-v1.0.18: groq==1.5.0 - py3.12-pydantic_ai-v1.0.18: h11==0.16.0 - py3.12-pydantic_ai-v1.0.18: httpx2==2.5.0 - py3.12-pydantic_ai-v1.0.18: httpcore2==2.5.0 - py3.12-pydantic_ai-v1.0.18: iniconfig==2.3.0 - py3.12-pydantic_ai-v1.0.18: logfire==4.37.0 - py3.12-pydantic_ai-v1.0.18: opentelemetry-exporter-otlp-proto-http==1.42.1 - py3.12-pydantic_ai-v1.0.18: opentelemetry-exporter-otlp-proto-common==1.42.1 - py3.12-pydantic_ai-v1.0.18: opentelemetry-proto==1.42.1 - py3.12-pydantic_ai-v1.0.18: googleapis-common-protos==1.75.0 - py3.12-pydantic_ai-v1.0.18: opentelemetry-sdk==1.42.1 - py3.12-pydantic_ai-v1.0.18: opentelemetry-api==1.42.1 - py3.12-pydantic_ai-v1.0.18: opentelemetry-semantic-conventions==0.63b1 - py3.12-pydantic_ai-v1.0.18: executing==2.2.1 - py3.12-pydantic_ai-v1.0.18: logfire-api==4.37.0 - py3.12-pydantic_ai-v1.0.18: mcp==1.28.1 - py3.12-pydantic_ai-v1.0.18: httpx-sse==0.4.3 - py3.12-pydantic_ai-v1.0.18: jsonschema==4.26.0 - py3.12-pydantic_ai-v1.0.18: attrs==26.1.0 - py3.12-pydantic_ai-v1.0.18: jsonschema-specifications==2025.9.1 - py3.12-pydantic_ai-v1.0.18: mistralai==1.12.4 - py3.12-pydantic_ai-v1.0.18: invoke==2.2.1 - py3.12-pydantic_ai-v1.0.18: PyYAML==6.0.3 - py3.12-pydantic_ai-v1.0.18: eval_type_backport==0.4.0 - py3.12-pydantic_ai-v1.0.18: openai==2.44.0 - py3.12-pydantic_ai-v1.0.18: opentelemetry-instrumentation==0.63b1 - py3.12-pydantic_ai-v1.0.18: wrapt==2.2.2 - py3.12-pydantic_ai-v1.0.18: opentelemetry-instrumentation-httpx==0.63b1 - py3.12-pydantic_ai-v1.0.18: opentelemetry-util-http==0.63b1 - py3.12-pydantic_ai-v1.0.18: packaging==26.2 - py3.12-pydantic_ai-v1.0.18: prompt_toolkit==3.0.52 - py3.12-pydantic_ai-v1.0.18: pyasn1_modules==0.4.2 - py3.12-pydantic_ai-v1.0.18: pyasn1==0.6.3 - py3.12-pydantic_ai-v1.0.18: pydantic-settings==2.14.2 - py3.12-pydantic_ai-v1.0.18: Pygments==2.20.0 - py3.12-pydantic_ai-v1.0.18: PyJWT==2.13.0 - py3.12-pydantic_ai-v1.0.18: pyperclip==1.11.0 - py3.12-pydantic_ai-v1.0.18: python-dotenv==1.2.2 - py3.12-pydantic_ai-v1.0.18: python-multipart==0.0.32 - py3.12-pydantic_ai-v1.0.18: referencing==0.37.0 - py3.12-pydantic_ai-v1.0.18: rich==15.0.0 - py3.12-pydantic_ai-v1.0.18: markdown-it-py==4.2.0 - py3.12-pydantic_ai-v1.0.18: mdurl==0.1.2 - py3.12-pydantic_ai-v1.0.18: rpds-py==2026.6.3 - py3.12-pydantic_ai-v1.0.18: six==1.17.0 - py3.12-pydantic_ai-v1.0.18: sse-starlette==3.4.5 - py3.12-pydantic_ai-v1.0.18: starlette==1.3.1 - py3.12-pydantic_ai-v1.0.18: tqdm==4.68.3 - py3.12-pydantic_ai-v1.0.18: truststore==0.10.4 - py3.12-pydantic_ai-v1.0.18: types-protobuf==7.34.1.20260518 - py3.12-pydantic_ai-v1.0.18: typing-inspection==0.4.2 - py3.12-pydantic_ai-v1.0.18: uvicorn==0.50.1 - py3.12-pydantic_ai-v1.0.18: pycparser==3.0 - py3.12-pydantic_ai-v1.0.18: sniffio==1.3.1 - py3.12-pydantic_ai-v1.0.18: wcwidth==0.8.2 - - py3.13-pydantic_ai-v1.0.18: pydantic-ai-slim==1.0.18 - py3.13-pydantic_ai-v1.0.18: pydantic-evals==1.0.18 - py3.13-pydantic_ai-v1.0.18: pydantic-graph==1.0.18 - py3.13-pydantic_ai-v1.0.18: temporalio==1.18.0 - py3.13-pydantic_ai-v1.0.18: nexus-rpc==1.1.0 - py3.13-pydantic_ai-v1.0.18: pytest-asyncio==1.4.0 - py3.13-pydantic_ai-v1.0.18: pytest==9.1.1 - py3.13-pydantic_ai-v1.0.18: ag-ui-protocol==0.1.19 - py3.13-pydantic_ai-v1.0.18: anthropic==0.116.0 - py3.13-pydantic_ai-v1.0.18: argcomplete==3.7.0 - py3.13-pydantic_ai-v1.0.18: boto3==1.43.40 - py3.13-pydantic_ai-v1.0.18: cohere==7.0.5 - py3.13-pydantic_ai-v1.0.18: genai-prices==0.0.69 - py3.13-pydantic_ai-v1.0.18: google-auth==2.55.1 - py3.13-pydantic_ai-v1.0.18: google-genai==2.10.0 - py3.13-pydantic_ai-v1.0.18: griffe==2.1.0 - py3.13-pydantic_ai-v1.0.18: griffecli==2.1.0 - py3.13-pydantic_ai-v1.0.18: griffelib==2.1.0 - py3.13-pydantic_ai-v1.0.18: groq==1.5.0 - py3.13-pydantic_ai-v1.0.18: httpx==0.28.1 - py3.13-pydantic_ai-v1.0.18: httpcore==1.0.9 - py3.13-pydantic_ai-v1.0.18: huggingface_hub==1.22.0 - py3.13-pydantic_ai-v1.0.18: iniconfig==2.3.0 - py3.13-pydantic_ai-v1.0.18: logfire==4.37.0 - py3.13-pydantic_ai-v1.0.18: mcp==1.28.1 - py3.13-pydantic_ai-v1.0.18: mistralai==2.5.1 - py3.13-pydantic_ai-v1.0.18: opentelemetry-instrumentation==0.60b1 - py3.13-pydantic_ai-v1.0.18: opentelemetry-semantic-conventions==0.60b1 - py3.13-pydantic_ai-v1.0.18: opentelemetry-api==1.39.1 - py3.13-pydantic_ai-v1.0.18: opentelemetry-instrumentation-httpx==0.60b1 - py3.13-pydantic_ai-v1.0.18: opentelemetry-util-http==0.60b1 - py3.13-pydantic_ai-v1.0.18: openai==2.44.0 - py3.13-pydantic_ai-v1.0.18: packaging==26.2 - py3.13-pydantic_ai-v1.0.18: pluggy==1.6.0 - py3.13-pydantic_ai-v1.0.18: prompt_toolkit==3.0.52 - py3.13-pydantic_ai-v1.0.18: pydantic==2.13.4 - py3.13-pydantic_ai-v1.0.18: pydantic_core==2.46.4 - py3.13-pydantic_ai-v1.0.18: Pygments==2.20.0 - py3.13-pydantic_ai-v1.0.18: pyperclip==1.11.0 - py3.13-pydantic_ai-v1.0.18: requests==2.34.2 - py3.13-pydantic_ai-v1.0.18: rich==15.0.0 - py3.13-pydantic_ai-v1.0.18: starlette==1.3.1 - py3.13-pydantic_ai-v1.0.18: tenacity==9.1.4 - py3.13-pydantic_ai-v1.0.18: typing-inspection==0.4.2 - py3.13-pydantic_ai-v1.0.18: annotated-types==0.7.0 - py3.13-pydantic_ai-v1.0.18: anyio==4.14.1 - py3.13-pydantic_ai-v1.0.18: botocore==1.43.40 - py3.13-pydantic_ai-v1.0.18: certifi==2026.6.17 - py3.13-pydantic_ai-v1.0.18: charset-normalizer==3.4.7 - py3.13-pydantic_ai-v1.0.18: click==8.4.2 - py3.13-pydantic_ai-v1.0.18: cryptography==49.0.0 - py3.13-pydantic_ai-v1.0.18: distro==1.9.0 - py3.13-pydantic_ai-v1.0.18: docstring_parser==0.18.0 - py3.13-pydantic_ai-v1.0.18: eval_type_backport==0.4.0 - py3.13-pydantic_ai-v1.0.18: executing==2.2.1 - py3.13-pydantic_ai-v1.0.18: fastavro==1.12.2 - py3.13-pydantic_ai-v1.0.18: filelock==3.29.5 - py3.13-pydantic_ai-v1.0.18: fsspec==2026.6.0 - py3.13-pydantic_ai-v1.0.18: hf-xet==1.5.1 - py3.13-pydantic_ai-v1.0.18: httpx-sse==0.4.3 - py3.13-pydantic_ai-v1.0.18: httpx2==2.5.0 - py3.13-pydantic_ai-v1.0.18: httpcore2==2.5.0 - py3.13-pydantic_ai-v1.0.18: idna==3.18 - py3.13-pydantic_ai-v1.0.18: importlib_metadata==8.7.1 - py3.13-pydantic_ai-v1.0.18: jiter==0.16.0 - py3.13-pydantic_ai-v1.0.18: jmespath==1.1.0 - py3.13-pydantic_ai-v1.0.18: jsonpath-python==1.1.6 - py3.13-pydantic_ai-v1.0.18: jsonschema==4.26.0 - py3.13-pydantic_ai-v1.0.18: logfire-api==4.37.0 - py3.13-pydantic_ai-v1.0.18: markdown-it-py==4.2.0 - py3.13-pydantic_ai-v1.0.18: opentelemetry-exporter-otlp-proto-http==1.39.1 - py3.13-pydantic_ai-v1.0.18: opentelemetry-exporter-otlp-proto-common==1.39.1 - py3.13-pydantic_ai-v1.0.18: opentelemetry-proto==1.39.1 - py3.13-pydantic_ai-v1.0.18: opentelemetry-sdk==1.39.1 - py3.13-pydantic_ai-v1.0.18: protobuf==6.33.6 - py3.13-pydantic_ai-v1.0.18: pyasn1_modules==0.4.2 - py3.13-pydantic_ai-v1.0.18: pydantic-settings==2.14.2 - py3.13-pydantic_ai-v1.0.18: PyJWT==2.13.0 - py3.13-pydantic_ai-v1.0.18: python-dateutil==2.9.0.post0 - py3.13-pydantic_ai-v1.0.18: python-multipart==0.0.32 - py3.13-pydantic_ai-v1.0.18: PyYAML==6.0.3 - py3.13-pydantic_ai-v1.0.18: s3transfer==0.19.0 - py3.13-pydantic_ai-v1.0.18: sse-starlette==3.4.5 - py3.13-pydantic_ai-v1.0.18: tokenizers==0.23.1 - py3.13-pydantic_ai-v1.0.18: tqdm==4.68.3 - py3.13-pydantic_ai-v1.0.18: types-protobuf==7.34.1.20260518 - py3.13-pydantic_ai-v1.0.18: types-requests==2.33.0.20260518 - py3.13-pydantic_ai-v1.0.18: typing_extensions==4.16.0 - py3.13-pydantic_ai-v1.0.18: urllib3==2.7.0 - py3.13-pydantic_ai-v1.0.18: uvicorn==0.50.1 - py3.13-pydantic_ai-v1.0.18: websockets==16.0 - py3.13-pydantic_ai-v1.0.18: sniffio==1.3.1 - py3.13-pydantic_ai-v1.0.18: wcwidth==0.8.2 - py3.13-pydantic_ai-v1.0.18: attrs==26.1.0 - py3.13-pydantic_ai-v1.0.18: cffi==2.0.0 - py3.13-pydantic_ai-v1.0.18: colorama==0.4.6 - py3.13-pydantic_ai-v1.0.18: googleapis-common-protos==1.75.0 - py3.13-pydantic_ai-v1.0.18: h11==0.16.0 - py3.13-pydantic_ai-v1.0.18: jsonschema-specifications==2025.9.1 - py3.13-pydantic_ai-v1.0.18: mdurl==0.1.2 - py3.13-pydantic_ai-v1.0.18: pyasn1==0.6.3 - py3.13-pydantic_ai-v1.0.18: python-dotenv==1.2.2 - py3.13-pydantic_ai-v1.0.18: referencing==0.37.0 - py3.13-pydantic_ai-v1.0.18: rpds-py==2026.6.3 - py3.13-pydantic_ai-v1.0.18: six==1.17.0 - py3.13-pydantic_ai-v1.0.18: truststore==0.10.4 - py3.13-pydantic_ai-v1.0.18: wrapt==1.17.3 - py3.13-pydantic_ai-v1.0.18: zipp==4.1.0 - py3.13-pydantic_ai-v1.0.18: pycparser==3.0 + pydantic_ai-v1.76.0: pydantic-ai==1.76.0 + + py3.10-pydantic_ai-v1.76.0: pydantic-ai-slim==1.76.0 + py3.10-pydantic_ai-v1.76.0: pydantic-evals==1.76.0 + py3.10-pydantic_ai-v1.76.0: pydantic-graph==1.76.0 + py3.10-pydantic_ai-v1.76.0: pytest-asyncio==1.4.0 + py3.10-pydantic_ai-v1.76.0: backports.asyncio.runner==1.2.0 + py3.10-pydantic_ai-v1.76.0: pytest==9.1.1 + py3.10-pydantic_ai-v1.76.0: typing_extensions==4.16.0 + py3.10-pydantic_ai-v1.76.0: ag-ui-protocol==0.1.22 + py3.10-pydantic_ai-v1.76.0: anthropic==1.4.0 + py3.10-pydantic_ai-v1.76.0: argcomplete==3.7.2 + py3.10-pydantic_ai-v1.76.0: boto3==1.43.90 + py3.10-pydantic_ai-v1.76.0: cohere==7.1.1 + py3.10-pydantic_ai-v1.76.0: exceptiongroup==1.3.1 + py3.10-pydantic_ai-v1.76.0: mcp==1.30.0 + py3.10-pydantic_ai-v1.76.0: fastmcp==3.4.7 + py3.10-pydantic_ai-v1.76.0: fastmcp-slim==3.4.7 + py3.10-pydantic_ai-v1.76.0: genai-prices==0.1.6 + py3.10-pydantic_ai-v1.76.0: google-auth==2.57.1 + py3.10-pydantic_ai-v1.76.0: google-genai==2.22.0 + py3.10-pydantic_ai-v1.76.0: griffelib==2.3.0 + py3.10-pydantic_ai-v1.76.0: groq==1.7.0 + py3.10-pydantic_ai-v1.76.0: httpx==0.28.1 + py3.10-pydantic_ai-v1.76.0: httpcore==1.0.9 + py3.10-pydantic_ai-v1.76.0: huggingface_hub==1.30.0 + py3.10-pydantic_ai-v1.76.0: iniconfig==2.3.0 + py3.10-pydantic_ai-v1.76.0: logfire==5.0.0 + py3.10-pydantic_ai-v1.76.0: mistralai==2.9.4 + py3.10-pydantic_ai-v1.76.0: openai==3.10.0 + py3.10-pydantic_ai-v1.76.0: opentelemetry-api==1.44.0 + py3.10-pydantic_ai-v1.76.0: pluggy==1.6.0 + py3.10-pydantic_ai-v1.76.0: prompt_toolkit==3.0.53 + py3.10-pydantic_ai-v1.76.0: pydantic==2.13.5 + py3.10-pydantic_ai-v1.76.0: pydantic_core==2.46.5 + py3.10-pydantic_ai-v1.76.0: pydantic-handlebars==0.2.1 + py3.10-pydantic_ai-v1.76.0: Pygments==2.21.0 + py3.10-pydantic_ai-v1.76.0: pyperclip==1.11.0 + py3.10-pydantic_ai-v1.76.0: PyYAML==6.0.3 + py3.10-pydantic_ai-v1.76.0: requests==2.34.2 + py3.10-pydantic_ai-v1.76.0: rich==15.0.0 + py3.10-pydantic_ai-v1.76.0: starlette==1.6.0 + py3.10-pydantic_ai-v1.76.0: temporalio==1.32.0 + py3.10-pydantic_ai-v1.76.0: nexus-rpc==1.4.0 + py3.10-pydantic_ai-v1.76.0: tenacity==9.1.4 + py3.10-pydantic_ai-v1.76.0: tiktoken==0.14.0 + py3.10-pydantic_ai-v1.76.0: tomli==2.4.1 + py3.10-pydantic_ai-v1.76.0: typing-inspection==0.4.4 + py3.10-pydantic_ai-v1.76.0: xai-sdk==1.19.0 + py3.10-pydantic_ai-v1.76.0: packaging==25.0 + py3.10-pydantic_ai-v1.76.0: aiohttp==3.14.3 + py3.10-pydantic_ai-v1.76.0: annotated-types==0.8.0 + py3.10-pydantic_ai-v1.76.0: anyio==4.15.1 + py3.10-pydantic_ai-v1.76.0: botocore==1.43.90 + py3.10-pydantic_ai-v1.76.0: certifi==2026.7.22 + py3.10-pydantic_ai-v1.76.0: charset-normalizer==3.5.1 + py3.10-pydantic_ai-v1.76.0: click==8.5.0 + py3.10-pydantic_ai-v1.76.0: cryptography==50.0.1 + py3.10-pydantic_ai-v1.76.0: distro==1.9.0 + py3.10-pydantic_ai-v1.76.0: docstring_parser==0.18.0 + py3.10-pydantic_ai-v1.76.0: eval_type_backport==0.4.0 + py3.10-pydantic_ai-v1.76.0: executing==2.2.1 + py3.10-pydantic_ai-v1.76.0: fastavro==1.12.2 + py3.10-pydantic_ai-v1.76.0: filelock==3.32.6 + py3.10-pydantic_ai-v1.76.0: fsspec==2026.7.0 + py3.10-pydantic_ai-v1.76.0: googleapis-common-protos==1.75.3 + py3.10-pydantic_ai-v1.76.0: grpcio==1.83.1 + py3.10-pydantic_ai-v1.76.0: hf-xet==1.6.0 + py3.10-pydantic_ai-v1.76.0: httpx-sse==0.4.3 + py3.10-pydantic_ai-v1.76.0: httpx2==2.12.0 + py3.10-pydantic_ai-v1.76.0: httpcore2==2.12.0 + py3.10-pydantic_ai-v1.76.0: idna==3.19 + py3.10-pydantic_ai-v1.76.0: jiter==0.16.0 + py3.10-pydantic_ai-v1.76.0: jmespath==1.1.0 + py3.10-pydantic_ai-v1.76.0: jsonpath-python==1.1.6 + py3.10-pydantic_ai-v1.76.0: jsonschema==4.26.0 + py3.10-pydantic_ai-v1.76.0: logfire-api==5.0.0 + py3.10-pydantic_ai-v1.76.0: markdown-it-py==4.2.0 + py3.10-pydantic_ai-v1.76.0: opentelemetry-exporter-otlp-proto-http==1.44.0 + py3.10-pydantic_ai-v1.76.0: opentelemetry-exporter-otlp-proto-common==1.44.0 + py3.10-pydantic_ai-v1.76.0: opentelemetry-proto==1.44.0 + py3.10-pydantic_ai-v1.76.0: opentelemetry-instrumentation==0.65b0 + py3.10-pydantic_ai-v1.76.0: opentelemetry-semantic-conventions==0.65b0 + py3.10-pydantic_ai-v1.76.0: opentelemetry-instrumentation-httpx==0.65b0 + py3.10-pydantic_ai-v1.76.0: opentelemetry-util-http==0.65b0 + py3.10-pydantic_ai-v1.76.0: opentelemetry-sdk==1.44.0 + py3.10-pydantic_ai-v1.76.0: protobuf==6.33.6 + py3.10-pydantic_ai-v1.76.0: pyasn1_modules==0.4.2 + py3.10-pydantic_ai-v1.76.0: pydantic-settings==2.15.0 + py3.10-pydantic_ai-v1.76.0: PyJWT==2.13.0 + py3.10-pydantic_ai-v1.76.0: python-dateutil==2.9.0.post0 + py3.10-pydantic_ai-v1.76.0: python-multipart==0.0.32 + py3.10-pydantic_ai-v1.76.0: s3transfer==0.19.2 + py3.10-pydantic_ai-v1.76.0: sniffio==1.3.1 + py3.10-pydantic_ai-v1.76.0: sse-starlette==3.4.11 + py3.10-pydantic_ai-v1.76.0: tokenizers==0.23.2 + py3.10-pydantic_ai-v1.76.0: tqdm==4.70.0 + py3.10-pydantic_ai-v1.76.0: types-protobuf==7.35.1.20260906 + py3.10-pydantic_ai-v1.76.0: types-requests==2.33.0.20260906 + py3.10-pydantic_ai-v1.76.0: urllib3==2.7.0 + py3.10-pydantic_ai-v1.76.0: uvicorn==0.52.4 + py3.10-pydantic_ai-v1.76.0: wcwidth==0.8.3 + py3.10-pydantic_ai-v1.76.0: websockets==16.1.1 + py3.10-pydantic_ai-v1.76.0: regex==2026.9.3 + py3.10-pydantic_ai-v1.76.0: aiohappyeyeballs==2.7.1 + py3.10-pydantic_ai-v1.76.0: aiosignal==1.4.0 + py3.10-pydantic_ai-v1.76.0: async-timeout==5.0.1 + py3.10-pydantic_ai-v1.76.0: attrs==26.1.0 + py3.10-pydantic_ai-v1.76.0: Authlib==1.8.0 + py3.10-pydantic_ai-v1.76.0: cffi==2.1.1 + py3.10-pydantic_ai-v1.76.0: cyclopts==4.25.2 + py3.10-pydantic_ai-v1.76.0: frozenlist==1.8.0 + py3.10-pydantic_ai-v1.76.0: h11==0.16.0 + py3.10-pydantic_ai-v1.76.0: joserfc==1.7.5 + py3.10-pydantic_ai-v1.76.0: jsonref==1.1.0 + py3.10-pydantic_ai-v1.76.0: jsonschema-path==0.5.0 + py3.10-pydantic_ai-v1.76.0: jsonschema-specifications==2025.9.1 + py3.10-pydantic_ai-v1.76.0: mdurl==0.1.2 + py3.10-pydantic_ai-v1.76.0: multidict==6.7.1 + py3.10-pydantic_ai-v1.76.0: openapi-pydantic==0.5.1 + py3.10-pydantic_ai-v1.76.0: platformdirs==4.11.8 + py3.10-pydantic_ai-v1.76.0: propcache==0.5.2 + py3.10-pydantic_ai-v1.76.0: py-key-value-aio==0.4.5 + py3.10-pydantic_ai-v1.76.0: pyasn1==0.6.4 + py3.10-pydantic_ai-v1.76.0: python-dotenv==1.2.3 + py3.10-pydantic_ai-v1.76.0: referencing==0.37.0 + py3.10-pydantic_ai-v1.76.0: rpds-py==0.30.0 + py3.10-pydantic_ai-v1.76.0: six==1.17.0 + py3.10-pydantic_ai-v1.76.0: truststore==0.10.4 + py3.10-pydantic_ai-v1.76.0: uncalled-for==0.4.0 + py3.10-pydantic_ai-v1.76.0: watchfiles==1.2.0 + py3.10-pydantic_ai-v1.76.0: wrapt==2.4.0 + py3.10-pydantic_ai-v1.76.0: yarl==1.24.5 + py3.10-pydantic_ai-v1.76.0: aiofile==3.9.0 + py3.10-pydantic_ai-v1.76.0: beartype==0.22.9 + py3.10-pydantic_ai-v1.76.0: cachetools==7.1.8 + py3.10-pydantic_ai-v1.76.0: email-validator==2.3.0 + py3.10-pydantic_ai-v1.76.0: keyring==25.7.0 + py3.10-pydantic_ai-v1.76.0: pathable==0.6.0 + py3.10-pydantic_ai-v1.76.0: rich-rst==2.1.0 + py3.10-pydantic_ai-v1.76.0: pycparser==3.0 + py3.10-pydantic_ai-v1.76.0: caio==0.9.25 + py3.10-pydantic_ai-v1.76.0: dnspython==2.8.0 + py3.10-pydantic_ai-v1.76.0: importlib_metadata==9.0.1 + py3.10-pydantic_ai-v1.76.0: jaraco.classes==3.4.0 + py3.10-pydantic_ai-v1.76.0: jaraco.context==6.1.2 + py3.10-pydantic_ai-v1.76.0: jaraco.functools==4.6.0 + py3.10-pydantic_ai-v1.76.0: zipp==4.1.0 + py3.10-pydantic_ai-v1.76.0: backports.tarfile==1.2.0 + py3.10-pydantic_ai-v1.76.0: more-itertools==11.1.0 + + py3.13-pydantic_ai-v1.76.0: pydantic-ai-slim==1.76.0 + py3.13-pydantic_ai-v1.76.0: pydantic-evals==1.76.0 + py3.13-pydantic_ai-v1.76.0: pydantic-graph==1.76.0 + py3.13-pydantic_ai-v1.76.0: pytest-asyncio==1.4.0 + py3.13-pydantic_ai-v1.76.0: pytest==9.1.1 + py3.13-pydantic_ai-v1.76.0: ag-ui-protocol==0.1.22 + py3.13-pydantic_ai-v1.76.0: anthropic==1.4.0 + py3.13-pydantic_ai-v1.76.0: argcomplete==3.7.2 + py3.13-pydantic_ai-v1.76.0: boto3==1.43.90 + py3.13-pydantic_ai-v1.76.0: cohere==7.1.1 + py3.13-pydantic_ai-v1.76.0: mcp==1.30.0 + py3.13-pydantic_ai-v1.76.0: fastmcp==3.4.7 + py3.13-pydantic_ai-v1.76.0: fastmcp-slim==3.4.7 + py3.13-pydantic_ai-v1.76.0: genai-prices==0.1.6 + py3.13-pydantic_ai-v1.76.0: google-auth==2.57.1 + py3.13-pydantic_ai-v1.76.0: google-genai==2.22.0 + py3.13-pydantic_ai-v1.76.0: griffelib==2.3.0 + py3.13-pydantic_ai-v1.76.0: groq==1.7.0 + py3.13-pydantic_ai-v1.76.0: httpx==0.28.1 + py3.13-pydantic_ai-v1.76.0: httpcore==1.0.9 + py3.13-pydantic_ai-v1.76.0: huggingface_hub==1.30.0 + py3.13-pydantic_ai-v1.76.0: iniconfig==2.3.0 + py3.13-pydantic_ai-v1.76.0: logfire==5.0.0 + py3.13-pydantic_ai-v1.76.0: mistralai==2.9.4 + py3.13-pydantic_ai-v1.76.0: openai==3.10.0 + py3.13-pydantic_ai-v1.76.0: opentelemetry-api==1.44.0 + py3.13-pydantic_ai-v1.76.0: pluggy==1.6.0 + py3.13-pydantic_ai-v1.76.0: prompt_toolkit==3.0.53 + py3.13-pydantic_ai-v1.76.0: pydantic==2.13.5 + py3.13-pydantic_ai-v1.76.0: pydantic_core==2.46.5 + py3.13-pydantic_ai-v1.76.0: pydantic-handlebars==0.2.1 + py3.13-pydantic_ai-v1.76.0: Pygments==2.21.0 + py3.13-pydantic_ai-v1.76.0: pyperclip==1.11.0 + py3.13-pydantic_ai-v1.76.0: PyYAML==6.0.3 + py3.13-pydantic_ai-v1.76.0: requests==2.34.2 + py3.13-pydantic_ai-v1.76.0: rich==15.0.0 + py3.13-pydantic_ai-v1.76.0: starlette==1.6.0 + py3.13-pydantic_ai-v1.76.0: temporalio==1.32.0 + py3.13-pydantic_ai-v1.76.0: nexus-rpc==1.4.0 + py3.13-pydantic_ai-v1.76.0: tenacity==9.1.4 + py3.13-pydantic_ai-v1.76.0: tiktoken==0.14.0 + py3.13-pydantic_ai-v1.76.0: typing-inspection==0.4.4 + py3.13-pydantic_ai-v1.76.0: xai-sdk==1.19.0 + py3.13-pydantic_ai-v1.76.0: packaging==25.0 + py3.13-pydantic_ai-v1.76.0: aiohttp==3.14.3 + py3.13-pydantic_ai-v1.76.0: annotated-types==0.8.0 + py3.13-pydantic_ai-v1.76.0: anyio==4.15.1 + py3.13-pydantic_ai-v1.76.0: botocore==1.43.90 + py3.13-pydantic_ai-v1.76.0: certifi==2026.7.22 + py3.13-pydantic_ai-v1.76.0: charset-normalizer==3.5.1 + py3.13-pydantic_ai-v1.76.0: click==8.5.0 + py3.13-pydantic_ai-v1.76.0: cryptography==50.0.1 + py3.13-pydantic_ai-v1.76.0: distro==1.9.0 + py3.13-pydantic_ai-v1.76.0: docstring_parser==0.18.0 + py3.13-pydantic_ai-v1.76.0: eval_type_backport==0.4.0 + py3.13-pydantic_ai-v1.76.0: executing==2.2.1 + py3.13-pydantic_ai-v1.76.0: fastavro==1.12.2 + py3.13-pydantic_ai-v1.76.0: filelock==3.32.6 + py3.13-pydantic_ai-v1.76.0: fsspec==2026.7.0 + py3.13-pydantic_ai-v1.76.0: googleapis-common-protos==1.75.3 + py3.13-pydantic_ai-v1.76.0: grpcio==1.83.1 + py3.13-pydantic_ai-v1.76.0: hf-xet==1.6.0 + py3.13-pydantic_ai-v1.76.0: httpx-sse==0.4.3 + py3.13-pydantic_ai-v1.76.0: httpx2==2.12.0 + py3.13-pydantic_ai-v1.76.0: httpcore2==2.12.0 + py3.13-pydantic_ai-v1.76.0: idna==3.19 + py3.13-pydantic_ai-v1.76.0: jiter==0.16.0 + py3.13-pydantic_ai-v1.76.0: jmespath==1.1.0 + py3.13-pydantic_ai-v1.76.0: jsonpath-python==1.1.6 + py3.13-pydantic_ai-v1.76.0: jsonschema==4.26.0 + py3.13-pydantic_ai-v1.76.0: logfire-api==5.0.0 + py3.13-pydantic_ai-v1.76.0: markdown-it-py==4.2.0 + py3.13-pydantic_ai-v1.76.0: opentelemetry-exporter-otlp-proto-http==1.44.0 + py3.13-pydantic_ai-v1.76.0: opentelemetry-exporter-otlp-proto-common==1.44.0 + py3.13-pydantic_ai-v1.76.0: opentelemetry-proto==1.44.0 + py3.13-pydantic_ai-v1.76.0: opentelemetry-instrumentation==0.65b0 + py3.13-pydantic_ai-v1.76.0: opentelemetry-semantic-conventions==0.65b0 + py3.13-pydantic_ai-v1.76.0: opentelemetry-instrumentation-httpx==0.65b0 + py3.13-pydantic_ai-v1.76.0: opentelemetry-util-http==0.65b0 + py3.13-pydantic_ai-v1.76.0: opentelemetry-sdk==1.44.0 + py3.13-pydantic_ai-v1.76.0: protobuf==6.33.6 + py3.13-pydantic_ai-v1.76.0: pyasn1_modules==0.4.2 + py3.13-pydantic_ai-v1.76.0: pydantic-settings==2.15.0 + py3.13-pydantic_ai-v1.76.0: PyJWT==2.13.0 + py3.13-pydantic_ai-v1.76.0: python-dateutil==2.9.0.post0 + py3.13-pydantic_ai-v1.76.0: python-multipart==0.0.32 + py3.13-pydantic_ai-v1.76.0: s3transfer==0.19.2 + py3.13-pydantic_ai-v1.76.0: sniffio==1.3.1 + py3.13-pydantic_ai-v1.76.0: sse-starlette==3.4.11 + py3.13-pydantic_ai-v1.76.0: tokenizers==0.23.2 + py3.13-pydantic_ai-v1.76.0: tqdm==4.70.0 + py3.13-pydantic_ai-v1.76.0: types-protobuf==7.35.1.20260906 + py3.13-pydantic_ai-v1.76.0: types-requests==2.33.0.20260906 + py3.13-pydantic_ai-v1.76.0: typing_extensions==4.16.0 + py3.13-pydantic_ai-v1.76.0: urllib3==2.7.0 + py3.13-pydantic_ai-v1.76.0: uvicorn==0.52.4 + py3.13-pydantic_ai-v1.76.0: wcwidth==0.8.3 + py3.13-pydantic_ai-v1.76.0: websockets==16.1.1 + py3.13-pydantic_ai-v1.76.0: regex==2026.9.3 + py3.13-pydantic_ai-v1.76.0: aiohappyeyeballs==2.7.1 + py3.13-pydantic_ai-v1.76.0: aiosignal==1.4.0 + py3.13-pydantic_ai-v1.76.0: attrs==26.1.0 + py3.13-pydantic_ai-v1.76.0: Authlib==1.8.0 + py3.13-pydantic_ai-v1.76.0: cffi==2.1.1 + py3.13-pydantic_ai-v1.76.0: cyclopts==4.25.2 + py3.13-pydantic_ai-v1.76.0: exceptiongroup==1.3.1 + py3.13-pydantic_ai-v1.76.0: frozenlist==1.8.0 + py3.13-pydantic_ai-v1.76.0: h11==0.16.0 + py3.13-pydantic_ai-v1.76.0: joserfc==1.7.5 + py3.13-pydantic_ai-v1.76.0: jsonref==1.1.0 + py3.13-pydantic_ai-v1.76.0: jsonschema-path==0.5.0 + py3.13-pydantic_ai-v1.76.0: jsonschema-specifications==2025.9.1 + py3.13-pydantic_ai-v1.76.0: mdurl==0.1.2 + py3.13-pydantic_ai-v1.76.0: multidict==6.7.1 + py3.13-pydantic_ai-v1.76.0: openapi-pydantic==0.5.1 + py3.13-pydantic_ai-v1.76.0: platformdirs==4.11.8 + py3.13-pydantic_ai-v1.76.0: propcache==0.5.2 + py3.13-pydantic_ai-v1.76.0: py-key-value-aio==0.4.5 + py3.13-pydantic_ai-v1.76.0: pyasn1==0.6.4 + py3.13-pydantic_ai-v1.76.0: python-dotenv==1.2.3 + py3.13-pydantic_ai-v1.76.0: referencing==0.37.0 + py3.13-pydantic_ai-v1.76.0: rpds-py==2026.6.3 + py3.13-pydantic_ai-v1.76.0: six==1.17.0 + py3.13-pydantic_ai-v1.76.0: truststore==0.10.4 + py3.13-pydantic_ai-v1.76.0: uncalled-for==0.4.0 + py3.13-pydantic_ai-v1.76.0: watchfiles==1.2.0 + py3.13-pydantic_ai-v1.76.0: wrapt==2.4.0 + py3.13-pydantic_ai-v1.76.0: yarl==1.24.5 + py3.13-pydantic_ai-v1.76.0: aiofile==3.12.3 + py3.13-pydantic_ai-v1.76.0: beartype==0.22.9 + py3.13-pydantic_ai-v1.76.0: cachetools==7.1.8 + py3.13-pydantic_ai-v1.76.0: email-validator==2.3.0 + py3.13-pydantic_ai-v1.76.0: keyring==25.7.0 + py3.13-pydantic_ai-v1.76.0: pathable==0.6.0 + py3.13-pydantic_ai-v1.76.0: rich-rst==2.1.0 + py3.13-pydantic_ai-v1.76.0: pycparser==3.0 + py3.13-pydantic_ai-v1.76.0: caio==0.12.4 + py3.13-pydantic_ai-v1.76.0: dnspython==2.8.0 + py3.13-pydantic_ai-v1.76.0: jaraco.classes==3.4.0 + py3.13-pydantic_ai-v1.76.0: jaraco.context==6.1.2 + py3.13-pydantic_ai-v1.76.0: jaraco.functools==4.6.0 + py3.13-pydantic_ai-v1.76.0: more-itertools==11.1.0 + + py3.14-pydantic_ai-v1.76.0: pydantic-ai-slim==1.76.0 + py3.14-pydantic_ai-v1.76.0: pydantic-evals==1.76.0 + py3.14-pydantic_ai-v1.76.0: pydantic-graph==1.76.0 + py3.14-pydantic_ai-v1.76.0: huggingface_hub==1.30.0 + py3.14-pydantic_ai-v1.76.0: click==8.5.0 + py3.14-pydantic_ai-v1.76.0: hf-xet==1.6.0 + py3.14-pydantic_ai-v1.76.0: httpx==0.28.1 + py3.14-pydantic_ai-v1.76.0: httpcore==1.0.9 + py3.14-pydantic_ai-v1.76.0: mcp==1.30.0 + py3.14-pydantic_ai-v1.76.0: pydantic==2.13.5 + py3.14-pydantic_ai-v1.76.0: pydantic_core==2.46.5 + py3.14-pydantic_ai-v1.76.0: pytest-asyncio==1.4.0 + py3.14-pydantic_ai-v1.76.0: pytest==9.1.1 + py3.14-pydantic_ai-v1.76.0: pluggy==1.6.0 + py3.14-pydantic_ai-v1.76.0: ag-ui-protocol==0.1.22 + py3.14-pydantic_ai-v1.76.0: annotated-types==0.8.0 + py3.14-pydantic_ai-v1.76.0: anthropic==1.4.0 + py3.14-pydantic_ai-v1.76.0: anyio==4.15.1 + py3.14-pydantic_ai-v1.76.0: docstring_parser==0.18.0 + py3.14-pydantic_ai-v1.76.0: httpx2==2.12.0 + py3.14-pydantic_ai-v1.76.0: httpcore2==2.12.0 + py3.14-pydantic_ai-v1.76.0: jiter==0.16.0 + py3.14-pydantic_ai-v1.76.0: sniffio==1.3.1 + py3.14-pydantic_ai-v1.76.0: typing_extensions==4.16.0 + py3.14-pydantic_ai-v1.76.0: argcomplete==3.7.2 + py3.14-pydantic_ai-v1.76.0: boto3==1.43.90 + py3.14-pydantic_ai-v1.76.0: botocore==1.43.90 + py3.14-pydantic_ai-v1.76.0: jmespath==1.1.0 + py3.14-pydantic_ai-v1.76.0: python-dateutil==2.9.0.post0 + py3.14-pydantic_ai-v1.76.0: s3transfer==0.19.2 + py3.14-pydantic_ai-v1.76.0: urllib3==2.7.0 + py3.14-pydantic_ai-v1.76.0: cohere==7.1.1 + py3.14-pydantic_ai-v1.76.0: fastavro==1.12.2 + py3.14-pydantic_ai-v1.76.0: requests==2.34.2 + py3.14-pydantic_ai-v1.76.0: charset-normalizer==3.5.1 + py3.14-pydantic_ai-v1.76.0: idna==3.19 + py3.14-pydantic_ai-v1.76.0: tokenizers==0.23.2 + py3.14-pydantic_ai-v1.76.0: types-requests==2.33.0.20260906 + py3.14-pydantic_ai-v1.76.0: certifi==2026.7.22 + py3.14-pydantic_ai-v1.76.0: fastmcp==3.4.7 + py3.14-pydantic_ai-v1.76.0: fastmcp-slim==3.4.7 + py3.14-pydantic_ai-v1.76.0: py-key-value-aio==0.4.5 + py3.14-pydantic_ai-v1.76.0: PyYAML==6.0.3 + py3.14-pydantic_ai-v1.76.0: aiofile==3.12.3 + py3.14-pydantic_ai-v1.76.0: caio==0.12.4 + py3.14-pydantic_ai-v1.76.0: Authlib==1.8.0 + py3.14-pydantic_ai-v1.76.0: beartype==0.22.9 + py3.14-pydantic_ai-v1.76.0: cachetools==7.1.8 + py3.14-pydantic_ai-v1.76.0: cryptography==50.0.1 + py3.14-pydantic_ai-v1.76.0: cffi==2.1.1 + py3.14-pydantic_ai-v1.76.0: cyclopts==4.25.2 + py3.14-pydantic_ai-v1.76.0: rich-rst==2.1.0 + py3.14-pydantic_ai-v1.76.0: attrs==26.1.0 + py3.14-pydantic_ai-v1.76.0: exceptiongroup==1.3.1 + py3.14-pydantic_ai-v1.76.0: filelock==3.32.6 + py3.14-pydantic_ai-v1.76.0: fsspec==2026.7.0 + py3.14-pydantic_ai-v1.76.0: genai-prices==0.1.6 + py3.14-pydantic_ai-v1.76.0: google-auth==2.57.1 + py3.14-pydantic_ai-v1.76.0: google-genai==2.22.0 + py3.14-pydantic_ai-v1.76.0: distro==1.9.0 + py3.14-pydantic_ai-v1.76.0: tenacity==9.1.4 + py3.14-pydantic_ai-v1.76.0: websockets==16.1.1 + py3.14-pydantic_ai-v1.76.0: griffelib==2.3.0 + py3.14-pydantic_ai-v1.76.0: groq==1.7.0 + py3.14-pydantic_ai-v1.76.0: h11==0.16.0 + py3.14-pydantic_ai-v1.76.0: httpx-sse==0.4.3 + py3.14-pydantic_ai-v1.76.0: iniconfig==2.3.0 + py3.14-pydantic_ai-v1.76.0: joserfc==1.7.5 + py3.14-pydantic_ai-v1.76.0: jsonref==1.1.0 + py3.14-pydantic_ai-v1.76.0: jsonschema==4.26.0 + py3.14-pydantic_ai-v1.76.0: jsonschema-path==0.5.0 + py3.14-pydantic_ai-v1.76.0: pathable==0.6.0 + py3.14-pydantic_ai-v1.76.0: referencing==0.37.0 + py3.14-pydantic_ai-v1.76.0: jsonschema-specifications==2025.9.1 + py3.14-pydantic_ai-v1.76.0: keyring==25.7.0 + py3.14-pydantic_ai-v1.76.0: logfire==5.0.0 + py3.14-pydantic_ai-v1.76.0: opentelemetry-exporter-otlp-proto-http==1.44.0 + py3.14-pydantic_ai-v1.76.0: opentelemetry-exporter-otlp-proto-common==1.44.0 + py3.14-pydantic_ai-v1.76.0: opentelemetry-proto==1.44.0 + py3.14-pydantic_ai-v1.76.0: googleapis-common-protos==1.75.3 + py3.14-pydantic_ai-v1.76.0: opentelemetry-api==1.44.0 + py3.14-pydantic_ai-v1.76.0: opentelemetry-sdk==1.44.0 + py3.14-pydantic_ai-v1.76.0: opentelemetry-semantic-conventions==0.65b0 + py3.14-pydantic_ai-v1.76.0: executing==2.2.1 + py3.14-pydantic_ai-v1.76.0: logfire-api==5.0.0 + py3.14-pydantic_ai-v1.76.0: mistralai==2.9.4 + py3.14-pydantic_ai-v1.76.0: eval_type_backport==0.4.0 + py3.14-pydantic_ai-v1.76.0: jsonpath-python==1.1.6 + py3.14-pydantic_ai-v1.76.0: openai==3.10.0 + py3.14-pydantic_ai-v1.76.0: openapi-pydantic==0.5.1 + py3.14-pydantic_ai-v1.76.0: opentelemetry-instrumentation==0.65b0 + py3.14-pydantic_ai-v1.76.0: wrapt==2.4.0 + py3.14-pydantic_ai-v1.76.0: opentelemetry-instrumentation-httpx==0.65b0 + py3.14-pydantic_ai-v1.76.0: opentelemetry-util-http==0.65b0 + py3.14-pydantic_ai-v1.76.0: platformdirs==4.11.8 + py3.14-pydantic_ai-v1.76.0: prompt_toolkit==3.0.53 + py3.14-pydantic_ai-v1.76.0: pyasn1_modules==0.4.2 + py3.14-pydantic_ai-v1.76.0: pyasn1==0.6.4 + py3.14-pydantic_ai-v1.76.0: pydantic-handlebars==0.2.1 + py3.14-pydantic_ai-v1.76.0: pydantic-settings==2.15.0 + py3.14-pydantic_ai-v1.76.0: email-validator==2.3.0 + py3.14-pydantic_ai-v1.76.0: dnspython==2.8.0 + py3.14-pydantic_ai-v1.76.0: Pygments==2.21.0 + py3.14-pydantic_ai-v1.76.0: PyJWT==2.13.0 + py3.14-pydantic_ai-v1.76.0: pyperclip==1.11.0 + py3.14-pydantic_ai-v1.76.0: python-dotenv==1.2.3 + py3.14-pydantic_ai-v1.76.0: python-multipart==0.0.32 + py3.14-pydantic_ai-v1.76.0: rich==15.0.0 + py3.14-pydantic_ai-v1.76.0: markdown-it-py==4.2.0 + py3.14-pydantic_ai-v1.76.0: mdurl==0.1.2 + py3.14-pydantic_ai-v1.76.0: rpds-py==2026.6.3 + py3.14-pydantic_ai-v1.76.0: six==1.17.0 + py3.14-pydantic_ai-v1.76.0: sse-starlette==3.4.11 + py3.14-pydantic_ai-v1.76.0: starlette==1.6.0 + py3.14-pydantic_ai-v1.76.0: temporalio==1.32.0 + py3.14-pydantic_ai-v1.76.0: nexus-rpc==1.4.0 + py3.14-pydantic_ai-v1.76.0: types-protobuf==7.35.1.20260906 + py3.14-pydantic_ai-v1.76.0: tiktoken==0.14.0 + py3.14-pydantic_ai-v1.76.0: tqdm==4.70.0 + py3.14-pydantic_ai-v1.76.0: truststore==0.10.4 + py3.14-pydantic_ai-v1.76.0: typing-inspection==0.4.4 + py3.14-pydantic_ai-v1.76.0: uncalled-for==0.4.0 + py3.14-pydantic_ai-v1.76.0: uvicorn==0.52.4 + py3.14-pydantic_ai-v1.76.0: watchfiles==1.2.0 + py3.14-pydantic_ai-v1.76.0: wcwidth==0.8.3 + py3.14-pydantic_ai-v1.76.0: xai-sdk==1.19.0 + py3.14-pydantic_ai-v1.76.0: aiohttp==3.14.3 + py3.14-pydantic_ai-v1.76.0: grpcio==1.83.1 + py3.14-pydantic_ai-v1.76.0: multidict==6.7.1 + py3.14-pydantic_ai-v1.76.0: packaging==25.0 + py3.14-pydantic_ai-v1.76.0: protobuf==6.33.6 + py3.14-pydantic_ai-v1.76.0: yarl==1.24.5 + py3.14-pydantic_ai-v1.76.0: aiohappyeyeballs==2.7.1 + py3.14-pydantic_ai-v1.76.0: aiosignal==1.4.0 + py3.14-pydantic_ai-v1.76.0: frozenlist==1.8.0 + py3.14-pydantic_ai-v1.76.0: propcache==0.5.2 + py3.14-pydantic_ai-v1.76.0: jaraco.classes==3.4.0 + py3.14-pydantic_ai-v1.76.0: jaraco.context==6.1.2 + py3.14-pydantic_ai-v1.76.0: jaraco.functools==4.6.0 + py3.14-pydantic_ai-v1.76.0: more-itertools==11.1.0 + py3.14-pydantic_ai-v1.76.0: pycparser==3.0 + py3.14-pydantic_ai-v1.76.0: regex==2026.9.3 pydantic_ai-v1.107.6: pydantic-ai==1.107.6 @@ -4188,430 +3378,422 @@ deps = py3.14-pydantic_ai-v1.107.6: pycparser==3.0 py3.14-pydantic_ai-v1.107.6: regex==2026.9.10 - pydantic_ai-v2.46.0: pydantic-ai==2.46.0 - - py3.10-pydantic_ai-v2.46.0: pydantic-ai-slim==2.46.0 - py3.10-pydantic_ai-v2.46.0: pydantic-evals==2.46.0 - py3.10-pydantic_ai-v2.46.0: pydantic-graph==2.46.0 - py3.10-pydantic_ai-v2.46.0: fastmcp-slim==4.0.5 - py3.10-pydantic_ai-v2.46.0: mcp==2.2.0 - py3.10-pydantic_ai-v2.46.0: mcp-types==2.2.0 - py3.10-pydantic_ai-v2.46.0: py-key-value-aio==0.4.6 - py3.10-pydantic_ai-v2.46.0: aiofile==3.8.8 - py3.10-pydantic_ai-v2.46.0: caio==0.9.25 - py3.10-pydantic_ai-v2.46.0: pytest-asyncio==1.4.0 - py3.10-pydantic_ai-v2.46.0: backports.asyncio.runner==1.2.0 - py3.10-pydantic_ai-v2.46.0: pytest==9.1.1 - py3.10-pydantic_ai-v2.46.0: pluggy==1.6.0 - py3.10-pydantic_ai-v2.46.0: anthropic==1.7.0 - py3.10-pydantic_ai-v2.46.0: anyio==4.15.1 - py3.10-pydantic_ai-v2.46.0: docstring_parser==0.18.0 - py3.10-pydantic_ai-v2.46.0: httpx2==2.13.0 - py3.10-pydantic_ai-v2.46.0: httpcore2==2.13.0 - py3.10-pydantic_ai-v2.46.0: jiter==0.17.0 - py3.10-pydantic_ai-v2.46.0: pydantic==2.13.5 - py3.10-pydantic_ai-v2.46.0: pydantic_core==2.46.5 - py3.10-pydantic_ai-v2.46.0: sniffio==1.3.1 - py3.10-pydantic_ai-v2.46.0: typing_extensions==4.16.0 - py3.10-pydantic_ai-v2.46.0: annotated-types==0.8.0 - py3.10-pydantic_ai-v2.46.0: argcomplete==3.7.2 - py3.10-pydantic_ai-v2.46.0: Authlib==1.8.0 - py3.10-pydantic_ai-v2.46.0: beartype==0.22.9 - py3.10-pydantic_ai-v2.46.0: cachetools==7.2.0 - py3.10-pydantic_ai-v2.46.0: cryptography==50.0.1 - py3.10-pydantic_ai-v2.46.0: cffi==2.1.1 - py3.10-pydantic_ai-v2.46.0: exceptiongroup==1.3.1 - py3.10-pydantic_ai-v2.46.0: genai-prices==0.1.7 - py3.10-pydantic_ai-v2.46.0: google-genai==2.24.0 - py3.10-pydantic_ai-v2.46.0: distro==1.9.0 - py3.10-pydantic_ai-v2.46.0: google-auth==2.58.0 - py3.10-pydantic_ai-v2.46.0: httpx==0.28.1 - py3.10-pydantic_ai-v2.46.0: httpcore==1.0.9 - py3.10-pydantic_ai-v2.46.0: requests==2.34.2 - py3.10-pydantic_ai-v2.46.0: charset-normalizer==3.5.1 - py3.10-pydantic_ai-v2.46.0: idna==3.20 - py3.10-pydantic_ai-v2.46.0: tenacity==9.1.4 - py3.10-pydantic_ai-v2.46.0: urllib3==2.8.0 - py3.10-pydantic_ai-v2.46.0: websockets==16.1.1 - py3.10-pydantic_ai-v2.46.0: certifi==2026.7.22 - py3.10-pydantic_ai-v2.46.0: griffelib==2.3.0 - py3.10-pydantic_ai-v2.46.0: h11==0.16.0 - py3.10-pydantic_ai-v2.46.0: iniconfig==2.3.0 - py3.10-pydantic_ai-v2.46.0: joserfc==1.7.5 - py3.10-pydantic_ai-v2.46.0: jsonschema==4.26.0 - py3.10-pydantic_ai-v2.46.0: attrs==26.1.0 - py3.10-pydantic_ai-v2.46.0: jsonschema-specifications==2025.9.1 - py3.10-pydantic_ai-v2.46.0: keyring==25.7.0 - py3.10-pydantic_ai-v2.46.0: importlib_metadata==9.0.1 - py3.10-pydantic_ai-v2.46.0: jeepney==0.9.0 - py3.10-pydantic_ai-v2.46.0: logfire==5.1.0 - py3.10-pydantic_ai-v2.46.0: opentelemetry-exporter-otlp-proto-http==1.44.0 - py3.10-pydantic_ai-v2.46.0: opentelemetry-exporter-otlp-proto-common==1.44.0 - py3.10-pydantic_ai-v2.46.0: opentelemetry-proto==1.44.0 - py3.10-pydantic_ai-v2.46.0: googleapis-common-protos==1.75.3 - py3.10-pydantic_ai-v2.46.0: opentelemetry-api==1.44.0 - py3.10-pydantic_ai-v2.46.0: opentelemetry-sdk==1.44.0 - py3.10-pydantic_ai-v2.46.0: opentelemetry-semantic-conventions==0.65b0 - py3.10-pydantic_ai-v2.46.0: protobuf==7.36.2 - py3.10-pydantic_ai-v2.46.0: executing==2.2.1 - py3.10-pydantic_ai-v2.46.0: logfire-api==5.1.0 - py3.10-pydantic_ai-v2.46.0: openai==3.16.2 - py3.10-pydantic_ai-v2.46.0: opentelemetry-instrumentation==0.65b0 - py3.10-pydantic_ai-v2.46.0: wrapt==2.4.1 - py3.10-pydantic_ai-v2.46.0: opentelemetry-instrumentation-httpx==0.65b0 - py3.10-pydantic_ai-v2.46.0: opentelemetry-util-http==0.65b0 - py3.10-pydantic_ai-v2.46.0: packaging==26.3 - py3.10-pydantic_ai-v2.46.0: platformdirs==4.11.11 - py3.10-pydantic_ai-v2.46.0: prompt_toolkit==3.0.53 - py3.10-pydantic_ai-v2.46.0: pyasn1_modules==0.4.2 - py3.10-pydantic_ai-v2.46.0: pyasn1==0.6.4 - py3.10-pydantic_ai-v2.46.0: pydantic-settings==2.15.0 - py3.10-pydantic_ai-v2.46.0: email-validator==2.3.0 - py3.10-pydantic_ai-v2.46.0: dnspython==2.8.0 - py3.10-pydantic_ai-v2.46.0: Pygments==2.21.0 - py3.10-pydantic_ai-v2.46.0: PyJWT==2.14.0 - py3.10-pydantic_ai-v2.46.0: pyperclip==1.11.0 - py3.10-pydantic_ai-v2.46.0: python-dotenv==1.2.3 - py3.10-pydantic_ai-v2.46.0: python-multipart==0.0.32 - py3.10-pydantic_ai-v2.46.0: PyYAML==6.0.3 - py3.10-pydantic_ai-v2.46.0: referencing==0.37.0 - py3.10-pydantic_ai-v2.46.0: rich==15.0.0 - py3.10-pydantic_ai-v2.46.0: markdown-it-py==4.2.0 - py3.10-pydantic_ai-v2.46.0: mdurl==0.1.2 - py3.10-pydantic_ai-v2.46.0: rpds-py==0.30.0 - py3.10-pydantic_ai-v2.46.0: SecretStorage==3.5.0 - py3.10-pydantic_ai-v2.46.0: sse-starlette==3.4.11 - py3.10-pydantic_ai-v2.46.0: starlette==1.6.0 - py3.10-pydantic_ai-v2.46.0: tiktoken==0.14.0 - py3.10-pydantic_ai-v2.46.0: tomli==2.4.1 - py3.10-pydantic_ai-v2.46.0: truststore==0.10.4 - py3.10-pydantic_ai-v2.46.0: typing-inspection==0.4.4 - py3.10-pydantic_ai-v2.46.0: uvicorn==0.53.0 - py3.10-pydantic_ai-v2.46.0: click==8.5.0 - py3.10-pydantic_ai-v2.46.0: wcwidth==0.8.4 - py3.10-pydantic_ai-v2.46.0: zipp==4.1.0 - py3.10-pydantic_ai-v2.46.0: jaraco.classes==3.4.0 - py3.10-pydantic_ai-v2.46.0: jaraco.context==6.1.2 - py3.10-pydantic_ai-v2.46.0: backports.tarfile==1.2.0 - py3.10-pydantic_ai-v2.46.0: jaraco.functools==4.6.0 - py3.10-pydantic_ai-v2.46.0: more-itertools==11.1.0 - py3.10-pydantic_ai-v2.46.0: pycparser==3.0 - py3.10-pydantic_ai-v2.46.0: regex==2026.9.10 - - py3.13-pydantic_ai-v2.46.0: pydantic-ai-slim==2.46.0 - py3.13-pydantic_ai-v2.46.0: pydantic-evals==2.46.0 - py3.13-pydantic_ai-v2.46.0: pydantic-graph==2.46.0 - py3.13-pydantic_ai-v2.46.0: fastmcp-slim==4.0.5 - py3.13-pydantic_ai-v2.46.0: mcp==2.2.0 - py3.13-pydantic_ai-v2.46.0: mcp-types==2.2.0 - py3.13-pydantic_ai-v2.46.0: py-key-value-aio==0.4.6 - py3.13-pydantic_ai-v2.46.0: pytest-asyncio==1.4.0 - py3.13-pydantic_ai-v2.46.0: pytest==9.1.1 - py3.13-pydantic_ai-v2.46.0: pluggy==1.6.0 - py3.13-pydantic_ai-v2.46.0: aiofile==3.12.3 - py3.13-pydantic_ai-v2.46.0: caio==0.12.4 - py3.13-pydantic_ai-v2.46.0: anthropic==1.7.0 - py3.13-pydantic_ai-v2.46.0: anyio==4.15.1 - py3.13-pydantic_ai-v2.46.0: docstring_parser==0.18.0 - py3.13-pydantic_ai-v2.46.0: httpx2==2.13.0 - py3.13-pydantic_ai-v2.46.0: httpcore2==2.13.0 - py3.13-pydantic_ai-v2.46.0: jiter==0.17.0 - py3.13-pydantic_ai-v2.46.0: pydantic==2.13.5 - py3.13-pydantic_ai-v2.46.0: pydantic_core==2.46.5 - py3.13-pydantic_ai-v2.46.0: sniffio==1.3.1 - py3.13-pydantic_ai-v2.46.0: typing_extensions==4.16.0 - py3.13-pydantic_ai-v2.46.0: annotated-types==0.8.0 - py3.13-pydantic_ai-v2.46.0: argcomplete==3.7.2 - py3.13-pydantic_ai-v2.46.0: Authlib==1.8.0 - py3.13-pydantic_ai-v2.46.0: beartype==0.22.9 - py3.13-pydantic_ai-v2.46.0: cachetools==7.2.0 - py3.13-pydantic_ai-v2.46.0: cryptography==50.0.1 - py3.13-pydantic_ai-v2.46.0: cffi==2.1.1 - py3.13-pydantic_ai-v2.46.0: exceptiongroup==1.3.1 - py3.13-pydantic_ai-v2.46.0: genai-prices==0.1.7 - py3.13-pydantic_ai-v2.46.0: google-genai==2.24.0 - py3.13-pydantic_ai-v2.46.0: distro==1.9.0 - py3.13-pydantic_ai-v2.46.0: google-auth==2.58.0 - py3.13-pydantic_ai-v2.46.0: httpx==0.28.1 - py3.13-pydantic_ai-v2.46.0: httpcore==1.0.9 - py3.13-pydantic_ai-v2.46.0: requests==2.34.2 - py3.13-pydantic_ai-v2.46.0: charset-normalizer==3.5.1 - py3.13-pydantic_ai-v2.46.0: idna==3.20 - py3.13-pydantic_ai-v2.46.0: tenacity==9.1.4 - py3.13-pydantic_ai-v2.46.0: urllib3==2.8.0 - py3.13-pydantic_ai-v2.46.0: websockets==16.1.1 - py3.13-pydantic_ai-v2.46.0: certifi==2026.7.22 - py3.13-pydantic_ai-v2.46.0: griffelib==2.3.0 - py3.13-pydantic_ai-v2.46.0: h11==0.16.0 - py3.13-pydantic_ai-v2.46.0: iniconfig==2.3.0 - py3.13-pydantic_ai-v2.46.0: joserfc==1.7.5 - py3.13-pydantic_ai-v2.46.0: jsonschema==4.26.0 - py3.13-pydantic_ai-v2.46.0: attrs==26.1.0 - py3.13-pydantic_ai-v2.46.0: jsonschema-specifications==2025.9.1 - py3.13-pydantic_ai-v2.46.0: keyring==25.7.0 - py3.13-pydantic_ai-v2.46.0: jeepney==0.9.0 - py3.13-pydantic_ai-v2.46.0: logfire==5.1.0 - py3.13-pydantic_ai-v2.46.0: opentelemetry-exporter-otlp-proto-http==1.44.0 - py3.13-pydantic_ai-v2.46.0: opentelemetry-exporter-otlp-proto-common==1.44.0 - py3.13-pydantic_ai-v2.46.0: opentelemetry-proto==1.44.0 - py3.13-pydantic_ai-v2.46.0: googleapis-common-protos==1.75.3 - py3.13-pydantic_ai-v2.46.0: opentelemetry-api==1.44.0 - py3.13-pydantic_ai-v2.46.0: opentelemetry-sdk==1.44.0 - py3.13-pydantic_ai-v2.46.0: opentelemetry-semantic-conventions==0.65b0 - py3.13-pydantic_ai-v2.46.0: protobuf==7.36.2 - py3.13-pydantic_ai-v2.46.0: executing==2.2.1 - py3.13-pydantic_ai-v2.46.0: logfire-api==5.1.0 - py3.13-pydantic_ai-v2.46.0: openai==3.16.2 - py3.13-pydantic_ai-v2.46.0: opentelemetry-instrumentation==0.65b0 - py3.13-pydantic_ai-v2.46.0: wrapt==2.4.1 - py3.13-pydantic_ai-v2.46.0: opentelemetry-instrumentation-httpx==0.65b0 - py3.13-pydantic_ai-v2.46.0: opentelemetry-util-http==0.65b0 - py3.13-pydantic_ai-v2.46.0: packaging==26.3 - py3.13-pydantic_ai-v2.46.0: platformdirs==4.11.11 - py3.13-pydantic_ai-v2.46.0: prompt_toolkit==3.0.53 - py3.13-pydantic_ai-v2.46.0: pyasn1_modules==0.4.2 - py3.13-pydantic_ai-v2.46.0: pyasn1==0.6.4 - py3.13-pydantic_ai-v2.46.0: pydantic-settings==2.15.0 - py3.13-pydantic_ai-v2.46.0: email-validator==2.3.0 - py3.13-pydantic_ai-v2.46.0: dnspython==2.8.0 - py3.13-pydantic_ai-v2.46.0: Pygments==2.21.0 - py3.13-pydantic_ai-v2.46.0: PyJWT==2.14.0 - py3.13-pydantic_ai-v2.46.0: pyperclip==1.11.0 - py3.13-pydantic_ai-v2.46.0: python-dotenv==1.2.3 - py3.13-pydantic_ai-v2.46.0: python-multipart==0.0.32 - py3.13-pydantic_ai-v2.46.0: PyYAML==6.0.3 - py3.13-pydantic_ai-v2.46.0: referencing==0.37.0 - py3.13-pydantic_ai-v2.46.0: rich==15.0.0 - py3.13-pydantic_ai-v2.46.0: markdown-it-py==4.2.0 - py3.13-pydantic_ai-v2.46.0: mdurl==0.1.2 - py3.13-pydantic_ai-v2.46.0: rpds-py==2026.6.3 - py3.13-pydantic_ai-v2.46.0: SecretStorage==3.5.0 - py3.13-pydantic_ai-v2.46.0: sse-starlette==3.4.11 - py3.13-pydantic_ai-v2.46.0: starlette==1.6.0 - py3.13-pydantic_ai-v2.46.0: tiktoken==0.14.0 - py3.13-pydantic_ai-v2.46.0: truststore==0.10.4 - py3.13-pydantic_ai-v2.46.0: typing-inspection==0.4.4 - py3.13-pydantic_ai-v2.46.0: uvicorn==0.53.0 - py3.13-pydantic_ai-v2.46.0: click==8.5.0 - py3.13-pydantic_ai-v2.46.0: wcwidth==0.8.4 - py3.13-pydantic_ai-v2.46.0: jaraco.classes==3.4.0 - py3.13-pydantic_ai-v2.46.0: jaraco.context==6.1.2 - py3.13-pydantic_ai-v2.46.0: jaraco.functools==4.6.0 - py3.13-pydantic_ai-v2.46.0: more-itertools==11.1.0 - py3.13-pydantic_ai-v2.46.0: pycparser==3.0 - py3.13-pydantic_ai-v2.46.0: regex==2026.9.10 - - py3.14-pydantic_ai-v2.46.0: pydantic-ai-slim==2.46.0 - py3.14-pydantic_ai-v2.46.0: pydantic-evals==2.46.0 - py3.14-pydantic_ai-v2.46.0: pydantic-graph==2.46.0 - py3.14-pydantic_ai-v2.46.0: fastmcp-slim==4.0.5 - py3.14-pydantic_ai-v2.46.0: mcp==2.2.0 - py3.14-pydantic_ai-v2.46.0: mcp-types==2.2.0 - py3.14-pydantic_ai-v2.46.0: py-key-value-aio==0.4.6 - py3.14-pydantic_ai-v2.46.0: pytest-asyncio==1.4.0 - py3.14-pydantic_ai-v2.46.0: pytest==9.1.1 - py3.14-pydantic_ai-v2.46.0: pluggy==1.6.0 - py3.14-pydantic_ai-v2.46.0: aiofile==3.12.3 - py3.14-pydantic_ai-v2.46.0: caio==0.12.4 - py3.14-pydantic_ai-v2.46.0: anthropic==1.7.0 - py3.14-pydantic_ai-v2.46.0: anyio==4.15.1 - py3.14-pydantic_ai-v2.46.0: docstring_parser==0.18.0 - py3.14-pydantic_ai-v2.46.0: httpx2==2.13.0 - py3.14-pydantic_ai-v2.46.0: httpcore2==2.13.0 - py3.14-pydantic_ai-v2.46.0: jiter==0.17.0 - py3.14-pydantic_ai-v2.46.0: pydantic==2.13.5 - py3.14-pydantic_ai-v2.46.0: pydantic_core==2.46.5 - py3.14-pydantic_ai-v2.46.0: sniffio==1.3.1 - py3.14-pydantic_ai-v2.46.0: typing_extensions==4.16.0 - py3.14-pydantic_ai-v2.46.0: annotated-types==0.8.0 - py3.14-pydantic_ai-v2.46.0: argcomplete==3.7.2 - py3.14-pydantic_ai-v2.46.0: Authlib==1.8.0 - py3.14-pydantic_ai-v2.46.0: beartype==0.22.9 - py3.14-pydantic_ai-v2.46.0: cachetools==7.2.0 - py3.14-pydantic_ai-v2.46.0: cryptography==50.0.1 - py3.14-pydantic_ai-v2.46.0: cffi==2.1.1 - py3.14-pydantic_ai-v2.46.0: exceptiongroup==1.3.1 - py3.14-pydantic_ai-v2.46.0: genai-prices==0.1.7 - py3.14-pydantic_ai-v2.46.0: google-genai==2.24.0 - py3.14-pydantic_ai-v2.46.0: distro==1.9.0 - py3.14-pydantic_ai-v2.46.0: google-auth==2.58.0 - py3.14-pydantic_ai-v2.46.0: httpx==0.28.1 - py3.14-pydantic_ai-v2.46.0: httpcore==1.0.9 - py3.14-pydantic_ai-v2.46.0: requests==2.34.2 - py3.14-pydantic_ai-v2.46.0: charset-normalizer==3.5.1 - py3.14-pydantic_ai-v2.46.0: idna==3.20 - py3.14-pydantic_ai-v2.46.0: tenacity==9.1.4 - py3.14-pydantic_ai-v2.46.0: urllib3==2.8.0 - py3.14-pydantic_ai-v2.46.0: websockets==16.1.1 - py3.14-pydantic_ai-v2.46.0: certifi==2026.7.22 - py3.14-pydantic_ai-v2.46.0: griffelib==2.3.0 - py3.14-pydantic_ai-v2.46.0: h11==0.16.0 - py3.14-pydantic_ai-v2.46.0: iniconfig==2.3.0 - py3.14-pydantic_ai-v2.46.0: joserfc==1.7.5 - py3.14-pydantic_ai-v2.46.0: jsonschema==4.26.0 - py3.14-pydantic_ai-v2.46.0: attrs==26.1.0 - py3.14-pydantic_ai-v2.46.0: jsonschema-specifications==2025.9.1 - py3.14-pydantic_ai-v2.46.0: keyring==25.7.0 - py3.14-pydantic_ai-v2.46.0: jeepney==0.9.0 - py3.14-pydantic_ai-v2.46.0: logfire==5.1.0 - py3.14-pydantic_ai-v2.46.0: opentelemetry-exporter-otlp-proto-http==1.44.0 - py3.14-pydantic_ai-v2.46.0: opentelemetry-exporter-otlp-proto-common==1.44.0 - py3.14-pydantic_ai-v2.46.0: opentelemetry-proto==1.44.0 - py3.14-pydantic_ai-v2.46.0: googleapis-common-protos==1.75.3 - py3.14-pydantic_ai-v2.46.0: opentelemetry-api==1.44.0 - py3.14-pydantic_ai-v2.46.0: opentelemetry-sdk==1.44.0 - py3.14-pydantic_ai-v2.46.0: opentelemetry-semantic-conventions==0.65b0 - py3.14-pydantic_ai-v2.46.0: protobuf==7.36.2 - py3.14-pydantic_ai-v2.46.0: executing==2.2.1 - py3.14-pydantic_ai-v2.46.0: logfire-api==5.1.0 - py3.14-pydantic_ai-v2.46.0: openai==3.16.2 - py3.14-pydantic_ai-v2.46.0: opentelemetry-instrumentation==0.65b0 - py3.14-pydantic_ai-v2.46.0: wrapt==2.4.1 - py3.14-pydantic_ai-v2.46.0: opentelemetry-instrumentation-httpx==0.65b0 - py3.14-pydantic_ai-v2.46.0: opentelemetry-util-http==0.65b0 - py3.14-pydantic_ai-v2.46.0: packaging==26.3 - py3.14-pydantic_ai-v2.46.0: platformdirs==4.11.11 - py3.14-pydantic_ai-v2.46.0: prompt_toolkit==3.0.53 - py3.14-pydantic_ai-v2.46.0: pyasn1_modules==0.4.2 - py3.14-pydantic_ai-v2.46.0: pyasn1==0.6.4 - py3.14-pydantic_ai-v2.46.0: pydantic-settings==2.15.0 - py3.14-pydantic_ai-v2.46.0: email-validator==2.3.0 - py3.14-pydantic_ai-v2.46.0: dnspython==2.8.0 - py3.14-pydantic_ai-v2.46.0: Pygments==2.21.0 - py3.14-pydantic_ai-v2.46.0: PyJWT==2.14.0 - py3.14-pydantic_ai-v2.46.0: pyperclip==1.11.0 - py3.14-pydantic_ai-v2.46.0: python-dotenv==1.2.3 - py3.14-pydantic_ai-v2.46.0: python-multipart==0.0.32 - py3.14-pydantic_ai-v2.46.0: PyYAML==6.0.3 - py3.14-pydantic_ai-v2.46.0: referencing==0.37.0 - py3.14-pydantic_ai-v2.46.0: rich==15.0.0 - py3.14-pydantic_ai-v2.46.0: markdown-it-py==4.2.0 - py3.14-pydantic_ai-v2.46.0: mdurl==0.1.2 - py3.14-pydantic_ai-v2.46.0: rpds-py==2026.6.3 - py3.14-pydantic_ai-v2.46.0: SecretStorage==3.5.0 - py3.14-pydantic_ai-v2.46.0: sse-starlette==3.4.11 - py3.14-pydantic_ai-v2.46.0: starlette==1.6.0 - py3.14-pydantic_ai-v2.46.0: tiktoken==0.14.0 - py3.14-pydantic_ai-v2.46.0: truststore==0.10.4 - py3.14-pydantic_ai-v2.46.0: typing-inspection==0.4.4 - py3.14-pydantic_ai-v2.46.0: uvicorn==0.53.0 - py3.14-pydantic_ai-v2.46.0: click==8.5.0 - py3.14-pydantic_ai-v2.46.0: wcwidth==0.8.4 - py3.14-pydantic_ai-v2.46.0: jaraco.classes==3.4.0 - py3.14-pydantic_ai-v2.46.0: jaraco.context==6.1.2 - py3.14-pydantic_ai-v2.46.0: jaraco.functools==4.6.0 - py3.14-pydantic_ai-v2.46.0: more-itertools==11.1.0 - py3.14-pydantic_ai-v2.46.0: pycparser==3.0 - py3.14-pydantic_ai-v2.46.0: regex==2026.9.10 - - py3.14t-pydantic_ai-v2.46.0: pydantic-ai-slim==2.46.0 - py3.14t-pydantic_ai-v2.46.0: pydantic-evals==2.46.0 - py3.14t-pydantic_ai-v2.46.0: pydantic-graph==2.46.0 - py3.14t-pydantic_ai-v2.46.0: fastmcp-slim==4.0.5 - py3.14t-pydantic_ai-v2.46.0: mcp==2.2.0 - py3.14t-pydantic_ai-v2.46.0: mcp-types==2.2.0 - py3.14t-pydantic_ai-v2.46.0: py-key-value-aio==0.4.6 - py3.14t-pydantic_ai-v2.46.0: pytest-asyncio==1.4.0 - py3.14t-pydantic_ai-v2.46.0: pytest==9.1.1 - py3.14t-pydantic_ai-v2.46.0: pluggy==1.6.0 - py3.14t-pydantic_ai-v2.46.0: aiofile==3.12.3 - py3.14t-pydantic_ai-v2.46.0: caio==0.12.4 - py3.14t-pydantic_ai-v2.46.0: anthropic==1.7.0 - py3.14t-pydantic_ai-v2.46.0: anyio==4.15.1 - py3.14t-pydantic_ai-v2.46.0: docstring_parser==0.18.0 - py3.14t-pydantic_ai-v2.46.0: httpx2==2.13.0 - py3.14t-pydantic_ai-v2.46.0: httpcore2==2.13.0 - py3.14t-pydantic_ai-v2.46.0: jiter==0.17.0 - py3.14t-pydantic_ai-v2.46.0: pydantic==2.13.5 - py3.14t-pydantic_ai-v2.46.0: pydantic_core==2.46.5 - py3.14t-pydantic_ai-v2.46.0: sniffio==1.3.1 - py3.14t-pydantic_ai-v2.46.0: typing_extensions==4.16.0 - py3.14t-pydantic_ai-v2.46.0: annotated-types==0.8.0 - py3.14t-pydantic_ai-v2.46.0: argcomplete==3.7.2 - py3.14t-pydantic_ai-v2.46.0: Authlib==1.8.0 - py3.14t-pydantic_ai-v2.46.0: beartype==0.22.9 - py3.14t-pydantic_ai-v2.46.0: cachetools==7.2.0 - py3.14t-pydantic_ai-v2.46.0: cryptography==50.0.1 - py3.14t-pydantic_ai-v2.46.0: cffi==2.1.1 - py3.14t-pydantic_ai-v2.46.0: exceptiongroup==1.3.1 - py3.14t-pydantic_ai-v2.46.0: genai-prices==0.1.7 - py3.14t-pydantic_ai-v2.46.0: google-genai==2.24.0 - py3.14t-pydantic_ai-v2.46.0: distro==1.9.0 - py3.14t-pydantic_ai-v2.46.0: google-auth==2.58.0 - py3.14t-pydantic_ai-v2.46.0: httpx==0.28.1 - py3.14t-pydantic_ai-v2.46.0: httpcore==1.0.9 - py3.14t-pydantic_ai-v2.46.0: requests==2.34.2 - py3.14t-pydantic_ai-v2.46.0: charset-normalizer==3.5.1 - py3.14t-pydantic_ai-v2.46.0: idna==3.20 - py3.14t-pydantic_ai-v2.46.0: tenacity==9.1.4 - py3.14t-pydantic_ai-v2.46.0: urllib3==2.8.0 - py3.14t-pydantic_ai-v2.46.0: websockets==16.1.1 - py3.14t-pydantic_ai-v2.46.0: certifi==2026.7.22 - py3.14t-pydantic_ai-v2.46.0: griffelib==2.3.0 - py3.14t-pydantic_ai-v2.46.0: h11==0.16.0 - py3.14t-pydantic_ai-v2.46.0: iniconfig==2.3.0 - py3.14t-pydantic_ai-v2.46.0: joserfc==1.7.5 - py3.14t-pydantic_ai-v2.46.0: jsonschema==4.26.0 - py3.14t-pydantic_ai-v2.46.0: attrs==26.1.0 - py3.14t-pydantic_ai-v2.46.0: jsonschema-specifications==2025.9.1 - py3.14t-pydantic_ai-v2.46.0: keyring==25.7.0 - py3.14t-pydantic_ai-v2.46.0: jeepney==0.9.0 - py3.14t-pydantic_ai-v2.46.0: logfire==5.1.0 - py3.14t-pydantic_ai-v2.46.0: opentelemetry-exporter-otlp-proto-http==1.44.0 - py3.14t-pydantic_ai-v2.46.0: opentelemetry-exporter-otlp-proto-common==1.44.0 - py3.14t-pydantic_ai-v2.46.0: opentelemetry-proto==1.44.0 - py3.14t-pydantic_ai-v2.46.0: googleapis-common-protos==1.75.3 - py3.14t-pydantic_ai-v2.46.0: opentelemetry-api==1.44.0 - py3.14t-pydantic_ai-v2.46.0: opentelemetry-sdk==1.44.0 - py3.14t-pydantic_ai-v2.46.0: opentelemetry-semantic-conventions==0.65b0 - py3.14t-pydantic_ai-v2.46.0: protobuf==7.36.2 - py3.14t-pydantic_ai-v2.46.0: executing==2.2.1 - py3.14t-pydantic_ai-v2.46.0: logfire-api==5.1.0 - py3.14t-pydantic_ai-v2.46.0: openai==3.16.2 - py3.14t-pydantic_ai-v2.46.0: opentelemetry-instrumentation==0.65b0 - py3.14t-pydantic_ai-v2.46.0: wrapt==2.4.1 - py3.14t-pydantic_ai-v2.46.0: opentelemetry-instrumentation-httpx==0.65b0 - py3.14t-pydantic_ai-v2.46.0: opentelemetry-util-http==0.65b0 - py3.14t-pydantic_ai-v2.46.0: packaging==26.3 - py3.14t-pydantic_ai-v2.46.0: platformdirs==4.11.11 - py3.14t-pydantic_ai-v2.46.0: prompt_toolkit==3.0.53 - py3.14t-pydantic_ai-v2.46.0: pyasn1_modules==0.4.2 - py3.14t-pydantic_ai-v2.46.0: pyasn1==0.6.4 - py3.14t-pydantic_ai-v2.46.0: pydantic-settings==2.15.0 - py3.14t-pydantic_ai-v2.46.0: email-validator==2.3.0 - py3.14t-pydantic_ai-v2.46.0: dnspython==2.8.0 - py3.14t-pydantic_ai-v2.46.0: Pygments==2.21.0 - py3.14t-pydantic_ai-v2.46.0: PyJWT==2.14.0 - py3.14t-pydantic_ai-v2.46.0: pyperclip==1.11.0 - py3.14t-pydantic_ai-v2.46.0: python-dotenv==1.2.3 - py3.14t-pydantic_ai-v2.46.0: python-multipart==0.0.32 - py3.14t-pydantic_ai-v2.46.0: PyYAML==6.0.3 - py3.14t-pydantic_ai-v2.46.0: referencing==0.37.0 - py3.14t-pydantic_ai-v2.46.0: rich==15.0.0 - py3.14t-pydantic_ai-v2.46.0: markdown-it-py==4.2.0 - py3.14t-pydantic_ai-v2.46.0: mdurl==0.1.2 - py3.14t-pydantic_ai-v2.46.0: rpds-py==2026.6.3 - py3.14t-pydantic_ai-v2.46.0: SecretStorage==3.5.0 - py3.14t-pydantic_ai-v2.46.0: sse-starlette==3.4.11 - py3.14t-pydantic_ai-v2.46.0: starlette==1.6.0 - py3.14t-pydantic_ai-v2.46.0: tiktoken==0.14.0 - py3.14t-pydantic_ai-v2.46.0: truststore==0.10.4 - py3.14t-pydantic_ai-v2.46.0: typing-inspection==0.4.4 - py3.14t-pydantic_ai-v2.46.0: uvicorn==0.53.0 - py3.14t-pydantic_ai-v2.46.0: click==8.5.0 - py3.14t-pydantic_ai-v2.46.0: wcwidth==0.8.4 - py3.14t-pydantic_ai-v2.46.0: jaraco.classes==3.4.0 - py3.14t-pydantic_ai-v2.46.0: jaraco.context==6.1.2 - py3.14t-pydantic_ai-v2.46.0: jaraco.functools==4.6.0 - py3.14t-pydantic_ai-v2.46.0: more-itertools==11.1.0 - py3.14t-pydantic_ai-v2.46.0: pycparser==3.0 - py3.14t-pydantic_ai-v2.46.0: regex==2026.9.10 - - pydantic_ai-latest: pydantic-ai==2.46.0 - - py3.10-pydantic_ai-latest: pydantic-ai-slim==2.46.0 - py3.10-pydantic_ai-latest: pydantic-evals==2.46.0 - py3.10-pydantic_ai-latest: pydantic-graph==2.46.0 + pydantic_ai-v2.47.0: pydantic-ai==2.47.0 + + py3.10-pydantic_ai-v2.47.0: pydantic-ai-slim==2.47.0 + py3.10-pydantic_ai-v2.47.0: pydantic-evals==2.47.0 + py3.10-pydantic_ai-v2.47.0: pydantic-graph==2.47.0 + py3.10-pydantic_ai-v2.47.0: fastmcp-slim==4.0.5 + py3.10-pydantic_ai-v2.47.0: mcp==2.2.0 + py3.10-pydantic_ai-v2.47.0: mcp-types==2.2.0 + py3.10-pydantic_ai-v2.47.0: py-key-value-aio==0.4.6 + py3.10-pydantic_ai-v2.47.0: aiofile==3.8.8 + py3.10-pydantic_ai-v2.47.0: caio==0.9.25 + py3.10-pydantic_ai-v2.47.0: pytest-asyncio==1.4.0 + py3.10-pydantic_ai-v2.47.0: backports.asyncio.runner==1.2.0 + py3.10-pydantic_ai-v2.47.0: pytest==9.1.1 + py3.10-pydantic_ai-v2.47.0: pluggy==1.6.0 + py3.10-pydantic_ai-v2.47.0: anthropic==1.7.0 + py3.10-pydantic_ai-v2.47.0: anyio==4.15.1 + py3.10-pydantic_ai-v2.47.0: docstring_parser==0.18.0 + py3.10-pydantic_ai-v2.47.0: httpx2==2.13.0 + py3.10-pydantic_ai-v2.47.0: httpcore2==2.13.0 + py3.10-pydantic_ai-v2.47.0: jiter==0.17.0 + py3.10-pydantic_ai-v2.47.0: pydantic==2.13.5 + py3.10-pydantic_ai-v2.47.0: pydantic_core==2.46.5 + py3.10-pydantic_ai-v2.47.0: sniffio==1.3.1 + py3.10-pydantic_ai-v2.47.0: typing_extensions==4.16.0 + py3.10-pydantic_ai-v2.47.0: annotated-types==0.8.0 + py3.10-pydantic_ai-v2.47.0: argcomplete==3.7.2 + py3.10-pydantic_ai-v2.47.0: Authlib==1.8.0 + py3.10-pydantic_ai-v2.47.0: beartype==0.22.9 + py3.10-pydantic_ai-v2.47.0: cachetools==7.2.0 + py3.10-pydantic_ai-v2.47.0: cryptography==50.0.1 + py3.10-pydantic_ai-v2.47.0: cffi==2.1.1 + py3.10-pydantic_ai-v2.47.0: exceptiongroup==1.3.1 + py3.10-pydantic_ai-v2.47.0: genai-prices==0.1.7 + py3.10-pydantic_ai-v2.47.0: google-genai==2.24.0 + py3.10-pydantic_ai-v2.47.0: distro==1.9.0 + py3.10-pydantic_ai-v2.47.0: google-auth==2.58.0 + py3.10-pydantic_ai-v2.47.0: httpx==0.28.1 + py3.10-pydantic_ai-v2.47.0: httpcore==1.0.9 + py3.10-pydantic_ai-v2.47.0: requests==2.34.2 + py3.10-pydantic_ai-v2.47.0: charset-normalizer==3.5.1 + py3.10-pydantic_ai-v2.47.0: idna==3.20 + py3.10-pydantic_ai-v2.47.0: tenacity==9.1.4 + py3.10-pydantic_ai-v2.47.0: urllib3==2.8.0 + py3.10-pydantic_ai-v2.47.0: websockets==16.1.1 + py3.10-pydantic_ai-v2.47.0: certifi==2026.7.22 + py3.10-pydantic_ai-v2.47.0: griffelib==2.3.0 + py3.10-pydantic_ai-v2.47.0: h11==0.16.0 + py3.10-pydantic_ai-v2.47.0: iniconfig==2.3.0 + py3.10-pydantic_ai-v2.47.0: joserfc==1.7.5 + py3.10-pydantic_ai-v2.47.0: jsonschema==4.26.0 + py3.10-pydantic_ai-v2.47.0: attrs==26.1.0 + py3.10-pydantic_ai-v2.47.0: jsonschema-specifications==2025.9.1 + py3.10-pydantic_ai-v2.47.0: keyring==25.7.0 + py3.10-pydantic_ai-v2.47.0: importlib_metadata==9.0.1 + py3.10-pydantic_ai-v2.47.0: logfire==5.1.0 + py3.10-pydantic_ai-v2.47.0: opentelemetry-exporter-otlp-proto-http==1.44.0 + py3.10-pydantic_ai-v2.47.0: opentelemetry-exporter-otlp-proto-common==1.44.0 + py3.10-pydantic_ai-v2.47.0: opentelemetry-proto==1.44.0 + py3.10-pydantic_ai-v2.47.0: googleapis-common-protos==1.75.3 + py3.10-pydantic_ai-v2.47.0: opentelemetry-api==1.44.0 + py3.10-pydantic_ai-v2.47.0: opentelemetry-sdk==1.44.0 + py3.10-pydantic_ai-v2.47.0: opentelemetry-semantic-conventions==0.65b0 + py3.10-pydantic_ai-v2.47.0: protobuf==7.36.2 + py3.10-pydantic_ai-v2.47.0: executing==2.2.1 + py3.10-pydantic_ai-v2.47.0: logfire-api==5.1.0 + py3.10-pydantic_ai-v2.47.0: openai==3.17.0 + py3.10-pydantic_ai-v2.47.0: opentelemetry-instrumentation==0.65b0 + py3.10-pydantic_ai-v2.47.0: wrapt==2.4.1 + py3.10-pydantic_ai-v2.47.0: opentelemetry-instrumentation-httpx==0.65b0 + py3.10-pydantic_ai-v2.47.0: opentelemetry-util-http==0.65b0 + py3.10-pydantic_ai-v2.47.0: packaging==26.3 + py3.10-pydantic_ai-v2.47.0: platformdirs==4.11.12 + py3.10-pydantic_ai-v2.47.0: prompt_toolkit==3.0.53 + py3.10-pydantic_ai-v2.47.0: pyasn1_modules==0.4.2 + py3.10-pydantic_ai-v2.47.0: pyasn1==0.6.4 + py3.10-pydantic_ai-v2.47.0: pydantic-settings==2.15.0 + py3.10-pydantic_ai-v2.47.0: email-validator==2.3.0 + py3.10-pydantic_ai-v2.47.0: dnspython==2.8.0 + py3.10-pydantic_ai-v2.47.0: Pygments==2.21.0 + py3.10-pydantic_ai-v2.47.0: PyJWT==2.14.0 + py3.10-pydantic_ai-v2.47.0: pyperclip==1.11.0 + py3.10-pydantic_ai-v2.47.0: python-dotenv==1.2.3 + py3.10-pydantic_ai-v2.47.0: python-multipart==0.0.32 + py3.10-pydantic_ai-v2.47.0: PyYAML==6.0.3 + py3.10-pydantic_ai-v2.47.0: referencing==0.37.0 + py3.10-pydantic_ai-v2.47.0: rich==15.0.0 + py3.10-pydantic_ai-v2.47.0: markdown-it-py==4.2.0 + py3.10-pydantic_ai-v2.47.0: mdurl==0.1.2 + py3.10-pydantic_ai-v2.47.0: rpds-py==0.30.0 + py3.10-pydantic_ai-v2.47.0: sse-starlette==3.4.11 + py3.10-pydantic_ai-v2.47.0: starlette==1.6.0 + py3.10-pydantic_ai-v2.47.0: tiktoken==0.14.0 + py3.10-pydantic_ai-v2.47.0: tomli==2.4.1 + py3.10-pydantic_ai-v2.47.0: truststore==0.10.4 + py3.10-pydantic_ai-v2.47.0: typing-inspection==0.4.4 + py3.10-pydantic_ai-v2.47.0: uvicorn==0.53.0 + py3.10-pydantic_ai-v2.47.0: click==8.5.0 + py3.10-pydantic_ai-v2.47.0: wcwidth==0.8.4 + py3.10-pydantic_ai-v2.47.0: zipp==4.1.0 + py3.10-pydantic_ai-v2.47.0: jaraco.classes==3.4.0 + py3.10-pydantic_ai-v2.47.0: jaraco.context==6.1.2 + py3.10-pydantic_ai-v2.47.0: backports.tarfile==1.2.0 + py3.10-pydantic_ai-v2.47.0: jaraco.functools==4.6.0 + py3.10-pydantic_ai-v2.47.0: more-itertools==11.1.0 + py3.10-pydantic_ai-v2.47.0: pycparser==3.0 + py3.10-pydantic_ai-v2.47.0: regex==2026.9.10 + + py3.13-pydantic_ai-v2.47.0: pydantic-ai-slim==2.47.0 + py3.13-pydantic_ai-v2.47.0: pydantic-evals==2.47.0 + py3.13-pydantic_ai-v2.47.0: pydantic-graph==2.47.0 + py3.13-pydantic_ai-v2.47.0: fastmcp-slim==4.0.5 + py3.13-pydantic_ai-v2.47.0: mcp==2.2.0 + py3.13-pydantic_ai-v2.47.0: mcp-types==2.2.0 + py3.13-pydantic_ai-v2.47.0: py-key-value-aio==0.4.6 + py3.13-pydantic_ai-v2.47.0: pytest-asyncio==1.4.0 + py3.13-pydantic_ai-v2.47.0: pytest==9.1.1 + py3.13-pydantic_ai-v2.47.0: pluggy==1.6.0 + py3.13-pydantic_ai-v2.47.0: aiofile==3.12.3 + py3.13-pydantic_ai-v2.47.0: caio==0.12.4 + py3.13-pydantic_ai-v2.47.0: anthropic==1.7.0 + py3.13-pydantic_ai-v2.47.0: anyio==4.15.1 + py3.13-pydantic_ai-v2.47.0: docstring_parser==0.18.0 + py3.13-pydantic_ai-v2.47.0: httpx2==2.13.0 + py3.13-pydantic_ai-v2.47.0: httpcore2==2.13.0 + py3.13-pydantic_ai-v2.47.0: jiter==0.17.0 + py3.13-pydantic_ai-v2.47.0: pydantic==2.13.5 + py3.13-pydantic_ai-v2.47.0: pydantic_core==2.46.5 + py3.13-pydantic_ai-v2.47.0: sniffio==1.3.1 + py3.13-pydantic_ai-v2.47.0: typing_extensions==4.16.0 + py3.13-pydantic_ai-v2.47.0: annotated-types==0.8.0 + py3.13-pydantic_ai-v2.47.0: argcomplete==3.7.2 + py3.13-pydantic_ai-v2.47.0: Authlib==1.8.0 + py3.13-pydantic_ai-v2.47.0: beartype==0.22.9 + py3.13-pydantic_ai-v2.47.0: cachetools==7.2.0 + py3.13-pydantic_ai-v2.47.0: cryptography==50.0.1 + py3.13-pydantic_ai-v2.47.0: cffi==2.1.1 + py3.13-pydantic_ai-v2.47.0: exceptiongroup==1.3.1 + py3.13-pydantic_ai-v2.47.0: genai-prices==0.1.7 + py3.13-pydantic_ai-v2.47.0: google-genai==2.24.0 + py3.13-pydantic_ai-v2.47.0: distro==1.9.0 + py3.13-pydantic_ai-v2.47.0: google-auth==2.58.0 + py3.13-pydantic_ai-v2.47.0: httpx==0.28.1 + py3.13-pydantic_ai-v2.47.0: httpcore==1.0.9 + py3.13-pydantic_ai-v2.47.0: requests==2.34.2 + py3.13-pydantic_ai-v2.47.0: charset-normalizer==3.5.1 + py3.13-pydantic_ai-v2.47.0: idna==3.20 + py3.13-pydantic_ai-v2.47.0: tenacity==9.1.4 + py3.13-pydantic_ai-v2.47.0: urllib3==2.8.0 + py3.13-pydantic_ai-v2.47.0: websockets==16.1.1 + py3.13-pydantic_ai-v2.47.0: certifi==2026.7.22 + py3.13-pydantic_ai-v2.47.0: griffelib==2.3.0 + py3.13-pydantic_ai-v2.47.0: h11==0.16.0 + py3.13-pydantic_ai-v2.47.0: iniconfig==2.3.0 + py3.13-pydantic_ai-v2.47.0: joserfc==1.7.5 + py3.13-pydantic_ai-v2.47.0: jsonschema==4.26.0 + py3.13-pydantic_ai-v2.47.0: attrs==26.1.0 + py3.13-pydantic_ai-v2.47.0: jsonschema-specifications==2025.9.1 + py3.13-pydantic_ai-v2.47.0: keyring==25.7.0 + py3.13-pydantic_ai-v2.47.0: logfire==5.1.0 + py3.13-pydantic_ai-v2.47.0: opentelemetry-exporter-otlp-proto-http==1.44.0 + py3.13-pydantic_ai-v2.47.0: opentelemetry-exporter-otlp-proto-common==1.44.0 + py3.13-pydantic_ai-v2.47.0: opentelemetry-proto==1.44.0 + py3.13-pydantic_ai-v2.47.0: googleapis-common-protos==1.75.3 + py3.13-pydantic_ai-v2.47.0: opentelemetry-api==1.44.0 + py3.13-pydantic_ai-v2.47.0: opentelemetry-sdk==1.44.0 + py3.13-pydantic_ai-v2.47.0: opentelemetry-semantic-conventions==0.65b0 + py3.13-pydantic_ai-v2.47.0: protobuf==7.36.2 + py3.13-pydantic_ai-v2.47.0: executing==2.2.1 + py3.13-pydantic_ai-v2.47.0: logfire-api==5.1.0 + py3.13-pydantic_ai-v2.47.0: openai==3.17.0 + py3.13-pydantic_ai-v2.47.0: opentelemetry-instrumentation==0.65b0 + py3.13-pydantic_ai-v2.47.0: wrapt==2.4.1 + py3.13-pydantic_ai-v2.47.0: opentelemetry-instrumentation-httpx==0.65b0 + py3.13-pydantic_ai-v2.47.0: opentelemetry-util-http==0.65b0 + py3.13-pydantic_ai-v2.47.0: packaging==26.3 + py3.13-pydantic_ai-v2.47.0: platformdirs==4.11.12 + py3.13-pydantic_ai-v2.47.0: prompt_toolkit==3.0.53 + py3.13-pydantic_ai-v2.47.0: pyasn1_modules==0.4.2 + py3.13-pydantic_ai-v2.47.0: pyasn1==0.6.4 + py3.13-pydantic_ai-v2.47.0: pydantic-settings==2.15.0 + py3.13-pydantic_ai-v2.47.0: email-validator==2.3.0 + py3.13-pydantic_ai-v2.47.0: dnspython==2.8.0 + py3.13-pydantic_ai-v2.47.0: Pygments==2.21.0 + py3.13-pydantic_ai-v2.47.0: PyJWT==2.14.0 + py3.13-pydantic_ai-v2.47.0: pyperclip==1.11.0 + py3.13-pydantic_ai-v2.47.0: python-dotenv==1.2.3 + py3.13-pydantic_ai-v2.47.0: python-multipart==0.0.32 + py3.13-pydantic_ai-v2.47.0: PyYAML==6.0.3 + py3.13-pydantic_ai-v2.47.0: referencing==0.37.0 + py3.13-pydantic_ai-v2.47.0: rich==15.0.0 + py3.13-pydantic_ai-v2.47.0: markdown-it-py==4.2.0 + py3.13-pydantic_ai-v2.47.0: mdurl==0.1.2 + py3.13-pydantic_ai-v2.47.0: rpds-py==2026.6.3 + py3.13-pydantic_ai-v2.47.0: sse-starlette==3.4.11 + py3.13-pydantic_ai-v2.47.0: starlette==1.6.0 + py3.13-pydantic_ai-v2.47.0: tiktoken==0.14.0 + py3.13-pydantic_ai-v2.47.0: truststore==0.10.4 + py3.13-pydantic_ai-v2.47.0: typing-inspection==0.4.4 + py3.13-pydantic_ai-v2.47.0: uvicorn==0.53.0 + py3.13-pydantic_ai-v2.47.0: click==8.5.0 + py3.13-pydantic_ai-v2.47.0: wcwidth==0.8.4 + py3.13-pydantic_ai-v2.47.0: jaraco.classes==3.4.0 + py3.13-pydantic_ai-v2.47.0: jaraco.context==6.1.2 + py3.13-pydantic_ai-v2.47.0: jaraco.functools==4.6.0 + py3.13-pydantic_ai-v2.47.0: more-itertools==11.1.0 + py3.13-pydantic_ai-v2.47.0: pycparser==3.0 + py3.13-pydantic_ai-v2.47.0: regex==2026.9.10 + + py3.14-pydantic_ai-v2.47.0: pydantic-ai-slim==2.47.0 + py3.14-pydantic_ai-v2.47.0: pydantic-evals==2.47.0 + py3.14-pydantic_ai-v2.47.0: pydantic-graph==2.47.0 + py3.14-pydantic_ai-v2.47.0: fastmcp-slim==4.0.5 + py3.14-pydantic_ai-v2.47.0: mcp==2.2.0 + py3.14-pydantic_ai-v2.47.0: mcp-types==2.2.0 + py3.14-pydantic_ai-v2.47.0: py-key-value-aio==0.4.6 + py3.14-pydantic_ai-v2.47.0: pytest-asyncio==1.4.0 + py3.14-pydantic_ai-v2.47.0: pytest==9.1.1 + py3.14-pydantic_ai-v2.47.0: pluggy==1.6.0 + py3.14-pydantic_ai-v2.47.0: aiofile==3.12.3 + py3.14-pydantic_ai-v2.47.0: caio==0.12.4 + py3.14-pydantic_ai-v2.47.0: anthropic==1.7.0 + py3.14-pydantic_ai-v2.47.0: anyio==4.15.1 + py3.14-pydantic_ai-v2.47.0: docstring_parser==0.18.0 + py3.14-pydantic_ai-v2.47.0: httpx2==2.13.0 + py3.14-pydantic_ai-v2.47.0: httpcore2==2.13.0 + py3.14-pydantic_ai-v2.47.0: jiter==0.17.0 + py3.14-pydantic_ai-v2.47.0: pydantic==2.13.5 + py3.14-pydantic_ai-v2.47.0: pydantic_core==2.46.5 + py3.14-pydantic_ai-v2.47.0: sniffio==1.3.1 + py3.14-pydantic_ai-v2.47.0: typing_extensions==4.16.0 + py3.14-pydantic_ai-v2.47.0: annotated-types==0.8.0 + py3.14-pydantic_ai-v2.47.0: argcomplete==3.7.2 + py3.14-pydantic_ai-v2.47.0: Authlib==1.8.0 + py3.14-pydantic_ai-v2.47.0: beartype==0.22.9 + py3.14-pydantic_ai-v2.47.0: cachetools==7.2.0 + py3.14-pydantic_ai-v2.47.0: cryptography==50.0.1 + py3.14-pydantic_ai-v2.47.0: cffi==2.1.1 + py3.14-pydantic_ai-v2.47.0: exceptiongroup==1.3.1 + py3.14-pydantic_ai-v2.47.0: genai-prices==0.1.7 + py3.14-pydantic_ai-v2.47.0: google-genai==2.24.0 + py3.14-pydantic_ai-v2.47.0: distro==1.9.0 + py3.14-pydantic_ai-v2.47.0: google-auth==2.58.0 + py3.14-pydantic_ai-v2.47.0: httpx==0.28.1 + py3.14-pydantic_ai-v2.47.0: httpcore==1.0.9 + py3.14-pydantic_ai-v2.47.0: requests==2.34.2 + py3.14-pydantic_ai-v2.47.0: charset-normalizer==3.5.1 + py3.14-pydantic_ai-v2.47.0: idna==3.20 + py3.14-pydantic_ai-v2.47.0: tenacity==9.1.4 + py3.14-pydantic_ai-v2.47.0: urllib3==2.8.0 + py3.14-pydantic_ai-v2.47.0: websockets==16.1.1 + py3.14-pydantic_ai-v2.47.0: certifi==2026.7.22 + py3.14-pydantic_ai-v2.47.0: griffelib==2.3.0 + py3.14-pydantic_ai-v2.47.0: h11==0.16.0 + py3.14-pydantic_ai-v2.47.0: iniconfig==2.3.0 + py3.14-pydantic_ai-v2.47.0: joserfc==1.7.5 + py3.14-pydantic_ai-v2.47.0: jsonschema==4.26.0 + py3.14-pydantic_ai-v2.47.0: attrs==26.1.0 + py3.14-pydantic_ai-v2.47.0: jsonschema-specifications==2025.9.1 + py3.14-pydantic_ai-v2.47.0: keyring==25.7.0 + py3.14-pydantic_ai-v2.47.0: logfire==5.1.0 + py3.14-pydantic_ai-v2.47.0: opentelemetry-exporter-otlp-proto-http==1.44.0 + py3.14-pydantic_ai-v2.47.0: opentelemetry-exporter-otlp-proto-common==1.44.0 + py3.14-pydantic_ai-v2.47.0: opentelemetry-proto==1.44.0 + py3.14-pydantic_ai-v2.47.0: googleapis-common-protos==1.75.3 + py3.14-pydantic_ai-v2.47.0: opentelemetry-api==1.44.0 + py3.14-pydantic_ai-v2.47.0: opentelemetry-sdk==1.44.0 + py3.14-pydantic_ai-v2.47.0: opentelemetry-semantic-conventions==0.65b0 + py3.14-pydantic_ai-v2.47.0: protobuf==7.36.2 + py3.14-pydantic_ai-v2.47.0: executing==2.2.1 + py3.14-pydantic_ai-v2.47.0: logfire-api==5.1.0 + py3.14-pydantic_ai-v2.47.0: openai==3.17.0 + py3.14-pydantic_ai-v2.47.0: opentelemetry-instrumentation==0.65b0 + py3.14-pydantic_ai-v2.47.0: wrapt==2.4.1 + py3.14-pydantic_ai-v2.47.0: opentelemetry-instrumentation-httpx==0.65b0 + py3.14-pydantic_ai-v2.47.0: opentelemetry-util-http==0.65b0 + py3.14-pydantic_ai-v2.47.0: packaging==26.3 + py3.14-pydantic_ai-v2.47.0: platformdirs==4.11.12 + py3.14-pydantic_ai-v2.47.0: prompt_toolkit==3.0.53 + py3.14-pydantic_ai-v2.47.0: pyasn1_modules==0.4.2 + py3.14-pydantic_ai-v2.47.0: pyasn1==0.6.4 + py3.14-pydantic_ai-v2.47.0: pydantic-settings==2.15.0 + py3.14-pydantic_ai-v2.47.0: email-validator==2.3.0 + py3.14-pydantic_ai-v2.47.0: dnspython==2.8.0 + py3.14-pydantic_ai-v2.47.0: Pygments==2.21.0 + py3.14-pydantic_ai-v2.47.0: PyJWT==2.14.0 + py3.14-pydantic_ai-v2.47.0: pyperclip==1.11.0 + py3.14-pydantic_ai-v2.47.0: python-dotenv==1.2.3 + py3.14-pydantic_ai-v2.47.0: python-multipart==0.0.32 + py3.14-pydantic_ai-v2.47.0: PyYAML==6.0.3 + py3.14-pydantic_ai-v2.47.0: referencing==0.37.0 + py3.14-pydantic_ai-v2.47.0: rich==15.0.0 + py3.14-pydantic_ai-v2.47.0: markdown-it-py==4.2.0 + py3.14-pydantic_ai-v2.47.0: mdurl==0.1.2 + py3.14-pydantic_ai-v2.47.0: rpds-py==2026.6.3 + py3.14-pydantic_ai-v2.47.0: sse-starlette==3.4.11 + py3.14-pydantic_ai-v2.47.0: starlette==1.6.0 + py3.14-pydantic_ai-v2.47.0: tiktoken==0.14.0 + py3.14-pydantic_ai-v2.47.0: truststore==0.10.4 + py3.14-pydantic_ai-v2.47.0: typing-inspection==0.4.4 + py3.14-pydantic_ai-v2.47.0: uvicorn==0.53.0 + py3.14-pydantic_ai-v2.47.0: click==8.5.0 + py3.14-pydantic_ai-v2.47.0: wcwidth==0.8.4 + py3.14-pydantic_ai-v2.47.0: jaraco.classes==3.4.0 + py3.14-pydantic_ai-v2.47.0: jaraco.context==6.1.2 + py3.14-pydantic_ai-v2.47.0: jaraco.functools==4.6.0 + py3.14-pydantic_ai-v2.47.0: more-itertools==11.1.0 + py3.14-pydantic_ai-v2.47.0: pycparser==3.0 + py3.14-pydantic_ai-v2.47.0: regex==2026.9.10 + + py3.14t-pydantic_ai-v2.47.0: pydantic-ai-slim==2.47.0 + py3.14t-pydantic_ai-v2.47.0: pydantic-evals==2.47.0 + py3.14t-pydantic_ai-v2.47.0: pydantic-graph==2.47.0 + py3.14t-pydantic_ai-v2.47.0: fastmcp-slim==4.0.5 + py3.14t-pydantic_ai-v2.47.0: mcp==2.2.0 + py3.14t-pydantic_ai-v2.47.0: mcp-types==2.2.0 + py3.14t-pydantic_ai-v2.47.0: py-key-value-aio==0.4.6 + py3.14t-pydantic_ai-v2.47.0: pytest-asyncio==1.4.0 + py3.14t-pydantic_ai-v2.47.0: pytest==9.1.1 + py3.14t-pydantic_ai-v2.47.0: pluggy==1.6.0 + py3.14t-pydantic_ai-v2.47.0: aiofile==3.12.3 + py3.14t-pydantic_ai-v2.47.0: caio==0.12.4 + py3.14t-pydantic_ai-v2.47.0: anthropic==1.7.0 + py3.14t-pydantic_ai-v2.47.0: anyio==4.15.1 + py3.14t-pydantic_ai-v2.47.0: docstring_parser==0.18.0 + py3.14t-pydantic_ai-v2.47.0: httpx2==2.13.0 + py3.14t-pydantic_ai-v2.47.0: httpcore2==2.13.0 + py3.14t-pydantic_ai-v2.47.0: jiter==0.17.0 + py3.14t-pydantic_ai-v2.47.0: pydantic==2.13.5 + py3.14t-pydantic_ai-v2.47.0: pydantic_core==2.46.5 + py3.14t-pydantic_ai-v2.47.0: sniffio==1.3.1 + py3.14t-pydantic_ai-v2.47.0: typing_extensions==4.16.0 + py3.14t-pydantic_ai-v2.47.0: annotated-types==0.8.0 + py3.14t-pydantic_ai-v2.47.0: argcomplete==3.7.2 + py3.14t-pydantic_ai-v2.47.0: Authlib==1.8.0 + py3.14t-pydantic_ai-v2.47.0: beartype==0.22.9 + py3.14t-pydantic_ai-v2.47.0: cachetools==7.2.0 + py3.14t-pydantic_ai-v2.47.0: cryptography==50.0.1 + py3.14t-pydantic_ai-v2.47.0: cffi==2.1.1 + py3.14t-pydantic_ai-v2.47.0: exceptiongroup==1.3.1 + py3.14t-pydantic_ai-v2.47.0: genai-prices==0.1.7 + py3.14t-pydantic_ai-v2.47.0: google-genai==2.24.0 + py3.14t-pydantic_ai-v2.47.0: distro==1.9.0 + py3.14t-pydantic_ai-v2.47.0: google-auth==2.58.0 + py3.14t-pydantic_ai-v2.47.0: httpx==0.28.1 + py3.14t-pydantic_ai-v2.47.0: httpcore==1.0.9 + py3.14t-pydantic_ai-v2.47.0: requests==2.34.2 + py3.14t-pydantic_ai-v2.47.0: charset-normalizer==3.5.1 + py3.14t-pydantic_ai-v2.47.0: idna==3.20 + py3.14t-pydantic_ai-v2.47.0: tenacity==9.1.4 + py3.14t-pydantic_ai-v2.47.0: urllib3==2.8.0 + py3.14t-pydantic_ai-v2.47.0: websockets==16.1.1 + py3.14t-pydantic_ai-v2.47.0: certifi==2026.7.22 + py3.14t-pydantic_ai-v2.47.0: griffelib==2.3.0 + py3.14t-pydantic_ai-v2.47.0: h11==0.16.0 + py3.14t-pydantic_ai-v2.47.0: iniconfig==2.3.0 + py3.14t-pydantic_ai-v2.47.0: joserfc==1.7.5 + py3.14t-pydantic_ai-v2.47.0: jsonschema==4.26.0 + py3.14t-pydantic_ai-v2.47.0: attrs==26.1.0 + py3.14t-pydantic_ai-v2.47.0: jsonschema-specifications==2025.9.1 + py3.14t-pydantic_ai-v2.47.0: keyring==25.7.0 + py3.14t-pydantic_ai-v2.47.0: logfire==5.1.0 + py3.14t-pydantic_ai-v2.47.0: opentelemetry-exporter-otlp-proto-http==1.44.0 + py3.14t-pydantic_ai-v2.47.0: opentelemetry-exporter-otlp-proto-common==1.44.0 + py3.14t-pydantic_ai-v2.47.0: opentelemetry-proto==1.44.0 + py3.14t-pydantic_ai-v2.47.0: googleapis-common-protos==1.75.3 + py3.14t-pydantic_ai-v2.47.0: opentelemetry-api==1.44.0 + py3.14t-pydantic_ai-v2.47.0: opentelemetry-sdk==1.44.0 + py3.14t-pydantic_ai-v2.47.0: opentelemetry-semantic-conventions==0.65b0 + py3.14t-pydantic_ai-v2.47.0: protobuf==7.36.2 + py3.14t-pydantic_ai-v2.47.0: executing==2.2.1 + py3.14t-pydantic_ai-v2.47.0: logfire-api==5.1.0 + py3.14t-pydantic_ai-v2.47.0: openai==3.17.0 + py3.14t-pydantic_ai-v2.47.0: opentelemetry-instrumentation==0.65b0 + py3.14t-pydantic_ai-v2.47.0: wrapt==2.4.1 + py3.14t-pydantic_ai-v2.47.0: opentelemetry-instrumentation-httpx==0.65b0 + py3.14t-pydantic_ai-v2.47.0: opentelemetry-util-http==0.65b0 + py3.14t-pydantic_ai-v2.47.0: packaging==26.3 + py3.14t-pydantic_ai-v2.47.0: platformdirs==4.11.12 + py3.14t-pydantic_ai-v2.47.0: prompt_toolkit==3.0.53 + py3.14t-pydantic_ai-v2.47.0: pyasn1_modules==0.4.2 + py3.14t-pydantic_ai-v2.47.0: pyasn1==0.6.4 + py3.14t-pydantic_ai-v2.47.0: pydantic-settings==2.15.0 + py3.14t-pydantic_ai-v2.47.0: email-validator==2.3.0 + py3.14t-pydantic_ai-v2.47.0: dnspython==2.8.0 + py3.14t-pydantic_ai-v2.47.0: Pygments==2.21.0 + py3.14t-pydantic_ai-v2.47.0: PyJWT==2.14.0 + py3.14t-pydantic_ai-v2.47.0: pyperclip==1.11.0 + py3.14t-pydantic_ai-v2.47.0: python-dotenv==1.2.3 + py3.14t-pydantic_ai-v2.47.0: python-multipart==0.0.32 + py3.14t-pydantic_ai-v2.47.0: PyYAML==6.0.3 + py3.14t-pydantic_ai-v2.47.0: referencing==0.37.0 + py3.14t-pydantic_ai-v2.47.0: rich==15.0.0 + py3.14t-pydantic_ai-v2.47.0: markdown-it-py==4.2.0 + py3.14t-pydantic_ai-v2.47.0: mdurl==0.1.2 + py3.14t-pydantic_ai-v2.47.0: rpds-py==2026.6.3 + py3.14t-pydantic_ai-v2.47.0: sse-starlette==3.4.11 + py3.14t-pydantic_ai-v2.47.0: starlette==1.6.0 + py3.14t-pydantic_ai-v2.47.0: tiktoken==0.14.0 + py3.14t-pydantic_ai-v2.47.0: truststore==0.10.4 + py3.14t-pydantic_ai-v2.47.0: typing-inspection==0.4.4 + py3.14t-pydantic_ai-v2.47.0: uvicorn==0.53.0 + py3.14t-pydantic_ai-v2.47.0: click==8.5.0 + py3.14t-pydantic_ai-v2.47.0: wcwidth==0.8.4 + py3.14t-pydantic_ai-v2.47.0: jaraco.classes==3.4.0 + py3.14t-pydantic_ai-v2.47.0: jaraco.context==6.1.2 + py3.14t-pydantic_ai-v2.47.0: jaraco.functools==4.6.0 + py3.14t-pydantic_ai-v2.47.0: more-itertools==11.1.0 + py3.14t-pydantic_ai-v2.47.0: pycparser==3.0 + py3.14t-pydantic_ai-v2.47.0: regex==2026.9.10 + + pydantic_ai-latest: pydantic-ai==2.47.0 + + py3.10-pydantic_ai-latest: pydantic-ai-slim==2.47.0 + py3.10-pydantic_ai-latest: pydantic-evals==2.47.0 + py3.10-pydantic_ai-latest: pydantic-graph==2.47.0 py3.10-pydantic_ai-latest: fastmcp-slim==4.0.5 py3.10-pydantic_ai-latest: mcp==2.2.0 py3.10-pydantic_ai-latest: mcp-types==2.2.0 @@ -4662,7 +3844,6 @@ deps = py3.10-pydantic_ai-latest: jsonschema-specifications==2025.9.1 py3.10-pydantic_ai-latest: keyring==25.7.0 py3.10-pydantic_ai-latest: importlib_metadata==9.0.1 - py3.10-pydantic_ai-latest: jeepney==0.9.0 py3.10-pydantic_ai-latest: logfire==5.1.0 py3.10-pydantic_ai-latest: opentelemetry-exporter-otlp-proto-http==1.44.0 py3.10-pydantic_ai-latest: opentelemetry-exporter-otlp-proto-common==1.44.0 @@ -4674,13 +3855,13 @@ deps = py3.10-pydantic_ai-latest: protobuf==7.36.2 py3.10-pydantic_ai-latest: executing==2.2.1 py3.10-pydantic_ai-latest: logfire-api==5.1.0 - py3.10-pydantic_ai-latest: openai==3.16.2 + py3.10-pydantic_ai-latest: openai==3.17.0 py3.10-pydantic_ai-latest: opentelemetry-instrumentation==0.65b0 py3.10-pydantic_ai-latest: wrapt==2.4.1 py3.10-pydantic_ai-latest: opentelemetry-instrumentation-httpx==0.65b0 py3.10-pydantic_ai-latest: opentelemetry-util-http==0.65b0 py3.10-pydantic_ai-latest: packaging==26.3 - py3.10-pydantic_ai-latest: platformdirs==4.11.11 + py3.10-pydantic_ai-latest: platformdirs==4.11.12 py3.10-pydantic_ai-latest: prompt_toolkit==3.0.53 py3.10-pydantic_ai-latest: pyasn1_modules==0.4.2 py3.10-pydantic_ai-latest: pyasn1==0.6.4 @@ -4698,7 +3879,6 @@ deps = py3.10-pydantic_ai-latest: markdown-it-py==4.2.0 py3.10-pydantic_ai-latest: mdurl==0.1.2 py3.10-pydantic_ai-latest: rpds-py==0.30.0 - py3.10-pydantic_ai-latest: SecretStorage==3.5.0 py3.10-pydantic_ai-latest: sse-starlette==3.4.11 py3.10-pydantic_ai-latest: starlette==1.6.0 py3.10-pydantic_ai-latest: tiktoken==0.14.0 @@ -4717,9 +3897,9 @@ deps = py3.10-pydantic_ai-latest: pycparser==3.0 py3.10-pydantic_ai-latest: regex==2026.9.10 - py3.13-pydantic_ai-latest: pydantic-ai-slim==2.46.0 - py3.13-pydantic_ai-latest: pydantic-evals==2.46.0 - py3.13-pydantic_ai-latest: pydantic-graph==2.46.0 + py3.13-pydantic_ai-latest: pydantic-ai-slim==2.47.0 + py3.13-pydantic_ai-latest: pydantic-evals==2.47.0 + py3.13-pydantic_ai-latest: pydantic-graph==2.47.0 py3.13-pydantic_ai-latest: fastmcp-slim==4.0.5 py3.13-pydantic_ai-latest: mcp==2.2.0 py3.13-pydantic_ai-latest: mcp-types==2.2.0 @@ -4768,7 +3948,6 @@ deps = py3.13-pydantic_ai-latest: attrs==26.1.0 py3.13-pydantic_ai-latest: jsonschema-specifications==2025.9.1 py3.13-pydantic_ai-latest: keyring==25.7.0 - py3.13-pydantic_ai-latest: jeepney==0.9.0 py3.13-pydantic_ai-latest: logfire==5.1.0 py3.13-pydantic_ai-latest: opentelemetry-exporter-otlp-proto-http==1.44.0 py3.13-pydantic_ai-latest: opentelemetry-exporter-otlp-proto-common==1.44.0 @@ -4780,13 +3959,13 @@ deps = py3.13-pydantic_ai-latest: protobuf==7.36.2 py3.13-pydantic_ai-latest: executing==2.2.1 py3.13-pydantic_ai-latest: logfire-api==5.1.0 - py3.13-pydantic_ai-latest: openai==3.16.2 + py3.13-pydantic_ai-latest: openai==3.17.0 py3.13-pydantic_ai-latest: opentelemetry-instrumentation==0.65b0 py3.13-pydantic_ai-latest: wrapt==2.4.1 py3.13-pydantic_ai-latest: opentelemetry-instrumentation-httpx==0.65b0 py3.13-pydantic_ai-latest: opentelemetry-util-http==0.65b0 py3.13-pydantic_ai-latest: packaging==26.3 - py3.13-pydantic_ai-latest: platformdirs==4.11.11 + py3.13-pydantic_ai-latest: platformdirs==4.11.12 py3.13-pydantic_ai-latest: prompt_toolkit==3.0.53 py3.13-pydantic_ai-latest: pyasn1_modules==0.4.2 py3.13-pydantic_ai-latest: pyasn1==0.6.4 @@ -4804,7 +3983,6 @@ deps = py3.13-pydantic_ai-latest: markdown-it-py==4.2.0 py3.13-pydantic_ai-latest: mdurl==0.1.2 py3.13-pydantic_ai-latest: rpds-py==2026.6.3 - py3.13-pydantic_ai-latest: SecretStorage==3.5.0 py3.13-pydantic_ai-latest: sse-starlette==3.4.11 py3.13-pydantic_ai-latest: starlette==1.6.0 py3.13-pydantic_ai-latest: tiktoken==0.14.0 @@ -4820,9 +3998,9 @@ deps = py3.13-pydantic_ai-latest: pycparser==3.0 py3.13-pydantic_ai-latest: regex==2026.9.10 - py3.14-pydantic_ai-latest: pydantic-ai-slim==2.46.0 - py3.14-pydantic_ai-latest: pydantic-evals==2.46.0 - py3.14-pydantic_ai-latest: pydantic-graph==2.46.0 + py3.14-pydantic_ai-latest: pydantic-ai-slim==2.47.0 + py3.14-pydantic_ai-latest: pydantic-evals==2.47.0 + py3.14-pydantic_ai-latest: pydantic-graph==2.47.0 py3.14-pydantic_ai-latest: fastmcp-slim==4.0.5 py3.14-pydantic_ai-latest: mcp==2.2.0 py3.14-pydantic_ai-latest: mcp-types==2.2.0 @@ -4871,7 +4049,6 @@ deps = py3.14-pydantic_ai-latest: attrs==26.1.0 py3.14-pydantic_ai-latest: jsonschema-specifications==2025.9.1 py3.14-pydantic_ai-latest: keyring==25.7.0 - py3.14-pydantic_ai-latest: jeepney==0.9.0 py3.14-pydantic_ai-latest: logfire==5.1.0 py3.14-pydantic_ai-latest: opentelemetry-exporter-otlp-proto-http==1.44.0 py3.14-pydantic_ai-latest: opentelemetry-exporter-otlp-proto-common==1.44.0 @@ -4883,13 +4060,13 @@ deps = py3.14-pydantic_ai-latest: protobuf==7.36.2 py3.14-pydantic_ai-latest: executing==2.2.1 py3.14-pydantic_ai-latest: logfire-api==5.1.0 - py3.14-pydantic_ai-latest: openai==3.16.2 + py3.14-pydantic_ai-latest: openai==3.17.0 py3.14-pydantic_ai-latest: opentelemetry-instrumentation==0.65b0 py3.14-pydantic_ai-latest: wrapt==2.4.1 py3.14-pydantic_ai-latest: opentelemetry-instrumentation-httpx==0.65b0 py3.14-pydantic_ai-latest: opentelemetry-util-http==0.65b0 py3.14-pydantic_ai-latest: packaging==26.3 - py3.14-pydantic_ai-latest: platformdirs==4.11.11 + py3.14-pydantic_ai-latest: platformdirs==4.11.12 py3.14-pydantic_ai-latest: prompt_toolkit==3.0.53 py3.14-pydantic_ai-latest: pyasn1_modules==0.4.2 py3.14-pydantic_ai-latest: pyasn1==0.6.4 @@ -4907,7 +4084,6 @@ deps = py3.14-pydantic_ai-latest: markdown-it-py==4.2.0 py3.14-pydantic_ai-latest: mdurl==0.1.2 py3.14-pydantic_ai-latest: rpds-py==2026.6.3 - py3.14-pydantic_ai-latest: SecretStorage==3.5.0 py3.14-pydantic_ai-latest: sse-starlette==3.4.11 py3.14-pydantic_ai-latest: starlette==1.6.0 py3.14-pydantic_ai-latest: tiktoken==0.14.0 @@ -4923,9 +4099,9 @@ deps = py3.14-pydantic_ai-latest: pycparser==3.0 py3.14-pydantic_ai-latest: regex==2026.9.10 - py3.14t-pydantic_ai-latest: pydantic-ai-slim==2.46.0 - py3.14t-pydantic_ai-latest: pydantic-evals==2.46.0 - py3.14t-pydantic_ai-latest: pydantic-graph==2.46.0 + py3.14t-pydantic_ai-latest: pydantic-ai-slim==2.47.0 + py3.14t-pydantic_ai-latest: pydantic-evals==2.47.0 + py3.14t-pydantic_ai-latest: pydantic-graph==2.47.0 py3.14t-pydantic_ai-latest: fastmcp-slim==4.0.5 py3.14t-pydantic_ai-latest: mcp==2.2.0 py3.14t-pydantic_ai-latest: mcp-types==2.2.0 @@ -4974,7 +4150,6 @@ deps = py3.14t-pydantic_ai-latest: attrs==26.1.0 py3.14t-pydantic_ai-latest: jsonschema-specifications==2025.9.1 py3.14t-pydantic_ai-latest: keyring==25.7.0 - py3.14t-pydantic_ai-latest: jeepney==0.9.0 py3.14t-pydantic_ai-latest: logfire==5.1.0 py3.14t-pydantic_ai-latest: opentelemetry-exporter-otlp-proto-http==1.44.0 py3.14t-pydantic_ai-latest: opentelemetry-exporter-otlp-proto-common==1.44.0 @@ -4986,13 +4161,13 @@ deps = py3.14t-pydantic_ai-latest: protobuf==7.36.2 py3.14t-pydantic_ai-latest: executing==2.2.1 py3.14t-pydantic_ai-latest: logfire-api==5.1.0 - py3.14t-pydantic_ai-latest: openai==3.16.2 + py3.14t-pydantic_ai-latest: openai==3.17.0 py3.14t-pydantic_ai-latest: opentelemetry-instrumentation==0.65b0 py3.14t-pydantic_ai-latest: wrapt==2.4.1 py3.14t-pydantic_ai-latest: opentelemetry-instrumentation-httpx==0.65b0 py3.14t-pydantic_ai-latest: opentelemetry-util-http==0.65b0 py3.14t-pydantic_ai-latest: packaging==26.3 - py3.14t-pydantic_ai-latest: platformdirs==4.11.11 + py3.14t-pydantic_ai-latest: platformdirs==4.11.12 py3.14t-pydantic_ai-latest: prompt_toolkit==3.0.53 py3.14t-pydantic_ai-latest: pyasn1_modules==0.4.2 py3.14t-pydantic_ai-latest: pyasn1==0.6.4 @@ -5010,7 +4185,6 @@ deps = py3.14t-pydantic_ai-latest: markdown-it-py==4.2.0 py3.14t-pydantic_ai-latest: mdurl==0.1.2 py3.14t-pydantic_ai-latest: rpds-py==2026.6.3 - py3.14t-pydantic_ai-latest: SecretStorage==3.5.0 py3.14t-pydantic_ai-latest: sse-starlette==3.4.11 py3.14t-pydantic_ai-latest: starlette==1.6.0 py3.14t-pydantic_ai-latest: tiktoken==0.14.0 @@ -6795,221 +5969,239 @@ deps = py3.14-langgraph-v0.6.11: xxhash==3.8.0 py3.14-langgraph-v0.6.11: zstandard==0.25.0 - langgraph-v1.2.11: langgraph==1.2.11 - - py3.10-langgraph-v1.2.11: langchain-core==1.6.0 - py3.10-langgraph-v1.2.11: httpx==0.28.1 - py3.10-langgraph-v1.2.11: httpcore==1.0.9 - py3.10-langgraph-v1.2.11: jsonpatch==1.33 - py3.10-langgraph-v1.2.11: langgraph-checkpoint==4.2.0 - py3.10-langgraph-v1.2.11: langgraph-prebuilt==1.1.0 - py3.10-langgraph-v1.2.11: langgraph-sdk==0.4.3 - py3.10-langgraph-v1.2.11: langsmith==0.11.1 - py3.10-langgraph-v1.2.11: pydantic==2.13.4 - py3.10-langgraph-v1.2.11: pydantic_core==2.46.4 - py3.10-langgraph-v1.2.11: PyYAML==6.0.3 - py3.10-langgraph-v1.2.11: tenacity==9.1.4 - py3.10-langgraph-v1.2.11: typing_extensions==4.16.0 - py3.10-langgraph-v1.2.11: uuid_utils==0.17.0 - py3.10-langgraph-v1.2.11: websockets==16.1.1 - py3.10-langgraph-v1.2.11: annotated-types==0.8.0 - py3.10-langgraph-v1.2.11: anyio==4.14.2 - py3.10-langgraph-v1.2.11: distro==1.9.0 - py3.10-langgraph-v1.2.11: exceptiongroup==1.3.1 - py3.10-langgraph-v1.2.11: h11==0.16.0 - py3.10-langgraph-v1.2.11: idna==3.19 - py3.10-langgraph-v1.2.11: jsonpointer==3.1.1 - py3.10-langgraph-v1.2.11: langchain-protocol==0.0.18 - py3.10-langgraph-v1.2.11: orjson==3.12.0 - py3.10-langgraph-v1.2.11: ormsgpack==1.12.2 - py3.10-langgraph-v1.2.11: packaging==26.3 - py3.10-langgraph-v1.2.11: requests==2.34.2 - py3.10-langgraph-v1.2.11: charset-normalizer==3.5.1 - py3.10-langgraph-v1.2.11: urllib3==2.7.0 - py3.10-langgraph-v1.2.11: certifi==2026.7.22 - py3.10-langgraph-v1.2.11: requests-toolbelt==1.0.0 - py3.10-langgraph-v1.2.11: sniffio==1.3.1 - py3.10-langgraph-v1.2.11: typing-inspection==0.4.4 - py3.10-langgraph-v1.2.11: xxhash==4.0.1 - py3.10-langgraph-v1.2.11: zstandard==0.25.0 - - py3.12-langgraph-v1.2.11: langchain-core==1.6.0 - py3.12-langgraph-v1.2.11: httpx==0.28.1 - py3.12-langgraph-v1.2.11: httpcore==1.0.9 - py3.12-langgraph-v1.2.11: jsonpatch==1.33 - py3.12-langgraph-v1.2.11: langgraph-checkpoint==4.2.0 - py3.12-langgraph-v1.2.11: langgraph-prebuilt==1.1.0 - py3.12-langgraph-v1.2.11: langgraph-sdk==0.4.3 - py3.12-langgraph-v1.2.11: langsmith==0.11.1 - py3.12-langgraph-v1.2.11: pydantic==2.13.4 - py3.12-langgraph-v1.2.11: pydantic_core==2.46.4 - py3.12-langgraph-v1.2.11: PyYAML==6.0.3 - py3.12-langgraph-v1.2.11: tenacity==9.1.4 - py3.12-langgraph-v1.2.11: typing_extensions==4.16.0 - py3.12-langgraph-v1.2.11: uuid_utils==0.17.0 - py3.12-langgraph-v1.2.11: websockets==16.1.1 - py3.12-langgraph-v1.2.11: annotated-types==0.8.0 - py3.12-langgraph-v1.2.11: anyio==4.14.2 - py3.12-langgraph-v1.2.11: distro==1.9.0 - py3.12-langgraph-v1.2.11: h11==0.16.0 - py3.12-langgraph-v1.2.11: idna==3.19 - py3.12-langgraph-v1.2.11: jsonpointer==3.1.1 - py3.12-langgraph-v1.2.11: langchain-protocol==0.0.18 - py3.12-langgraph-v1.2.11: orjson==3.12.0 - py3.12-langgraph-v1.2.11: ormsgpack==1.12.2 - py3.12-langgraph-v1.2.11: packaging==26.3 - py3.12-langgraph-v1.2.11: requests==2.34.2 - py3.12-langgraph-v1.2.11: charset-normalizer==3.5.1 - py3.12-langgraph-v1.2.11: urllib3==2.7.0 - py3.12-langgraph-v1.2.11: certifi==2026.7.22 - py3.12-langgraph-v1.2.11: requests-toolbelt==1.0.0 - py3.12-langgraph-v1.2.11: sniffio==1.3.1 - py3.12-langgraph-v1.2.11: typing-inspection==0.4.4 - py3.12-langgraph-v1.2.11: xxhash==4.0.1 - py3.12-langgraph-v1.2.11: zstandard==0.25.0 - - py3.13-langgraph-v1.2.11: langchain-core==1.6.0 - py3.13-langgraph-v1.2.11: langgraph-checkpoint==4.2.0 - py3.13-langgraph-v1.2.11: langgraph-prebuilt==1.1.0 - py3.13-langgraph-v1.2.11: langgraph-sdk==0.4.3 - py3.13-langgraph-v1.2.11: pydantic==2.13.4 - py3.13-langgraph-v1.2.11: pydantic_core==2.46.4 - py3.13-langgraph-v1.2.11: xxhash==4.0.1 - py3.13-langgraph-v1.2.11: annotated-types==0.8.0 - py3.13-langgraph-v1.2.11: httpx==0.28.1 - py3.13-langgraph-v1.2.11: httpcore==1.0.9 - py3.13-langgraph-v1.2.11: jsonpatch==1.33 - py3.13-langgraph-v1.2.11: langchain-protocol==0.0.18 - py3.13-langgraph-v1.2.11: langsmith==0.11.1 - py3.13-langgraph-v1.2.11: orjson==3.12.0 - py3.13-langgraph-v1.2.11: ormsgpack==1.12.2 - py3.13-langgraph-v1.2.11: packaging==26.3 - py3.13-langgraph-v1.2.11: PyYAML==6.0.3 - py3.13-langgraph-v1.2.11: tenacity==9.1.4 - py3.13-langgraph-v1.2.11: typing_extensions==4.16.0 - py3.13-langgraph-v1.2.11: typing-inspection==0.4.4 - py3.13-langgraph-v1.2.11: uuid_utils==0.17.0 - py3.13-langgraph-v1.2.11: websockets==16.1.1 - py3.13-langgraph-v1.2.11: anyio==4.14.2 - py3.13-langgraph-v1.2.11: distro==1.9.0 - py3.13-langgraph-v1.2.11: idna==3.19 - py3.13-langgraph-v1.2.11: jsonpointer==3.1.1 - py3.13-langgraph-v1.2.11: requests==2.34.2 - py3.13-langgraph-v1.2.11: certifi==2026.7.22 - py3.13-langgraph-v1.2.11: requests-toolbelt==1.0.0 - py3.13-langgraph-v1.2.11: sniffio==1.3.1 - py3.13-langgraph-v1.2.11: zstandard==0.25.0 - py3.13-langgraph-v1.2.11: charset-normalizer==3.5.1 - py3.13-langgraph-v1.2.11: h11==0.16.0 - py3.13-langgraph-v1.2.11: urllib3==2.7.0 - - langgraph-latest: langgraph==1.2.11 - - py3.10-langgraph-latest: langchain-core==1.6.0 + langgraph-v1.2.12: langgraph==1.2.12 + + py3.10-langgraph-v1.2.12: langchain-core==1.6.4 + py3.10-langgraph-v1.2.12: httpx==0.28.1 + py3.10-langgraph-v1.2.12: httpcore==1.0.9 + py3.10-langgraph-v1.2.12: jsonpatch==1.33 + py3.10-langgraph-v1.2.12: langgraph-checkpoint==4.2.0 + py3.10-langgraph-v1.2.12: langgraph-prebuilt==1.1.0 + py3.10-langgraph-v1.2.12: langgraph-sdk==0.4.5 + py3.10-langgraph-v1.2.12: langsmith==0.14.0 + py3.10-langgraph-v1.2.12: httpx2==2.13.0 + py3.10-langgraph-v1.2.12: httpcore2==2.13.0 + py3.10-langgraph-v1.2.12: pydantic==2.13.5 + py3.10-langgraph-v1.2.12: pydantic_core==2.46.5 + py3.10-langgraph-v1.2.12: PyYAML==6.0.3 + py3.10-langgraph-v1.2.12: tenacity==9.1.4 + py3.10-langgraph-v1.2.12: typing_extensions==4.16.0 + py3.10-langgraph-v1.2.12: uuid_utils==0.17.1 + py3.10-langgraph-v1.2.12: websockets==16.1.1 + py3.10-langgraph-v1.2.12: annotated-types==0.8.0 + py3.10-langgraph-v1.2.12: anyio==4.15.1 + py3.10-langgraph-v1.2.12: distro==1.9.0 + py3.10-langgraph-v1.2.12: exceptiongroup==1.3.1 + py3.10-langgraph-v1.2.12: h11==0.16.0 + py3.10-langgraph-v1.2.12: idna==3.20 + py3.10-langgraph-v1.2.12: jsonpointer==3.1.1 + py3.10-langgraph-v1.2.12: langchain-protocol==0.0.19 + py3.10-langgraph-v1.2.12: orjson==3.12.0 + py3.10-langgraph-v1.2.12: ormsgpack==1.12.2 + py3.10-langgraph-v1.2.12: packaging==26.3 + py3.10-langgraph-v1.2.12: requests==2.34.2 + py3.10-langgraph-v1.2.12: charset-normalizer==3.5.1 + py3.10-langgraph-v1.2.12: urllib3==2.8.0 + py3.10-langgraph-v1.2.12: certifi==2026.7.22 + py3.10-langgraph-v1.2.12: requests-toolbelt==1.0.0 + py3.10-langgraph-v1.2.12: sniffio==1.3.1 + py3.10-langgraph-v1.2.12: truststore==0.10.4 + py3.10-langgraph-v1.2.12: typing-inspection==0.4.4 + py3.10-langgraph-v1.2.12: xxhash==4.0.1 + py3.10-langgraph-v1.2.12: zstandard==0.25.0 + + py3.12-langgraph-v1.2.12: langchain-core==1.6.4 + py3.12-langgraph-v1.2.12: httpx==0.28.1 + py3.12-langgraph-v1.2.12: httpcore==1.0.9 + py3.12-langgraph-v1.2.12: jsonpatch==1.33 + py3.12-langgraph-v1.2.12: langgraph-checkpoint==4.2.0 + py3.12-langgraph-v1.2.12: langgraph-prebuilt==1.1.0 + py3.12-langgraph-v1.2.12: langgraph-sdk==0.4.5 + py3.12-langgraph-v1.2.12: langsmith==0.14.0 + py3.12-langgraph-v1.2.12: httpx2==2.13.0 + py3.12-langgraph-v1.2.12: httpcore2==2.13.0 + py3.12-langgraph-v1.2.12: pydantic==2.13.5 + py3.12-langgraph-v1.2.12: pydantic_core==2.46.5 + py3.12-langgraph-v1.2.12: PyYAML==6.0.3 + py3.12-langgraph-v1.2.12: tenacity==9.1.4 + py3.12-langgraph-v1.2.12: typing_extensions==4.16.0 + py3.12-langgraph-v1.2.12: uuid_utils==0.17.1 + py3.12-langgraph-v1.2.12: websockets==16.1.1 + py3.12-langgraph-v1.2.12: annotated-types==0.8.0 + py3.12-langgraph-v1.2.12: anyio==4.15.1 + py3.12-langgraph-v1.2.12: distro==1.9.0 + py3.12-langgraph-v1.2.12: h11==0.16.0 + py3.12-langgraph-v1.2.12: idna==3.20 + py3.12-langgraph-v1.2.12: jsonpointer==3.1.1 + py3.12-langgraph-v1.2.12: langchain-protocol==0.0.19 + py3.12-langgraph-v1.2.12: orjson==3.12.0 + py3.12-langgraph-v1.2.12: ormsgpack==1.12.2 + py3.12-langgraph-v1.2.12: packaging==26.3 + py3.12-langgraph-v1.2.12: requests==2.34.2 + py3.12-langgraph-v1.2.12: charset-normalizer==3.5.1 + py3.12-langgraph-v1.2.12: urllib3==2.8.0 + py3.12-langgraph-v1.2.12: certifi==2026.7.22 + py3.12-langgraph-v1.2.12: requests-toolbelt==1.0.0 + py3.12-langgraph-v1.2.12: sniffio==1.3.1 + py3.12-langgraph-v1.2.12: truststore==0.10.4 + py3.12-langgraph-v1.2.12: typing-inspection==0.4.4 + py3.12-langgraph-v1.2.12: xxhash==4.0.1 + py3.12-langgraph-v1.2.12: zstandard==0.25.0 + + py3.13-langgraph-v1.2.12: langchain-core==1.6.4 + py3.13-langgraph-v1.2.12: httpx==0.28.1 + py3.13-langgraph-v1.2.12: httpcore==1.0.9 + py3.13-langgraph-v1.2.12: jsonpatch==1.33 + py3.13-langgraph-v1.2.12: langgraph-checkpoint==4.2.0 + py3.13-langgraph-v1.2.12: langgraph-prebuilt==1.1.0 + py3.13-langgraph-v1.2.12: langgraph-sdk==0.4.5 + py3.13-langgraph-v1.2.12: langsmith==0.14.0 + py3.13-langgraph-v1.2.12: httpx2==2.13.0 + py3.13-langgraph-v1.2.12: httpcore2==2.13.0 + py3.13-langgraph-v1.2.12: pydantic==2.13.5 + py3.13-langgraph-v1.2.12: pydantic_core==2.46.5 + py3.13-langgraph-v1.2.12: PyYAML==6.0.3 + py3.13-langgraph-v1.2.12: tenacity==9.1.4 + py3.13-langgraph-v1.2.12: typing_extensions==4.16.0 + py3.13-langgraph-v1.2.12: uuid_utils==0.17.1 + py3.13-langgraph-v1.2.12: websockets==16.1.1 + py3.13-langgraph-v1.2.12: annotated-types==0.8.0 + py3.13-langgraph-v1.2.12: anyio==4.15.1 + py3.13-langgraph-v1.2.12: distro==1.9.0 + py3.13-langgraph-v1.2.12: h11==0.16.0 + py3.13-langgraph-v1.2.12: idna==3.20 + py3.13-langgraph-v1.2.12: jsonpointer==3.1.1 + py3.13-langgraph-v1.2.12: langchain-protocol==0.0.19 + py3.13-langgraph-v1.2.12: orjson==3.12.0 + py3.13-langgraph-v1.2.12: ormsgpack==1.12.2 + py3.13-langgraph-v1.2.12: packaging==26.3 + py3.13-langgraph-v1.2.12: requests==2.34.2 + py3.13-langgraph-v1.2.12: charset-normalizer==3.5.1 + py3.13-langgraph-v1.2.12: urllib3==2.8.0 + py3.13-langgraph-v1.2.12: certifi==2026.7.22 + py3.13-langgraph-v1.2.12: requests-toolbelt==1.0.0 + py3.13-langgraph-v1.2.12: sniffio==1.3.1 + py3.13-langgraph-v1.2.12: truststore==0.10.4 + py3.13-langgraph-v1.2.12: typing-inspection==0.4.4 + py3.13-langgraph-v1.2.12: xxhash==4.0.1 + py3.13-langgraph-v1.2.12: zstandard==0.25.0 + + langgraph-latest: langgraph==1.2.12 + + py3.10-langgraph-latest: langchain-core==1.6.4 py3.10-langgraph-latest: httpx==0.28.1 py3.10-langgraph-latest: httpcore==1.0.9 py3.10-langgraph-latest: jsonpatch==1.33 py3.10-langgraph-latest: langgraph-checkpoint==4.2.0 py3.10-langgraph-latest: langgraph-prebuilt==1.1.0 - py3.10-langgraph-latest: langgraph-sdk==0.4.3 - py3.10-langgraph-latest: langsmith==0.11.1 - py3.10-langgraph-latest: pydantic==2.13.4 - py3.10-langgraph-latest: pydantic_core==2.46.4 + py3.10-langgraph-latest: langgraph-sdk==0.4.5 + py3.10-langgraph-latest: langsmith==0.14.0 + py3.10-langgraph-latest: httpx2==2.13.0 + py3.10-langgraph-latest: httpcore2==2.13.0 + py3.10-langgraph-latest: pydantic==2.13.5 + py3.10-langgraph-latest: pydantic_core==2.46.5 py3.10-langgraph-latest: PyYAML==6.0.3 py3.10-langgraph-latest: tenacity==9.1.4 py3.10-langgraph-latest: typing_extensions==4.16.0 - py3.10-langgraph-latest: uuid_utils==0.17.0 + py3.10-langgraph-latest: uuid_utils==0.17.1 py3.10-langgraph-latest: websockets==16.1.1 py3.10-langgraph-latest: annotated-types==0.8.0 - py3.10-langgraph-latest: anyio==4.14.2 + py3.10-langgraph-latest: anyio==4.15.1 py3.10-langgraph-latest: distro==1.9.0 py3.10-langgraph-latest: exceptiongroup==1.3.1 py3.10-langgraph-latest: h11==0.16.0 - py3.10-langgraph-latest: idna==3.19 + py3.10-langgraph-latest: idna==3.20 py3.10-langgraph-latest: jsonpointer==3.1.1 - py3.10-langgraph-latest: langchain-protocol==0.0.18 + py3.10-langgraph-latest: langchain-protocol==0.0.19 py3.10-langgraph-latest: orjson==3.12.0 py3.10-langgraph-latest: ormsgpack==1.12.2 py3.10-langgraph-latest: packaging==26.3 py3.10-langgraph-latest: requests==2.34.2 py3.10-langgraph-latest: charset-normalizer==3.5.1 - py3.10-langgraph-latest: urllib3==2.7.0 + py3.10-langgraph-latest: urllib3==2.8.0 py3.10-langgraph-latest: certifi==2026.7.22 py3.10-langgraph-latest: requests-toolbelt==1.0.0 py3.10-langgraph-latest: sniffio==1.3.1 + py3.10-langgraph-latest: truststore==0.10.4 py3.10-langgraph-latest: typing-inspection==0.4.4 py3.10-langgraph-latest: xxhash==4.0.1 py3.10-langgraph-latest: zstandard==0.25.0 - py3.12-langgraph-latest: langchain-core==1.6.0 + py3.12-langgraph-latest: langchain-core==1.6.4 py3.12-langgraph-latest: httpx==0.28.1 py3.12-langgraph-latest: httpcore==1.0.9 py3.12-langgraph-latest: jsonpatch==1.33 py3.12-langgraph-latest: langgraph-checkpoint==4.2.0 py3.12-langgraph-latest: langgraph-prebuilt==1.1.0 - py3.12-langgraph-latest: langgraph-sdk==0.4.3 - py3.12-langgraph-latest: langsmith==0.11.1 - py3.12-langgraph-latest: pydantic==2.13.4 - py3.12-langgraph-latest: pydantic_core==2.46.4 + py3.12-langgraph-latest: langgraph-sdk==0.4.5 + py3.12-langgraph-latest: langsmith==0.14.0 + py3.12-langgraph-latest: httpx2==2.13.0 + py3.12-langgraph-latest: httpcore2==2.13.0 + py3.12-langgraph-latest: pydantic==2.13.5 + py3.12-langgraph-latest: pydantic_core==2.46.5 py3.12-langgraph-latest: PyYAML==6.0.3 py3.12-langgraph-latest: tenacity==9.1.4 py3.12-langgraph-latest: typing_extensions==4.16.0 - py3.12-langgraph-latest: uuid_utils==0.17.0 + py3.12-langgraph-latest: uuid_utils==0.17.1 py3.12-langgraph-latest: websockets==16.1.1 py3.12-langgraph-latest: annotated-types==0.8.0 - py3.12-langgraph-latest: anyio==4.14.2 + py3.12-langgraph-latest: anyio==4.15.1 py3.12-langgraph-latest: distro==1.9.0 py3.12-langgraph-latest: h11==0.16.0 - py3.12-langgraph-latest: idna==3.19 + py3.12-langgraph-latest: idna==3.20 py3.12-langgraph-latest: jsonpointer==3.1.1 - py3.12-langgraph-latest: langchain-protocol==0.0.18 + py3.12-langgraph-latest: langchain-protocol==0.0.19 py3.12-langgraph-latest: orjson==3.12.0 py3.12-langgraph-latest: ormsgpack==1.12.2 py3.12-langgraph-latest: packaging==26.3 py3.12-langgraph-latest: requests==2.34.2 py3.12-langgraph-latest: charset-normalizer==3.5.1 - py3.12-langgraph-latest: urllib3==2.7.0 + py3.12-langgraph-latest: urllib3==2.8.0 py3.12-langgraph-latest: certifi==2026.7.22 py3.12-langgraph-latest: requests-toolbelt==1.0.0 py3.12-langgraph-latest: sniffio==1.3.1 + py3.12-langgraph-latest: truststore==0.10.4 py3.12-langgraph-latest: typing-inspection==0.4.4 py3.12-langgraph-latest: xxhash==4.0.1 py3.12-langgraph-latest: zstandard==0.25.0 - py3.13-langgraph-latest: langchain-core==1.6.0 - py3.13-langgraph-latest: langgraph-checkpoint==4.2.0 - py3.13-langgraph-latest: langgraph-prebuilt==1.1.0 - py3.13-langgraph-latest: langgraph-sdk==0.4.3 - py3.13-langgraph-latest: pydantic==2.13.4 - py3.13-langgraph-latest: pydantic_core==2.46.4 - py3.13-langgraph-latest: xxhash==4.0.1 - py3.13-langgraph-latest: annotated-types==0.8.0 + py3.13-langgraph-latest: langchain-core==1.6.4 py3.13-langgraph-latest: httpx==0.28.1 py3.13-langgraph-latest: httpcore==1.0.9 py3.13-langgraph-latest: jsonpatch==1.33 - py3.13-langgraph-latest: langchain-protocol==0.0.18 - py3.13-langgraph-latest: langsmith==0.11.1 - py3.13-langgraph-latest: orjson==3.12.0 - py3.13-langgraph-latest: ormsgpack==1.12.2 - py3.13-langgraph-latest: packaging==26.3 + py3.13-langgraph-latest: langgraph-checkpoint==4.2.0 + py3.13-langgraph-latest: langgraph-prebuilt==1.1.0 + py3.13-langgraph-latest: langgraph-sdk==0.4.5 + py3.13-langgraph-latest: langsmith==0.14.0 + py3.13-langgraph-latest: httpx2==2.13.0 + py3.13-langgraph-latest: httpcore2==2.13.0 + py3.13-langgraph-latest: pydantic==2.13.5 + py3.13-langgraph-latest: pydantic_core==2.46.5 py3.13-langgraph-latest: PyYAML==6.0.3 py3.13-langgraph-latest: tenacity==9.1.4 py3.13-langgraph-latest: typing_extensions==4.16.0 - py3.13-langgraph-latest: typing-inspection==0.4.4 - py3.13-langgraph-latest: uuid_utils==0.17.0 + py3.13-langgraph-latest: uuid_utils==0.17.1 py3.13-langgraph-latest: websockets==16.1.1 - py3.13-langgraph-latest: anyio==4.14.2 + py3.13-langgraph-latest: annotated-types==0.8.0 + py3.13-langgraph-latest: anyio==4.15.1 py3.13-langgraph-latest: distro==1.9.0 - py3.13-langgraph-latest: idna==3.19 + py3.13-langgraph-latest: h11==0.16.0 + py3.13-langgraph-latest: idna==3.20 py3.13-langgraph-latest: jsonpointer==3.1.1 + py3.13-langgraph-latest: langchain-protocol==0.0.19 + py3.13-langgraph-latest: orjson==3.12.0 + py3.13-langgraph-latest: ormsgpack==1.12.2 + py3.13-langgraph-latest: packaging==26.3 py3.13-langgraph-latest: requests==2.34.2 + py3.13-langgraph-latest: charset-normalizer==3.5.1 + py3.13-langgraph-latest: urllib3==2.8.0 py3.13-langgraph-latest: certifi==2026.7.22 py3.13-langgraph-latest: requests-toolbelt==1.0.0 py3.13-langgraph-latest: sniffio==1.3.1 + py3.13-langgraph-latest: truststore==0.10.4 + py3.13-langgraph-latest: typing-inspection==0.4.4 + py3.13-langgraph-latest: xxhash==4.0.1 py3.13-langgraph-latest: zstandard==0.25.0 - py3.13-langgraph-latest: charset-normalizer==3.5.1 - py3.13-langgraph-latest: h11==0.16.0 - py3.13-langgraph-latest: urllib3==2.7.0 @@ -10535,124 +9727,124 @@ deps = py3.14t-openai-base-v2.54.0: urllib3==2.7.0 py3.14t-openai-base-v2.54.0: sniffio==1.3.1 - openai-base-v3.16.2: openai==3.16.2 - - py3.10-openai-base-v3.16.2: anyio==4.15.1 - py3.10-openai-base-v3.16.2: httpx2==2.13.0 - py3.10-openai-base-v3.16.2: httpcore2==2.13.0 - py3.10-openai-base-v3.16.2: jiter==0.17.0 - py3.10-openai-base-v3.16.2: pydantic==2.13.5 - py3.10-openai-base-v3.16.2: pydantic_core==2.46.5 - py3.10-openai-base-v3.16.2: typing_extensions==4.16.0 - py3.10-openai-base-v3.16.2: pytest-asyncio==1.4.0 - py3.10-openai-base-v3.16.2: backports.asyncio.runner==1.2.0 - py3.10-openai-base-v3.16.2: pytest==9.1.1 - py3.10-openai-base-v3.16.2: pluggy==1.6.0 - py3.10-openai-base-v3.16.2: tiktoken==0.14.0 - py3.10-openai-base-v3.16.2: httpx==0.28.1 - py3.10-openai-base-v3.16.2: httpcore==1.0.9 - py3.10-openai-base-v3.16.2: annotated-types==0.8.0 - py3.10-openai-base-v3.16.2: exceptiongroup==1.3.1 - py3.10-openai-base-v3.16.2: h11==0.16.0 - py3.10-openai-base-v3.16.2: idna==3.20 - py3.10-openai-base-v3.16.2: iniconfig==2.3.0 - py3.10-openai-base-v3.16.2: packaging==26.3 - py3.10-openai-base-v3.16.2: Pygments==2.21.0 - py3.10-openai-base-v3.16.2: tomli==2.4.1 - py3.10-openai-base-v3.16.2: truststore==0.10.4 - py3.10-openai-base-v3.16.2: typing-inspection==0.4.4 - py3.10-openai-base-v3.16.2: certifi==2026.7.22 - py3.10-openai-base-v3.16.2: regex==2026.9.10 - py3.10-openai-base-v3.16.2: requests==2.34.2 - py3.10-openai-base-v3.16.2: charset-normalizer==3.5.1 - py3.10-openai-base-v3.16.2: urllib3==2.8.0 - py3.10-openai-base-v3.16.2: sniffio==1.3.1 - - py3.13-openai-base-v3.16.2: anyio==4.15.1 - py3.13-openai-base-v3.16.2: httpx2==2.13.0 - py3.13-openai-base-v3.16.2: httpcore2==2.13.0 - py3.13-openai-base-v3.16.2: jiter==0.17.0 - py3.13-openai-base-v3.16.2: pydantic==2.13.5 - py3.13-openai-base-v3.16.2: pydantic_core==2.46.5 - py3.13-openai-base-v3.16.2: typing_extensions==4.16.0 - py3.13-openai-base-v3.16.2: pytest-asyncio==1.4.0 - py3.13-openai-base-v3.16.2: pytest==9.1.1 - py3.13-openai-base-v3.16.2: pluggy==1.6.0 - py3.13-openai-base-v3.16.2: tiktoken==0.14.0 - py3.13-openai-base-v3.16.2: httpx==0.28.1 - py3.13-openai-base-v3.16.2: httpcore==1.0.9 - py3.13-openai-base-v3.16.2: annotated-types==0.8.0 - py3.13-openai-base-v3.16.2: h11==0.16.0 - py3.13-openai-base-v3.16.2: idna==3.20 - py3.13-openai-base-v3.16.2: iniconfig==2.3.0 - py3.13-openai-base-v3.16.2: packaging==26.3 - py3.13-openai-base-v3.16.2: Pygments==2.21.0 - py3.13-openai-base-v3.16.2: truststore==0.10.4 - py3.13-openai-base-v3.16.2: typing-inspection==0.4.4 - py3.13-openai-base-v3.16.2: certifi==2026.7.22 - py3.13-openai-base-v3.16.2: regex==2026.9.10 - py3.13-openai-base-v3.16.2: requests==2.34.2 - py3.13-openai-base-v3.16.2: charset-normalizer==3.5.1 - py3.13-openai-base-v3.16.2: urllib3==2.8.0 - py3.13-openai-base-v3.16.2: sniffio==1.3.1 - - py3.14-openai-base-v3.16.2: anyio==4.15.1 - py3.14-openai-base-v3.16.2: httpx2==2.13.0 - py3.14-openai-base-v3.16.2: httpcore2==2.13.0 - py3.14-openai-base-v3.16.2: jiter==0.17.0 - py3.14-openai-base-v3.16.2: pydantic==2.13.5 - py3.14-openai-base-v3.16.2: pydantic_core==2.46.5 - py3.14-openai-base-v3.16.2: typing_extensions==4.16.0 - py3.14-openai-base-v3.16.2: pytest-asyncio==1.4.0 - py3.14-openai-base-v3.16.2: pytest==9.1.1 - py3.14-openai-base-v3.16.2: pluggy==1.6.0 - py3.14-openai-base-v3.16.2: tiktoken==0.14.0 - py3.14-openai-base-v3.16.2: httpx==0.28.1 - py3.14-openai-base-v3.16.2: httpcore==1.0.9 - py3.14-openai-base-v3.16.2: annotated-types==0.8.0 - py3.14-openai-base-v3.16.2: h11==0.16.0 - py3.14-openai-base-v3.16.2: idna==3.20 - py3.14-openai-base-v3.16.2: iniconfig==2.3.0 - py3.14-openai-base-v3.16.2: packaging==26.3 - py3.14-openai-base-v3.16.2: Pygments==2.21.0 - py3.14-openai-base-v3.16.2: truststore==0.10.4 - py3.14-openai-base-v3.16.2: typing-inspection==0.4.4 - py3.14-openai-base-v3.16.2: certifi==2026.7.22 - py3.14-openai-base-v3.16.2: regex==2026.9.10 - py3.14-openai-base-v3.16.2: requests==2.34.2 - py3.14-openai-base-v3.16.2: charset-normalizer==3.5.1 - py3.14-openai-base-v3.16.2: urllib3==2.8.0 - py3.14-openai-base-v3.16.2: sniffio==1.3.1 - - py3.14t-openai-base-v3.16.2: anyio==4.15.1 - py3.14t-openai-base-v3.16.2: httpx2==2.13.0 - py3.14t-openai-base-v3.16.2: httpcore2==2.13.0 - py3.14t-openai-base-v3.16.2: jiter==0.17.0 - py3.14t-openai-base-v3.16.2: pydantic==2.13.5 - py3.14t-openai-base-v3.16.2: pydantic_core==2.46.5 - py3.14t-openai-base-v3.16.2: typing_extensions==4.16.0 - py3.14t-openai-base-v3.16.2: pytest-asyncio==1.4.0 - py3.14t-openai-base-v3.16.2: pytest==9.1.1 - py3.14t-openai-base-v3.16.2: pluggy==1.6.0 - py3.14t-openai-base-v3.16.2: tiktoken==0.14.0 - py3.14t-openai-base-v3.16.2: httpx==0.28.1 - py3.14t-openai-base-v3.16.2: httpcore==1.0.9 - py3.14t-openai-base-v3.16.2: annotated-types==0.8.0 - py3.14t-openai-base-v3.16.2: h11==0.16.0 - py3.14t-openai-base-v3.16.2: idna==3.20 - py3.14t-openai-base-v3.16.2: iniconfig==2.3.0 - py3.14t-openai-base-v3.16.2: packaging==26.3 - py3.14t-openai-base-v3.16.2: Pygments==2.21.0 - py3.14t-openai-base-v3.16.2: truststore==0.10.4 - py3.14t-openai-base-v3.16.2: typing-inspection==0.4.4 - py3.14t-openai-base-v3.16.2: certifi==2026.7.22 - py3.14t-openai-base-v3.16.2: regex==2026.9.10 - py3.14t-openai-base-v3.16.2: requests==2.34.2 - py3.14t-openai-base-v3.16.2: charset-normalizer==3.5.1 - py3.14t-openai-base-v3.16.2: urllib3==2.8.0 - py3.14t-openai-base-v3.16.2: sniffio==1.3.1 - - openai-base-latest: openai==3.16.2 + openai-base-v3.17.0: openai==3.17.0 + + py3.10-openai-base-v3.17.0: anyio==4.15.1 + py3.10-openai-base-v3.17.0: httpx2==2.13.0 + py3.10-openai-base-v3.17.0: httpcore2==2.13.0 + py3.10-openai-base-v3.17.0: jiter==0.17.0 + py3.10-openai-base-v3.17.0: pydantic==2.13.5 + py3.10-openai-base-v3.17.0: pydantic_core==2.46.5 + py3.10-openai-base-v3.17.0: typing_extensions==4.16.0 + py3.10-openai-base-v3.17.0: pytest-asyncio==1.4.0 + py3.10-openai-base-v3.17.0: backports.asyncio.runner==1.2.0 + py3.10-openai-base-v3.17.0: pytest==9.1.1 + py3.10-openai-base-v3.17.0: pluggy==1.6.0 + py3.10-openai-base-v3.17.0: tiktoken==0.14.0 + py3.10-openai-base-v3.17.0: httpx==0.28.1 + py3.10-openai-base-v3.17.0: httpcore==1.0.9 + py3.10-openai-base-v3.17.0: annotated-types==0.8.0 + py3.10-openai-base-v3.17.0: exceptiongroup==1.3.1 + py3.10-openai-base-v3.17.0: h11==0.16.0 + py3.10-openai-base-v3.17.0: idna==3.20 + py3.10-openai-base-v3.17.0: iniconfig==2.3.0 + py3.10-openai-base-v3.17.0: packaging==26.3 + py3.10-openai-base-v3.17.0: Pygments==2.21.0 + py3.10-openai-base-v3.17.0: tomli==2.4.1 + py3.10-openai-base-v3.17.0: truststore==0.10.4 + py3.10-openai-base-v3.17.0: typing-inspection==0.4.4 + py3.10-openai-base-v3.17.0: certifi==2026.7.22 + py3.10-openai-base-v3.17.0: regex==2026.9.10 + py3.10-openai-base-v3.17.0: requests==2.34.2 + py3.10-openai-base-v3.17.0: charset-normalizer==3.5.1 + py3.10-openai-base-v3.17.0: urllib3==2.8.0 + py3.10-openai-base-v3.17.0: sniffio==1.3.1 + + py3.13-openai-base-v3.17.0: anyio==4.15.1 + py3.13-openai-base-v3.17.0: httpx2==2.13.0 + py3.13-openai-base-v3.17.0: httpcore2==2.13.0 + py3.13-openai-base-v3.17.0: jiter==0.17.0 + py3.13-openai-base-v3.17.0: pydantic==2.13.5 + py3.13-openai-base-v3.17.0: pydantic_core==2.46.5 + py3.13-openai-base-v3.17.0: typing_extensions==4.16.0 + py3.13-openai-base-v3.17.0: pytest-asyncio==1.4.0 + py3.13-openai-base-v3.17.0: pytest==9.1.1 + py3.13-openai-base-v3.17.0: pluggy==1.6.0 + py3.13-openai-base-v3.17.0: tiktoken==0.14.0 + py3.13-openai-base-v3.17.0: httpx==0.28.1 + py3.13-openai-base-v3.17.0: httpcore==1.0.9 + py3.13-openai-base-v3.17.0: annotated-types==0.8.0 + py3.13-openai-base-v3.17.0: h11==0.16.0 + py3.13-openai-base-v3.17.0: idna==3.20 + py3.13-openai-base-v3.17.0: iniconfig==2.3.0 + py3.13-openai-base-v3.17.0: packaging==26.3 + py3.13-openai-base-v3.17.0: Pygments==2.21.0 + py3.13-openai-base-v3.17.0: truststore==0.10.4 + py3.13-openai-base-v3.17.0: typing-inspection==0.4.4 + py3.13-openai-base-v3.17.0: certifi==2026.7.22 + py3.13-openai-base-v3.17.0: regex==2026.9.10 + py3.13-openai-base-v3.17.0: requests==2.34.2 + py3.13-openai-base-v3.17.0: charset-normalizer==3.5.1 + py3.13-openai-base-v3.17.0: urllib3==2.8.0 + py3.13-openai-base-v3.17.0: sniffio==1.3.1 + + py3.14-openai-base-v3.17.0: anyio==4.15.1 + py3.14-openai-base-v3.17.0: httpx2==2.13.0 + py3.14-openai-base-v3.17.0: httpcore2==2.13.0 + py3.14-openai-base-v3.17.0: jiter==0.17.0 + py3.14-openai-base-v3.17.0: pydantic==2.13.5 + py3.14-openai-base-v3.17.0: pydantic_core==2.46.5 + py3.14-openai-base-v3.17.0: typing_extensions==4.16.0 + py3.14-openai-base-v3.17.0: pytest-asyncio==1.4.0 + py3.14-openai-base-v3.17.0: pytest==9.1.1 + py3.14-openai-base-v3.17.0: pluggy==1.6.0 + py3.14-openai-base-v3.17.0: tiktoken==0.14.0 + py3.14-openai-base-v3.17.0: httpx==0.28.1 + py3.14-openai-base-v3.17.0: httpcore==1.0.9 + py3.14-openai-base-v3.17.0: annotated-types==0.8.0 + py3.14-openai-base-v3.17.0: h11==0.16.0 + py3.14-openai-base-v3.17.0: idna==3.20 + py3.14-openai-base-v3.17.0: iniconfig==2.3.0 + py3.14-openai-base-v3.17.0: packaging==26.3 + py3.14-openai-base-v3.17.0: Pygments==2.21.0 + py3.14-openai-base-v3.17.0: truststore==0.10.4 + py3.14-openai-base-v3.17.0: typing-inspection==0.4.4 + py3.14-openai-base-v3.17.0: certifi==2026.7.22 + py3.14-openai-base-v3.17.0: regex==2026.9.10 + py3.14-openai-base-v3.17.0: requests==2.34.2 + py3.14-openai-base-v3.17.0: charset-normalizer==3.5.1 + py3.14-openai-base-v3.17.0: urllib3==2.8.0 + py3.14-openai-base-v3.17.0: sniffio==1.3.1 + + py3.14t-openai-base-v3.17.0: anyio==4.15.1 + py3.14t-openai-base-v3.17.0: httpx2==2.13.0 + py3.14t-openai-base-v3.17.0: httpcore2==2.13.0 + py3.14t-openai-base-v3.17.0: jiter==0.17.0 + py3.14t-openai-base-v3.17.0: pydantic==2.13.5 + py3.14t-openai-base-v3.17.0: pydantic_core==2.46.5 + py3.14t-openai-base-v3.17.0: typing_extensions==4.16.0 + py3.14t-openai-base-v3.17.0: pytest-asyncio==1.4.0 + py3.14t-openai-base-v3.17.0: pytest==9.1.1 + py3.14t-openai-base-v3.17.0: pluggy==1.6.0 + py3.14t-openai-base-v3.17.0: tiktoken==0.14.0 + py3.14t-openai-base-v3.17.0: httpx==0.28.1 + py3.14t-openai-base-v3.17.0: httpcore==1.0.9 + py3.14t-openai-base-v3.17.0: annotated-types==0.8.0 + py3.14t-openai-base-v3.17.0: h11==0.16.0 + py3.14t-openai-base-v3.17.0: idna==3.20 + py3.14t-openai-base-v3.17.0: iniconfig==2.3.0 + py3.14t-openai-base-v3.17.0: packaging==26.3 + py3.14t-openai-base-v3.17.0: Pygments==2.21.0 + py3.14t-openai-base-v3.17.0: truststore==0.10.4 + py3.14t-openai-base-v3.17.0: typing-inspection==0.4.4 + py3.14t-openai-base-v3.17.0: certifi==2026.7.22 + py3.14t-openai-base-v3.17.0: regex==2026.9.10 + py3.14t-openai-base-v3.17.0: requests==2.34.2 + py3.14t-openai-base-v3.17.0: charset-normalizer==3.5.1 + py3.14t-openai-base-v3.17.0: urllib3==2.8.0 + py3.14t-openai-base-v3.17.0: sniffio==1.3.1 + + openai-base-latest: openai==3.17.0 py3.10-openai-base-latest: anyio==4.15.1 py3.10-openai-base-latest: httpx2==2.13.0 @@ -11000,104 +10192,104 @@ deps = py3.14t-openai-notiktoken-v2.54.0: certifi==2026.7.22 py3.14t-openai-notiktoken-v2.54.0: sniffio==1.3.1 - openai-notiktoken-v3.16.2: openai==3.16.2 - - py3.10-openai-notiktoken-v3.16.2: anyio==4.15.1 - py3.10-openai-notiktoken-v3.16.2: httpx2==2.13.0 - py3.10-openai-notiktoken-v3.16.2: httpcore2==2.13.0 - py3.10-openai-notiktoken-v3.16.2: jiter==0.17.0 - py3.10-openai-notiktoken-v3.16.2: pydantic==2.13.5 - py3.10-openai-notiktoken-v3.16.2: pydantic_core==2.46.5 - py3.10-openai-notiktoken-v3.16.2: typing_extensions==4.16.0 - py3.10-openai-notiktoken-v3.16.2: pytest-asyncio==1.4.0 - py3.10-openai-notiktoken-v3.16.2: backports.asyncio.runner==1.2.0 - py3.10-openai-notiktoken-v3.16.2: pytest==9.1.1 - py3.10-openai-notiktoken-v3.16.2: pluggy==1.6.0 - py3.10-openai-notiktoken-v3.16.2: httpx==0.28.1 - py3.10-openai-notiktoken-v3.16.2: httpcore==1.0.9 - py3.10-openai-notiktoken-v3.16.2: annotated-types==0.8.0 - py3.10-openai-notiktoken-v3.16.2: exceptiongroup==1.3.1 - py3.10-openai-notiktoken-v3.16.2: h11==0.16.0 - py3.10-openai-notiktoken-v3.16.2: idna==3.20 - py3.10-openai-notiktoken-v3.16.2: iniconfig==2.3.0 - py3.10-openai-notiktoken-v3.16.2: packaging==26.3 - py3.10-openai-notiktoken-v3.16.2: Pygments==2.21.0 - py3.10-openai-notiktoken-v3.16.2: tomli==2.4.1 - py3.10-openai-notiktoken-v3.16.2: truststore==0.10.4 - py3.10-openai-notiktoken-v3.16.2: typing-inspection==0.4.4 - py3.10-openai-notiktoken-v3.16.2: certifi==2026.7.22 - py3.10-openai-notiktoken-v3.16.2: sniffio==1.3.1 - - py3.13-openai-notiktoken-v3.16.2: anyio==4.15.1 - py3.13-openai-notiktoken-v3.16.2: httpx2==2.13.0 - py3.13-openai-notiktoken-v3.16.2: httpcore2==2.13.0 - py3.13-openai-notiktoken-v3.16.2: jiter==0.17.0 - py3.13-openai-notiktoken-v3.16.2: pydantic==2.13.5 - py3.13-openai-notiktoken-v3.16.2: pydantic_core==2.46.5 - py3.13-openai-notiktoken-v3.16.2: typing_extensions==4.16.0 - py3.13-openai-notiktoken-v3.16.2: pytest-asyncio==1.4.0 - py3.13-openai-notiktoken-v3.16.2: pytest==9.1.1 - py3.13-openai-notiktoken-v3.16.2: pluggy==1.6.0 - py3.13-openai-notiktoken-v3.16.2: httpx==0.28.1 - py3.13-openai-notiktoken-v3.16.2: httpcore==1.0.9 - py3.13-openai-notiktoken-v3.16.2: annotated-types==0.8.0 - py3.13-openai-notiktoken-v3.16.2: h11==0.16.0 - py3.13-openai-notiktoken-v3.16.2: idna==3.20 - py3.13-openai-notiktoken-v3.16.2: iniconfig==2.3.0 - py3.13-openai-notiktoken-v3.16.2: packaging==26.3 - py3.13-openai-notiktoken-v3.16.2: Pygments==2.21.0 - py3.13-openai-notiktoken-v3.16.2: truststore==0.10.4 - py3.13-openai-notiktoken-v3.16.2: typing-inspection==0.4.4 - py3.13-openai-notiktoken-v3.16.2: certifi==2026.7.22 - py3.13-openai-notiktoken-v3.16.2: sniffio==1.3.1 - - py3.14-openai-notiktoken-v3.16.2: anyio==4.15.1 - py3.14-openai-notiktoken-v3.16.2: httpx2==2.13.0 - py3.14-openai-notiktoken-v3.16.2: httpcore2==2.13.0 - py3.14-openai-notiktoken-v3.16.2: jiter==0.17.0 - py3.14-openai-notiktoken-v3.16.2: pydantic==2.13.5 - py3.14-openai-notiktoken-v3.16.2: pydantic_core==2.46.5 - py3.14-openai-notiktoken-v3.16.2: typing_extensions==4.16.0 - py3.14-openai-notiktoken-v3.16.2: pytest-asyncio==1.4.0 - py3.14-openai-notiktoken-v3.16.2: pytest==9.1.1 - py3.14-openai-notiktoken-v3.16.2: pluggy==1.6.0 - py3.14-openai-notiktoken-v3.16.2: httpx==0.28.1 - py3.14-openai-notiktoken-v3.16.2: httpcore==1.0.9 - py3.14-openai-notiktoken-v3.16.2: annotated-types==0.8.0 - py3.14-openai-notiktoken-v3.16.2: h11==0.16.0 - py3.14-openai-notiktoken-v3.16.2: idna==3.20 - py3.14-openai-notiktoken-v3.16.2: iniconfig==2.3.0 - py3.14-openai-notiktoken-v3.16.2: packaging==26.3 - py3.14-openai-notiktoken-v3.16.2: Pygments==2.21.0 - py3.14-openai-notiktoken-v3.16.2: truststore==0.10.4 - py3.14-openai-notiktoken-v3.16.2: typing-inspection==0.4.4 - py3.14-openai-notiktoken-v3.16.2: certifi==2026.7.22 - py3.14-openai-notiktoken-v3.16.2: sniffio==1.3.1 - - py3.14t-openai-notiktoken-v3.16.2: anyio==4.15.1 - py3.14t-openai-notiktoken-v3.16.2: httpx2==2.13.0 - py3.14t-openai-notiktoken-v3.16.2: httpcore2==2.13.0 - py3.14t-openai-notiktoken-v3.16.2: jiter==0.17.0 - py3.14t-openai-notiktoken-v3.16.2: pydantic==2.13.5 - py3.14t-openai-notiktoken-v3.16.2: pydantic_core==2.46.5 - py3.14t-openai-notiktoken-v3.16.2: typing_extensions==4.16.0 - py3.14t-openai-notiktoken-v3.16.2: pytest-asyncio==1.4.0 - py3.14t-openai-notiktoken-v3.16.2: pytest==9.1.1 - py3.14t-openai-notiktoken-v3.16.2: pluggy==1.6.0 - py3.14t-openai-notiktoken-v3.16.2: httpx==0.28.1 - py3.14t-openai-notiktoken-v3.16.2: httpcore==1.0.9 - py3.14t-openai-notiktoken-v3.16.2: annotated-types==0.8.0 - py3.14t-openai-notiktoken-v3.16.2: h11==0.16.0 - py3.14t-openai-notiktoken-v3.16.2: idna==3.20 - py3.14t-openai-notiktoken-v3.16.2: iniconfig==2.3.0 - py3.14t-openai-notiktoken-v3.16.2: packaging==26.3 - py3.14t-openai-notiktoken-v3.16.2: Pygments==2.21.0 - py3.14t-openai-notiktoken-v3.16.2: truststore==0.10.4 - py3.14t-openai-notiktoken-v3.16.2: typing-inspection==0.4.4 - py3.14t-openai-notiktoken-v3.16.2: certifi==2026.7.22 - py3.14t-openai-notiktoken-v3.16.2: sniffio==1.3.1 - - openai-notiktoken-latest: openai==3.16.2 + openai-notiktoken-v3.17.0: openai==3.17.0 + + py3.10-openai-notiktoken-v3.17.0: anyio==4.15.1 + py3.10-openai-notiktoken-v3.17.0: httpx2==2.13.0 + py3.10-openai-notiktoken-v3.17.0: httpcore2==2.13.0 + py3.10-openai-notiktoken-v3.17.0: jiter==0.17.0 + py3.10-openai-notiktoken-v3.17.0: pydantic==2.13.5 + py3.10-openai-notiktoken-v3.17.0: pydantic_core==2.46.5 + py3.10-openai-notiktoken-v3.17.0: typing_extensions==4.16.0 + py3.10-openai-notiktoken-v3.17.0: pytest-asyncio==1.4.0 + py3.10-openai-notiktoken-v3.17.0: backports.asyncio.runner==1.2.0 + py3.10-openai-notiktoken-v3.17.0: pytest==9.1.1 + py3.10-openai-notiktoken-v3.17.0: pluggy==1.6.0 + py3.10-openai-notiktoken-v3.17.0: httpx==0.28.1 + py3.10-openai-notiktoken-v3.17.0: httpcore==1.0.9 + py3.10-openai-notiktoken-v3.17.0: annotated-types==0.8.0 + py3.10-openai-notiktoken-v3.17.0: exceptiongroup==1.3.1 + py3.10-openai-notiktoken-v3.17.0: h11==0.16.0 + py3.10-openai-notiktoken-v3.17.0: idna==3.20 + py3.10-openai-notiktoken-v3.17.0: iniconfig==2.3.0 + py3.10-openai-notiktoken-v3.17.0: packaging==26.3 + py3.10-openai-notiktoken-v3.17.0: Pygments==2.21.0 + py3.10-openai-notiktoken-v3.17.0: tomli==2.4.1 + py3.10-openai-notiktoken-v3.17.0: truststore==0.10.4 + py3.10-openai-notiktoken-v3.17.0: typing-inspection==0.4.4 + py3.10-openai-notiktoken-v3.17.0: certifi==2026.7.22 + py3.10-openai-notiktoken-v3.17.0: sniffio==1.3.1 + + py3.13-openai-notiktoken-v3.17.0: anyio==4.15.1 + py3.13-openai-notiktoken-v3.17.0: httpx2==2.13.0 + py3.13-openai-notiktoken-v3.17.0: httpcore2==2.13.0 + py3.13-openai-notiktoken-v3.17.0: jiter==0.17.0 + py3.13-openai-notiktoken-v3.17.0: pydantic==2.13.5 + py3.13-openai-notiktoken-v3.17.0: pydantic_core==2.46.5 + py3.13-openai-notiktoken-v3.17.0: typing_extensions==4.16.0 + py3.13-openai-notiktoken-v3.17.0: pytest-asyncio==1.4.0 + py3.13-openai-notiktoken-v3.17.0: pytest==9.1.1 + py3.13-openai-notiktoken-v3.17.0: pluggy==1.6.0 + py3.13-openai-notiktoken-v3.17.0: httpx==0.28.1 + py3.13-openai-notiktoken-v3.17.0: httpcore==1.0.9 + py3.13-openai-notiktoken-v3.17.0: annotated-types==0.8.0 + py3.13-openai-notiktoken-v3.17.0: h11==0.16.0 + py3.13-openai-notiktoken-v3.17.0: idna==3.20 + py3.13-openai-notiktoken-v3.17.0: iniconfig==2.3.0 + py3.13-openai-notiktoken-v3.17.0: packaging==26.3 + py3.13-openai-notiktoken-v3.17.0: Pygments==2.21.0 + py3.13-openai-notiktoken-v3.17.0: truststore==0.10.4 + py3.13-openai-notiktoken-v3.17.0: typing-inspection==0.4.4 + py3.13-openai-notiktoken-v3.17.0: certifi==2026.7.22 + py3.13-openai-notiktoken-v3.17.0: sniffio==1.3.1 + + py3.14-openai-notiktoken-v3.17.0: anyio==4.15.1 + py3.14-openai-notiktoken-v3.17.0: httpx2==2.13.0 + py3.14-openai-notiktoken-v3.17.0: httpcore2==2.13.0 + py3.14-openai-notiktoken-v3.17.0: jiter==0.17.0 + py3.14-openai-notiktoken-v3.17.0: pydantic==2.13.5 + py3.14-openai-notiktoken-v3.17.0: pydantic_core==2.46.5 + py3.14-openai-notiktoken-v3.17.0: typing_extensions==4.16.0 + py3.14-openai-notiktoken-v3.17.0: pytest-asyncio==1.4.0 + py3.14-openai-notiktoken-v3.17.0: pytest==9.1.1 + py3.14-openai-notiktoken-v3.17.0: pluggy==1.6.0 + py3.14-openai-notiktoken-v3.17.0: httpx==0.28.1 + py3.14-openai-notiktoken-v3.17.0: httpcore==1.0.9 + py3.14-openai-notiktoken-v3.17.0: annotated-types==0.8.0 + py3.14-openai-notiktoken-v3.17.0: h11==0.16.0 + py3.14-openai-notiktoken-v3.17.0: idna==3.20 + py3.14-openai-notiktoken-v3.17.0: iniconfig==2.3.0 + py3.14-openai-notiktoken-v3.17.0: packaging==26.3 + py3.14-openai-notiktoken-v3.17.0: Pygments==2.21.0 + py3.14-openai-notiktoken-v3.17.0: truststore==0.10.4 + py3.14-openai-notiktoken-v3.17.0: typing-inspection==0.4.4 + py3.14-openai-notiktoken-v3.17.0: certifi==2026.7.22 + py3.14-openai-notiktoken-v3.17.0: sniffio==1.3.1 + + py3.14t-openai-notiktoken-v3.17.0: anyio==4.15.1 + py3.14t-openai-notiktoken-v3.17.0: httpx2==2.13.0 + py3.14t-openai-notiktoken-v3.17.0: httpcore2==2.13.0 + py3.14t-openai-notiktoken-v3.17.0: jiter==0.17.0 + py3.14t-openai-notiktoken-v3.17.0: pydantic==2.13.5 + py3.14t-openai-notiktoken-v3.17.0: pydantic_core==2.46.5 + py3.14t-openai-notiktoken-v3.17.0: typing_extensions==4.16.0 + py3.14t-openai-notiktoken-v3.17.0: pytest-asyncio==1.4.0 + py3.14t-openai-notiktoken-v3.17.0: pytest==9.1.1 + py3.14t-openai-notiktoken-v3.17.0: pluggy==1.6.0 + py3.14t-openai-notiktoken-v3.17.0: httpx==0.28.1 + py3.14t-openai-notiktoken-v3.17.0: httpcore==1.0.9 + py3.14t-openai-notiktoken-v3.17.0: annotated-types==0.8.0 + py3.14t-openai-notiktoken-v3.17.0: h11==0.16.0 + py3.14t-openai-notiktoken-v3.17.0: idna==3.20 + py3.14t-openai-notiktoken-v3.17.0: iniconfig==2.3.0 + py3.14t-openai-notiktoken-v3.17.0: packaging==26.3 + py3.14t-openai-notiktoken-v3.17.0: Pygments==2.21.0 + py3.14t-openai-notiktoken-v3.17.0: truststore==0.10.4 + py3.14t-openai-notiktoken-v3.17.0: typing-inspection==0.4.4 + py3.14t-openai-notiktoken-v3.17.0: certifi==2026.7.22 + py3.14t-openai-notiktoken-v3.17.0: sniffio==1.3.1 + + openai-notiktoken-latest: openai==3.17.0 py3.10-openai-notiktoken-latest: anyio==4.15.1 py3.10-openai-notiktoken-latest: httpx2==2.13.0 @@ -11248,60 +10440,60 @@ deps = py3.13-boto3-v1.35.99: urllib3==2.7.0 py3.13-boto3-v1.35.99: six==1.17.0 - boto3-v1.43.98: boto3==1.43.98 - - py3.10-boto3-v1.43.98: botocore==1.43.98 - py3.10-boto3-v1.43.98: jmespath==1.1.0 - py3.10-boto3-v1.43.98: python-dateutil==2.9.0.post0 - py3.10-boto3-v1.43.98: s3transfer==0.19.2 - py3.10-boto3-v1.43.98: urllib3==2.8.0 - py3.10-boto3-v1.43.98: six==1.17.0 - - py3.13-boto3-v1.43.98: botocore==1.43.98 - py3.13-boto3-v1.43.98: jmespath==1.1.0 - py3.13-boto3-v1.43.98: python-dateutil==2.9.0.post0 - py3.13-boto3-v1.43.98: s3transfer==0.19.2 - py3.13-boto3-v1.43.98: urllib3==2.8.0 - py3.13-boto3-v1.43.98: six==1.17.0 - - py3.14-boto3-v1.43.98: botocore==1.43.98 - py3.14-boto3-v1.43.98: jmespath==1.1.0 - py3.14-boto3-v1.43.98: python-dateutil==2.9.0.post0 - py3.14-boto3-v1.43.98: s3transfer==0.19.2 - py3.14-boto3-v1.43.98: urllib3==2.8.0 - py3.14-boto3-v1.43.98: six==1.17.0 - - py3.14t-boto3-v1.43.98: botocore==1.43.98 - py3.14t-boto3-v1.43.98: jmespath==1.1.0 - py3.14t-boto3-v1.43.98: python-dateutil==2.9.0.post0 - py3.14t-boto3-v1.43.98: s3transfer==0.19.2 - py3.14t-boto3-v1.43.98: urllib3==2.8.0 - py3.14t-boto3-v1.43.98: six==1.17.0 - - boto3-latest: boto3==1.43.98 - - py3.10-boto3-latest: botocore==1.43.98 + boto3-v1.43.99: boto3==1.43.99 + + py3.10-boto3-v1.43.99: botocore==1.43.99 + py3.10-boto3-v1.43.99: jmespath==1.1.0 + py3.10-boto3-v1.43.99: python-dateutil==2.9.0.post0 + py3.10-boto3-v1.43.99: s3transfer==0.19.2 + py3.10-boto3-v1.43.99: urllib3==2.8.0 + py3.10-boto3-v1.43.99: six==1.17.0 + + py3.13-boto3-v1.43.99: botocore==1.43.99 + py3.13-boto3-v1.43.99: jmespath==1.1.0 + py3.13-boto3-v1.43.99: python-dateutil==2.9.0.post0 + py3.13-boto3-v1.43.99: s3transfer==0.19.2 + py3.13-boto3-v1.43.99: urllib3==2.8.0 + py3.13-boto3-v1.43.99: six==1.17.0 + + py3.14-boto3-v1.43.99: botocore==1.43.99 + py3.14-boto3-v1.43.99: jmespath==1.1.0 + py3.14-boto3-v1.43.99: python-dateutil==2.9.0.post0 + py3.14-boto3-v1.43.99: s3transfer==0.19.2 + py3.14-boto3-v1.43.99: urllib3==2.8.0 + py3.14-boto3-v1.43.99: six==1.17.0 + + py3.14t-boto3-v1.43.99: botocore==1.43.99 + py3.14t-boto3-v1.43.99: jmespath==1.1.0 + py3.14t-boto3-v1.43.99: python-dateutil==2.9.0.post0 + py3.14t-boto3-v1.43.99: s3transfer==0.19.2 + py3.14t-boto3-v1.43.99: urllib3==2.8.0 + py3.14t-boto3-v1.43.99: six==1.17.0 + + boto3-latest: boto3==1.43.99 + + py3.10-boto3-latest: botocore==1.43.99 py3.10-boto3-latest: jmespath==1.1.0 py3.10-boto3-latest: python-dateutil==2.9.0.post0 py3.10-boto3-latest: s3transfer==0.19.2 py3.10-boto3-latest: urllib3==2.8.0 py3.10-boto3-latest: six==1.17.0 - py3.13-boto3-latest: botocore==1.43.98 + py3.13-boto3-latest: botocore==1.43.99 py3.13-boto3-latest: jmespath==1.1.0 py3.13-boto3-latest: python-dateutil==2.9.0.post0 py3.13-boto3-latest: s3transfer==0.19.2 py3.13-boto3-latest: urllib3==2.8.0 py3.13-boto3-latest: six==1.17.0 - py3.14-boto3-latest: botocore==1.43.98 + py3.14-boto3-latest: botocore==1.43.99 py3.14-boto3-latest: jmespath==1.1.0 py3.14-boto3-latest: python-dateutil==2.9.0.post0 py3.14-boto3-latest: s3transfer==0.19.2 py3.14-boto3-latest: urllib3==2.8.0 py3.14-boto3-latest: six==1.17.0 - py3.14t-boto3-latest: botocore==1.43.98 + py3.14t-boto3-latest: botocore==1.43.99 py3.14t-boto3-latest: jmespath==1.1.0 py3.14t-boto3-latest: python-dateutil==2.9.0.post0 py3.14t-boto3-latest: s3transfer==0.19.2 @@ -11310,29 +10502,7 @@ deps = {py3.7,py3.8}-boto3: urllib3<2.0.0 - chalice-v1.16.0: chalice==1.16.0 - - py3.8-chalice-v1.16.0: mypy-extensions==0.4.3 - py3.8-chalice-v1.16.0: pytest-chalice==0.0.5 - py3.8-chalice-v1.16.0: setuptools==75.3.4 - py3.8-chalice-v1.16.0: attrs==19.3.0 - py3.8-chalice-v1.16.0: botocore==1.37.38 - py3.8-chalice-v1.16.0: click==7.1.2 - py3.8-chalice-v1.16.0: enum-compat==0.0.3 - py3.8-chalice-v1.16.0: jmespath==0.10.0 - py3.8-chalice-v1.16.0: pip==20.1.1 - py3.8-chalice-v1.16.0: pytest==8.3.5 - py3.8-chalice-v1.16.0: PyYAML==5.4.1 - py3.8-chalice-v1.16.0: six==1.17.0 - py3.8-chalice-v1.16.0: wheel==0.45.1 - py3.8-chalice-v1.16.0: exceptiongroup==1.3.1 - py3.8-chalice-v1.16.0: pluggy==1.5.0 - py3.8-chalice-v1.16.0: python-dateutil==2.9.0.post0 - py3.8-chalice-v1.16.0: tomli==2.4.1 - py3.8-chalice-v1.16.0: urllib3==1.26.20 - py3.8-chalice-v1.16.0: iniconfig==2.1.0 - py3.8-chalice-v1.16.0: packaging==26.2 - py3.8-chalice-v1.16.0: typing_extensions==4.13.2 + chalice-v1.22.4: chalice==1.22.4 chalice-v1.33.0: chalice==1.33.0 @@ -11802,7 +10972,7 @@ deps = py3.14-clickhouse_driver-latest: tzlocal==5.4.4 - pymongo-v3.5.1: pymongo==3.5.1 + pymongo-v3.7.2: pymongo==3.7.2 pymongo-v3.13.0: pymongo==3.13.0 @@ -11815,8 +10985,8 @@ deps = py3.9-pymongo-v4.18.1: dnspython==2.7.0 py3.9-pymongo-v4.18.1: mockupdb==1.8.1 - py3.13-pymongo-v4.18.1: dnspython==2.8.0 py3.13-pymongo-v4.18.1: mockupdb==1.8.1 + py3.13-pymongo-v4.18.1: dnspython==2.8.0 py3.14-pymongo-v4.18.1: dnspython==2.8.0 py3.14-pymongo-v4.18.1: mockupdb==1.8.1 @@ -11829,8 +10999,8 @@ deps = py3.9-pymongo-latest: dnspython==2.7.0 py3.9-pymongo-latest: mockupdb==1.8.1 - py3.13-pymongo-latest: dnspython==2.8.0 py3.13-pymongo-latest: mockupdb==1.8.1 + py3.13-pymongo-latest: dnspython==2.8.0 py3.14-pymongo-latest: dnspython==2.8.0 py3.14-pymongo-latest: mockupdb==1.8.1 @@ -11840,20 +11010,35 @@ deps = pymongo: mockupdb - redis-v2.10.6: redis==2.10.6 - - redis-v3.5.3: redis==3.5.3 - - py3.8-redis-v3.5.3: fakeredis==2.7.1 - py3.8-redis-v3.5.3: pytest==7.4.4 - py3.8-redis-v3.5.3: pytest-asyncio==0.23.8 - py3.8-redis-v3.5.3: exceptiongroup==1.3.1 - py3.8-redis-v3.5.3: pluggy==1.5.0 - py3.8-redis-v3.5.3: sortedcontainers==2.4.0 - py3.8-redis-v3.5.3: tomli==2.4.1 - py3.8-redis-v3.5.3: iniconfig==2.1.0 - py3.8-redis-v3.5.3: packaging==26.2 - py3.8-redis-v3.5.3: typing_extensions==4.13.2 + redis-v4.2.2: redis==4.2.2 + + py3.9-redis-v4.2.2: fakeredis==2.24.1 + py3.9-redis-v4.2.2: pytest==7.4.4 + py3.9-redis-v4.2.2: pluggy==1.6.0 + py3.9-redis-v4.2.2: sortedcontainers==2.4.0 + py3.9-redis-v4.2.2: typing_extensions==4.16.0 + py3.9-redis-v4.2.2: pytest-asyncio==0.23.8 + py3.9-redis-v4.2.2: async-timeout==5.0.1 + py3.9-redis-v4.2.2: Deprecated==1.3.1 + py3.9-redis-v4.2.2: wrapt==2.3.0 + py3.9-redis-v4.2.2: exceptiongroup==1.3.1 + py3.9-redis-v4.2.2: packaging==26.3 + py3.9-redis-v4.2.2: tomli==2.4.1 + py3.9-redis-v4.2.2: iniconfig==2.1.0 + + py3.10-redis-v4.2.2: fakeredis==2.24.1 + py3.10-redis-v4.2.2: pytest==7.4.4 + py3.10-redis-v4.2.2: pluggy==1.6.0 + py3.10-redis-v4.2.2: sortedcontainers==2.4.0 + py3.10-redis-v4.2.2: typing_extensions==4.16.0 + py3.10-redis-v4.2.2: pytest-asyncio==0.23.8 + py3.10-redis-v4.2.2: async-timeout==5.0.1 + py3.10-redis-v4.2.2: Deprecated==1.3.1 + py3.10-redis-v4.2.2: wrapt==2.3.0 + py3.10-redis-v4.2.2: exceptiongroup==1.3.1 + py3.10-redis-v4.2.2: packaging==26.3 + py3.10-redis-v4.2.2: tomli==2.4.1 + py3.10-redis-v4.2.2: iniconfig==2.3.0 redis-v4.6.0: redis==4.6.0 @@ -12056,22 +11241,10 @@ deps = redis: fakeredis!=1.7.4 redis: pytest<8.0.0 + redis: pytest-asyncio + redis-v4.2.2: fakeredis<2.31.0 redis-v4.6.0: fakeredis<2.31.0 - {py3.6,py3.7,py3.8}-redis: fakeredis<2.26.0 - {py3.7,py3.8,py3.9,py3.10,py3.11,py3.12,py3.13,py3.14,py3.14t}-redis: pytest-asyncio - - redis_py_cluster_legacy-v1.3.6: redis-py-cluster==1.3.6 - - redis_py_cluster_legacy-v2.1.3: redis-py-cluster==2.1.3 - - py3.8-redis_py_cluster_legacy-v2.1.3: redis==3.5.3 - - redis_py_cluster_legacy-latest: redis-py-cluster==2.1.3 - - py3.8-redis_py_cluster_legacy-latest: redis==3.5.3 - - - sqlalchemy-v1.2.19: sqlalchemy==1.2.19 + {py3.7,py3.8}-redis: fakeredis<2.26.0 sqlalchemy-v1.4.54: sqlalchemy==1.4.54 @@ -13332,8 +12505,6 @@ deps = graphene: fastapi[test] graphene: flask graphene: httpx - {py3.6}-graphene: aiocontextvars - {py3.6}-graphene: setuptools<82 {py3.7}-graphene: setuptools<82 strawberry-v0.209.8: strawberry-graphql[fastapi,flask]==0.209.8 @@ -13888,10 +13059,10 @@ deps = py3.9-httpx0-v0.20.0: sniffio==1.3.1 py3.9-httpx0-v0.20.0: pytest-asyncio==0.20.3 py3.9-httpx0-v0.20.0: attrs==26.1.0 - py3.9-httpx0-v0.20.0: idna==3.18 + py3.9-httpx0-v0.20.0: idna==3.19 py3.9-httpx0-v0.20.0: py==1.11.0 py3.9-httpx0-v0.20.0: certifi==2026.7.22 - py3.9-httpx0-v0.20.0: charset-normalizer==3.4.9 + py3.9-httpx0-v0.20.0: charset-normalizer==3.5.1 py3.9-httpx0-v0.20.0: exceptiongroup==1.3.1 py3.9-httpx0-v0.20.0: typing_extensions==4.16.0 py3.9-httpx0-v0.20.0: iniconfig==2.1.0 @@ -13921,27 +13092,27 @@ deps = httpx0-v0.24.1: httpx==0.24.1 py3.10-httpx0-v0.24.1: pytest-httpx==0.22.0 - py3.10-httpx0-v0.24.1: anyio==4.14.2 - py3.10-httpx0-v0.24.1: httpcore==0.17.3 - py3.10-httpx0-v0.24.1: h11==0.14.0 - py3.10-httpx0-v0.24.1: pytest==7.4.4 - py3.10-httpx0-v0.24.1: pluggy==1.6.0 - py3.10-httpx0-v0.24.1: sniffio==1.3.1 + py3.10-httpx0-v0.24.1: anyio==4.15.1 py3.10-httpx0-v0.24.1: pytest-asyncio==0.23.8 py3.10-httpx0-v0.24.1: exceptiongroup==1.3.1 - py3.10-httpx0-v0.24.1: idna==3.18 - py3.10-httpx0-v0.24.1: tomli==2.4.1 + py3.10-httpx0-v0.24.1: httpcore==0.17.3 + py3.10-httpx0-v0.24.1: sniffio==1.3.1 + py3.10-httpx0-v0.24.1: idna==3.19 + py3.10-httpx0-v0.24.1: pytest==7.4.4 py3.10-httpx0-v0.24.1: typing_extensions==4.16.0 py3.10-httpx0-v0.24.1: certifi==2026.7.22 + py3.10-httpx0-v0.24.1: h11==0.14.0 + py3.10-httpx0-v0.24.1: pluggy==1.6.0 + py3.10-httpx0-v0.24.1: tomli==2.4.1 py3.10-httpx0-v0.24.1: iniconfig==2.3.0 py3.10-httpx0-v0.24.1: packaging==26.3 py3.11-httpx0-v0.24.1: pytest-httpx==0.22.0 - py3.11-httpx0-v0.24.1: anyio==4.14.2 + py3.11-httpx0-v0.24.1: anyio==4.15.1 py3.11-httpx0-v0.24.1: pytest-asyncio==0.23.8 py3.11-httpx0-v0.24.1: httpcore==0.17.3 py3.11-httpx0-v0.24.1: sniffio==1.3.1 - py3.11-httpx0-v0.24.1: idna==3.18 + py3.11-httpx0-v0.24.1: idna==3.19 py3.11-httpx0-v0.24.1: pytest==7.4.4 py3.11-httpx0-v0.24.1: typing_extensions==4.16.0 py3.11-httpx0-v0.24.1: certifi==2026.7.22 @@ -13961,10 +13132,10 @@ deps = py3.9-httpx0-v0.28.1: backports.asyncio.runner==1.2.0 py3.9-httpx0-v0.28.1: exceptiongroup==1.3.1 py3.9-httpx0-v0.28.1: h11==0.16.0 - py3.9-httpx0-v0.28.1: idna==3.18 + py3.9-httpx0-v0.28.1: idna==3.19 py3.9-httpx0-v0.28.1: iniconfig==2.1.0 py3.9-httpx0-v0.28.1: packaging==26.3 - py3.9-httpx0-v0.28.1: Pygments==2.20.0 + py3.9-httpx0-v0.28.1: Pygments==2.21.0 py3.9-httpx0-v0.28.1: tomli==2.4.1 py3.9-httpx0-v0.28.1: typing_extensions==4.16.0 py3.9-httpx0-v0.28.1: certifi==2026.7.22 @@ -13972,28 +13143,28 @@ deps = py3.11-httpx0-v0.28.1: pytest-httpx==0.35.0 py3.11-httpx0-v0.28.1: httpcore==1.0.9 py3.11-httpx0-v0.28.1: pytest==8.4.2 - py3.11-httpx0-v0.28.1: anyio==4.14.2 + py3.11-httpx0-v0.28.1: anyio==4.15.1 py3.11-httpx0-v0.28.1: pytest-asyncio==1.4.0 - py3.11-httpx0-v0.28.1: idna==3.18 + py3.11-httpx0-v0.28.1: idna==3.19 py3.11-httpx0-v0.28.1: typing_extensions==4.16.0 py3.11-httpx0-v0.28.1: certifi==2026.7.22 py3.11-httpx0-v0.28.1: h11==0.16.0 py3.11-httpx0-v0.28.1: iniconfig==2.3.0 py3.11-httpx0-v0.28.1: packaging==26.3 py3.11-httpx0-v0.28.1: pluggy==1.6.0 - py3.11-httpx0-v0.28.1: Pygments==2.20.0 + py3.11-httpx0-v0.28.1: Pygments==2.21.0 py3.12-httpx0-v0.28.1: pytest-httpx==0.35.0 - py3.12-httpx0-v0.28.1: anyio==4.14.2 + py3.12-httpx0-v0.28.1: anyio==4.15.1 py3.12-httpx0-v0.28.1: httpcore==1.0.9 py3.12-httpx0-v0.28.1: pytest==8.4.2 py3.12-httpx0-v0.28.1: pluggy==1.6.0 py3.12-httpx0-v0.28.1: pytest-asyncio==1.4.0 py3.12-httpx0-v0.28.1: h11==0.16.0 - py3.12-httpx0-v0.28.1: idna==3.18 + py3.12-httpx0-v0.28.1: idna==3.19 py3.12-httpx0-v0.28.1: iniconfig==2.3.0 py3.12-httpx0-v0.28.1: packaging==26.3 - py3.12-httpx0-v0.28.1: Pygments==2.20.0 + py3.12-httpx0-v0.28.1: Pygments==2.21.0 py3.12-httpx0-v0.28.1: typing_extensions==4.16.0 py3.12-httpx0-v0.28.1: certifi==2026.7.22 @@ -14010,10 +13181,10 @@ deps = py3.9-httpx0-latest: backports.asyncio.runner==1.2.0 py3.9-httpx0-latest: exceptiongroup==1.3.1 py3.9-httpx0-latest: h11==0.16.0 - py3.9-httpx0-latest: idna==3.18 + py3.9-httpx0-latest: idna==3.19 py3.9-httpx0-latest: iniconfig==2.1.0 py3.9-httpx0-latest: packaging==26.3 - py3.9-httpx0-latest: Pygments==2.20.0 + py3.9-httpx0-latest: Pygments==2.21.0 py3.9-httpx0-latest: tomli==2.4.1 py3.9-httpx0-latest: typing_extensions==4.16.0 py3.9-httpx0-latest: certifi==2026.7.22 @@ -14021,28 +13192,28 @@ deps = py3.11-httpx0-latest: pytest-httpx==0.35.0 py3.11-httpx0-latest: httpcore==1.0.9 py3.11-httpx0-latest: pytest==8.4.2 - py3.11-httpx0-latest: anyio==4.14.2 + py3.11-httpx0-latest: anyio==4.15.1 py3.11-httpx0-latest: pytest-asyncio==1.4.0 - py3.11-httpx0-latest: idna==3.18 + py3.11-httpx0-latest: idna==3.19 py3.11-httpx0-latest: typing_extensions==4.16.0 py3.11-httpx0-latest: certifi==2026.7.22 py3.11-httpx0-latest: h11==0.16.0 py3.11-httpx0-latest: iniconfig==2.3.0 py3.11-httpx0-latest: packaging==26.3 py3.11-httpx0-latest: pluggy==1.6.0 - py3.11-httpx0-latest: Pygments==2.20.0 + py3.11-httpx0-latest: Pygments==2.21.0 py3.12-httpx0-latest: pytest-httpx==0.35.0 - py3.12-httpx0-latest: anyio==4.14.2 + py3.12-httpx0-latest: anyio==4.15.1 py3.12-httpx0-latest: httpcore==1.0.9 py3.12-httpx0-latest: pytest==8.4.2 py3.12-httpx0-latest: pluggy==1.6.0 py3.12-httpx0-latest: pytest-asyncio==1.4.0 py3.12-httpx0-latest: h11==0.16.0 - py3.12-httpx0-latest: idna==3.18 + py3.12-httpx0-latest: idna==3.19 py3.12-httpx0-latest: iniconfig==2.3.0 py3.12-httpx0-latest: packaging==26.3 - py3.12-httpx0-latest: Pygments==2.20.0 + py3.12-httpx0-latest: Pygments==2.21.0 py3.12-httpx0-latest: typing_extensions==4.16.0 py3.12-httpx0-latest: certifi==2026.7.22 @@ -14392,11 +13563,11 @@ deps = py3.11-pyreqwest-v0.13.0: pytest-asyncio==1.4.0 py3.11-pyreqwest-v0.13.0: pytest==9.1.1 - py3.11-pyreqwest-v0.13.0: pluggy==1.6.0 + py3.11-pyreqwest-v0.13.0: typing_extensions==4.16.0 py3.11-pyreqwest-v0.13.0: iniconfig==2.3.0 py3.11-pyreqwest-v0.13.0: packaging==26.3 + py3.11-pyreqwest-v0.13.0: pluggy==1.6.0 py3.11-pyreqwest-v0.13.0: Pygments==2.21.0 - py3.11-pyreqwest-v0.13.0: typing_extensions==4.16.0 py3.13-pyreqwest-v0.13.0: pytest-asyncio==1.4.0 py3.13-pyreqwest-v0.13.0: pytest==9.1.1 @@ -14416,11 +13587,11 @@ deps = py3.11-pyreqwest-latest: pytest-asyncio==1.4.0 py3.11-pyreqwest-latest: pytest==9.1.1 - py3.11-pyreqwest-latest: pluggy==1.6.0 + py3.11-pyreqwest-latest: typing_extensions==4.16.0 py3.11-pyreqwest-latest: iniconfig==2.3.0 py3.11-pyreqwest-latest: packaging==26.3 + py3.11-pyreqwest-latest: pluggy==1.6.0 py3.11-pyreqwest-latest: Pygments==2.21.0 - py3.11-pyreqwest-latest: typing_extensions==4.16.0 py3.13-pyreqwest-latest: pytest-asyncio==1.4.0 py3.13-pyreqwest-latest: pytest==9.1.1 @@ -14438,7 +13609,17 @@ deps = pyreqwest: pytest-asyncio - requests-v2.12.5: requests==2.12.5 + requests-v2.30.0: requests==2.30.0 + + py3.10-requests-v2.30.0: charset-normalizer==3.4.9 + py3.10-requests-v2.30.0: idna==3.18 + py3.10-requests-v2.30.0: urllib3==2.7.0 + py3.10-requests-v2.30.0: certifi==2026.7.22 + + py3.11-requests-v2.30.0: certifi==2026.7.22 + py3.11-requests-v2.30.0: charset-normalizer==3.4.9 + py3.11-requests-v2.30.0: idna==3.18 + py3.11-requests-v2.30.0: urllib3==2.7.0 requests-v2.34.2: requests==2.34.2 @@ -14651,7 +13832,7 @@ deps = arq: pytest-asyncio arq: fakeredis arq-v0.23: pydantic<2 - {py3.6,py3.7,py3.8}-arq: fakeredis<2.36.0 + {py3.7,py3.8}-arq: fakeredis<2.36.0 beam-v2.14.0: apache-beam==2.14.0 @@ -14735,6 +13916,86 @@ deps = py3.13-beam-v2.76.0: multidict==6.7.1 py3.13-beam-v2.76.0: pycparser==3.0 + beam-v2.77.0rc1: apache-beam==2.77.0rc1 + + py3.10-beam-v2.77.0rc1: betterproto==2.0.0b6 + py3.10-beam-v2.77.0rc1: beartype==0.22.9 + py3.10-beam-v2.77.0rc1: cryptography==50.0.1 + py3.10-beam-v2.77.0rc1: fastavro==1.12.2 + py3.10-beam-v2.77.0rc1: fasteners==0.20 + py3.10-beam-v2.77.0rc1: grpcio==1.84.0 + py3.10-beam-v2.77.0rc1: grpclib==0.4.9 + py3.10-beam-v2.77.0rc1: h2==4.4.1 + py3.10-beam-v2.77.0rc1: hpack==4.2.0 + py3.10-beam-v2.77.0rc1: httplib2==0.32.0 + py3.10-beam-v2.77.0rc1: hyperframe==6.1.0 + py3.10-beam-v2.77.0rc1: jsonpickle==4.1.2 + py3.10-beam-v2.77.0rc1: numpy==2.2.6 + py3.10-beam-v2.77.0rc1: objsize==0.7.1 + py3.10-beam-v2.77.0rc1: pillow==12.3.0 + py3.10-beam-v2.77.0rc1: proto-plus==1.28.4 + py3.10-beam-v2.77.0rc1: protobuf==6.33.6 + py3.10-beam-v2.77.0rc1: pyarrow==25.0.1 + py3.10-beam-v2.77.0rc1: pymongo==4.18.1 + py3.10-beam-v2.77.0rc1: dnspython==2.8.0 + py3.10-beam-v2.77.0rc1: pyparsing==3.3.3 + py3.10-beam-v2.77.0rc1: python-dateutil==2.9.0.post0 + py3.10-beam-v2.77.0rc1: PyYAML==6.0.3 + py3.10-beam-v2.77.0rc1: requests==2.34.2 + py3.10-beam-v2.77.0rc1: charset-normalizer==3.5.1 + py3.10-beam-v2.77.0rc1: idna==3.20 + py3.10-beam-v2.77.0rc1: typing_extensions==4.16.0 + py3.10-beam-v2.77.0rc1: urllib3==2.8.0 + py3.10-beam-v2.77.0rc1: zstandard==0.25.0 + py3.10-beam-v2.77.0rc1: dill==0.4.1 + py3.10-beam-v2.77.0rc1: certifi==2026.7.22 + py3.10-beam-v2.77.0rc1: cffi==2.1.1 + py3.10-beam-v2.77.0rc1: packaging==26.3 + py3.10-beam-v2.77.0rc1: pytz==2026.3.post1 + py3.10-beam-v2.77.0rc1: six==1.17.0 + py3.10-beam-v2.77.0rc1: sortedcontainers==2.4.0 + py3.10-beam-v2.77.0rc1: multidict==6.9.1 + py3.10-beam-v2.77.0rc1: pycparser==3.0 + + py3.13-beam-v2.77.0rc1: betterproto==2.0.0b6 + py3.13-beam-v2.77.0rc1: beartype==0.22.9 + py3.13-beam-v2.77.0rc1: cryptography==50.0.1 + py3.13-beam-v2.77.0rc1: fastavro==1.12.2 + py3.13-beam-v2.77.0rc1: fasteners==0.20 + py3.13-beam-v2.77.0rc1: grpcio==1.84.0 + py3.13-beam-v2.77.0rc1: grpclib==0.4.9 + py3.13-beam-v2.77.0rc1: h2==4.4.1 + py3.13-beam-v2.77.0rc1: hpack==4.2.0 + py3.13-beam-v2.77.0rc1: httplib2==0.32.0 + py3.13-beam-v2.77.0rc1: hyperframe==6.1.0 + py3.13-beam-v2.77.0rc1: jsonpickle==4.1.2 + py3.13-beam-v2.77.0rc1: numpy==2.4.6 + py3.13-beam-v2.77.0rc1: objsize==0.7.1 + py3.13-beam-v2.77.0rc1: pillow==12.3.0 + py3.13-beam-v2.77.0rc1: proto-plus==1.28.4 + py3.13-beam-v2.77.0rc1: protobuf==6.33.6 + py3.13-beam-v2.77.0rc1: pyarrow==25.0.1 + py3.13-beam-v2.77.0rc1: pymongo==4.18.1 + py3.13-beam-v2.77.0rc1: dnspython==2.8.0 + py3.13-beam-v2.77.0rc1: pyparsing==3.3.3 + py3.13-beam-v2.77.0rc1: python-dateutil==2.9.0.post0 + py3.13-beam-v2.77.0rc1: PyYAML==6.0.3 + py3.13-beam-v2.77.0rc1: requests==2.34.2 + py3.13-beam-v2.77.0rc1: charset-normalizer==3.5.1 + py3.13-beam-v2.77.0rc1: idna==3.20 + py3.13-beam-v2.77.0rc1: typing_extensions==4.16.0 + py3.13-beam-v2.77.0rc1: urllib3==2.8.0 + py3.13-beam-v2.77.0rc1: zstandard==0.25.0 + py3.13-beam-v2.77.0rc1: dill==0.4.1 + py3.13-beam-v2.77.0rc1: certifi==2026.7.22 + py3.13-beam-v2.77.0rc1: cffi==2.1.1 + py3.13-beam-v2.77.0rc1: packaging==26.3 + py3.13-beam-v2.77.0rc1: pytz==2026.3.post1 + py3.13-beam-v2.77.0rc1: six==1.17.0 + py3.13-beam-v2.77.0rc1: sortedcontainers==2.4.0 + py3.13-beam-v2.77.0rc1: multidict==6.9.1 + py3.13-beam-v2.77.0rc1: pycparser==3.0 + beam-latest: apache-beam==2.76.0 beam-latest: betterproto==2.0.0b6 @@ -14819,9 +14080,139 @@ deps = beam: dill beam-v2.76.0: betterproto==2.0.0b6 + beam-v2.77.0rc1: betterproto==2.0.0b6 beam-latest: betterproto==2.0.0b6 - celery-v4.4.7: celery==4.4.7 + celery-v5.0.5: celery==5.0.5 + + celery-v5.2.7: celery==5.2.7 + + py3.9-celery-v5.2.7: newrelic==10.16.0 + py3.9-celery-v5.2.7: billiard==3.6.4.0 + py3.9-celery-v5.2.7: click==8.1.8 + py3.9-celery-v5.2.7: kombu==5.6.2 + py3.9-celery-v5.2.7: vine==5.1.0 + py3.9-celery-v5.2.7: amqp==5.3.1 + py3.9-celery-v5.2.7: redis==7.0.1 + py3.9-celery-v5.2.7: pytest-forked==1.6.0 + py3.9-celery-v5.2.7: async-timeout==5.0.1 + py3.9-celery-v5.2.7: click-didyoumean==0.3.1 + py3.9-celery-v5.2.7: click-plugins==1.1.1.2 + py3.9-celery-v5.2.7: click-repl==0.3.0 + py3.9-celery-v5.2.7: prompt_toolkit==3.0.52 + py3.9-celery-v5.2.7: pytest==8.4.2 + py3.9-celery-v5.2.7: pluggy==1.6.0 + py3.9-celery-v5.2.7: exceptiongroup==1.3.1 + py3.9-celery-v5.2.7: iniconfig==2.1.0 + py3.9-celery-v5.2.7: packaging==26.2 + py3.9-celery-v5.2.7: Pygments==2.20.0 + py3.9-celery-v5.2.7: pytz==2026.3.post1 + py3.9-celery-v5.2.7: tomli==2.4.1 + py3.9-celery-v5.2.7: typing_extensions==4.16.0 + py3.9-celery-v5.2.7: tzdata==2026.3 + py3.9-celery-v5.2.7: py==1.11.0 + py3.9-celery-v5.2.7: wcwidth==0.8.2 + + py3.10-celery-v5.2.7: newrelic==10.16.0 + py3.10-celery-v5.2.7: billiard==3.6.4.0 + py3.10-celery-v5.2.7: click==8.4.2 + py3.10-celery-v5.2.7: kombu==5.6.2 + py3.10-celery-v5.2.7: vine==5.1.0 + py3.10-celery-v5.2.7: amqp==5.3.1 + py3.10-celery-v5.2.7: redis==8.1.0 + py3.10-celery-v5.2.7: pytest-forked==1.6.0 + py3.10-celery-v5.2.7: async-timeout==5.0.1 + py3.10-celery-v5.2.7: click-didyoumean==0.3.1 + py3.10-celery-v5.2.7: click-plugins==1.1.1.2 + py3.10-celery-v5.2.7: click-repl==0.3.0 + py3.10-celery-v5.2.7: prompt_toolkit==3.0.53 + py3.10-celery-v5.2.7: pytest==9.1.1 + py3.10-celery-v5.2.7: pluggy==1.6.0 + py3.10-celery-v5.2.7: exceptiongroup==1.3.1 + py3.10-celery-v5.2.7: iniconfig==2.3.0 + py3.10-celery-v5.2.7: packaging==26.2 + py3.10-celery-v5.2.7: Pygments==2.20.0 + py3.10-celery-v5.2.7: pytz==2026.3.post1 + py3.10-celery-v5.2.7: tomli==2.4.1 + py3.10-celery-v5.2.7: typing_extensions==4.16.0 + py3.10-celery-v5.2.7: tzdata==2026.3 + py3.10-celery-v5.2.7: wcwidth==0.8.2 + py3.10-celery-v5.2.7: py==1.11.0 + + celery-v5.4.0: celery==5.4.0 + + py3.8-celery-v5.4.0: newrelic==10.16.0 + py3.8-celery-v5.4.0: redis==6.1.1 + py3.8-celery-v5.4.0: pytest-forked==1.6.0 + py3.8-celery-v5.4.0: async-timeout==5.0.1 + py3.8-celery-v5.4.0: backports.zoneinfo==0.2.1 + py3.8-celery-v5.4.0: billiard==4.2.4 + py3.8-celery-v5.4.0: click==8.1.8 + py3.8-celery-v5.4.0: click-didyoumean==0.3.1 + py3.8-celery-v5.4.0: click-plugins==1.1.1.2 + py3.8-celery-v5.4.0: click-repl==0.3.0 + py3.8-celery-v5.4.0: kombu==5.5.4 + py3.8-celery-v5.4.0: vine==5.1.0 + py3.8-celery-v5.4.0: pytest==8.3.5 + py3.8-celery-v5.4.0: python-dateutil==2.9.0.post0 + py3.8-celery-v5.4.0: tzdata==2026.3 + py3.8-celery-v5.4.0: py==1.11.0 + py3.8-celery-v5.4.0: amqp==5.3.1 + py3.8-celery-v5.4.0: exceptiongroup==1.3.1 + py3.8-celery-v5.4.0: pluggy==1.5.0 + py3.8-celery-v5.4.0: prompt_toolkit==3.0.52 + py3.8-celery-v5.4.0: six==1.17.0 + py3.8-celery-v5.4.0: tomli==2.4.1 + py3.8-celery-v5.4.0: iniconfig==2.1.0 + py3.8-celery-v5.4.0: packaging==26.2 + py3.8-celery-v5.4.0: typing_extensions==4.13.2 + py3.8-celery-v5.4.0: wcwidth==0.8.2 + + py3.11-celery-v5.4.0: newrelic==10.16.0 + py3.11-celery-v5.4.0: redis==8.1.0 + py3.11-celery-v5.4.0: pytest-forked==1.6.0 + py3.11-celery-v5.4.0: billiard==4.2.4 + py3.11-celery-v5.4.0: click==8.4.2 + py3.11-celery-v5.4.0: click-didyoumean==0.3.1 + py3.11-celery-v5.4.0: click-plugins==1.1.1.2 + py3.11-celery-v5.4.0: click-repl==0.3.0 + py3.11-celery-v5.4.0: kombu==5.6.2 + py3.11-celery-v5.4.0: vine==5.1.0 + py3.11-celery-v5.4.0: pytest==9.1.1 + py3.11-celery-v5.4.0: python-dateutil==2.9.0.post0 + py3.11-celery-v5.4.0: tzdata==2026.3 + py3.11-celery-v5.4.0: py==1.11.0 + py3.11-celery-v5.4.0: amqp==5.3.1 + py3.11-celery-v5.4.0: iniconfig==2.3.0 + py3.11-celery-v5.4.0: packaging==26.2 + py3.11-celery-v5.4.0: pluggy==1.6.0 + py3.11-celery-v5.4.0: prompt_toolkit==3.0.53 + py3.11-celery-v5.4.0: Pygments==2.20.0 + py3.11-celery-v5.4.0: six==1.17.0 + py3.11-celery-v5.4.0: wcwidth==0.8.2 + + py3.12-celery-v5.4.0: newrelic==10.16.0 + py3.12-celery-v5.4.0: billiard==4.2.4 + py3.12-celery-v5.4.0: click==8.4.2 + py3.12-celery-v5.4.0: kombu==5.6.2 + py3.12-celery-v5.4.0: vine==5.1.0 + py3.12-celery-v5.4.0: amqp==5.3.1 + py3.12-celery-v5.4.0: redis==8.1.0 + py3.12-celery-v5.4.0: pytest-forked==1.6.0 + py3.12-celery-v5.4.0: click-didyoumean==0.3.1 + py3.12-celery-v5.4.0: click-plugins==1.1.1.2 + py3.12-celery-v5.4.0: click-repl==0.3.0 + py3.12-celery-v5.4.0: prompt_toolkit==3.0.53 + py3.12-celery-v5.4.0: pytest==9.1.1 + py3.12-celery-v5.4.0: pluggy==1.6.0 + py3.12-celery-v5.4.0: iniconfig==2.3.0 + py3.12-celery-v5.4.0: packaging==26.2 + py3.12-celery-v5.4.0: Pygments==2.20.0 + py3.12-celery-v5.4.0: python-dateutil==2.9.0.post0 + py3.12-celery-v5.4.0: six==1.17.0 + py3.12-celery-v5.4.0: tzdata==2026.3 + py3.12-celery-v5.4.0: wcwidth==0.8.2 + py3.12-celery-v5.4.0: py==1.11.0 celery-v5.6.3: celery==5.6.3 @@ -14901,6 +14292,107 @@ deps = py3.13-celery-v5.6.3: tzdata==2026.2 py3.13-celery-v5.6.3: wcwidth==0.8.2 + celery-v5.7.0a1: celery==5.7.0a1 + + py3.10-celery-v5.7.0a1: billiard==4.3.0 + py3.10-celery-v5.7.0a1: click-repl==0.4.0 + py3.10-celery-v5.7.0a1: newrelic==10.16.0 + py3.10-celery-v5.7.0a1: click==8.5.0 + py3.10-celery-v5.7.0a1: vine==5.1.0 + py3.10-celery-v5.7.0a1: redis==8.1.0 + py3.10-celery-v5.7.0a1: pytest-forked==1.7.5 + py3.10-celery-v5.7.0a1: async-timeout==5.0.1 + py3.10-celery-v5.7.0a1: click-didyoumean==0.3.1 + py3.10-celery-v5.7.0a1: click-plugins==1.1.1.2 + py3.10-celery-v5.7.0a1: exceptiongroup==1.3.1 + py3.10-celery-v5.7.0a1: kombu==5.7.0a1 + py3.10-celery-v5.7.0a1: amqp==5.4.0 + py3.10-celery-v5.7.0a1: prompt_toolkit==3.0.53 + py3.10-celery-v5.7.0a1: pytest==9.1.1 + py3.10-celery-v5.7.0a1: pluggy==1.6.0 + py3.10-celery-v5.7.0a1: iniconfig==2.3.0 + py3.10-celery-v5.7.0a1: packaging==26.3 + py3.10-celery-v5.7.0a1: Pygments==2.21.0 + py3.10-celery-v5.7.0a1: python-dateutil==2.9.0.post0 + py3.10-celery-v5.7.0a1: six==1.17.0 + py3.10-celery-v5.7.0a1: tomli==2.4.1 + py3.10-celery-v5.7.0a1: typing_extensions==4.16.0 + py3.10-celery-v5.7.0a1: tzdata==2026.4 + py3.10-celery-v5.7.0a1: wcwidth==0.8.4 + py3.10-celery-v5.7.0a1: tzlocal==5.4.4 + + py3.13-celery-v5.7.0a1: billiard==4.3.0 + py3.13-celery-v5.7.0a1: click-repl==0.4.0 + py3.13-celery-v5.7.0a1: newrelic==10.16.0 + py3.13-celery-v5.7.0a1: click==8.5.0 + py3.13-celery-v5.7.0a1: vine==5.1.0 + py3.13-celery-v5.7.0a1: redis==8.1.0 + py3.13-celery-v5.7.0a1: pytest-forked==1.7.5 + py3.13-celery-v5.7.0a1: click-didyoumean==0.3.1 + py3.13-celery-v5.7.0a1: click-plugins==1.1.1.2 + py3.13-celery-v5.7.0a1: kombu==5.7.0a1 + py3.13-celery-v5.7.0a1: amqp==5.4.0 + py3.13-celery-v5.7.0a1: prompt_toolkit==3.0.53 + py3.13-celery-v5.7.0a1: pytest==9.1.1 + py3.13-celery-v5.7.0a1: pluggy==1.6.0 + py3.13-celery-v5.7.0a1: iniconfig==2.3.0 + py3.13-celery-v5.7.0a1: packaging==26.3 + py3.13-celery-v5.7.0a1: Pygments==2.21.0 + py3.13-celery-v5.7.0a1: python-dateutil==2.9.0.post0 + py3.13-celery-v5.7.0a1: six==1.17.0 + py3.13-celery-v5.7.0a1: typing_extensions==4.16.0 + py3.13-celery-v5.7.0a1: tzdata==2026.4 + py3.13-celery-v5.7.0a1: wcwidth==0.8.4 + py3.13-celery-v5.7.0a1: tzlocal==5.4.4 + + py3.14-celery-v5.7.0a1: billiard==4.3.0 + py3.14-celery-v5.7.0a1: click-repl==0.4.0 + py3.14-celery-v5.7.0a1: newrelic==10.16.0 + py3.14-celery-v5.7.0a1: click==8.5.0 + py3.14-celery-v5.7.0a1: vine==5.1.0 + py3.14-celery-v5.7.0a1: redis==8.1.0 + py3.14-celery-v5.7.0a1: pytest-forked==1.7.5 + py3.14-celery-v5.7.0a1: click-didyoumean==0.3.1 + py3.14-celery-v5.7.0a1: click-plugins==1.1.1.2 + py3.14-celery-v5.7.0a1: kombu==5.7.0a1 + py3.14-celery-v5.7.0a1: amqp==5.4.0 + py3.14-celery-v5.7.0a1: prompt_toolkit==3.0.53 + py3.14-celery-v5.7.0a1: pytest==9.1.1 + py3.14-celery-v5.7.0a1: pluggy==1.6.0 + py3.14-celery-v5.7.0a1: iniconfig==2.3.0 + py3.14-celery-v5.7.0a1: packaging==26.3 + py3.14-celery-v5.7.0a1: Pygments==2.21.0 + py3.14-celery-v5.7.0a1: python-dateutil==2.9.0.post0 + py3.14-celery-v5.7.0a1: six==1.17.0 + py3.14-celery-v5.7.0a1: typing_extensions==4.16.0 + py3.14-celery-v5.7.0a1: tzdata==2026.4 + py3.14-celery-v5.7.0a1: wcwidth==0.8.4 + py3.14-celery-v5.7.0a1: tzlocal==5.4.4 + + py3.14t-celery-v5.7.0a1: billiard==4.3.0 + py3.14t-celery-v5.7.0a1: click-repl==0.4.0 + py3.14t-celery-v5.7.0a1: newrelic==10.16.0 + py3.14t-celery-v5.7.0a1: click==8.5.0 + py3.14t-celery-v5.7.0a1: vine==5.1.0 + py3.14t-celery-v5.7.0a1: redis==8.1.0 + py3.14t-celery-v5.7.0a1: pytest-forked==1.7.5 + py3.14t-celery-v5.7.0a1: click-didyoumean==0.3.1 + py3.14t-celery-v5.7.0a1: click-plugins==1.1.1.2 + py3.14t-celery-v5.7.0a1: kombu==5.7.0a1 + py3.14t-celery-v5.7.0a1: amqp==5.4.0 + py3.14t-celery-v5.7.0a1: prompt_toolkit==3.0.53 + py3.14t-celery-v5.7.0a1: pytest==9.1.1 + py3.14t-celery-v5.7.0a1: pluggy==1.6.0 + py3.14t-celery-v5.7.0a1: iniconfig==2.3.0 + py3.14t-celery-v5.7.0a1: packaging==26.3 + py3.14t-celery-v5.7.0a1: Pygments==2.21.0 + py3.14t-celery-v5.7.0a1: python-dateutil==2.9.0.post0 + py3.14t-celery-v5.7.0a1: six==1.17.0 + py3.14t-celery-v5.7.0a1: typing_extensions==4.16.0 + py3.14t-celery-v5.7.0a1: tzdata==2026.4 + py3.14t-celery-v5.7.0a1: wcwidth==0.8.4 + py3.14t-celery-v5.7.0a1: tzlocal==5.4.4 + celery-latest: celery==5.6.3 py3.9-celery-latest: newrelic==10.16.0 @@ -14982,7 +14474,6 @@ deps = celery: newrelic<10.17.0 celery: redis celery: pytest-forked - {py3.6}-celery: newrelic<8 {py3.7}-celery: importlib-metadata<5.0 dramatiq-v1.9.0: dramatiq==1.9.0 @@ -15119,9 +14610,7 @@ deps = ray-v2.7.2: setuptools<82 - rq-v0.6.0: rq==0.6.0 - - rq-v0.13.0: rq==0.13.0 + rq-v1.0: rq==1.0 rq-v1.16.2: rq==1.16.2 @@ -15212,10 +14701,7 @@ deps = rq: fakeredis rq-v1.16.2: fakeredis<2.36.0 rq-v2.12.0: fakeredis<2.36.0 - rq-v0.6.0: fakeredis<1.0 - rq-v0.6.0: redis<3.2.2 - rq-v0.13.0: fakeredis>=1.0,<1.7.4 - {py3.6,py3.7}-rq: fakeredis!=2.26.0 + {py3.7}-rq: fakeredis!=2.26.0 rq-latest: fakeredis<2.36.0 spark-v3.0.3: pyspark==3.0.3 @@ -15251,7 +14737,7 @@ deps = # ~~~ Web 1 ~~~ - django-v1.11.29: django==1.11.29 + django-v2.0.13: django==2.0.13 django-v2.2.28: django==2.2.28 @@ -15681,8 +15167,8 @@ deps = django-v6.1.1: django==6.1.1 - py3.12-django-v6.1.1: psycopg2-binary==2.9.12 - py3.12-django-v6.1.1: djangorestframework==3.18.0 + py3.12-django-v6.1.1: psycopg2-binary==2.9.13 + py3.12-django-v6.1.1: djangorestframework==3.18.1 py3.12-django-v6.1.1: pytest-django==4.14.0 py3.12-django-v6.1.1: pytest-forked==1.7.5 py3.12-django-v6.1.1: Werkzeug==3.1.8 @@ -15835,8 +15321,8 @@ deps = django-latest: pytest-asyncio - py3.12-django-latest: psycopg2-binary==2.9.12 - py3.12-django-latest: djangorestframework==3.18.0 + py3.12-django-latest: psycopg2-binary==2.9.13 + py3.12-django-latest: djangorestframework==3.18.1 py3.12-django-latest: pytest-django==4.14.0 py3.12-django-latest: pytest-forked==1.7.5 py3.12-django-latest: Werkzeug==3.1.8 @@ -15996,28 +15482,36 @@ deps = django-v4.2.30: pytest-asyncio django-v5.2.17: pytest-asyncio django-v6.1.1: pytest-asyncio - django-v1.11.29: djangorestframework>=3.0,<4.0 - django-v1.11.29: Werkzeug<2.1.0 + django-v2.0.13: djangorestframework>=3.0,<4.0 + django-v2.0.13: Werkzeug<2.1.0 django-v2.2.28: djangorestframework>=3.0,<4.0 django-v2.2.28: Werkzeug<2.1.0 django-v3.2.25: djangorestframework>=3.0,<4.0 django-v3.2.25: Werkzeug<2.1.0 - django-v1.11.29: pytest-django<4.0 - django-v1.11.29: six + django-v2.0.13: pytest-django<4.0 + django-v2.0.13: six django-v2.2.28: pytest-django<4.0 django-v2.2.28: six {py3.14,py3.14t}-django: coverage==7.11.0 django-latest: pytest-asyncio - flask-v1.1.4: flask==1.1.4 + flask-v2.0.3: flask==2.0.3 + + py3.9-flask-v2.0.3: Werkzeug==2.2.3 + py3.9-flask-v2.0.3: Flask-Login==0.6.3 + py3.9-flask-v2.0.3: blinker==1.9.0 + py3.9-flask-v2.0.3: click==8.1.8 + py3.9-flask-v2.0.3: itsdangerous==2.2.0 + py3.9-flask-v2.0.3: Jinja2==3.1.6 + py3.9-flask-v2.0.3: MarkupSafe==3.0.3 - py3.8-flask-v1.1.4: Flask-Login==0.6.3 - py3.8-flask-v1.1.4: Werkzeug==1.0.1 - py3.8-flask-v1.1.4: blinker==1.8.2 - py3.8-flask-v1.1.4: MarkupSafe==1.1.1 - py3.8-flask-v1.1.4: itsdangerous==1.1.0 - py3.8-flask-v1.1.4: Jinja2==2.11.3 - py3.8-flask-v1.1.4: click==7.1.2 + py3.10-flask-v2.0.3: Werkzeug==2.2.3 + py3.10-flask-v2.0.3: Flask-Login==0.6.3 + py3.10-flask-v2.0.3: blinker==1.9.0 + py3.10-flask-v2.0.3: click==8.4.2 + py3.10-flask-v2.0.3: itsdangerous==2.2.0 + py3.10-flask-v2.0.3: Jinja2==3.1.6 + py3.10-flask-v2.0.3: MarkupSafe==3.0.3 flask-v2.3.3: flask==2.3.3 @@ -16130,61 +15624,58 @@ deps = flask: flask-login flask: werkzeug flask: blinker - flask-v1.1.4: werkzeug<2.1.0 - flask-v1.1.4: markupsafe<2.0.0 - flask-v1.1.4: itsdangerous>=0.24,<2.0 - flask-v1.1.4: jinja2<3.1.1 - {py3.6,py3.7}-flask: setuptools<82 - - starlette-v0.16.0: starlette==0.16.0 - - py3.9-starlette-v0.16.0: anyio==3.7.1 - py3.9-starlette-v0.16.0: httpx==0.27.2 - py3.9-starlette-v0.16.0: httpcore==1.0.9 - py3.9-starlette-v0.16.0: pytest-asyncio==1.2.0 - py3.9-starlette-v0.16.0: backports.asyncio.runner==1.2.0 - py3.9-starlette-v0.16.0: pytest==8.4.2 - py3.9-starlette-v0.16.0: pluggy==1.6.0 - py3.9-starlette-v0.16.0: python-multipart==0.0.20 - py3.9-starlette-v0.16.0: requests==2.32.5 - py3.9-starlette-v0.16.0: charset-normalizer==3.4.7 - py3.9-starlette-v0.16.0: idna==3.18 - py3.9-starlette-v0.16.0: urllib3==2.6.3 - py3.9-starlette-v0.16.0: Jinja2==3.1.6 - py3.9-starlette-v0.16.0: certifi==2026.6.17 - py3.9-starlette-v0.16.0: exceptiongroup==1.3.1 - py3.9-starlette-v0.16.0: h11==0.16.0 - py3.9-starlette-v0.16.0: iniconfig==2.1.0 - py3.9-starlette-v0.16.0: MarkupSafe==3.0.3 - py3.9-starlette-v0.16.0: packaging==26.2 - py3.9-starlette-v0.16.0: Pygments==2.20.0 - py3.9-starlette-v0.16.0: sniffio==1.3.1 - py3.9-starlette-v0.16.0: tomli==2.4.1 - py3.9-starlette-v0.16.0: typing_extensions==4.16.0 - - py3.10-starlette-v0.16.0: anyio==3.7.1 - py3.10-starlette-v0.16.0: httpx==0.27.2 - py3.10-starlette-v0.16.0: httpcore==1.0.9 - py3.10-starlette-v0.16.0: pytest-asyncio==1.4.0 - py3.10-starlette-v0.16.0: backports.asyncio.runner==1.2.0 - py3.10-starlette-v0.16.0: pytest==9.1.1 - py3.10-starlette-v0.16.0: pluggy==1.6.0 - py3.10-starlette-v0.16.0: python-multipart==0.0.32 - py3.10-starlette-v0.16.0: requests==2.34.2 - py3.10-starlette-v0.16.0: charset-normalizer==3.4.7 - py3.10-starlette-v0.16.0: idna==3.18 - py3.10-starlette-v0.16.0: urllib3==2.7.0 - py3.10-starlette-v0.16.0: Jinja2==3.1.6 - py3.10-starlette-v0.16.0: certifi==2026.6.17 - py3.10-starlette-v0.16.0: exceptiongroup==1.3.1 - py3.10-starlette-v0.16.0: h11==0.16.0 - py3.10-starlette-v0.16.0: iniconfig==2.3.0 - py3.10-starlette-v0.16.0: MarkupSafe==3.0.3 - py3.10-starlette-v0.16.0: packaging==26.2 - py3.10-starlette-v0.16.0: Pygments==2.20.0 - py3.10-starlette-v0.16.0: sniffio==1.3.1 - py3.10-starlette-v0.16.0: tomli==2.4.1 - py3.10-starlette-v0.16.0: typing_extensions==4.16.0 + flask-v2.0.3: werkzeug<2.3 + {py3.7}-flask: setuptools<82 + + starlette-v0.20.4: starlette==0.20.4 + + py3.9-starlette-v0.20.4: anyio==3.7.1 + py3.9-starlette-v0.20.4: httpx==0.27.2 + py3.9-starlette-v0.20.4: httpcore==1.0.9 + py3.9-starlette-v0.20.4: pytest-asyncio==1.2.0 + py3.9-starlette-v0.20.4: backports.asyncio.runner==1.2.0 + py3.9-starlette-v0.20.4: pytest==8.4.2 + py3.9-starlette-v0.20.4: pluggy==1.6.0 + py3.9-starlette-v0.20.4: python-multipart==0.0.20 + py3.9-starlette-v0.20.4: requests==2.32.5 + py3.9-starlette-v0.20.4: charset-normalizer==3.4.9 + py3.9-starlette-v0.20.4: idna==3.18 + py3.9-starlette-v0.20.4: urllib3==2.6.3 + py3.9-starlette-v0.20.4: Jinja2==3.1.6 + py3.9-starlette-v0.20.4: certifi==2026.7.22 + py3.9-starlette-v0.20.4: exceptiongroup==1.3.1 + py3.9-starlette-v0.20.4: h11==0.16.0 + py3.9-starlette-v0.20.4: iniconfig==2.1.0 + py3.9-starlette-v0.20.4: MarkupSafe==3.0.3 + py3.9-starlette-v0.20.4: packaging==26.3 + py3.9-starlette-v0.20.4: Pygments==2.20.0 + py3.9-starlette-v0.20.4: sniffio==1.3.1 + py3.9-starlette-v0.20.4: tomli==2.4.1 + py3.9-starlette-v0.20.4: typing_extensions==4.16.0 + + py3.10-starlette-v0.20.4: anyio==3.7.1 + py3.10-starlette-v0.20.4: httpx==0.27.2 + py3.10-starlette-v0.20.4: httpcore==1.0.9 + py3.10-starlette-v0.20.4: pytest-asyncio==1.4.0 + py3.10-starlette-v0.20.4: backports.asyncio.runner==1.2.0 + py3.10-starlette-v0.20.4: pytest==9.1.1 + py3.10-starlette-v0.20.4: pluggy==1.6.0 + py3.10-starlette-v0.20.4: python-multipart==0.0.32 + py3.10-starlette-v0.20.4: requests==2.34.2 + py3.10-starlette-v0.20.4: charset-normalizer==3.4.9 + py3.10-starlette-v0.20.4: idna==3.18 + py3.10-starlette-v0.20.4: urllib3==2.7.0 + py3.10-starlette-v0.20.4: Jinja2==3.1.6 + py3.10-starlette-v0.20.4: certifi==2026.7.22 + py3.10-starlette-v0.20.4: exceptiongroup==1.3.1 + py3.10-starlette-v0.20.4: h11==0.16.0 + py3.10-starlette-v0.20.4: iniconfig==2.3.0 + py3.10-starlette-v0.20.4: MarkupSafe==3.0.3 + py3.10-starlette-v0.20.4: packaging==26.3 + py3.10-starlette-v0.20.4: Pygments==2.20.0 + py3.10-starlette-v0.20.4: sniffio==1.3.1 + py3.10-starlette-v0.20.4: tomli==2.4.1 + py3.10-starlette-v0.20.4: typing_extensions==4.16.0 starlette-v0.52.1: starlette==0.52.1 @@ -16450,226 +15941,251 @@ deps = starlette: anyio<4.0.0 starlette: jinja2 starlette: httpx - starlette-v0.16.0: httpx<0.28.0 - {py3.6}-starlette: aiocontextvars - - fastapi-v0.79.1: fastapi==0.79.1 - - py3.9-fastapi-v0.79.1: starlette==0.19.1 - py3.9-fastapi-v0.79.1: httpx==0.27.2 - py3.9-fastapi-v0.79.1: anyio==3.7.1 - py3.9-fastapi-v0.79.1: httpcore==1.0.9 - py3.9-fastapi-v0.79.1: pydantic==1.10.26 - py3.9-fastapi-v0.79.1: pytest-asyncio==1.2.0 - py3.9-fastapi-v0.79.1: backports.asyncio.runner==1.2.0 - py3.9-fastapi-v0.79.1: pytest==8.4.2 - py3.9-fastapi-v0.79.1: pluggy==1.6.0 - py3.9-fastapi-v0.79.1: python-multipart==0.0.20 - py3.9-fastapi-v0.79.1: requests==2.32.5 - py3.9-fastapi-v0.79.1: charset-normalizer==3.4.7 - py3.9-fastapi-v0.79.1: idna==3.18 - py3.9-fastapi-v0.79.1: urllib3==2.6.3 - py3.9-fastapi-v0.79.1: Jinja2==3.1.6 - py3.9-fastapi-v0.79.1: certifi==2026.6.17 - py3.9-fastapi-v0.79.1: exceptiongroup==1.3.1 - py3.9-fastapi-v0.79.1: h11==0.16.0 - py3.9-fastapi-v0.79.1: iniconfig==2.1.0 - py3.9-fastapi-v0.79.1: MarkupSafe==3.0.3 - py3.9-fastapi-v0.79.1: packaging==26.2 - py3.9-fastapi-v0.79.1: Pygments==2.20.0 - py3.9-fastapi-v0.79.1: sniffio==1.3.1 - py3.9-fastapi-v0.79.1: tomli==2.4.1 - py3.9-fastapi-v0.79.1: typing_extensions==4.16.0 - - py3.10-fastapi-v0.79.1: starlette==0.19.1 - py3.10-fastapi-v0.79.1: httpx==0.27.2 - py3.10-fastapi-v0.79.1: anyio==3.7.1 - py3.10-fastapi-v0.79.1: httpcore==1.0.9 - py3.10-fastapi-v0.79.1: pydantic==1.10.26 - py3.10-fastapi-v0.79.1: pytest-asyncio==1.4.0 - py3.10-fastapi-v0.79.1: backports.asyncio.runner==1.2.0 - py3.10-fastapi-v0.79.1: pytest==9.1.1 - py3.10-fastapi-v0.79.1: pluggy==1.6.0 - py3.10-fastapi-v0.79.1: python-multipart==0.0.32 - py3.10-fastapi-v0.79.1: requests==2.34.2 - py3.10-fastapi-v0.79.1: charset-normalizer==3.4.7 - py3.10-fastapi-v0.79.1: idna==3.18 - py3.10-fastapi-v0.79.1: urllib3==2.7.0 - py3.10-fastapi-v0.79.1: Jinja2==3.1.6 - py3.10-fastapi-v0.79.1: certifi==2026.6.17 - py3.10-fastapi-v0.79.1: exceptiongroup==1.3.1 - py3.10-fastapi-v0.79.1: h11==0.16.0 - py3.10-fastapi-v0.79.1: iniconfig==2.3.0 - py3.10-fastapi-v0.79.1: MarkupSafe==3.0.3 - py3.10-fastapi-v0.79.1: packaging==26.2 - py3.10-fastapi-v0.79.1: Pygments==2.20.0 - py3.10-fastapi-v0.79.1: sniffio==1.3.1 - py3.10-fastapi-v0.79.1: tomli==2.4.1 - py3.10-fastapi-v0.79.1: typing_extensions==4.16.0 - - fastapi-v0.100.1: fastapi==0.100.1 - - py3.10-fastapi-v0.100.1: httpx==0.27.2 - py3.10-fastapi-v0.100.1: anyio==4.14.2 - py3.10-fastapi-v0.100.1: httpcore==1.0.9 - py3.10-fastapi-v0.100.1: pydantic==2.13.4 - py3.10-fastapi-v0.100.1: pydantic_core==2.46.4 - py3.10-fastapi-v0.100.1: starlette==0.27.0 - py3.10-fastapi-v0.100.1: pytest-asyncio==1.4.0 - py3.10-fastapi-v0.100.1: backports.asyncio.runner==1.2.0 - py3.10-fastapi-v0.100.1: pytest==9.1.1 - py3.10-fastapi-v0.100.1: pluggy==1.6.0 - py3.10-fastapi-v0.100.1: python-multipart==0.0.32 - py3.10-fastapi-v0.100.1: requests==2.34.2 - py3.10-fastapi-v0.100.1: charset-normalizer==3.4.9 - py3.10-fastapi-v0.100.1: idna==3.18 - py3.10-fastapi-v0.100.1: urllib3==2.7.0 - py3.10-fastapi-v0.100.1: Jinja2==3.1.6 - py3.10-fastapi-v0.100.1: annotated-types==0.8.0 - py3.10-fastapi-v0.100.1: certifi==2026.7.22 - py3.10-fastapi-v0.100.1: exceptiongroup==1.3.1 - py3.10-fastapi-v0.100.1: h11==0.16.0 - py3.10-fastapi-v0.100.1: iniconfig==2.3.0 - py3.10-fastapi-v0.100.1: MarkupSafe==3.0.3 - py3.10-fastapi-v0.100.1: packaging==26.2 - py3.10-fastapi-v0.100.1: Pygments==2.20.0 - py3.10-fastapi-v0.100.1: tomli==2.4.1 - py3.10-fastapi-v0.100.1: typing_extensions==4.16.0 - py3.10-fastapi-v0.100.1: typing-inspection==0.4.2 - py3.10-fastapi-v0.100.1: sniffio==1.3.1 - - py3.11-fastapi-v0.100.1: httpx==0.27.2 - py3.11-fastapi-v0.100.1: anyio==4.14.2 - py3.11-fastapi-v0.100.1: httpcore==1.0.9 - py3.11-fastapi-v0.100.1: pydantic==2.13.4 - py3.11-fastapi-v0.100.1: pydantic_core==2.46.4 - py3.11-fastapi-v0.100.1: starlette==0.27.0 - py3.11-fastapi-v0.100.1: pytest-asyncio==1.4.0 - py3.11-fastapi-v0.100.1: pytest==9.1.1 - py3.11-fastapi-v0.100.1: pluggy==1.6.0 - py3.11-fastapi-v0.100.1: python-multipart==0.0.32 - py3.11-fastapi-v0.100.1: requests==2.34.2 - py3.11-fastapi-v0.100.1: charset-normalizer==3.4.9 - py3.11-fastapi-v0.100.1: idna==3.18 - py3.11-fastapi-v0.100.1: urllib3==2.7.0 - py3.11-fastapi-v0.100.1: Jinja2==3.1.6 - py3.11-fastapi-v0.100.1: annotated-types==0.8.0 - py3.11-fastapi-v0.100.1: certifi==2026.7.22 - py3.11-fastapi-v0.100.1: h11==0.16.0 - py3.11-fastapi-v0.100.1: iniconfig==2.3.0 - py3.11-fastapi-v0.100.1: MarkupSafe==3.0.3 - py3.11-fastapi-v0.100.1: packaging==26.2 - py3.11-fastapi-v0.100.1: Pygments==2.20.0 - py3.11-fastapi-v0.100.1: typing_extensions==4.16.0 - py3.11-fastapi-v0.100.1: typing-inspection==0.4.2 - py3.11-fastapi-v0.100.1: sniffio==1.3.1 - - fastapi-v0.121.3: fastapi==0.121.3 - - py3.8-fastapi-v0.121.3: httpx==0.28.1 - py3.8-fastapi-v0.121.3: httpcore==1.0.9 - py3.8-fastapi-v0.121.3: pytest-asyncio==0.24.0 - py3.8-fastapi-v0.121.3: python-multipart==0.0.20 - py3.8-fastapi-v0.121.3: requests==2.32.4 - py3.8-fastapi-v0.121.3: anyio==4.5.2 - py3.8-fastapi-v0.121.3: Jinja2==3.1.6 - py3.8-fastapi-v0.121.3: annotated-doc==0.0.4 - py3.8-fastapi-v0.121.3: certifi==2026.7.22 - py3.8-fastapi-v0.121.3: charset-normalizer==3.4.9 - py3.8-fastapi-v0.121.3: exceptiongroup==1.3.1 - py3.8-fastapi-v0.121.3: idna==3.15 - py3.8-fastapi-v0.121.3: MarkupSafe==2.1.5 - py3.8-fastapi-v0.121.3: pydantic==2.10.6 - py3.8-fastapi-v0.121.3: pydantic_core==2.27.2 - py3.8-fastapi-v0.121.3: pytest==8.3.5 - py3.8-fastapi-v0.121.3: sniffio==1.3.1 - py3.8-fastapi-v0.121.3: starlette==0.44.0 - py3.8-fastapi-v0.121.3: typing_extensions==4.13.2 - py3.8-fastapi-v0.121.3: urllib3==2.2.3 - py3.8-fastapi-v0.121.3: annotated-types==0.7.0 - py3.8-fastapi-v0.121.3: h11==0.16.0 - py3.8-fastapi-v0.121.3: pluggy==1.5.0 - py3.8-fastapi-v0.121.3: tomli==2.4.1 - py3.8-fastapi-v0.121.3: iniconfig==2.1.0 - py3.8-fastapi-v0.121.3: packaging==26.2 - - py3.13-fastapi-v0.121.3: anyio==4.14.2 - py3.13-fastapi-v0.121.3: pydantic==2.13.4 - py3.13-fastapi-v0.121.3: pydantic_core==2.46.4 - py3.13-fastapi-v0.121.3: starlette==0.50.0 - py3.13-fastapi-v0.121.3: httpx==0.28.1 - py3.13-fastapi-v0.121.3: httpcore==1.0.9 - py3.13-fastapi-v0.121.3: pytest-asyncio==1.4.0 - py3.13-fastapi-v0.121.3: pytest==9.1.1 - py3.13-fastapi-v0.121.3: pluggy==1.6.0 - py3.13-fastapi-v0.121.3: python-multipart==0.0.32 - py3.13-fastapi-v0.121.3: requests==2.34.2 - py3.13-fastapi-v0.121.3: charset-normalizer==3.4.9 - py3.13-fastapi-v0.121.3: idna==3.18 - py3.13-fastapi-v0.121.3: urllib3==2.7.0 - py3.13-fastapi-v0.121.3: Jinja2==3.1.6 - py3.13-fastapi-v0.121.3: annotated-doc==0.0.5 - py3.13-fastapi-v0.121.3: annotated-types==0.8.0 - py3.13-fastapi-v0.121.3: certifi==2026.7.22 - py3.13-fastapi-v0.121.3: h11==0.16.0 - py3.13-fastapi-v0.121.3: iniconfig==2.3.0 - py3.13-fastapi-v0.121.3: MarkupSafe==3.0.3 - py3.13-fastapi-v0.121.3: packaging==26.2 - py3.13-fastapi-v0.121.3: Pygments==2.20.0 - py3.13-fastapi-v0.121.3: typing_extensions==4.16.0 - py3.13-fastapi-v0.121.3: typing-inspection==0.4.2 - - py3.14-fastapi-v0.121.3: anyio==4.14.2 - py3.14-fastapi-v0.121.3: pydantic==2.13.4 - py3.14-fastapi-v0.121.3: pydantic_core==2.46.4 - py3.14-fastapi-v0.121.3: starlette==0.50.0 - py3.14-fastapi-v0.121.3: httpx==0.28.1 - py3.14-fastapi-v0.121.3: httpcore==1.0.9 - py3.14-fastapi-v0.121.3: pytest-asyncio==1.4.0 - py3.14-fastapi-v0.121.3: pytest==9.1.1 - py3.14-fastapi-v0.121.3: pluggy==1.6.0 - py3.14-fastapi-v0.121.3: python-multipart==0.0.32 - py3.14-fastapi-v0.121.3: requests==2.34.2 - py3.14-fastapi-v0.121.3: charset-normalizer==3.4.9 - py3.14-fastapi-v0.121.3: idna==3.18 - py3.14-fastapi-v0.121.3: urllib3==2.7.0 - py3.14-fastapi-v0.121.3: Jinja2==3.1.6 - py3.14-fastapi-v0.121.3: annotated-doc==0.0.5 - py3.14-fastapi-v0.121.3: annotated-types==0.8.0 - py3.14-fastapi-v0.121.3: certifi==2026.7.22 - py3.14-fastapi-v0.121.3: h11==0.16.0 - py3.14-fastapi-v0.121.3: iniconfig==2.3.0 - py3.14-fastapi-v0.121.3: MarkupSafe==3.0.3 - py3.14-fastapi-v0.121.3: packaging==26.2 - py3.14-fastapi-v0.121.3: Pygments==2.20.0 - py3.14-fastapi-v0.121.3: typing_extensions==4.16.0 - py3.14-fastapi-v0.121.3: typing-inspection==0.4.2 - - py3.14t-fastapi-v0.121.3: anyio==4.14.2 - py3.14t-fastapi-v0.121.3: pydantic==2.13.4 - py3.14t-fastapi-v0.121.3: pydantic_core==2.46.4 - py3.14t-fastapi-v0.121.3: starlette==0.50.0 - py3.14t-fastapi-v0.121.3: httpx==0.28.1 - py3.14t-fastapi-v0.121.3: httpcore==1.0.9 - py3.14t-fastapi-v0.121.3: pytest-asyncio==1.4.0 - py3.14t-fastapi-v0.121.3: pytest==9.1.1 - py3.14t-fastapi-v0.121.3: pluggy==1.6.0 - py3.14t-fastapi-v0.121.3: python-multipart==0.0.32 - py3.14t-fastapi-v0.121.3: requests==2.34.2 - py3.14t-fastapi-v0.121.3: charset-normalizer==3.4.9 - py3.14t-fastapi-v0.121.3: idna==3.18 - py3.14t-fastapi-v0.121.3: urllib3==2.7.0 - py3.14t-fastapi-v0.121.3: Jinja2==3.1.6 - py3.14t-fastapi-v0.121.3: annotated-doc==0.0.5 - py3.14t-fastapi-v0.121.3: annotated-types==0.8.0 - py3.14t-fastapi-v0.121.3: certifi==2026.7.22 - py3.14t-fastapi-v0.121.3: h11==0.16.0 - py3.14t-fastapi-v0.121.3: iniconfig==2.3.0 - py3.14t-fastapi-v0.121.3: MarkupSafe==3.0.3 - py3.14t-fastapi-v0.121.3: packaging==26.2 - py3.14t-fastapi-v0.121.3: Pygments==2.20.0 - py3.14t-fastapi-v0.121.3: typing_extensions==4.16.0 - py3.14t-fastapi-v0.121.3: typing-inspection==0.4.2 + starlette-v0.20.4: httpx<0.28.0 + + fastapi-v0.85.2: fastapi==0.85.2 + + py3.9-fastapi-v0.85.2: starlette==0.20.4 + py3.9-fastapi-v0.85.2: httpx==0.27.2 + py3.9-fastapi-v0.85.2: anyio==3.7.1 + py3.9-fastapi-v0.85.2: urllib3==1.26.20 + py3.9-fastapi-v0.85.2: httpcore==1.0.9 + py3.9-fastapi-v0.85.2: pydantic==1.10.26 + py3.9-fastapi-v0.85.2: pytest-asyncio==1.2.0 + py3.9-fastapi-v0.85.2: backports.asyncio.runner==1.2.0 + py3.9-fastapi-v0.85.2: pytest==8.4.2 + py3.9-fastapi-v0.85.2: pluggy==1.6.0 + py3.9-fastapi-v0.85.2: python-multipart==0.0.20 + py3.9-fastapi-v0.85.2: requests==2.32.5 + py3.9-fastapi-v0.85.2: charset-normalizer==3.4.9 + py3.9-fastapi-v0.85.2: idna==3.18 + py3.9-fastapi-v0.85.2: Jinja2==3.1.6 + py3.9-fastapi-v0.85.2: certifi==2026.7.22 + py3.9-fastapi-v0.85.2: exceptiongroup==1.3.1 + py3.9-fastapi-v0.85.2: h11==0.16.0 + py3.9-fastapi-v0.85.2: iniconfig==2.1.0 + py3.9-fastapi-v0.85.2: MarkupSafe==3.0.3 + py3.9-fastapi-v0.85.2: packaging==26.3 + py3.9-fastapi-v0.85.2: Pygments==2.20.0 + py3.9-fastapi-v0.85.2: sniffio==1.3.1 + py3.9-fastapi-v0.85.2: tomli==2.4.1 + py3.9-fastapi-v0.85.2: typing_extensions==4.16.0 + + py3.10-fastapi-v0.85.2: starlette==0.20.4 + py3.10-fastapi-v0.85.2: httpx==0.27.2 + py3.10-fastapi-v0.85.2: anyio==3.7.1 + py3.10-fastapi-v0.85.2: urllib3==1.26.20 + py3.10-fastapi-v0.85.2: httpcore==1.0.9 + py3.10-fastapi-v0.85.2: pydantic==1.10.26 + py3.10-fastapi-v0.85.2: pytest-asyncio==1.4.0 + py3.10-fastapi-v0.85.2: backports.asyncio.runner==1.2.0 + py3.10-fastapi-v0.85.2: pytest==9.1.1 + py3.10-fastapi-v0.85.2: pluggy==1.6.0 + py3.10-fastapi-v0.85.2: python-multipart==0.0.32 + py3.10-fastapi-v0.85.2: requests==2.34.2 + py3.10-fastapi-v0.85.2: charset-normalizer==3.4.9 + py3.10-fastapi-v0.85.2: idna==3.18 + py3.10-fastapi-v0.85.2: Jinja2==3.1.6 + py3.10-fastapi-v0.85.2: certifi==2026.7.22 + py3.10-fastapi-v0.85.2: exceptiongroup==1.3.1 + py3.10-fastapi-v0.85.2: h11==0.16.0 + py3.10-fastapi-v0.85.2: iniconfig==2.3.0 + py3.10-fastapi-v0.85.2: MarkupSafe==3.0.3 + py3.10-fastapi-v0.85.2: packaging==26.3 + py3.10-fastapi-v0.85.2: Pygments==2.20.0 + py3.10-fastapi-v0.85.2: sniffio==1.3.1 + py3.10-fastapi-v0.85.2: tomli==2.4.1 + py3.10-fastapi-v0.85.2: typing_extensions==4.16.0 + + fastapi-v0.104.1: fastapi==0.104.1 + + py3.8-fastapi-v0.104.1: httpx==0.27.2 + py3.8-fastapi-v0.104.1: httpcore==1.0.9 + py3.8-fastapi-v0.104.1: pytest-asyncio==0.24.0 + py3.8-fastapi-v0.104.1: python-multipart==0.0.20 + py3.8-fastapi-v0.104.1: requests==2.32.4 + py3.8-fastapi-v0.104.1: anyio==3.7.1 + py3.8-fastapi-v0.104.1: Jinja2==3.1.6 + py3.8-fastapi-v0.104.1: certifi==2026.7.22 + py3.8-fastapi-v0.104.1: charset-normalizer==3.4.9 + py3.8-fastapi-v0.104.1: idna==3.15 + py3.8-fastapi-v0.104.1: MarkupSafe==2.1.5 + py3.8-fastapi-v0.104.1: pydantic==2.10.6 + py3.8-fastapi-v0.104.1: pydantic_core==2.27.2 + py3.8-fastapi-v0.104.1: pytest==8.3.5 + py3.8-fastapi-v0.104.1: exceptiongroup==1.3.1 + py3.8-fastapi-v0.104.1: sniffio==1.3.1 + py3.8-fastapi-v0.104.1: starlette==0.27.0 + py3.8-fastapi-v0.104.1: typing_extensions==4.13.2 + py3.8-fastapi-v0.104.1: urllib3==2.2.3 + py3.8-fastapi-v0.104.1: annotated-types==0.7.0 + py3.8-fastapi-v0.104.1: h11==0.16.0 + py3.8-fastapi-v0.104.1: pluggy==1.5.0 + py3.8-fastapi-v0.104.1: tomli==2.4.1 + py3.8-fastapi-v0.104.1: iniconfig==2.1.0 + py3.8-fastapi-v0.104.1: packaging==26.2 + + py3.10-fastapi-v0.104.1: httpx==0.27.2 + py3.10-fastapi-v0.104.1: anyio==3.7.1 + py3.10-fastapi-v0.104.1: httpcore==1.0.9 + py3.10-fastapi-v0.104.1: pydantic==2.13.4 + py3.10-fastapi-v0.104.1: pydantic_core==2.46.4 + py3.10-fastapi-v0.104.1: starlette==0.27.0 + py3.10-fastapi-v0.104.1: pytest-asyncio==1.4.0 + py3.10-fastapi-v0.104.1: backports.asyncio.runner==1.2.0 + py3.10-fastapi-v0.104.1: pytest==9.1.1 + py3.10-fastapi-v0.104.1: pluggy==1.6.0 + py3.10-fastapi-v0.104.1: python-multipart==0.0.32 + py3.10-fastapi-v0.104.1: requests==2.34.2 + py3.10-fastapi-v0.104.1: charset-normalizer==3.4.9 + py3.10-fastapi-v0.104.1: idna==3.18 + py3.10-fastapi-v0.104.1: urllib3==2.7.0 + py3.10-fastapi-v0.104.1: Jinja2==3.1.6 + py3.10-fastapi-v0.104.1: annotated-types==0.8.0 + py3.10-fastapi-v0.104.1: certifi==2026.7.22 + py3.10-fastapi-v0.104.1: exceptiongroup==1.3.1 + py3.10-fastapi-v0.104.1: h11==0.16.0 + py3.10-fastapi-v0.104.1: iniconfig==2.3.0 + py3.10-fastapi-v0.104.1: MarkupSafe==3.0.3 + py3.10-fastapi-v0.104.1: packaging==26.3 + py3.10-fastapi-v0.104.1: Pygments==2.20.0 + py3.10-fastapi-v0.104.1: sniffio==1.3.1 + py3.10-fastapi-v0.104.1: tomli==2.4.1 + py3.10-fastapi-v0.104.1: typing_extensions==4.16.0 + py3.10-fastapi-v0.104.1: typing-inspection==0.4.2 + + py3.11-fastapi-v0.104.1: httpx==0.27.2 + py3.11-fastapi-v0.104.1: httpcore==1.0.9 + py3.11-fastapi-v0.104.1: pytest-asyncio==1.4.0 + py3.11-fastapi-v0.104.1: python-multipart==0.0.32 + py3.11-fastapi-v0.104.1: requests==2.34.2 + py3.11-fastapi-v0.104.1: anyio==3.7.1 + py3.11-fastapi-v0.104.1: Jinja2==3.1.6 + py3.11-fastapi-v0.104.1: certifi==2026.7.22 + py3.11-fastapi-v0.104.1: charset-normalizer==3.4.9 + py3.11-fastapi-v0.104.1: idna==3.18 + py3.11-fastapi-v0.104.1: MarkupSafe==3.0.3 + py3.11-fastapi-v0.104.1: pydantic==2.13.4 + py3.11-fastapi-v0.104.1: pydantic_core==2.46.4 + py3.11-fastapi-v0.104.1: pytest==9.1.1 + py3.11-fastapi-v0.104.1: sniffio==1.3.1 + py3.11-fastapi-v0.104.1: starlette==0.27.0 + py3.11-fastapi-v0.104.1: typing_extensions==4.16.0 + py3.11-fastapi-v0.104.1: urllib3==2.7.0 + py3.11-fastapi-v0.104.1: annotated-types==0.8.0 + py3.11-fastapi-v0.104.1: h11==0.16.0 + py3.11-fastapi-v0.104.1: iniconfig==2.3.0 + py3.11-fastapi-v0.104.1: packaging==26.3 + py3.11-fastapi-v0.104.1: pluggy==1.6.0 + py3.11-fastapi-v0.104.1: Pygments==2.20.0 + py3.11-fastapi-v0.104.1: typing-inspection==0.4.2 + + fastapi-v0.123.10: fastapi==0.123.10 + + py3.8-fastapi-v0.123.10: httpx==0.28.1 + py3.8-fastapi-v0.123.10: httpcore==1.0.9 + py3.8-fastapi-v0.123.10: pytest-asyncio==0.24.0 + py3.8-fastapi-v0.123.10: python-multipart==0.0.20 + py3.8-fastapi-v0.123.10: requests==2.32.4 + py3.8-fastapi-v0.123.10: anyio==4.5.2 + py3.8-fastapi-v0.123.10: Jinja2==3.1.6 + py3.8-fastapi-v0.123.10: annotated-doc==0.0.4 + py3.8-fastapi-v0.123.10: certifi==2026.7.22 + py3.8-fastapi-v0.123.10: charset-normalizer==3.4.9 + py3.8-fastapi-v0.123.10: exceptiongroup==1.3.1 + py3.8-fastapi-v0.123.10: idna==3.15 + py3.8-fastapi-v0.123.10: MarkupSafe==2.1.5 + py3.8-fastapi-v0.123.10: pydantic==2.10.6 + py3.8-fastapi-v0.123.10: pydantic_core==2.27.2 + py3.8-fastapi-v0.123.10: pytest==8.3.5 + py3.8-fastapi-v0.123.10: sniffio==1.3.1 + py3.8-fastapi-v0.123.10: starlette==0.44.0 + py3.8-fastapi-v0.123.10: typing_extensions==4.13.2 + py3.8-fastapi-v0.123.10: urllib3==2.2.3 + py3.8-fastapi-v0.123.10: annotated-types==0.7.0 + py3.8-fastapi-v0.123.10: h11==0.16.0 + py3.8-fastapi-v0.123.10: pluggy==1.5.0 + py3.8-fastapi-v0.123.10: tomli==2.4.1 + py3.8-fastapi-v0.123.10: iniconfig==2.1.0 + py3.8-fastapi-v0.123.10: packaging==26.2 + + py3.13-fastapi-v0.123.10: anyio==4.14.2 + py3.13-fastapi-v0.123.10: pydantic==2.13.4 + py3.13-fastapi-v0.123.10: pydantic_core==2.46.4 + py3.13-fastapi-v0.123.10: starlette==0.50.0 + py3.13-fastapi-v0.123.10: httpx==0.28.1 + py3.13-fastapi-v0.123.10: httpcore==1.0.9 + py3.13-fastapi-v0.123.10: pytest-asyncio==1.4.0 + py3.13-fastapi-v0.123.10: pytest==9.1.1 + py3.13-fastapi-v0.123.10: pluggy==1.6.0 + py3.13-fastapi-v0.123.10: python-multipart==0.0.32 + py3.13-fastapi-v0.123.10: requests==2.34.2 + py3.13-fastapi-v0.123.10: charset-normalizer==3.4.9 + py3.13-fastapi-v0.123.10: idna==3.18 + py3.13-fastapi-v0.123.10: urllib3==2.7.0 + py3.13-fastapi-v0.123.10: Jinja2==3.1.6 + py3.13-fastapi-v0.123.10: annotated-doc==0.0.5 + py3.13-fastapi-v0.123.10: annotated-types==0.8.0 + py3.13-fastapi-v0.123.10: certifi==2026.7.22 + py3.13-fastapi-v0.123.10: h11==0.16.0 + py3.13-fastapi-v0.123.10: iniconfig==2.3.0 + py3.13-fastapi-v0.123.10: MarkupSafe==3.0.3 + py3.13-fastapi-v0.123.10: packaging==26.3 + py3.13-fastapi-v0.123.10: Pygments==2.20.0 + py3.13-fastapi-v0.123.10: typing_extensions==4.16.0 + py3.13-fastapi-v0.123.10: typing-inspection==0.4.2 + + py3.14-fastapi-v0.123.10: anyio==4.14.2 + py3.14-fastapi-v0.123.10: pydantic==2.13.4 + py3.14-fastapi-v0.123.10: pydantic_core==2.46.4 + py3.14-fastapi-v0.123.10: starlette==0.50.0 + py3.14-fastapi-v0.123.10: httpx==0.28.1 + py3.14-fastapi-v0.123.10: httpcore==1.0.9 + py3.14-fastapi-v0.123.10: pytest-asyncio==1.4.0 + py3.14-fastapi-v0.123.10: pytest==9.1.1 + py3.14-fastapi-v0.123.10: pluggy==1.6.0 + py3.14-fastapi-v0.123.10: python-multipart==0.0.32 + py3.14-fastapi-v0.123.10: requests==2.34.2 + py3.14-fastapi-v0.123.10: charset-normalizer==3.4.9 + py3.14-fastapi-v0.123.10: idna==3.18 + py3.14-fastapi-v0.123.10: urllib3==2.7.0 + py3.14-fastapi-v0.123.10: Jinja2==3.1.6 + py3.14-fastapi-v0.123.10: annotated-doc==0.0.5 + py3.14-fastapi-v0.123.10: annotated-types==0.8.0 + py3.14-fastapi-v0.123.10: certifi==2026.7.22 + py3.14-fastapi-v0.123.10: h11==0.16.0 + py3.14-fastapi-v0.123.10: iniconfig==2.3.0 + py3.14-fastapi-v0.123.10: MarkupSafe==3.0.3 + py3.14-fastapi-v0.123.10: packaging==26.3 + py3.14-fastapi-v0.123.10: Pygments==2.20.0 + py3.14-fastapi-v0.123.10: typing_extensions==4.16.0 + py3.14-fastapi-v0.123.10: typing-inspection==0.4.2 + + py3.14t-fastapi-v0.123.10: anyio==4.14.2 + py3.14t-fastapi-v0.123.10: pydantic==2.13.4 + py3.14t-fastapi-v0.123.10: pydantic_core==2.46.4 + py3.14t-fastapi-v0.123.10: starlette==0.50.0 + py3.14t-fastapi-v0.123.10: httpx==0.28.1 + py3.14t-fastapi-v0.123.10: httpcore==1.0.9 + py3.14t-fastapi-v0.123.10: pytest-asyncio==1.4.0 + py3.14t-fastapi-v0.123.10: pytest==9.1.1 + py3.14t-fastapi-v0.123.10: pluggy==1.6.0 + py3.14t-fastapi-v0.123.10: python-multipart==0.0.32 + py3.14t-fastapi-v0.123.10: requests==2.34.2 + py3.14t-fastapi-v0.123.10: charset-normalizer==3.4.9 + py3.14t-fastapi-v0.123.10: idna==3.18 + py3.14t-fastapi-v0.123.10: urllib3==2.7.0 + py3.14t-fastapi-v0.123.10: Jinja2==3.1.6 + py3.14t-fastapi-v0.123.10: annotated-doc==0.0.5 + py3.14t-fastapi-v0.123.10: annotated-types==0.8.0 + py3.14t-fastapi-v0.123.10: certifi==2026.7.22 + py3.14t-fastapi-v0.123.10: h11==0.16.0 + py3.14t-fastapi-v0.123.10: iniconfig==2.3.0 + py3.14t-fastapi-v0.123.10: MarkupSafe==3.0.3 + py3.14t-fastapi-v0.123.10: packaging==26.3 + py3.14t-fastapi-v0.123.10: Pygments==2.20.0 + py3.14t-fastapi-v0.123.10: typing_extensions==4.16.0 + py3.14t-fastapi-v0.123.10: typing-inspection==0.4.2 fastapi-v0.141.1: fastapi==0.141.1 @@ -16895,15 +16411,13 @@ deps = fastapi: requests fastapi: anyio>=3,<5 fastapi: jinja2 - fastapi-v0.79.1: httpx<0.28.0 - fastapi-v0.100.1: httpx<0.28.0 - fastapi-v0.79.1: anyio<4 - {py3.6}-fastapi: aiocontextvars + fastapi-v0.85.2: httpx<0.28.0 + fastapi-v0.104.1: httpx<0.28.0 + fastapi-v0.85.2: anyio<4 + fastapi-v0.85.2: urllib3<2 # ~~~ Web 2 ~~~ - aiohttp-v3.4.4: aiohttp==3.4.4 - aiohttp-v3.7.4: aiohttp==3.7.4 py3.8-aiohttp-v3.7.4: pytest-aiohttp==0.3.0 @@ -16939,59 +16453,113 @@ deps = py3.9-aiohttp-v3.7.4: Pygments==2.20.0 py3.9-aiohttp-v3.7.4: tomli==2.4.1 - aiohttp-v3.10.11: aiohttp==3.10.11 - - py3.8-aiohttp-v3.10.11: pytest-aiohttp==1.0.5 - py3.8-aiohttp-v3.10.11: pytest-asyncio==0.24.0 - py3.8-aiohttp-v3.10.11: aiohappyeyeballs==2.4.4 - py3.8-aiohttp-v3.10.11: aiosignal==1.3.1 - py3.8-aiohttp-v3.10.11: async-timeout==5.0.1 - py3.8-aiohttp-v3.10.11: attrs==25.3.0 - py3.8-aiohttp-v3.10.11: frozenlist==1.5.0 - py3.8-aiohttp-v3.10.11: multidict==6.1.0 - py3.8-aiohttp-v3.10.11: pytest==8.3.5 - py3.8-aiohttp-v3.10.11: yarl==1.15.2 - py3.8-aiohttp-v3.10.11: exceptiongroup==1.3.1 - py3.8-aiohttp-v3.10.11: idna==3.15 - py3.8-aiohttp-v3.10.11: pluggy==1.5.0 - py3.8-aiohttp-v3.10.11: propcache==0.2.0 - py3.8-aiohttp-v3.10.11: tomli==2.4.1 - py3.8-aiohttp-v3.10.11: typing_extensions==4.13.2 - py3.8-aiohttp-v3.10.11: iniconfig==2.1.0 - py3.8-aiohttp-v3.10.11: packaging==26.2 - - py3.12-aiohttp-v3.10.11: multidict==6.7.1 - py3.12-aiohttp-v3.10.11: yarl==1.24.2 - py3.12-aiohttp-v3.10.11: pytest-aiohttp==1.0.5 - py3.12-aiohttp-v3.10.11: pytest-asyncio==1.4.0 - py3.12-aiohttp-v3.10.11: pytest==9.1.1 - py3.12-aiohttp-v3.10.11: pluggy==1.6.0 - py3.12-aiohttp-v3.10.11: aiohappyeyeballs==2.7.1 - py3.12-aiohttp-v3.10.11: aiosignal==1.4.0 - py3.12-aiohttp-v3.10.11: attrs==26.1.0 - py3.12-aiohttp-v3.10.11: frozenlist==1.8.0 - py3.12-aiohttp-v3.10.11: idna==3.18 - py3.12-aiohttp-v3.10.11: iniconfig==2.3.0 - py3.12-aiohttp-v3.10.11: packaging==26.2 - py3.12-aiohttp-v3.10.11: propcache==0.5.2 - py3.12-aiohttp-v3.10.11: Pygments==2.20.0 - py3.12-aiohttp-v3.10.11: typing_extensions==4.16.0 - - py3.13-aiohttp-v3.10.11: pytest-aiohttp==1.0.5 - py3.13-aiohttp-v3.10.11: pytest-asyncio==1.4.0 - py3.13-aiohttp-v3.10.11: aiohappyeyeballs==2.7.1 - py3.13-aiohttp-v3.10.11: aiosignal==1.4.0 - py3.13-aiohttp-v3.10.11: attrs==26.1.0 - py3.13-aiohttp-v3.10.11: frozenlist==1.8.0 - py3.13-aiohttp-v3.10.11: multidict==6.7.1 - py3.13-aiohttp-v3.10.11: pytest==9.1.1 - py3.13-aiohttp-v3.10.11: yarl==1.24.2 - py3.13-aiohttp-v3.10.11: idna==3.18 - py3.13-aiohttp-v3.10.11: iniconfig==2.3.0 - py3.13-aiohttp-v3.10.11: packaging==26.2 - py3.13-aiohttp-v3.10.11: pluggy==1.6.0 - py3.13-aiohttp-v3.10.11: propcache==0.5.2 - py3.13-aiohttp-v3.10.11: Pygments==2.20.0 + aiohttp-v3.9.5: aiohttp==3.9.5 + + py3.8-aiohttp-v3.9.5: pytest-aiohttp==1.0.5 + py3.8-aiohttp-v3.9.5: pytest-asyncio==0.24.0 + py3.8-aiohttp-v3.9.5: aiosignal==1.3.1 + py3.8-aiohttp-v3.9.5: async-timeout==4.0.3 + py3.8-aiohttp-v3.9.5: attrs==25.3.0 + py3.8-aiohttp-v3.9.5: frozenlist==1.5.0 + py3.8-aiohttp-v3.9.5: multidict==6.1.0 + py3.8-aiohttp-v3.9.5: pytest==8.3.5 + py3.8-aiohttp-v3.9.5: yarl==1.15.2 + py3.8-aiohttp-v3.9.5: exceptiongroup==1.3.1 + py3.8-aiohttp-v3.9.5: idna==3.15 + py3.8-aiohttp-v3.9.5: pluggy==1.5.0 + py3.8-aiohttp-v3.9.5: propcache==0.2.0 + py3.8-aiohttp-v3.9.5: tomli==2.4.1 + py3.8-aiohttp-v3.9.5: typing_extensions==4.13.2 + py3.8-aiohttp-v3.9.5: iniconfig==2.1.0 + py3.8-aiohttp-v3.9.5: packaging==26.2 + + py3.11-aiohttp-v3.9.5: pytest-aiohttp==1.0.5 + py3.11-aiohttp-v3.9.5: pytest-asyncio==1.4.0 + py3.11-aiohttp-v3.9.5: aiosignal==1.4.0 + py3.11-aiohttp-v3.9.5: attrs==26.1.0 + py3.11-aiohttp-v3.9.5: frozenlist==1.8.0 + py3.11-aiohttp-v3.9.5: multidict==6.7.1 + py3.11-aiohttp-v3.9.5: pytest==9.1.1 + py3.11-aiohttp-v3.9.5: typing_extensions==4.16.0 + py3.11-aiohttp-v3.9.5: yarl==1.24.5 + py3.11-aiohttp-v3.9.5: idna==3.18 + py3.11-aiohttp-v3.9.5: iniconfig==2.3.0 + py3.11-aiohttp-v3.9.5: packaging==26.2 + py3.11-aiohttp-v3.9.5: pluggy==1.6.0 + py3.11-aiohttp-v3.9.5: propcache==0.5.2 + py3.11-aiohttp-v3.9.5: Pygments==2.20.0 + + py3.12-aiohttp-v3.9.5: multidict==6.7.1 + py3.12-aiohttp-v3.9.5: yarl==1.24.5 + py3.12-aiohttp-v3.9.5: pytest-aiohttp==1.0.5 + py3.12-aiohttp-v3.9.5: pytest-asyncio==1.4.0 + py3.12-aiohttp-v3.9.5: pytest==9.1.1 + py3.12-aiohttp-v3.9.5: pluggy==1.6.0 + py3.12-aiohttp-v3.9.5: aiosignal==1.4.0 + py3.12-aiohttp-v3.9.5: attrs==26.1.0 + py3.12-aiohttp-v3.9.5: frozenlist==1.8.0 + py3.12-aiohttp-v3.9.5: idna==3.18 + py3.12-aiohttp-v3.9.5: iniconfig==2.3.0 + py3.12-aiohttp-v3.9.5: packaging==26.2 + py3.12-aiohttp-v3.9.5: propcache==0.5.2 + py3.12-aiohttp-v3.9.5: Pygments==2.20.0 + py3.12-aiohttp-v3.9.5: typing_extensions==4.16.0 + + aiohttp-v3.11.18: aiohttp==3.11.18 + + py3.9-aiohttp-v3.11.18: async-timeout==5.0.1 + py3.9-aiohttp-v3.11.18: multidict==6.7.1 + py3.9-aiohttp-v3.11.18: yarl==1.22.0 + py3.9-aiohttp-v3.11.18: pytest-aiohttp==1.1.0 + py3.9-aiohttp-v3.11.18: pytest-asyncio==1.2.0 + py3.9-aiohttp-v3.11.18: backports.asyncio.runner==1.2.0 + py3.9-aiohttp-v3.11.18: pytest==8.4.2 + py3.9-aiohttp-v3.11.18: pluggy==1.6.0 + py3.9-aiohttp-v3.11.18: aiohappyeyeballs==2.6.1 + py3.9-aiohttp-v3.11.18: aiosignal==1.4.0 + py3.9-aiohttp-v3.11.18: attrs==26.1.0 + py3.9-aiohttp-v3.11.18: exceptiongroup==1.3.1 + py3.9-aiohttp-v3.11.18: frozenlist==1.8.0 + py3.9-aiohttp-v3.11.18: idna==3.18 + py3.9-aiohttp-v3.11.18: iniconfig==2.1.0 + py3.9-aiohttp-v3.11.18: packaging==26.2 + py3.9-aiohttp-v3.11.18: propcache==0.4.1 + py3.9-aiohttp-v3.11.18: Pygments==2.20.0 + py3.9-aiohttp-v3.11.18: tomli==2.4.1 + py3.9-aiohttp-v3.11.18: typing_extensions==4.16.0 + + py3.12-aiohttp-v3.11.18: multidict==6.7.1 + py3.12-aiohttp-v3.11.18: yarl==1.24.5 + py3.12-aiohttp-v3.11.18: pytest-aiohttp==1.1.1 + py3.12-aiohttp-v3.11.18: pytest-asyncio==1.4.0 + py3.12-aiohttp-v3.11.18: pytest==9.1.1 + py3.12-aiohttp-v3.11.18: pluggy==1.6.0 + py3.12-aiohttp-v3.11.18: aiohappyeyeballs==2.7.1 + py3.12-aiohttp-v3.11.18: aiosignal==1.4.0 + py3.12-aiohttp-v3.11.18: attrs==26.1.0 + py3.12-aiohttp-v3.11.18: frozenlist==1.8.0 + py3.12-aiohttp-v3.11.18: idna==3.18 + py3.12-aiohttp-v3.11.18: iniconfig==2.3.0 + py3.12-aiohttp-v3.11.18: packaging==26.2 + py3.12-aiohttp-v3.11.18: propcache==0.5.2 + py3.12-aiohttp-v3.11.18: Pygments==2.20.0 + py3.12-aiohttp-v3.11.18: typing_extensions==4.16.0 + + py3.13-aiohttp-v3.11.18: multidict==6.7.1 + py3.13-aiohttp-v3.11.18: yarl==1.24.5 + py3.13-aiohttp-v3.11.18: pytest-aiohttp==1.1.1 + py3.13-aiohttp-v3.11.18: pytest-asyncio==1.4.0 + py3.13-aiohttp-v3.11.18: pytest==9.1.1 + py3.13-aiohttp-v3.11.18: pluggy==1.6.0 + py3.13-aiohttp-v3.11.18: aiohappyeyeballs==2.7.1 + py3.13-aiohttp-v3.11.18: aiosignal==1.4.0 + py3.13-aiohttp-v3.11.18: attrs==26.1.0 + py3.13-aiohttp-v3.11.18: frozenlist==1.8.0 + py3.13-aiohttp-v3.11.18: idna==3.18 + py3.13-aiohttp-v3.11.18: iniconfig==2.3.0 + py3.13-aiohttp-v3.11.18: packaging==26.2 + py3.13-aiohttp-v3.11.18: propcache==0.5.2 + py3.13-aiohttp-v3.11.18: Pygments==2.20.0 aiohttp-v3.14.3: aiohttp==3.14.3 @@ -17138,7 +16706,8 @@ deps = py3.14t-aiohttp-latest: Pygments==2.20.0 aiohttp: pytest-aiohttp - aiohttp-v3.10.11: pytest-asyncio + aiohttp-v3.9.5: pytest-asyncio + aiohttp-v3.11.18: pytest-asyncio aiohttp-v3.14.3: pytest-asyncio aiohttp-latest: pytest-asyncio @@ -17162,9 +16731,7 @@ deps = bottle: werkzeug<2.1.0 - falcon-v1.4.1: falcon==1.4.1 - - falcon-v2.0.0: falcon==2.0.0 + falcon-v3.0.1: falcon==3.0.1 falcon-v3.1.3: falcon==3.1.3 @@ -17781,33 +17348,31 @@ deps = litestar: sniffio litestar-v2.0.1: httpx<0.28 - pyramid-v1.8.6: pyramid==1.8.6 - - pyramid-v1.10.8: pyramid==1.10.8 - - py3.8-pyramid-v1.10.8: Werkzeug==2.0.3 - py3.8-pyramid-v1.10.8: setuptools==75.3.4 - py3.8-pyramid-v1.10.8: hupper==1.12.1 - py3.8-pyramid-v1.10.8: translationstring==1.4 - py3.8-pyramid-v1.10.8: venusian==3.1.1 - py3.8-pyramid-v1.10.8: WebOb==1.8.10 - py3.8-pyramid-v1.10.8: zope.deprecation==5.0 - py3.8-pyramid-v1.10.8: zope.interface==7.2 - py3.8-pyramid-v1.10.8: plaster==1.1.2 - py3.8-pyramid-v1.10.8: plaster-pastedeploy==1.0.1 - py3.8-pyramid-v1.10.8: PasteDeploy==3.1.0 - - py3.9-pyramid-v1.10.8: Werkzeug==2.0.3 - py3.9-pyramid-v1.10.8: setuptools==81.0.0 - py3.9-pyramid-v1.10.8: hupper==1.12.1 - py3.9-pyramid-v1.10.8: translationstring==1.4 - py3.9-pyramid-v1.10.8: venusian==3.1.1 - py3.9-pyramid-v1.10.8: WebOb==1.8.10 - py3.9-pyramid-v1.10.8: zope.deprecation==6.0 - py3.9-pyramid-v1.10.8: zope.interface==8.0.1 - py3.9-pyramid-v1.10.8: plaster==1.1.2 - py3.9-pyramid-v1.10.8: plaster-pastedeploy==1.0.1 - py3.9-pyramid-v1.10.8: PasteDeploy==3.1.0 + pyramid-v2.0.2: pyramid==2.0.2 + + py3.10-pyramid-v2.0.2: Werkzeug==2.0.3 + py3.10-pyramid-v2.0.2: setuptools==81.0.0 + py3.10-pyramid-v2.0.2: hupper==1.12.1 + py3.10-pyramid-v2.0.2: translationstring==1.4 + py3.10-pyramid-v2.0.2: venusian==3.1.1 + py3.10-pyramid-v2.0.2: WebOb==1.8.11 + py3.10-pyramid-v2.0.2: zope.deprecation==6.0 + py3.10-pyramid-v2.0.2: zope.interface==8.5 + py3.10-pyramid-v2.0.2: plaster==1.1.2 + py3.10-pyramid-v2.0.2: plaster-pastedeploy==1.0.1 + py3.10-pyramid-v2.0.2: PasteDeploy==3.1.0 + + py3.11-pyramid-v2.0.2: Werkzeug==2.0.3 + py3.11-pyramid-v2.0.2: setuptools==81.0.0 + py3.11-pyramid-v2.0.2: hupper==1.12.1 + py3.11-pyramid-v2.0.2: translationstring==1.4 + py3.11-pyramid-v2.0.2: venusian==3.1.1 + py3.11-pyramid-v2.0.2: WebOb==1.8.11 + py3.11-pyramid-v2.0.2: zope.deprecation==6.0 + py3.11-pyramid-v2.0.2: zope.interface==8.5 + py3.11-pyramid-v2.0.2: plaster==1.1.2 + py3.11-pyramid-v2.0.2: plaster-pastedeploy==1.0.1 + py3.11-pyramid-v2.0.2: PasteDeploy==3.1.0 pyramid-v2.1: pyramid==2.1 @@ -17916,68 +17481,93 @@ deps = py3.14t-pyramid-latest: PasteDeploy==3.1.0 pyramid: werkzeug<2.1.0 - pyramid-v1.8.6: setuptools<82 - pyramid-v1.10.8: setuptools<82 - - quart-v0.16.3: quart==0.16.3 - - py3.9-quart-v0.16.3: Werkzeug==2.2.3 - py3.9-quart-v0.16.3: blinker==1.5 - py3.9-quart-v0.16.3: Jinja2==3.0.3 - py3.9-quart-v0.16.3: hypercorn==0.14.4 - py3.9-quart-v0.16.3: quart-auth==0.6.0 - py3.9-quart-v0.16.3: pytest-asyncio==1.2.0 - py3.9-quart-v0.16.3: backports.asyncio.runner==1.2.0 - py3.9-quart-v0.16.3: pytest==8.4.2 - py3.9-quart-v0.16.3: pluggy==1.6.0 - py3.9-quart-v0.16.3: pytest-forked==1.6.0 - py3.9-quart-v0.16.3: exceptiongroup==1.3.1 - py3.9-quart-v0.16.3: h2==4.3.0 - py3.9-quart-v0.16.3: hpack==4.1.0 - py3.9-quart-v0.16.3: hyperframe==6.1.0 - py3.9-quart-v0.16.3: iniconfig==2.1.0 - py3.9-quart-v0.16.3: MarkupSafe==3.0.3 - py3.9-quart-v0.16.3: packaging==26.2 - py3.9-quart-v0.16.3: Pygments==2.20.0 - py3.9-quart-v0.16.3: tomli==2.4.1 - py3.9-quart-v0.16.3: typing_extensions==4.16.0 - py3.9-quart-v0.16.3: wsproto==1.2.0 - py3.9-quart-v0.16.3: h11==0.16.0 - py3.9-quart-v0.16.3: aiofiles==25.1.0 - py3.9-quart-v0.16.3: click==8.1.8 - py3.9-quart-v0.16.3: itsdangerous==2.2.0 - py3.9-quart-v0.16.3: priority==2.0.0 - py3.9-quart-v0.16.3: py==1.11.0 - py3.9-quart-v0.16.3: toml==0.10.2 - - py3.10-quart-v0.16.3: Werkzeug==2.2.3 - py3.10-quart-v0.16.3: blinker==1.5 - py3.10-quart-v0.16.3: Jinja2==3.0.3 - py3.10-quart-v0.16.3: hypercorn==0.14.4 - py3.10-quart-v0.16.3: quart-auth==0.6.0 - py3.10-quart-v0.16.3: pytest-asyncio==1.4.0 - py3.10-quart-v0.16.3: backports.asyncio.runner==1.2.0 - py3.10-quart-v0.16.3: pytest==9.1.1 - py3.10-quart-v0.16.3: pluggy==1.6.0 - py3.10-quart-v0.16.3: pytest-forked==1.6.0 - py3.10-quart-v0.16.3: exceptiongroup==1.3.1 - py3.10-quart-v0.16.3: h2==4.3.0 - py3.10-quart-v0.16.3: hpack==4.2.0 - py3.10-quart-v0.16.3: hyperframe==6.1.0 - py3.10-quart-v0.16.3: iniconfig==2.3.0 - py3.10-quart-v0.16.3: MarkupSafe==3.0.3 - py3.10-quart-v0.16.3: packaging==26.2 - py3.10-quart-v0.16.3: Pygments==2.20.0 - py3.10-quart-v0.16.3: tomli==2.4.1 - py3.10-quart-v0.16.3: typing_extensions==4.16.0 - py3.10-quart-v0.16.3: wsproto==1.3.2 - py3.10-quart-v0.16.3: h11==0.16.0 - py3.10-quart-v0.16.3: aiofiles==25.1.0 - py3.10-quart-v0.16.3: click==8.4.2 - py3.10-quart-v0.16.3: itsdangerous==2.2.0 - py3.10-quart-v0.16.3: priority==2.0.0 - py3.10-quart-v0.16.3: py==1.11.0 - py3.10-quart-v0.16.3: toml==0.10.2 + pyramid-v2.0.2: setuptools<82 + + quart-v0.19.9: quart==0.19.9 + + py3.8-quart-v0.19.9: taskgroup==0.0.0a4 + py3.8-quart-v0.19.9: quart-auth==0.10.1 + py3.8-quart-v0.19.9: pytest-asyncio==0.24.0 + py3.8-quart-v0.19.9: pytest-forked==1.6.0 + py3.8-quart-v0.19.9: Werkzeug==3.0.6 + py3.8-quart-v0.19.9: quart-flask-patch==0.3.0 + py3.8-quart-v0.19.9: blinker==1.8.2 + py3.8-quart-v0.19.9: click==8.1.8 + py3.8-quart-v0.19.9: Flask==3.0.3 + py3.8-quart-v0.19.9: Hypercorn==0.17.3 + py3.8-quart-v0.19.9: exceptiongroup==1.3.1 + py3.8-quart-v0.19.9: importlib_metadata==8.5.0 + py3.8-quart-v0.19.9: itsdangerous==2.2.0 + py3.8-quart-v0.19.9: Jinja2==3.1.6 + py3.8-quart-v0.19.9: MarkupSafe==2.1.5 + py3.8-quart-v0.19.9: pytest==8.3.5 + py3.8-quart-v0.19.9: typing_extensions==4.13.2 + py3.8-quart-v0.19.9: aiofiles==24.1.0 + py3.8-quart-v0.19.9: py==1.11.0 + py3.8-quart-v0.19.9: h2==4.1.0 + py3.8-quart-v0.19.9: pluggy==1.5.0 + py3.8-quart-v0.19.9: tomli==2.4.1 + py3.8-quart-v0.19.9: wsproto==1.2.0 + py3.8-quart-v0.19.9: h11==0.16.0 + py3.8-quart-v0.19.9: zipp==3.20.2 + py3.8-quart-v0.19.9: iniconfig==2.1.0 + py3.8-quart-v0.19.9: packaging==26.2 + py3.8-quart-v0.19.9: priority==2.0.0 + py3.8-quart-v0.19.9: hpack==4.0.0 + py3.8-quart-v0.19.9: hyperframe==6.0.1 + + py3.12-quart-v0.19.9: quart-auth==0.11.0 + py3.12-quart-v0.19.9: pytest-asyncio==1.4.0 + py3.12-quart-v0.19.9: pytest==9.1.1 + py3.12-quart-v0.19.9: pluggy==1.6.0 + py3.12-quart-v0.19.9: pytest-forked==1.6.0 + py3.12-quart-v0.19.9: Werkzeug==3.1.8 + py3.12-quart-v0.19.9: quart-flask-patch==0.3.0 + py3.12-quart-v0.19.9: blinker==1.9.0 + py3.12-quart-v0.19.9: click==8.4.2 + py3.12-quart-v0.19.9: Flask==3.1.3 + py3.12-quart-v0.19.9: Hypercorn==0.18.0 + py3.12-quart-v0.19.9: h2==4.4.1 + py3.12-quart-v0.19.9: hpack==4.2.0 + py3.12-quart-v0.19.9: hyperframe==6.1.0 + py3.12-quart-v0.19.9: iniconfig==2.3.0 + py3.12-quart-v0.19.9: itsdangerous==2.2.0 + py3.12-quart-v0.19.9: Jinja2==3.1.6 + py3.12-quart-v0.19.9: MarkupSafe==3.0.3 + py3.12-quart-v0.19.9: packaging==26.3 + py3.12-quart-v0.19.9: Pygments==2.20.0 + py3.12-quart-v0.19.9: typing_extensions==4.16.0 + py3.12-quart-v0.19.9: wsproto==1.3.2 + py3.12-quart-v0.19.9: h11==0.16.0 + py3.12-quart-v0.19.9: aiofiles==25.1.0 + py3.12-quart-v0.19.9: priority==2.0.0 + py3.12-quart-v0.19.9: py==1.11.0 + + py3.13-quart-v0.19.9: quart-auth==0.11.0 + py3.13-quart-v0.19.9: pytest-asyncio==1.4.0 + py3.13-quart-v0.19.9: pytest==9.1.1 + py3.13-quart-v0.19.9: pluggy==1.6.0 + py3.13-quart-v0.19.9: pytest-forked==1.6.0 + py3.13-quart-v0.19.9: Werkzeug==3.1.8 + py3.13-quart-v0.19.9: quart-flask-patch==0.3.0 + py3.13-quart-v0.19.9: blinker==1.9.0 + py3.13-quart-v0.19.9: click==8.4.2 + py3.13-quart-v0.19.9: Flask==3.1.3 + py3.13-quart-v0.19.9: Hypercorn==0.18.0 + py3.13-quart-v0.19.9: h2==4.4.1 + py3.13-quart-v0.19.9: hpack==4.2.0 + py3.13-quart-v0.19.9: hyperframe==6.1.0 + py3.13-quart-v0.19.9: iniconfig==2.3.0 + py3.13-quart-v0.19.9: itsdangerous==2.2.0 + py3.13-quart-v0.19.9: Jinja2==3.1.6 + py3.13-quart-v0.19.9: MarkupSafe==3.0.3 + py3.13-quart-v0.19.9: packaging==26.3 + py3.13-quart-v0.19.9: Pygments==2.20.0 + py3.13-quart-v0.19.9: wsproto==1.3.2 + py3.13-quart-v0.19.9: h11==0.16.0 + py3.13-quart-v0.19.9: aiofiles==25.1.0 + py3.13-quart-v0.19.9: priority==2.0.0 + py3.13-quart-v0.19.9: py==1.11.0 quart-v0.23.1: quart==0.23.1 @@ -18179,64 +17769,115 @@ deps = quart: pytest-asyncio quart: pytest-forked quart: Werkzeug - quart-v0.16.3: blinker<1.6 - quart-v0.16.3: jinja2<3.1.0 - quart-v0.16.3: Werkzeug<2.3.0 - quart-v0.16.3: hypercorn<0.15.0 + quart-v0.19.9: quart-flask-patch {py3.8}-quart: taskgroup==0.0.0a4 - {py3.6,py3.7}-quart: importlib_metadata - - sanic-v0.8.3: sanic==0.8.3 - - sanic-v20.12.7: sanic==20.12.7 - - py3.8-sanic-v20.12.7: httpx==0.15.4 - py3.8-sanic-v20.12.7: httpcore==0.11.1 - py3.8-sanic-v20.12.7: sniffio==1.3.1 - py3.8-sanic-v20.12.7: websockets==9.1 - py3.8-sanic-v20.12.7: aiohttp==3.10.11 - py3.8-sanic-v20.12.7: tracerite==1.1.1 - py3.8-sanic-v20.12.7: setuptools==75.3.4 - py3.8-sanic-v20.12.7: aiofiles==24.1.0 - py3.8-sanic-v20.12.7: aiohappyeyeballs==2.4.4 - py3.8-sanic-v20.12.7: aiosignal==1.3.1 - py3.8-sanic-v20.12.7: async-timeout==5.0.1 - py3.8-sanic-v20.12.7: attrs==25.3.0 - py3.8-sanic-v20.12.7: frozenlist==1.5.0 - py3.8-sanic-v20.12.7: html5tagger==1.3.0 - py3.8-sanic-v20.12.7: httptools==0.6.4 - py3.8-sanic-v20.12.7: multidict==5.2.0 - py3.8-sanic-v20.12.7: ujson==5.10.0 - py3.8-sanic-v20.12.7: uvloop==0.22.1 - py3.8-sanic-v20.12.7: yarl==1.15.2 - py3.8-sanic-v20.12.7: idna==3.15 - py3.8-sanic-v20.12.7: propcache==0.2.0 - py3.8-sanic-v20.12.7: rfc3986==1.5.0 - py3.8-sanic-v20.12.7: certifi==2026.6.17 - py3.8-sanic-v20.12.7: h11==0.9.0 - - py3.9-sanic-v20.12.7: httpx==0.15.4 - py3.9-sanic-v20.12.7: websockets==9.1 - py3.9-sanic-v20.12.7: httpcore==0.11.1 - py3.9-sanic-v20.12.7: h11==0.9.0 - py3.9-sanic-v20.12.7: multidict==5.2.0 - py3.9-sanic-v20.12.7: rfc3986==1.5.0 - py3.9-sanic-v20.12.7: sniffio==1.3.1 - py3.9-sanic-v20.12.7: aiohttp==3.13.5 - py3.9-sanic-v20.12.7: async-timeout==5.0.1 - py3.9-sanic-v20.12.7: yarl==1.22.0 - py3.9-sanic-v20.12.7: aiofiles==25.1.0 - py3.9-sanic-v20.12.7: aiohappyeyeballs==2.6.1 - py3.9-sanic-v20.12.7: aiosignal==1.4.0 - py3.9-sanic-v20.12.7: attrs==26.1.0 - py3.9-sanic-v20.12.7: frozenlist==1.8.0 - py3.9-sanic-v20.12.7: httptools==0.8.0 - py3.9-sanic-v20.12.7: idna==3.18 - py3.9-sanic-v20.12.7: propcache==0.4.1 - py3.9-sanic-v20.12.7: typing_extensions==4.16.0 - py3.9-sanic-v20.12.7: ujson==5.11.0 - py3.9-sanic-v20.12.7: uvloop==0.22.1 - py3.9-sanic-v20.12.7: certifi==2026.6.17 + {py3.7}-quart: importlib_metadata + + sanic-v22.3.2: sanic==22.3.2 + + py3.9-sanic-v22.3.2: websockets==10.4 + py3.9-sanic-v22.3.2: sanic-testing==22.6.0 + py3.9-sanic-v22.3.2: httpx==0.23.3 + py3.9-sanic-v22.3.2: httpcore==0.16.3 + py3.9-sanic-v22.3.2: anyio==4.12.1 + py3.9-sanic-v22.3.2: h11==0.14.0 + py3.9-sanic-v22.3.2: multidict==6.7.1 + py3.9-sanic-v22.3.2: rfc3986==1.5.0 + py3.9-sanic-v22.3.2: sanic-routing==22.3.0 + py3.9-sanic-v22.3.2: sniffio==1.3.1 + py3.9-sanic-v22.3.2: aiohttp==3.13.5 + py3.9-sanic-v22.3.2: async-timeout==5.0.1 + py3.9-sanic-v22.3.2: yarl==1.22.0 + py3.9-sanic-v22.3.2: aiofiles==25.1.0 + py3.9-sanic-v22.3.2: aiohappyeyeballs==2.6.1 + py3.9-sanic-v22.3.2: aiosignal==1.4.0 + py3.9-sanic-v22.3.2: attrs==26.1.0 + py3.9-sanic-v22.3.2: exceptiongroup==1.3.1 + py3.9-sanic-v22.3.2: frozenlist==1.8.0 + py3.9-sanic-v22.3.2: httptools==0.8.0 + py3.9-sanic-v22.3.2: idna==3.18 + py3.9-sanic-v22.3.2: propcache==0.4.1 + py3.9-sanic-v22.3.2: typing_extensions==4.16.0 + py3.9-sanic-v22.3.2: ujson==5.11.0 + py3.9-sanic-v22.3.2: uvloop==0.22.1 + py3.9-sanic-v22.3.2: certifi==2026.7.22 + + py3.10-sanic-v22.3.2: websockets==10.4 + py3.10-sanic-v22.3.2: sanic-testing==22.6.0 + py3.10-sanic-v22.3.2: httpx==0.23.3 + py3.10-sanic-v22.3.2: httpcore==0.16.3 + py3.10-sanic-v22.3.2: anyio==4.14.2 + py3.10-sanic-v22.3.2: h11==0.14.0 + py3.10-sanic-v22.3.2: multidict==6.7.1 + py3.10-sanic-v22.3.2: rfc3986==1.5.0 + py3.10-sanic-v22.3.2: sanic-routing==22.3.0 + py3.10-sanic-v22.3.2: sniffio==1.3.1 + py3.10-sanic-v22.3.2: aiohttp==3.14.3 + py3.10-sanic-v22.3.2: async-timeout==5.0.1 + py3.10-sanic-v22.3.2: yarl==1.24.5 + py3.10-sanic-v22.3.2: aiofiles==25.1.0 + py3.10-sanic-v22.3.2: aiohappyeyeballs==2.7.1 + py3.10-sanic-v22.3.2: aiosignal==1.4.0 + py3.10-sanic-v22.3.2: attrs==26.1.0 + py3.10-sanic-v22.3.2: exceptiongroup==1.3.1 + py3.10-sanic-v22.3.2: frozenlist==1.8.0 + py3.10-sanic-v22.3.2: httptools==0.8.0 + py3.10-sanic-v22.3.2: idna==3.18 + py3.10-sanic-v22.3.2: propcache==0.5.2 + py3.10-sanic-v22.3.2: typing_extensions==4.16.0 + py3.10-sanic-v22.3.2: ujson==5.13.0 + py3.10-sanic-v22.3.2: uvloop==0.22.1 + py3.10-sanic-v22.3.2: certifi==2026.7.22 + + sanic-v22.12.0: sanic==22.12.0 + + py3.10-sanic-v22.12.0: websockets==10.4 + py3.10-sanic-v22.12.0: multidict==6.7.1 + py3.10-sanic-v22.12.0: aiohttp==3.14.3 + py3.10-sanic-v22.12.0: async-timeout==5.0.1 + py3.10-sanic-v22.12.0: yarl==1.24.5 + py3.10-sanic-v22.12.0: sanic-testing==24.6.0 + py3.10-sanic-v22.12.0: aiofiles==25.1.0 + py3.10-sanic-v22.12.0: aiohappyeyeballs==2.7.1 + py3.10-sanic-v22.12.0: aiosignal==1.4.0 + py3.10-sanic-v22.12.0: attrs==26.1.0 + py3.10-sanic-v22.12.0: frozenlist==1.8.0 + py3.10-sanic-v22.12.0: httptools==0.8.0 + py3.10-sanic-v22.12.0: httpx==0.28.1 + py3.10-sanic-v22.12.0: httpcore==1.0.9 + py3.10-sanic-v22.12.0: h11==0.16.0 + py3.10-sanic-v22.12.0: idna==3.18 + py3.10-sanic-v22.12.0: propcache==0.5.2 + py3.10-sanic-v22.12.0: sanic-routing==23.12.0 + py3.10-sanic-v22.12.0: typing_extensions==4.16.0 + py3.10-sanic-v22.12.0: ujson==5.13.0 + py3.10-sanic-v22.12.0: uvloop==0.22.1 + py3.10-sanic-v22.12.0: anyio==4.14.2 + py3.10-sanic-v22.12.0: exceptiongroup==1.3.1 + py3.10-sanic-v22.12.0: certifi==2026.7.22 + + py3.11-sanic-v22.12.0: websockets==10.4 + py3.11-sanic-v22.12.0: aiohttp==3.14.3 + py3.11-sanic-v22.12.0: sanic-testing==24.6.0 + py3.11-sanic-v22.12.0: aiofiles==25.1.0 + py3.11-sanic-v22.12.0: aiohappyeyeballs==2.7.1 + py3.11-sanic-v22.12.0: aiosignal==1.4.0 + py3.11-sanic-v22.12.0: attrs==26.1.0 + py3.11-sanic-v22.12.0: frozenlist==1.8.0 + py3.11-sanic-v22.12.0: httptools==0.8.0 + py3.11-sanic-v22.12.0: httpx==0.28.1 + py3.11-sanic-v22.12.0: httpcore==1.0.9 + py3.11-sanic-v22.12.0: multidict==6.7.1 + py3.11-sanic-v22.12.0: propcache==0.5.2 + py3.11-sanic-v22.12.0: sanic-routing==23.12.0 + py3.11-sanic-v22.12.0: typing_extensions==4.16.0 + py3.11-sanic-v22.12.0: ujson==5.13.0 + py3.11-sanic-v22.12.0: uvloop==0.22.1 + py3.11-sanic-v22.12.0: yarl==1.24.5 + py3.11-sanic-v22.12.0: idna==3.18 + py3.11-sanic-v22.12.0: anyio==4.14.2 + py3.11-sanic-v22.12.0: certifi==2026.7.22 + py3.11-sanic-v22.12.0: h11==0.16.0 sanic-v23.12.2: sanic==23.12.2 @@ -18431,8 +18072,6 @@ deps = sanic-latest: sanic==25.12.1 - sanic-latest: sanic-testing - py3.10-sanic-latest: websockets==10.4 py3.10-sanic-latest: multidict==6.7.1 py3.10-sanic-latest: aiohttp==3.14.1 @@ -18541,12 +18180,11 @@ deps = sanic: websockets<11.0 sanic: aiohttp - sanic-v23.12.2: sanic-testing - sanic-v25.12.1: sanic-testing - {py3.6}-sanic: aiocontextvars==0.2.1 + sanic: sanic-testing + sanic-v22.3.2: sanic-testing<22.9 + sanic-v22.3.2: httpx<0.24 {py3.8}-sanic: tracerite<1.1.2 {py3.8}-sanic: setuptools<82 - sanic-latest: sanic-testing starlite-v1.48.1: starlite==1.48.1 @@ -18927,6 +18565,32 @@ deps = py3.13-tornado-v6.5.10: packaging==26.3 py3.13-tornado-v6.5.10: Pygments==2.21.0 + tornado-v6.6a1: tornado==6.6a1 + + py3.11-tornado-v6.6a1: pytest==9.1.1 + py3.11-tornado-v6.6a1: pluggy==1.6.0 + py3.11-tornado-v6.6a1: iniconfig==2.3.0 + py3.11-tornado-v6.6a1: packaging==26.3 + py3.11-tornado-v6.6a1: Pygments==2.21.0 + + py3.14-tornado-v6.6a1: pytest==9.1.1 + py3.14-tornado-v6.6a1: pluggy==1.6.0 + py3.14-tornado-v6.6a1: iniconfig==2.3.0 + py3.14-tornado-v6.6a1: packaging==26.3 + py3.14-tornado-v6.6a1: Pygments==2.21.0 + + py3.15-tornado-v6.6a1: pytest==9.1.1 + py3.15-tornado-v6.6a1: pluggy==1.6.0 + py3.15-tornado-v6.6a1: iniconfig==2.3.0 + py3.15-tornado-v6.6a1: packaging==26.3 + py3.15-tornado-v6.6a1: Pygments==2.21.0 + + py3.15t-tornado-v6.6a1: pytest==9.1.1 + py3.15t-tornado-v6.6a1: pluggy==1.6.0 + py3.15t-tornado-v6.6a1: iniconfig==2.3.0 + py3.15t-tornado-v6.6a1: packaging==26.3 + py3.15t-tornado-v6.6a1: Pygments==2.21.0 + tornado-latest: tornado==6.5.10 py3.9-tornado-latest: pytest==8.4.2 @@ -18952,7 +18616,6 @@ deps = tornado: pytest tornado-v6.0.4: pytest<8.2 - {py3.6}-tornado: aiocontextvars # ~~~ Misc ~~~ @@ -18997,280 +18660,277 @@ deps = pure_eval: asttokens pure_eval: executing - trytond-v4.6.22: trytond==4.6.22 - - trytond-v4.8.18: trytond==4.8.18 - - trytond-v5.8.16: trytond==5.8.16 - - py3.8-trytond-v5.8.16: Werkzeug==1.0.1 - py3.8-trytond-v5.8.16: lxml==6.1.1 - py3.8-trytond-v5.8.16: passlib==1.7.4 - py3.8-trytond-v5.8.16: python-sql==1.7.0 - py3.8-trytond-v5.8.16: relatorio==0.11.1 - py3.8-trytond-v5.8.16: Genshi==0.7.11 - py3.8-trytond-v5.8.16: polib==1.2.0 - py3.8-trytond-v5.8.16: python-dateutil==2.9.0.post0 - py3.8-trytond-v5.8.16: wrapt==2.0.1 - py3.8-trytond-v5.8.16: six==1.17.0 - py3.8-trytond-v5.8.16: importlib_resources==6.4.5 - py3.8-trytond-v5.8.16: python-magic==0.4.27 - py3.8-trytond-v5.8.16: zipp==3.20.2 - - trytond-v6.8.17: trytond==6.8.17 - - py3.8-trytond-v6.8.17: Werkzeug==3.0.6 - py3.8-trytond-v6.8.17: lxml==6.1.1 - py3.8-trytond-v6.8.17: MarkupSafe==2.1.5 - py3.8-trytond-v6.8.17: passlib==1.7.4 - py3.8-trytond-v6.8.17: python-sql==1.7.0 - py3.8-trytond-v6.8.17: relatorio==0.11.1 - py3.8-trytond-v6.8.17: Genshi==0.7.11 - py3.8-trytond-v6.8.17: defusedxml==0.7.1 - py3.8-trytond-v6.8.17: polib==1.2.0 - py3.8-trytond-v6.8.17: python-dateutil==2.9.0.post0 - py3.8-trytond-v6.8.17: pytz==2026.2 - py3.8-trytond-v6.8.17: six==1.17.0 - py3.8-trytond-v6.8.17: importlib_resources==6.4.5 - py3.8-trytond-v6.8.17: python-magic==0.4.27 - py3.8-trytond-v6.8.17: zipp==3.20.2 - - py3.10-trytond-v6.8.17: Werkzeug==3.1.8 - py3.10-trytond-v6.8.17: lxml==6.1.1 - py3.10-trytond-v6.8.17: MarkupSafe==3.0.3 - py3.10-trytond-v6.8.17: passlib==1.7.4 - py3.10-trytond-v6.8.17: python-sql==1.8.1 - py3.10-trytond-v6.8.17: relatorio==0.12.1 - py3.10-trytond-v6.8.17: Genshi==0.7.11 - py3.10-trytond-v6.8.17: defusedxml==0.7.1 - py3.10-trytond-v6.8.17: polib==1.2.0 - py3.10-trytond-v6.8.17: python-dateutil==2.9.0.post0 - py3.10-trytond-v6.8.17: six==1.17.0 - py3.10-trytond-v6.8.17: python-magic==0.4.27 - - py3.11-trytond-v6.8.17: Werkzeug==3.1.8 - py3.11-trytond-v6.8.17: lxml==6.1.1 - py3.11-trytond-v6.8.17: MarkupSafe==3.0.3 - py3.11-trytond-v6.8.17: passlib==1.7.4 - py3.11-trytond-v6.8.17: python-sql==1.8.1 - py3.11-trytond-v6.8.17: relatorio==0.12.1 - py3.11-trytond-v6.8.17: Genshi==0.7.11 - py3.11-trytond-v6.8.17: defusedxml==0.7.1 - py3.11-trytond-v6.8.17: polib==1.2.0 - py3.11-trytond-v6.8.17: python-dateutil==2.9.0.post0 - py3.11-trytond-v6.8.17: six==1.17.0 - py3.11-trytond-v6.8.17: python-magic==0.4.27 - - trytond-v7.8.16: trytond==7.8.16 - - py3.9-trytond-v7.8.16: Werkzeug==3.1.8 - py3.9-trytond-v7.8.16: lxml==6.1.3 - py3.9-trytond-v7.8.16: MarkupSafe==3.0.3 - py3.9-trytond-v7.8.16: pwdlib==0.2.1 - py3.9-trytond-v7.8.16: argon2-cffi==23.1.0 - py3.9-trytond-v7.8.16: python-sql==1.8.1 - py3.9-trytond-v7.8.16: relatorio==1.0.0 - py3.9-trytond-v7.8.16: Genshi==0.7.11 - py3.9-trytond-v7.8.16: argon2-cffi-bindings==25.1.0 - py3.9-trytond-v7.8.16: cffi==2.0.0 - py3.9-trytond-v7.8.16: backports.entry-points-selectable==1.3.0 - py3.9-trytond-v7.8.16: defusedxml==0.7.1 - py3.9-trytond-v7.8.16: polib==1.2.0 - py3.9-trytond-v7.8.16: puremagic==1.30 - py3.9-trytond-v7.8.16: pycparser==2.23 - py3.9-trytond-v7.8.16: python-dateutil==2.9.0.post0 - py3.9-trytond-v7.8.16: six==1.17.0 - py3.9-trytond-v7.8.16: simpleeval==1.0.8 - - py3.12-trytond-v7.8.16: Werkzeug==3.1.8 - py3.12-trytond-v7.8.16: lxml==6.1.3 - py3.12-trytond-v7.8.16: MarkupSafe==3.0.3 - py3.12-trytond-v7.8.16: pwdlib==0.3.1 - py3.12-trytond-v7.8.16: argon2-cffi==25.1.0 - py3.12-trytond-v7.8.16: python-sql==1.8.1 - py3.12-trytond-v7.8.16: relatorio==1.0.0 - py3.12-trytond-v7.8.16: Genshi==0.7.11 - py3.12-trytond-v7.8.16: argon2-cffi-bindings==26.1.0 - py3.12-trytond-v7.8.16: cffi==2.1.1 - py3.12-trytond-v7.8.16: defusedxml==0.7.1 - py3.12-trytond-v7.8.16: polib==1.2.0 - py3.12-trytond-v7.8.16: puremagic==2.2.0 - py3.12-trytond-v7.8.16: pycparser==3.0 - py3.12-trytond-v7.8.16: python-dateutil==2.9.0.post0 - py3.12-trytond-v7.8.16: six==1.17.0 - py3.12-trytond-v7.8.16: simpleeval==1.0.8 - - py3.13-trytond-v7.8.16: Werkzeug==3.1.8 - py3.13-trytond-v7.8.16: lxml==6.1.3 - py3.13-trytond-v7.8.16: MarkupSafe==3.0.3 - py3.13-trytond-v7.8.16: pwdlib==0.3.1 - py3.13-trytond-v7.8.16: argon2-cffi==25.1.0 - py3.13-trytond-v7.8.16: python-sql==1.8.1 - py3.13-trytond-v7.8.16: relatorio==1.0.0 - py3.13-trytond-v7.8.16: Genshi==0.7.11 - py3.13-trytond-v7.8.16: argon2-cffi-bindings==26.1.0 - py3.13-trytond-v7.8.16: cffi==2.1.1 - py3.13-trytond-v7.8.16: defusedxml==0.7.1 - py3.13-trytond-v7.8.16: polib==1.2.0 - py3.13-trytond-v7.8.16: puremagic==2.2.0 - py3.13-trytond-v7.8.16: pycparser==3.0 - py3.13-trytond-v7.8.16: python-dateutil==2.9.0.post0 - py3.13-trytond-v7.8.16: six==1.17.0 - py3.13-trytond-v7.8.16: simpleeval==1.0.8 - - trytond-v8.0.10: trytond==8.0.10 - - py3.10-trytond-v8.0.10: Werkzeug==3.1.8 - py3.10-trytond-v8.0.10: lxml==6.1.3 - py3.10-trytond-v8.0.10: MarkupSafe==3.0.3 - py3.10-trytond-v8.0.10: pwdlib==0.3.1 - py3.10-trytond-v8.0.10: argon2-cffi==25.1.0 - py3.10-trytond-v8.0.10: python-sql==1.8.1 - py3.10-trytond-v8.0.10: relatorio==1.0.0 - py3.10-trytond-v8.0.10: Genshi==0.7.11 - py3.10-trytond-v8.0.10: typing_extensions==4.16.0 - py3.10-trytond-v8.0.10: argon2-cffi-bindings==26.1.0 - py3.10-trytond-v8.0.10: cffi==2.1.1 - py3.10-trytond-v8.0.10: defusedxml==0.7.1 - py3.10-trytond-v8.0.10: polib==1.2.0 - py3.10-trytond-v8.0.10: puremagic==1.30 - py3.10-trytond-v8.0.10: pycparser==3.0 - py3.10-trytond-v8.0.10: python-dateutil==2.9.0.post0 - py3.10-trytond-v8.0.10: six==1.17.0 - py3.10-trytond-v8.0.10: simpleeval==1.0.8 - - py3.14-trytond-v8.0.10: Werkzeug==3.1.8 - py3.14-trytond-v8.0.10: lxml==6.1.3 - py3.14-trytond-v8.0.10: MarkupSafe==3.0.3 - py3.14-trytond-v8.0.10: pwdlib==0.3.1 - py3.14-trytond-v8.0.10: argon2-cffi==25.1.0 - py3.14-trytond-v8.0.10: python-sql==1.8.1 - py3.14-trytond-v8.0.10: relatorio==1.0.0 - py3.14-trytond-v8.0.10: Genshi==0.7.11 - py3.14-trytond-v8.0.10: argon2-cffi-bindings==26.1.0 - py3.14-trytond-v8.0.10: cffi==2.1.1 - py3.14-trytond-v8.0.10: defusedxml==0.7.1 - py3.14-trytond-v8.0.10: polib==1.2.0 - py3.14-trytond-v8.0.10: puremagic==2.2.0 - py3.14-trytond-v8.0.10: pycparser==3.0 - py3.14-trytond-v8.0.10: python-dateutil==2.9.0.post0 - py3.14-trytond-v8.0.10: six==1.17.0 - py3.14-trytond-v8.0.10: simpleeval==1.0.8 - - py3.15-trytond-v8.0.10: Werkzeug==3.1.8 - py3.15-trytond-v8.0.10: lxml==6.1.3 - py3.15-trytond-v8.0.10: MarkupSafe==3.0.3 - py3.15-trytond-v8.0.10: pwdlib==0.3.1 - py3.15-trytond-v8.0.10: argon2-cffi==25.1.0 - py3.15-trytond-v8.0.10: python-sql==1.8.1 - py3.15-trytond-v8.0.10: relatorio==1.0.0 - py3.15-trytond-v8.0.10: Genshi==0.7.11 - py3.15-trytond-v8.0.10: argon2-cffi-bindings==26.1.0 - py3.15-trytond-v8.0.10: cffi==2.1.1 - py3.15-trytond-v8.0.10: defusedxml==0.7.1 - py3.15-trytond-v8.0.10: polib==1.2.0 - py3.15-trytond-v8.0.10: puremagic==2.2.0 - py3.15-trytond-v8.0.10: pycparser==3.0 - py3.15-trytond-v8.0.10: python-dateutil==2.9.0.post0 - py3.15-trytond-v8.0.10: six==1.17.0 - py3.15-trytond-v8.0.10: simpleeval==1.0.8 - - py3.15t-trytond-v8.0.10: Werkzeug==3.1.8 - py3.15t-trytond-v8.0.10: lxml==6.1.3 - py3.15t-trytond-v8.0.10: MarkupSafe==3.0.3 - py3.15t-trytond-v8.0.10: pwdlib==0.3.1 - py3.15t-trytond-v8.0.10: argon2-cffi==25.1.0 - py3.15t-trytond-v8.0.10: python-sql==1.8.1 - py3.15t-trytond-v8.0.10: relatorio==1.0.0 - py3.15t-trytond-v8.0.10: Genshi==0.7.11 - py3.15t-trytond-v8.0.10: argon2-cffi-bindings==26.1.0 - py3.15t-trytond-v8.0.10: cffi==2.1.1 - py3.15t-trytond-v8.0.10: defusedxml==0.7.1 - py3.15t-trytond-v8.0.10: polib==1.2.0 - py3.15t-trytond-v8.0.10: puremagic==2.2.0 - py3.15t-trytond-v8.0.10: pycparser==3.0 - py3.15t-trytond-v8.0.10: python-dateutil==2.9.0.post0 - py3.15t-trytond-v8.0.10: six==1.17.0 - py3.15t-trytond-v8.0.10: simpleeval==1.0.8 - - trytond-latest: trytond==8.0.10 - - py3.10-trytond-latest: Werkzeug==3.1.8 - py3.10-trytond-latest: lxml==6.1.3 - py3.10-trytond-latest: MarkupSafe==3.0.3 - py3.10-trytond-latest: pwdlib==0.3.1 - py3.10-trytond-latest: argon2-cffi==25.1.0 - py3.10-trytond-latest: python-sql==1.8.1 - py3.10-trytond-latest: relatorio==1.0.0 - py3.10-trytond-latest: Genshi==0.7.11 - py3.10-trytond-latest: typing_extensions==4.16.0 - py3.10-trytond-latest: argon2-cffi-bindings==26.1.0 - py3.10-trytond-latest: cffi==2.1.1 - py3.10-trytond-latest: defusedxml==0.7.1 - py3.10-trytond-latest: polib==1.2.0 - py3.10-trytond-latest: puremagic==1.30 - py3.10-trytond-latest: pycparser==3.0 - py3.10-trytond-latest: python-dateutil==2.9.0.post0 - py3.10-trytond-latest: six==1.17.0 - py3.10-trytond-latest: simpleeval==1.0.8 - - py3.14-trytond-latest: Werkzeug==3.1.8 - py3.14-trytond-latest: lxml==6.1.3 - py3.14-trytond-latest: MarkupSafe==3.0.3 - py3.14-trytond-latest: pwdlib==0.3.1 - py3.14-trytond-latest: argon2-cffi==25.1.0 - py3.14-trytond-latest: python-sql==1.8.1 - py3.14-trytond-latest: relatorio==1.0.0 - py3.14-trytond-latest: Genshi==0.7.11 - py3.14-trytond-latest: argon2-cffi-bindings==26.1.0 - py3.14-trytond-latest: cffi==2.1.1 - py3.14-trytond-latest: defusedxml==0.7.1 - py3.14-trytond-latest: polib==1.2.0 - py3.14-trytond-latest: puremagic==2.2.0 - py3.14-trytond-latest: pycparser==3.0 - py3.14-trytond-latest: python-dateutil==2.9.0.post0 - py3.14-trytond-latest: six==1.17.0 - py3.14-trytond-latest: simpleeval==1.0.8 - - py3.15-trytond-latest: Werkzeug==3.1.8 - py3.15-trytond-latest: lxml==6.1.3 - py3.15-trytond-latest: MarkupSafe==3.0.3 - py3.15-trytond-latest: pwdlib==0.3.1 - py3.15-trytond-latest: argon2-cffi==25.1.0 - py3.15-trytond-latest: python-sql==1.8.1 - py3.15-trytond-latest: relatorio==1.0.0 - py3.15-trytond-latest: Genshi==0.7.11 - py3.15-trytond-latest: argon2-cffi-bindings==26.1.0 - py3.15-trytond-latest: cffi==2.1.1 - py3.15-trytond-latest: defusedxml==0.7.1 - py3.15-trytond-latest: polib==1.2.0 - py3.15-trytond-latest: puremagic==2.2.0 - py3.15-trytond-latest: pycparser==3.0 - py3.15-trytond-latest: python-dateutil==2.9.0.post0 - py3.15-trytond-latest: six==1.17.0 - py3.15-trytond-latest: simpleeval==1.0.8 - - py3.15t-trytond-latest: Werkzeug==3.1.8 - py3.15t-trytond-latest: lxml==6.1.3 - py3.15t-trytond-latest: MarkupSafe==3.0.3 - py3.15t-trytond-latest: pwdlib==0.3.1 - py3.15t-trytond-latest: argon2-cffi==25.1.0 - py3.15t-trytond-latest: python-sql==1.8.1 - py3.15t-trytond-latest: relatorio==1.0.0 - py3.15t-trytond-latest: Genshi==0.7.11 - py3.15t-trytond-latest: argon2-cffi-bindings==26.1.0 - py3.15t-trytond-latest: cffi==2.1.1 - py3.15t-trytond-latest: defusedxml==0.7.1 - py3.15t-trytond-latest: polib==1.2.0 - py3.15t-trytond-latest: puremagic==2.2.0 - py3.15t-trytond-latest: pycparser==3.0 - py3.15t-trytond-latest: python-dateutil==2.9.0.post0 - py3.15t-trytond-latest: six==1.17.0 - py3.15t-trytond-latest: simpleeval==1.0.8 - - trytond: werkzeug - trytond-v4.6.22: werkzeug<1.0 - trytond-v4.8.18: werkzeug<1.0 + trytond_wsgi-v5.4.20: trytond==5.4.20 + + trytond_wsgi-v5.8.16: trytond==5.8.16 + + py3.8-trytond_wsgi-v5.8.16: Werkzeug==1.0.1 + py3.8-trytond_wsgi-v5.8.16: lxml==6.1.1 + py3.8-trytond_wsgi-v5.8.16: passlib==1.7.4 + py3.8-trytond_wsgi-v5.8.16: python-sql==1.7.0 + py3.8-trytond_wsgi-v5.8.16: relatorio==0.11.1 + py3.8-trytond_wsgi-v5.8.16: Genshi==0.7.11 + py3.8-trytond_wsgi-v5.8.16: polib==1.2.0 + py3.8-trytond_wsgi-v5.8.16: python-dateutil==2.9.0.post0 + py3.8-trytond_wsgi-v5.8.16: wrapt==2.0.1 + py3.8-trytond_wsgi-v5.8.16: six==1.17.0 + py3.8-trytond_wsgi-v5.8.16: importlib_resources==6.4.5 + py3.8-trytond_wsgi-v5.8.16: python-magic==0.4.27 + py3.8-trytond_wsgi-v5.8.16: zipp==3.20.2 + + trytond_wsgi-v6.8.17: trytond==6.8.17 + + py3.8-trytond_wsgi-v6.8.17: Werkzeug==3.0.6 + py3.8-trytond_wsgi-v6.8.17: lxml==6.1.1 + py3.8-trytond_wsgi-v6.8.17: MarkupSafe==2.1.5 + py3.8-trytond_wsgi-v6.8.17: passlib==1.7.4 + py3.8-trytond_wsgi-v6.8.17: python-sql==1.7.0 + py3.8-trytond_wsgi-v6.8.17: relatorio==0.11.1 + py3.8-trytond_wsgi-v6.8.17: Genshi==0.7.11 + py3.8-trytond_wsgi-v6.8.17: defusedxml==0.7.1 + py3.8-trytond_wsgi-v6.8.17: polib==1.2.0 + py3.8-trytond_wsgi-v6.8.17: python-dateutil==2.9.0.post0 + py3.8-trytond_wsgi-v6.8.17: pytz==2026.2 + py3.8-trytond_wsgi-v6.8.17: six==1.17.0 + py3.8-trytond_wsgi-v6.8.17: importlib_resources==6.4.5 + py3.8-trytond_wsgi-v6.8.17: python-magic==0.4.27 + py3.8-trytond_wsgi-v6.8.17: zipp==3.20.2 + + py3.10-trytond_wsgi-v6.8.17: Werkzeug==3.1.8 + py3.10-trytond_wsgi-v6.8.17: lxml==6.1.1 + py3.10-trytond_wsgi-v6.8.17: MarkupSafe==3.0.3 + py3.10-trytond_wsgi-v6.8.17: passlib==1.7.4 + py3.10-trytond_wsgi-v6.8.17: python-sql==1.8.1 + py3.10-trytond_wsgi-v6.8.17: relatorio==0.12.1 + py3.10-trytond_wsgi-v6.8.17: Genshi==0.7.11 + py3.10-trytond_wsgi-v6.8.17: defusedxml==0.7.1 + py3.10-trytond_wsgi-v6.8.17: polib==1.2.0 + py3.10-trytond_wsgi-v6.8.17: python-dateutil==2.9.0.post0 + py3.10-trytond_wsgi-v6.8.17: six==1.17.0 + py3.10-trytond_wsgi-v6.8.17: python-magic==0.4.27 + + py3.11-trytond_wsgi-v6.8.17: Werkzeug==3.1.8 + py3.11-trytond_wsgi-v6.8.17: lxml==6.1.1 + py3.11-trytond_wsgi-v6.8.17: MarkupSafe==3.0.3 + py3.11-trytond_wsgi-v6.8.17: passlib==1.7.4 + py3.11-trytond_wsgi-v6.8.17: python-sql==1.8.1 + py3.11-trytond_wsgi-v6.8.17: relatorio==0.12.1 + py3.11-trytond_wsgi-v6.8.17: Genshi==0.7.11 + py3.11-trytond_wsgi-v6.8.17: defusedxml==0.7.1 + py3.11-trytond_wsgi-v6.8.17: polib==1.2.0 + py3.11-trytond_wsgi-v6.8.17: python-dateutil==2.9.0.post0 + py3.11-trytond_wsgi-v6.8.17: six==1.17.0 + py3.11-trytond_wsgi-v6.8.17: python-magic==0.4.27 + + trytond_wsgi-v7.8.16: trytond==7.8.16 + + py3.9-trytond_wsgi-v7.8.16: Werkzeug==3.1.8 + py3.9-trytond_wsgi-v7.8.16: lxml==6.1.3 + py3.9-trytond_wsgi-v7.8.16: MarkupSafe==3.0.3 + py3.9-trytond_wsgi-v7.8.16: pwdlib==0.2.1 + py3.9-trytond_wsgi-v7.8.16: argon2-cffi==23.1.0 + py3.9-trytond_wsgi-v7.8.16: python-sql==1.8.1 + py3.9-trytond_wsgi-v7.8.16: relatorio==1.0.0 + py3.9-trytond_wsgi-v7.8.16: Genshi==0.7.11 + py3.9-trytond_wsgi-v7.8.16: argon2-cffi-bindings==25.1.0 + py3.9-trytond_wsgi-v7.8.16: cffi==2.0.0 + py3.9-trytond_wsgi-v7.8.16: backports.entry-points-selectable==1.3.0 + py3.9-trytond_wsgi-v7.8.16: defusedxml==0.7.1 + py3.9-trytond_wsgi-v7.8.16: polib==1.2.0 + py3.9-trytond_wsgi-v7.8.16: puremagic==1.30 + py3.9-trytond_wsgi-v7.8.16: pycparser==2.23 + py3.9-trytond_wsgi-v7.8.16: python-dateutil==2.9.0.post0 + py3.9-trytond_wsgi-v7.8.16: six==1.17.0 + py3.9-trytond_wsgi-v7.8.16: simpleeval==1.0.8 + + py3.12-trytond_wsgi-v7.8.16: Werkzeug==3.1.8 + py3.12-trytond_wsgi-v7.8.16: lxml==6.1.3 + py3.12-trytond_wsgi-v7.8.16: MarkupSafe==3.0.3 + py3.12-trytond_wsgi-v7.8.16: pwdlib==0.3.1 + py3.12-trytond_wsgi-v7.8.16: argon2-cffi==25.1.0 + py3.12-trytond_wsgi-v7.8.16: python-sql==1.8.1 + py3.12-trytond_wsgi-v7.8.16: relatorio==1.0.0 + py3.12-trytond_wsgi-v7.8.16: Genshi==0.7.11 + py3.12-trytond_wsgi-v7.8.16: argon2-cffi-bindings==26.1.0 + py3.12-trytond_wsgi-v7.8.16: cffi==2.1.1 + py3.12-trytond_wsgi-v7.8.16: defusedxml==0.7.1 + py3.12-trytond_wsgi-v7.8.16: polib==1.2.0 + py3.12-trytond_wsgi-v7.8.16: puremagic==2.2.0 + py3.12-trytond_wsgi-v7.8.16: pycparser==3.0 + py3.12-trytond_wsgi-v7.8.16: python-dateutil==2.9.0.post0 + py3.12-trytond_wsgi-v7.8.16: six==1.17.0 + py3.12-trytond_wsgi-v7.8.16: simpleeval==1.0.8 + + py3.13-trytond_wsgi-v7.8.16: Werkzeug==3.1.8 + py3.13-trytond_wsgi-v7.8.16: lxml==6.1.3 + py3.13-trytond_wsgi-v7.8.16: MarkupSafe==3.0.3 + py3.13-trytond_wsgi-v7.8.16: pwdlib==0.3.1 + py3.13-trytond_wsgi-v7.8.16: argon2-cffi==25.1.0 + py3.13-trytond_wsgi-v7.8.16: python-sql==1.8.1 + py3.13-trytond_wsgi-v7.8.16: relatorio==1.0.0 + py3.13-trytond_wsgi-v7.8.16: Genshi==0.7.11 + py3.13-trytond_wsgi-v7.8.16: argon2-cffi-bindings==26.1.0 + py3.13-trytond_wsgi-v7.8.16: cffi==2.1.1 + py3.13-trytond_wsgi-v7.8.16: defusedxml==0.7.1 + py3.13-trytond_wsgi-v7.8.16: polib==1.2.0 + py3.13-trytond_wsgi-v7.8.16: puremagic==2.2.0 + py3.13-trytond_wsgi-v7.8.16: pycparser==3.0 + py3.13-trytond_wsgi-v7.8.16: python-dateutil==2.9.0.post0 + py3.13-trytond_wsgi-v7.8.16: six==1.17.0 + py3.13-trytond_wsgi-v7.8.16: simpleeval==1.0.8 + + trytond_wsgi-v8.0.10: trytond==8.0.10 + + py3.10-trytond_wsgi-v8.0.10: Werkzeug==3.1.8 + py3.10-trytond_wsgi-v8.0.10: lxml==6.1.3 + py3.10-trytond_wsgi-v8.0.10: MarkupSafe==3.0.3 + py3.10-trytond_wsgi-v8.0.10: pwdlib==0.3.1 + py3.10-trytond_wsgi-v8.0.10: argon2-cffi==25.1.0 + py3.10-trytond_wsgi-v8.0.10: python-sql==1.8.1 + py3.10-trytond_wsgi-v8.0.10: relatorio==1.0.0 + py3.10-trytond_wsgi-v8.0.10: Genshi==0.7.11 + py3.10-trytond_wsgi-v8.0.10: typing_extensions==4.16.0 + py3.10-trytond_wsgi-v8.0.10: argon2-cffi-bindings==26.1.0 + py3.10-trytond_wsgi-v8.0.10: cffi==2.1.1 + py3.10-trytond_wsgi-v8.0.10: defusedxml==0.7.1 + py3.10-trytond_wsgi-v8.0.10: polib==1.2.0 + py3.10-trytond_wsgi-v8.0.10: puremagic==1.30 + py3.10-trytond_wsgi-v8.0.10: pycparser==3.0 + py3.10-trytond_wsgi-v8.0.10: python-dateutil==2.9.0.post0 + py3.10-trytond_wsgi-v8.0.10: six==1.17.0 + py3.10-trytond_wsgi-v8.0.10: simpleeval==1.0.8 + + py3.14-trytond_wsgi-v8.0.10: Werkzeug==3.1.8 + py3.14-trytond_wsgi-v8.0.10: lxml==6.1.3 + py3.14-trytond_wsgi-v8.0.10: MarkupSafe==3.0.3 + py3.14-trytond_wsgi-v8.0.10: pwdlib==0.3.1 + py3.14-trytond_wsgi-v8.0.10: argon2-cffi==25.1.0 + py3.14-trytond_wsgi-v8.0.10: python-sql==1.8.1 + py3.14-trytond_wsgi-v8.0.10: relatorio==1.0.0 + py3.14-trytond_wsgi-v8.0.10: Genshi==0.7.11 + py3.14-trytond_wsgi-v8.0.10: argon2-cffi-bindings==26.1.0 + py3.14-trytond_wsgi-v8.0.10: cffi==2.1.1 + py3.14-trytond_wsgi-v8.0.10: defusedxml==0.7.1 + py3.14-trytond_wsgi-v8.0.10: polib==1.2.0 + py3.14-trytond_wsgi-v8.0.10: puremagic==2.2.0 + py3.14-trytond_wsgi-v8.0.10: pycparser==3.0 + py3.14-trytond_wsgi-v8.0.10: python-dateutil==2.9.0.post0 + py3.14-trytond_wsgi-v8.0.10: six==1.17.0 + py3.14-trytond_wsgi-v8.0.10: simpleeval==1.0.8 + + py3.15-trytond_wsgi-v8.0.10: Werkzeug==3.1.8 + py3.15-trytond_wsgi-v8.0.10: lxml==6.1.3 + py3.15-trytond_wsgi-v8.0.10: MarkupSafe==3.0.3 + py3.15-trytond_wsgi-v8.0.10: pwdlib==0.3.1 + py3.15-trytond_wsgi-v8.0.10: argon2-cffi==25.1.0 + py3.15-trytond_wsgi-v8.0.10: python-sql==1.8.1 + py3.15-trytond_wsgi-v8.0.10: relatorio==1.0.0 + py3.15-trytond_wsgi-v8.0.10: Genshi==0.7.11 + py3.15-trytond_wsgi-v8.0.10: argon2-cffi-bindings==26.1.0 + py3.15-trytond_wsgi-v8.0.10: cffi==2.1.1 + py3.15-trytond_wsgi-v8.0.10: defusedxml==0.7.1 + py3.15-trytond_wsgi-v8.0.10: polib==1.2.0 + py3.15-trytond_wsgi-v8.0.10: puremagic==2.2.0 + py3.15-trytond_wsgi-v8.0.10: pycparser==3.0 + py3.15-trytond_wsgi-v8.0.10: python-dateutil==2.9.0.post0 + py3.15-trytond_wsgi-v8.0.10: six==1.17.0 + py3.15-trytond_wsgi-v8.0.10: simpleeval==1.0.8 + + py3.15t-trytond_wsgi-v8.0.10: Werkzeug==3.1.8 + py3.15t-trytond_wsgi-v8.0.10: lxml==6.1.3 + py3.15t-trytond_wsgi-v8.0.10: MarkupSafe==3.0.3 + py3.15t-trytond_wsgi-v8.0.10: pwdlib==0.3.1 + py3.15t-trytond_wsgi-v8.0.10: argon2-cffi==25.1.0 + py3.15t-trytond_wsgi-v8.0.10: python-sql==1.8.1 + py3.15t-trytond_wsgi-v8.0.10: relatorio==1.0.0 + py3.15t-trytond_wsgi-v8.0.10: Genshi==0.7.11 + py3.15t-trytond_wsgi-v8.0.10: argon2-cffi-bindings==26.1.0 + py3.15t-trytond_wsgi-v8.0.10: cffi==2.1.1 + py3.15t-trytond_wsgi-v8.0.10: defusedxml==0.7.1 + py3.15t-trytond_wsgi-v8.0.10: polib==1.2.0 + py3.15t-trytond_wsgi-v8.0.10: puremagic==2.2.0 + py3.15t-trytond_wsgi-v8.0.10: pycparser==3.0 + py3.15t-trytond_wsgi-v8.0.10: python-dateutil==2.9.0.post0 + py3.15t-trytond_wsgi-v8.0.10: six==1.17.0 + py3.15t-trytond_wsgi-v8.0.10: simpleeval==1.0.8 + + trytond_wsgi-latest: trytond==8.0.10 + + py3.10-trytond_wsgi-latest: Werkzeug==3.1.8 + py3.10-trytond_wsgi-latest: lxml==6.1.3 + py3.10-trytond_wsgi-latest: MarkupSafe==3.0.3 + py3.10-trytond_wsgi-latest: pwdlib==0.3.1 + py3.10-trytond_wsgi-latest: argon2-cffi==25.1.0 + py3.10-trytond_wsgi-latest: python-sql==1.8.1 + py3.10-trytond_wsgi-latest: relatorio==1.0.0 + py3.10-trytond_wsgi-latest: Genshi==0.7.11 + py3.10-trytond_wsgi-latest: typing_extensions==4.16.0 + py3.10-trytond_wsgi-latest: argon2-cffi-bindings==26.1.0 + py3.10-trytond_wsgi-latest: cffi==2.1.1 + py3.10-trytond_wsgi-latest: defusedxml==0.7.1 + py3.10-trytond_wsgi-latest: polib==1.2.0 + py3.10-trytond_wsgi-latest: puremagic==1.30 + py3.10-trytond_wsgi-latest: pycparser==3.0 + py3.10-trytond_wsgi-latest: python-dateutil==2.9.0.post0 + py3.10-trytond_wsgi-latest: six==1.17.0 + py3.10-trytond_wsgi-latest: simpleeval==1.0.8 + + py3.14-trytond_wsgi-latest: Werkzeug==3.1.8 + py3.14-trytond_wsgi-latest: lxml==6.1.3 + py3.14-trytond_wsgi-latest: MarkupSafe==3.0.3 + py3.14-trytond_wsgi-latest: pwdlib==0.3.1 + py3.14-trytond_wsgi-latest: argon2-cffi==25.1.0 + py3.14-trytond_wsgi-latest: python-sql==1.8.1 + py3.14-trytond_wsgi-latest: relatorio==1.0.0 + py3.14-trytond_wsgi-latest: Genshi==0.7.11 + py3.14-trytond_wsgi-latest: argon2-cffi-bindings==26.1.0 + py3.14-trytond_wsgi-latest: cffi==2.1.1 + py3.14-trytond_wsgi-latest: defusedxml==0.7.1 + py3.14-trytond_wsgi-latest: polib==1.2.0 + py3.14-trytond_wsgi-latest: puremagic==2.2.0 + py3.14-trytond_wsgi-latest: pycparser==3.0 + py3.14-trytond_wsgi-latest: python-dateutil==2.9.0.post0 + py3.14-trytond_wsgi-latest: six==1.17.0 + py3.14-trytond_wsgi-latest: simpleeval==1.0.8 + + py3.15-trytond_wsgi-latest: Werkzeug==3.1.8 + py3.15-trytond_wsgi-latest: lxml==6.1.3 + py3.15-trytond_wsgi-latest: MarkupSafe==3.0.3 + py3.15-trytond_wsgi-latest: pwdlib==0.3.1 + py3.15-trytond_wsgi-latest: argon2-cffi==25.1.0 + py3.15-trytond_wsgi-latest: python-sql==1.8.1 + py3.15-trytond_wsgi-latest: relatorio==1.0.0 + py3.15-trytond_wsgi-latest: Genshi==0.7.11 + py3.15-trytond_wsgi-latest: argon2-cffi-bindings==26.1.0 + py3.15-trytond_wsgi-latest: cffi==2.1.1 + py3.15-trytond_wsgi-latest: defusedxml==0.7.1 + py3.15-trytond_wsgi-latest: polib==1.2.0 + py3.15-trytond_wsgi-latest: puremagic==2.2.0 + py3.15-trytond_wsgi-latest: pycparser==3.0 + py3.15-trytond_wsgi-latest: python-dateutil==2.9.0.post0 + py3.15-trytond_wsgi-latest: six==1.17.0 + py3.15-trytond_wsgi-latest: simpleeval==1.0.8 + + py3.15t-trytond_wsgi-latest: Werkzeug==3.1.8 + py3.15t-trytond_wsgi-latest: lxml==6.1.3 + py3.15t-trytond_wsgi-latest: MarkupSafe==3.0.3 + py3.15t-trytond_wsgi-latest: pwdlib==0.3.1 + py3.15t-trytond_wsgi-latest: argon2-cffi==25.1.0 + py3.15t-trytond_wsgi-latest: python-sql==1.8.1 + py3.15t-trytond_wsgi-latest: relatorio==1.0.0 + py3.15t-trytond_wsgi-latest: Genshi==0.7.11 + py3.15t-trytond_wsgi-latest: argon2-cffi-bindings==26.1.0 + py3.15t-trytond_wsgi-latest: cffi==2.1.1 + py3.15t-trytond_wsgi-latest: defusedxml==0.7.1 + py3.15t-trytond_wsgi-latest: polib==1.2.0 + py3.15t-trytond_wsgi-latest: puremagic==2.2.0 + py3.15t-trytond_wsgi-latest: pycparser==3.0 + py3.15t-trytond_wsgi-latest: python-dateutil==2.9.0.post0 + py3.15t-trytond_wsgi-latest: six==1.17.0 + py3.15t-trytond_wsgi-latest: simpleeval==1.0.8 + + trytond_wsgi: werkzeug + trytond_wsgi-v5.4.20: werkzeug<2.0 typer-v0.15.4: typer==0.15.4 @@ -19355,10 +19015,7 @@ deps = ; Install the SDK in deps so uv resolves runtime deps together with ; everything above in a single pass. - ; uv only supports PEP 660 editables; py3.6's max setuptools (~59) predates - ; PEP 660, so fall back to a non-editable install there. !py3.6: -e . - py3.6: . setenv = PYTHONDONTWRITEBYTECODE=1 @@ -19369,8 +19026,9 @@ setenv = UV_PRERELEASE=if-necessary-or-explicit sqlalchemy-v2.1.0rc2: UV_PRERELEASE=allow gql-v4.4.0b0: UV_PRERELEASE=allow - - py3.6: COVERAGE_RCFILE=.coveragerc36 + beam-v2.77.0rc1: UV_PRERELEASE=allow + celery-v5.7.0a1: UV_PRERELEASE=allow + tornado-v6.6a1: UV_PRERELEASE=allow django: DJANGO_SETTINGS_MODULE=tests.integrations.django.myapp.settings spark-v{3.0.3,3.5.6}: JAVA_HOME=/usr/lib/jvm/temurin-11-jdk-amd64 @@ -19388,15 +19046,12 @@ setenv = # TESTPATH definitions for test suites not managed by toxgen common: _TESTPATH=tests gevent: _TESTPATH=tests - integration_deactivation: _TESTPATH=tests/test_ai_integration_deactivation.py shadowed_module: _TESTPATH=tests/test_shadowed_module.py asgi: _TESTPATH=tests/integrations/asgi aws_lambda: _TESTPATH=tests/integrations/aws_lambda cloud_resource_context: _TESTPATH=tests/integrations/cloud_resource_context gcp: _TESTPATH=tests/integrations/gcp - opentelemetry: _TESTPATH=tests/integrations/opentelemetry otlp: _TESTPATH=tests/integrations/otlp - potel: _TESTPATH=tests/integrations/opentelemetry socket: _TESTPATH=tests/integrations/socket # These TESTPATH definitions are auto-generated by toxgen @@ -19448,7 +19103,6 @@ setenv = quart: _TESTPATH=tests/integrations/quart ray: _TESTPATH=tests/integrations/ray redis: _TESTPATH=tests/integrations/redis - redis_py_cluster_legacy: _TESTPATH=tests/integrations/redis_py_cluster_legacy requests: _TESTPATH=tests/integrations/requests rq: _TESTPATH=tests/integrations/rq sanic: _TESTPATH=tests/integrations/sanic @@ -19459,7 +19113,7 @@ setenv = statsig: _TESTPATH=tests/integrations/statsig strawberry: _TESTPATH=tests/integrations/strawberry tornado: _TESTPATH=tests/integrations/tornado - trytond: _TESTPATH=tests/integrations/trytond + trytond_wsgi: _TESTPATH=tests/integrations/trytond_wsgi typer: _TESTPATH=tests/integrations/typer unleash: _TESTPATH=tests/integrations/unleash @@ -19474,7 +19128,6 @@ passenv = TESTPATH basepython = - py3.6: python3.6 py3.7: python3.7 py3.8: python3.8 py3.9: python3.9